【问题标题】:Marshal.Copy vs ReadProcessMemory / WriteProcessMemory win32 api - in the same processMarshal.Copy vs ReadProcessMemory / WriteProcessMemory win32 api - 在同一个过程中
【发布时间】:2012-05-30 23:21:03
【问题描述】:

我想知道是否有人可以概述在 Windows .NET (C#/VB.net) 应用程序中使用 ReadProcessMemory/WriteProcessMemory 而不是 Marshal.Copy 的主要区别、利弊写入应用程序进程的内存(不是其他进程的内存)。特别是对于涉及进程内存中任意地址的操作以及将内存块作为字节数组处理(即读取/写入原始数据)。

Marshal.Copy 是否适用于 ReadProcessMemory/WriteProcessMemory 工作的所有情况,还是更受限制?

Marshal.Copy 的实现是否在内部使用ReadProcessMemory/WriteProcessMemory API?

澄清一下:我说的是读取/写入调用(拥有)进程的内存,而不是其他进程的内存!

谢谢。

【问题讨论】:

    标签: .net winapi memory readprocessmemory interopservices


    【解决方案1】:

    ReadProcessMemoryWriteProcessMemory 是本机 Win32 API,允许您从不同进程的内存中读取和写入。您只需要在尝试在不同进程中读取和写入内存时使用这些 API。正如您可能想象的那样,它们在日常开发中并不经常使用。

    Marshal.Copy 用于在托管和非托管内存之间进行复制,但在同一进程内。

    Marshal.Copy 会在 ReadProcessMemory/WriteProcessMemory 工作的所有情况下工作,还是更具限制性?

    不,Marshal.Copy 仅限于在单个进程中操作。

    Marshal.Copy 的实现是否在内部使用 ReadProcessMemory/WriteProcessMemory API?

    没有。

    澄清一下:我说的是读取/写入调用(拥有)进程的内存,而不是其他进程的内存!

    在这种情况下,ReadProcessMemoryWriteProcessMemory 根本不适合您的需求。

    【讨论】:

    • 感谢您的解释!我唯一不确定的是 ReadProcessMemory/WriteProcessMemory 都有关联的 bytesRead/Written 参数,而 Marshal.Copy 没有。例如,如果我使用 ReadProcessMemory 将加载的模块读入托管字节数组,我通过查看 ReadProcessMemory 提供的读取字节数来知道模块的大小。我不能对 Marshal.Copy 做同样的事情,这似乎需要我提前知道我将从内存中读取的模块的大小。
    • 不行,在使用ReadProcessMemory的时候你也得提前知道。您通过nSize 参数传递该信息。 lpNumberOfBytesRead 参数只是告诉您实际读取了多少字节。在Marshal.Copy 中,如果由于某种原因无法读取所有字节,则会引发异常。您根本不想与ReadProcessMemoryWriteProcessMemory 有任何关系。它们不适合你。
    • 是的,我知道 nSize 实际上类似于长度参数,但填充 lpNumberOfBytesRead 参数有一个很好的副作用,我会知道模块的确切大小。换句话说,对于 nSize 我可以猜测我想要读取的字节数,例如传递两倍的值,然后通过查看 lpNumberOfBytesRead 我会知道我感兴趣的数据的实际大小。请记住,仅在读取加载的程序集模块时,我将如何使用 Marshal.Copy 完成类似的任务?
    • 我不确定您是如何加载这些“组装模块”的,或者它们实际上是什么,但我敢打赌,无论您使用哪种机制,都可以通过某种方式告诉您内存块有多大是。 lpNumberOfBytesRead 不适合您描述的方式使用。
    • 这些模块是常规的 .net 汇编模块...在我调用 ReadProcessMemory(Process.GetCurrentProcess().Handle, Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]) 之后, ByteArrayLargeEnoughToHoldData, ArrayLengthBiggerThanModule, out ActualBytesReadIEModuleSize);我可以根据 ActualBytesReadIEModuleSize 调整 ByteArrayLargeEnoughToHoldData 的大小。如何用 Marshal.Copy 做同样的事情还不清楚......甚至可能吗?
    【解决方案2】:

    Marshal.Copy() 不是 Read/WriteProcessMemory() 的替代品。它无法进入进程的地址空间并访问该进程拥有的内存。最强烈的暗示是,它没有需要进程句柄的重载。

    请记住,Windows 中的每个进程都有自己的虚拟内存地址空间。一个进程中的指针在另一个进程中不可用。这是 Windows 提供的进程隔离的重要组成部分,可防止进程相互破坏。并且提供安全保证,如果进程不属于同一用户,则使用 ReadProcessMemory() 需要管理员权限。进程句柄必须通过在 OpenProcess() 调用中指定 PROCESS_VM_READ/WRITE 来获取,这是一个高权限。

    如果您在自己的进程中访问指针,这不是问题。在这种情况下,您只是依赖于 pinvoke 编组器中内置的 Marshal.Copy()。很好地隐藏在视图中,但肯定不会比 Copy() 快,因为您增加了进行 pinvoke 调用和 Windows 执行该函数的开销。 Marshal.Copy() 简单快速,相当于 memcpy()。

    【讨论】:

    • 感谢您的澄清。我想我没有说清楚。我只在读取/写入调用进程的内存方面寻找可能的差异,而不是其他进程的内存。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-01-22
    • 2014-06-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-28
    相关资源
    最近更新 更多