如何获取进程使用的所有内存地址空间?

问题描述:

我需要知道进程使用的所有内存地址空间。内存空间稍后将被扫描以定位过程中的值并标识其位置/地址。我目前的过程是通过其基地址+内存大小来获取每个模块的基地址。如何获取进程使用的所有内存地址空间?

我在一个已知地址的已知值的进程上测试它。当我查找具体的地址时,我可以得到我期望的价值。但是,当我扫描(我相信是)进程使用的所有地址空间时,我无法在任何地方找到该值。

我知道一个数值 “4143000” 存在于0x0CF8DC380x0CF8DDDC。当我调用ReadMemoryBytes(module,module.BaseAddress,4,(IntPtr)(0x0CF8DC38))我得到字节(152,55,63,0)。当我调用BitConverter.GetBytes(4143000)时,我得到了相同的一组字节。当我在这个过程中使用不同的内存扫描器时,我发现这些地址的价值。

但是,当我扫描“已知地址”时,我不会在任何地方找到此值。它看起来并不像我的代码甚至找到了这个进程正在使用的地址。

正是如此,我的问题是双重的:

  • 我如何才能找到这个过程中这些地址?
  • 我很担心我可能正在处理系统内存中的绝对地址与进程内的相对地址。我做对了吗?

// (in the calling method) 
foreach (ProcessModule module in process.Modules) { 
    ParameterizedThreadStart pst = new ParameterizedThreadStart(p => SearchModule(module, value)); 
    Thread t = new Thread(pst); 
    t.Start(); } 

private unsafe void SearchModule(ProcessModule module, string value) 
{ 
Process process = getProcess; 
int iVal; 
double dVal; 
int.TryParse(value, out iVal); 
double.TryParse(value, out dVal); 
for (Int64 addr = (Int64)module.BaseAddress; addr + value.Length < (Int64)module.BaseAddress + module.ModuleMemorySize; addr++) 
{ 
    // Compare ints 
    if (iVal > 0) 
    { 
     byte[] ExpectedBytes = BitConverter.GetBytes(iVal); 
     byte[] ActualBytes = ReadMemoryBytes(module, (IntPtr)addr, (uint)ExpectedBytes.Length, (IntPtr)addr); 

     bool isMatch = true; 
     for (int i = 0; i < ExpectedBytes.Length; i++) 
      if (ExpectedBytes[i] != ActualBytes[i]) 
       isMatch = false; 
     if (isMatch) 
      PossibleAddresses.Add((IntPtr)addr); 
    } 
} 

private byte[] ReadMemoryBytes(ProcessModule mod, IntPtr memAddress, uint size, IntPtr BaseAddress) 
{ 
    byte[] buffer = new byte[size]; 
    IntPtr bytesRead; 
    unsafe 
    { 
     ReadProcessMemory(processPointer, BaseAddress, buffer, size, out bytesRead); 
     return buffer; 
    } 
} 

[DllImport("kernel32.dll")] 
public static extern IntPtr OpenProcess(UInt32 dwDesiredAccess, Int32 bInheritHandle, UInt32 dwProcessId); 
[DllImport("kernel32.dll")] 
public static extern Int32 CloseHandle(IntPtr hObject); 
[DllImport("kernel32.dll")] 
public static extern Int32 ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [In, Out] byte[] buffer, UInt32 size, out IntPtr lpNumberOfBytesRead); 
+0

您错误的假设是(来自MSDN):“ModuleMemorySize不包含模块运行后的任何额外内存分配;它只包含模块文件中静态代码和数据的大小。”所以你的循环并不是无处不在。你需要的是整个过程的内存映射,但我不确定你在C#中如何做到这一点。 sysinternals VMMap工具可以实现,但没有可用的源代码...(http://technet.microsoft.com/en-us/sysinternals/dd535533) – Joe 2011-08-10 02:58:50

您得到的地址是指向托管(CLR)堆的指针。他们通常不会映射到绝对内存地址,并且他们可以在GC决定运行时从呼叫转移到呼叫。

如果使用“不安全”代码,您可以获取相对指针以及管理自己的内存空间。它仍然在堆上,但至少你保证GC不会修改你的地址空间。

不要期望能够从非CLR代码的堆中访问事物,而不需要大量的包装。在CLR管理的流程之间有办法执行IPC,但是如果您想让非CLR流程进入您的内存,您必须将访问代理写入“外部世界”。