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

6
我需要知道进程使用的所有内存地址空间。稍后将扫描内存空间以查找进程中的值并确定它们的位置/地址。我目前的处理方式是通过每个模块的基地址加上其内存大小来获取每个模块的基地址。
我正在测试一个具有已知值和已知地址的进程。当我查看该特定地址时,我得到了我预期的值。但是,当我扫描了(我认为的)进程使用的所有地址空间时,我无法在任何地方找到该值。
我知道数字值“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);

你的错误假设是(来自MSDN):“ModuleMemorySize不包括模块在运行后进行的任何其他内存分配;它仅包括模块文件中静态代码和数据的大小。”所以你的循环并没有遍历到所有地方。你需要的是进程的整体内存映射,但我不确定你如何在C#中实现这一点。Sysinternals VMMap工具可以做到这一点,但没有可用的源代码...(http://technet.microsoft.com/en-us/sysinternals/dd535533) - Joe
1个回答

1

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

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

不要指望能够在非CLR代码中访问堆上的内容而不进行广泛的包装。有方法在CLR管理的进程之间进行IPC,但如果您想让非CLR进程访问您的内存,则必须编写访问代理到“外部世界”的代码。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接