0

在 Windows(32 位和 64 位)中,通过程序(C++)是否可以确定某个内存位置是否已更改?我试图推断我们在 Visual Studio 中看到的概念,我们可以在其中设置数据断点。

用例I understand its a dirty hack, but the fastest to implement to be re-implemented later

我正在跨进程边界共享数据(在 32 位客户端和 64 位服务器之间读取)。客户端分配内存(超出我们的控制)并将地址传递给服务器。服务器分配一个存储来映射客户端内存,并通过各种代码路径可以更新该映射的内存位置。而不是识别和捕获每个位置(我试图找到一条更简单的路径),而是在更改时引发事件并最终将数据写回WriteProcessMemory客户端进程

4

2 回答 2

5

虽然使用Windows 调试界面VirtualProtect的组合可能会找到解决方案,我不确定这对于这种情况是一个特别好的解决方案。其中一个问题是您在每次新写入时都会引入延迟,并且您正在查看转移到另一个将程序作为“调试器”监视的进程。然后,该过程必须“取消保护”该页面,将其标记为其他服务器(或客户端,具体取决于您要去的方向)的“更新”,并“继续”进行更新的应用程序。这是相当耗时的。当然,没有简单的方法可以知道写入过程何时完成了一系列更新。当有一个 SEH“__except”调用时,你还需要确切地知道在哪里“继续”,这并不总是完全微不足道的,

当我处理图形时,我知道我们和一些竞争对手的驱动程序都会这样做,首先对内存进行写保护,然后通过挂钩到 windows 自己的页面错误处理程序,查找页面错误,看看它是否是特殊区域,如果是,则将该页面标记为已更新并将其重置为可写。这允许驱动程序仅复制更新的区域。但是在这种情况下,在完成所有更新之后,会有一个明显的“我要画这个东西”。

于 2013-09-09T18:07:41.020 回答
2

如果你非常想,你可以使用调试 API 在你自己的数据上设置一个断点,这将在写入时触发,就像 VS API 一样。

这样做的基础是启动一个线程来进行“调试”。它会:

  1. 暂时停止主线程。
  2. 使用 GetThreadContext 获取该线程的寄存器
  3. 将地址设置为在 DR0 到 DR 3 之一中中断。
  4. 在 DR 6 中设置相关数据的大小。
  5. 在 DR 7 中设置断点的类型(在本例中为数据写入)。
  6. 使用 SetThreadContext 告诉主线程使用修改后的寄存器。
  7. 重新开始执行主线程。

这是从记忆中得出的,所以虽然我相信它非常接近基本想法,但我可能已经弄错了一两个细节,或者(更有可能)遗漏了几个步骤。

在大多数情况下,在源代码级别做一些事情会更容易,因为您会operator=为有问题的目标重载,因此您会在分配给数据的过程中执行一些代码。然后在该运算符中,您可以(例如)设置另一个线程中的代码等待(并做出适当反应)的事件。

另一种可能性(特别是如果您想中断对整个地址范围的任何访问)是使用VirtualProtect强制异常对对该内存块的任何访问。就像调试异常一样,这将被同步触发,因此如果您想要异步执行,您必须通过设置一个事件(或其他)并让另一个线程等待它来完成它,以便在设置事件时执行它。

于 2013-09-09T17:41:25.310 回答