【问题标题】:Is it possible to read process memory of a 64 bit process from a 32bit app?是否可以从 32 位应用程序读取 64 位进程的进程内存?
【发布时间】:2011-08-08 12:42:03
【问题描述】:

在 Windows 64 位上,我有一个 32 位进程可以读取其他 32 位进程的内存,我希望它也能够读取 64 位进程。

ReadProcessMemory 用于读取内存,但它有 32 位限制。有什么方法可以在 64 位进程上执行相当于 ReadProcessMemory 的操作吗?

我知道我可以编写一个 64 位进程并从我的 32 位进程启动它来完成这项工作,但我想知道是否还有其他选择,这样我就不需要编写 64 位进程了。

谢谢。

【问题讨论】:

    标签: windows 32bit-64bit


    【解决方案1】:

    有可能。

    例如,您可以参考tofucoder答案中的优秀示例。 如需更多示例,您可以参考to this link

    要解释为什么它实际上有效,请check this thread

    可以找到另一个样本here

    整个技巧是调用 64 位版本的 ReadProcessMemory 函数。直观地说,这不是 32 位进程的选项,但上面的链接解释说:x64 版本的ntdll.dll 也作为 Windows WOW64 模拟器中 32 位进程的一部分加载。它有一个名为NtReadVirtualMemory 的函数,其原型与ReadProcessMemory64 相同:

    __declspec(SPEC)BOOL __cdecl ReadProcessMemory64(HANDLE hProcess, DWORD64 lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T *lpNumberOfBytesRead);
    

    地址是64位长的,因此可以引用整个64位进程的虚拟地址空间。

    你可能想知道如何获取这个函数的地址。这时 ntdll.dll 中的另一个函数派上用场了:LdrGetProcedureAddress。它的原型和GetProcAddress一样:

    __declspec(SPEC)DWORD64 __cdecl GetProcAddress64(DWORD64 hModule, char* funcName);
    

    我们要检查x64的导出目录ntdll.dll,手动找到这个函数的入口。然后我们可以获取任何其他函数的地址。

    目前还有一个问题没有解决:如何获取x64ntdll.dll的起始地址?我们需要手动遍历进程的 x64 PEB 结构并遍历已加载模块的列表 - 作为变体之一。以及如何获得PEB地址?请参考上面的链接,不要过多的细节溢出这篇文章。

    所有这些都包含在第一个链接的示例中。 第二个和第三个链接中提供了使用NtReadVirtualMemoryNtWow64ReadVirtualMemory64 函数的替代变体(以及获取PEB 地址的替代方法)。

    总结:可以从 x86 one 开始与 x64 进程交互。可以通过直接调用 x64 版本的函数(从作为 WOW64 进程的一部分加载的 x64 ntdll.dll)或调用旨在与 x64 进程一起使用的特定 x86 函数来完成(即 NtWow64ReadVirtualMemory64 )。

    附:有人可能会说它没有记录,更像是 hack - 但它只是没有正式记录。例如,UnlockerProcessHackerProcessExplorer 之类的软函数利用了这些未记录的功能(以及更多),当然,这由您决定。

    【讨论】:

      【解决方案2】:

      wow64ext 似乎已经解决了这个问题并提供了一个函数ReadProcessMemory64 Visual Studio 扩展VSDebugTool 似乎使用了这个库,并且适用于64 位进程。

      无论如何,这不应该是不可能的,因为(32 位)Visual Studio 调试器可以很好地处理 64 位调试器。

      【讨论】:

        【解决方案3】:
        【解决方案4】:

        没有办法解决这个问题。一种解决方案是停止使用 WOW64 模拟器并编写 64 位进程。另一种解决方案是使用 IPC 而不是直接读取内存。

        【讨论】:

        • 您可以编写一个驱动程序来执行此操作,但考虑到替代方案,这太过分了。只需编写一个 64 位的辅助进程即可。
        • 其实用WOW64系统是有办法的。 github.com/rwfpl/rewolf-wow64ext
        【解决方案5】:

        ReadProcessMemory 可以读取任何大小的内存,包括从 x86 进程读取 x64 进程。

        您可以毫无问题地在 x86 程序中执行以下操作:

        DWORD64 test = 0;
        ReadProcessMemory(hProcess, (LPCVOID)lpBaseAddress, &test, sizeof(DWORD64), NULL);
        

        这将允许您从 x86 进程中取消引用 x64 指针。

        【讨论】:

        • nSize 指定要从目标进程读取的字节数,而不是指针的大小,参见。 msdn.microsoft.com/en-us/library/windows/desktop/…
        • @hillu 我从来没有这么说过。我一直在读取和读取 x86 和 x64 进程,没有问题。
        • 在 32 位应用程序中,像 LPCVOID 这样的指针最大大小为 32 位。是否将目标 64 位地址存储在 DWORD64 变量中并不重要,当类型转换为 32 位指针时,它将被截断。因此,您根本无法使用 32 位版本的 ReadProcessMemory() 从 32 位应用程序读取高于 0xFFFFFFFF 的目标 64 位内存地址,它不适合 32 位指针。
        猜你喜欢
        • 2017-03-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-01-19
        • 2013-03-11
        • 2018-05-15
        • 2012-01-19
        相关资源
        最近更新 更多