【问题标题】:Why does ReadProcessMemory have `lpNumberOfBytesRead`?为什么 ReadProcessMemory 有 `lpNumberOfBytesRead`?
【发布时间】:2010-12-16 03:23:37
【问题描述】:

来自ReadProcessMemory in MSDN:

lpBaseAddress [in]
指向要从中读取的指定进程中的基地址的指针。在发生任何数据传输之前,系统会验证指定大小的基地址和内存中的所有数据是否可访问以进行读取访问,如果不可访问,则函数失败。

nSize [in]
要从指定进程读取的字节数。

lpNumberOfBytesRead [out]
指向变量的指针,该变量接收传输到指定缓冲区的字节数。如果 lpNumberOfBytesRead 为 NULL,则忽略该参数。

所以..ReadProcessMemory只能完全成功或完全失败。调用者显然知道大小 - 必须将其传入才能进行调用。为什么有lpNumberOfBytesRead

【问题讨论】:

  • 这是一个该死的好问题。
  • @paxdiablo:谢谢 :)
  • 这里有黑魔法。有一个特定的错误 ERROR_PARTIAL_COPY 指出“只有部分 ReadProcessMemory 或 WriteProcessMemory 请求已完成”。这似乎与“完全成功或失败”完全相反,但我不知道哪个是正确的。
  • 这是一个想法。即使您可以从其他进程读取整个缓冲区,但如果您不能在当前进程中写入整个缓冲区怎么办?抓着稻草,但我猜这似乎是合理的。
  • @pax:WriteProcessMemory 的文档说的差不多。我的假设是 1. 这里的“可访问”有一些特殊含义,或者 2. 函数“失败”,但仍然复制尽可能多的数据。

标签: c++ windows


【解决方案1】:

来自winerror.h

//
// MessageId: ERROR_PARTIAL_COPY
//
// MessageText:
//
//  Only part of a ReadProcessMemory or WriteProcessMemory request was completed.
//
#define ERROR_PARTIAL_COPY               299L

当副本遇到页面错误时,ReadProcessMemory 将返回 FALSE,GetLastError 将返回 ERROR_PARTIAL_COPY。这是转储程序中的常见情况,它们必须在可能已损坏的进程上工作,因此他们无法确定请求的区域是否有效(他们为获取起始地址而追逐的指针可能已损坏并指向 la- la-land),但他们仍然希望尽可能多地复制到转储中。

【讨论】:

  • 所以你是说 ReadProcessMemory 可以失败但仍然复制一些内存?
  • 是的。想象一下如何实现一个原子的 ReadProcessMemory(要么复制所有内容,要么什么都不复制)。您必须要么 回滚 副本(这意味着您已经保存了之前写入的内容),或者您必须分两次进行复制(一次验证请求区域中的每一页,一次验证)和希望目标进程不会在两次传递之间更改页面保护。
【解决方案2】:

也许在某些以前的 API 版本中,此函数并未完全失败,但可能会返回部分结果。所以 out 参数是为了兼容性而保留的,但是较新的程序可以传递一个 NULL 并忽略它。

【讨论】:

  • 但这意味着现在关注文档的人会在较旧的操作系统上随机失败他们的程序......我认为至少没有在 MSDN 上记录......
  • @Billy ONeal:如果您使用的是 MSDN 上记录的 API 版本,那么您的应用程序很可能无论如何都无法在那些较旧的操作系统上运行,因为某些 API 函数只是来自旧版本 API 的普通 missing。如果您打算为 Windows 95 开发,您应该将您的代码基于 Windows 95 文档。如果您不是为 Windows 95 开发,那么额外的信息只是噪音。
  • @Anon:我根本不知道 Win95 上存在 ReadProcessMemory。以为那只是新台币。 (反正除了NT我什么都不在乎……)
  • @Billy:我也真的不知道。只是指出在主文档中不记录旧系统的怪癖是一个合理的立场。
【解决方案3】:

我猜测该区域可能在权限方面是可访问的,但是页面错误中的错误可能只允许读取其中的一部分。不过这只是猜测。

编辑:查看此页面:ReactOS - STATUS_PARTIAL_COPY

> // Otherwise, we failed  probably during the move

似乎任何超出函数控制的问题都可能返回此错误代码。

【讨论】:

    【解决方案4】:

    存在固有的竞争条件。副本不是即时的。当然,该函数会预先检查它是否可能成功,但是在复制期间内存范围可能会变得未映射。这是您正在查看的另一个正在运行的进程,毕竟,很可能不知道您正在进行的ReadProcessMemory()

    (Remus Rusanu 也暗示了这样的部分副本,但建议将损坏的进程作为根本原因,而不是种族。)

    【讨论】:

      【解决方案5】:

      除了9000's answer 之外,另一种可能性是该参数用于将来的扩展目的。也许在某一时刻(甚至现在),有计划提供可能部分失败的 ReadProcessMemory 实现,因此出于这个原因将 out 参数放在那里。这将是一种(不是特别好的)方法来避免 Win32 的 API 多年来一直在努力解决的整个 API/APIEx/APIEx2/任何问题。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-10-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-10-17
        • 1970-01-01
        • 2012-05-22
        相关资源
        最近更新 更多