2013-06-05 39 views
0

所以我一直在通过问题与外部进程内存读取(读取进程的内存我不能访问。)我已经改变了,但有一件事我只是我无法理解我的头脑。内存在Windows中如何工作?

的Win32API函数ReadProcessMemory()接受几个参数,如下所示:

public static extern Int32 ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, 
     [In, Out] byte[] buffer, UInt32 size, out IntPtr lpNumberOfBytesRead); 

我传递这些参数是这样的:

public byte[] ReadBytes(IntPtr Handle, Int64 Address, uint BytesToRead) 
    { 
     IntPtr ptrBytesRead; 
     byte[] buffer = new byte[BytesToRead]; 
     ReadProcessMemory(Handle, new IntPtr(Address), buffer, BytesToRead, out ptrBytesRead); 
     return buffer; 
    } 

那是,直到最近,我的理解是这里列出的地址对于阅读内存来说是唯一非常重要的事情,这就是我在内存中找到的正确值。不幸的是,这似乎是一个托什的负担,而且看起来实际上这个句柄控制着我与之交互的那个窗口。例如:

我正在运行“Notepad.exe”进程的2个版本。

过程的每个实例有一个整数,第一个包含数字12345,第二个是包含54321

我期待读取整数,并让我们说(虽然我还没有证实了这一点,所以它可能是不真实的)该程序内存空间内存地址是0x1000。

如果我例如运行:

ReadProcessMemory(NP.Handle, NP.MainModule.BaseAddress + 0x1000, buffer, 32, bread); 

这将与手柄阅读的过程中,在该基地的地址添加到该偏移。然而这段代码将读取完全相同的值:

ReadProcessMemory(NP.Handle, NP2.MainModule.BaseAddress + 0x1000, buffer, 32, bread); 

注意NP2应该是第二个记事本窗口,NP是第一。在上述的顶部,这将读出的不同的值(尽管我们正在阅读是相同的与第一示例中的地址的):

ReadProcessMemory(NP2.Handle, NP.MainModule.BaseAddress + 0x1000, buffer, 32, bread); 

当然这意味着该把手控制,其中存储器是阅读,而不是地址,而且事实上这个地址与我实际上想要做的事情完全不相关?任何人都可以向我解释为什么会是这种情况?

道歉,如果这个问题过于具体,但这个问题一直困扰着我的脑子很长一段时间了,虽然我每天都和很多程序员说话,但他们都没有能够(或者更多他们不愿意)帮助我。

我完全意识到这只适用于同一个exe的2个运行实例,所以如果你要阅读Firefox和记事本(我认为),它将不起作用。我只是想知道为什么它是这个改变的句柄,而不是地址。

感谢

+2

由于您仅从基址读取4k,我怀疑您正在读取内存的可执行部分,这对于'notepad.exe'进程都是相同的。你有没有尝试过读两个不同的程序?两个过程的价值在这个位置是完全可行的。 – Steve

+0

“完全相同的价值”是什么意思?同样的答案,当它不应该? –

+0

@Steve - 我明白你的意思,实际上我没有使用记事本,但另一个程序,我怀疑这里会有人,记事本只是作为一个例子。我实际读取的偏移量是一个结构数组的一部分(在我注意到这个“问题”的情况下),并且距基数的偏移量为0x553008)。 (还是)感谢你的建议。 – XtrmJosh

回答

2

那是,直到最近,我的理解是,这里所列出的地址是读取存储真正重要的唯一的事情,那是什么找到了我记忆中正确的值。不幸的是,这似乎是一个托什的负担,而且看起来实际上这个句柄控制着我与之交互的那个窗口。

在这一段里有很多关于你在做什么的错误理解,我不确定从哪里开始。

但在这里不用(假设这是不完整):

阅读我没有访问进程的内存

你不能。

如果您没有足够的权限访问目标进程,Windows安全将阻止您获得具有必要权限的进程的句柄。 (如果情况并非如此,则不存在安全性。)

但是,我们将假设读取过程使用调试或具有足够访问权限的同等权限运行(这就是为什么,这部分被称为“上帝特权“允许持有者绕过安全)。

哪个窗口

你需要一个过程手柄,而不是一个窗口句柄手柄控制:他们是完全不同的事情。使用OpenProcess从进程ID获取进程句柄,读取内存请求的访问权限包括PROCESS_VM_READ

他们你需要利用Windows进程的(虚拟)内存布局知识来确定你需要读取哪些地址。请记住,ASLR和32与64位进程将改变该内存布局。另外分配的地址空间不太可能是连续的,所以你不能仅仅依次读取内存。

这是一个高级主题。最后几乎总是有一个更好的方法(适当的API,使用SendMessage来请求控件的内容,...),而不是直接读取进程内存(记住对一个DLL的小改动 - 例如来自安全补丁 - 将转移事物)。

摘要:找到另一种更好的方法。

编辑:一些资源来了解内存在Windows中:

  1. Mysteries of Memory Management Revealed,with Mark Russinovich (Part 1 of 2)
  2. Mysteries of Memory Management Revealed,with Mark Russinovich (Part 2 of 2)

    的两个部分谈话(第1部分:虚拟内存,第2部分:物理),也即会引入一些 非常有用的工具来查看内存以及它是如何组织的。

  3. 阅读Windows Internals,Mark Russinovich et al。 (并非所有的都是相关的,但你也需要了解Win32的安全性)。

  4. 阅读高级视窗,Jeffrey Richter。我认为这已经绝版了(我的第三版涵盖了Win95/NT4),但它是对于读取进程内存并解释结果所需知道的唯一严重信息。

+0

高度赞赏你的回应,但找到另一种更好的方式并不可行。如上所述,我没有直接访问该程序,并且我也不太了解开发人员要求他们做出任何更改。 ReadProcessMemory函数几乎是完美的,因为我希望尽可能少地与程序交互,主要替代方法可能是注入或像素解释,注入对于此目的有点过分,并且像素读取会需要一些强烈的算法,计算单词和什么不... – XtrmJosh

+0

@XtrmJosh:我已经添加了一些资源,你可以用作你需要的基本知识(一个[SO]答案只能在这里表面划伤)。还有关于编写Win32调试器的任何内容都可能会有所帮助(但是从内存管理的基础知识开始:例如理解物理和进程内存几乎完全不相关的原因)。了解其他开发人员*会更容易*(他们可能很乐意提供帮助)。 – Richard

相关问题