为什么WriteProcessMemory需要传入的句柄值,而不是目标进程的ID?

Why does WriteProcessMemory need the handle value passed in, not the ID of the target process?

在Windows系统中,我们可以跨进程修改另一个进程的内存。比如进程A要修改进程B的内存,A可以调用系统函数WriteProcessMemory。大致形式如下:

BOOL flag = WriteProcessMemory(handler, p_B_addr, &p_A_buff, write_size); ...

这个函数return一个布尔值,代表写操作是否成功。它需要传递四个参数,我们来看看这四个参数:

  1. 处理程序。这是一个进程句柄,可以用来查找B进程

  2. p_B_addr。 B进程中,要写入内存的地址偏移量。

  3. p_A_buff。进程A中,写入数据缓冲区的指针。

  4. write_size。要写入的字节数。

我对第一个参数handler感到困惑,它是一个HANDLE类型的变量。比如我们的程序其实是运行,进程B的ID是2680,然后我想写内存给进程B,首先我需要用这个2680在进程A中得到进程B的句柄.具体形式是handler=OpenProcess(PROCESS_ALL_ACCESS, FALSE, 2680),然后就可以使用这个handler落入内核修改进程B的内存了

既然都是困在内核函数中跨进程修改内存,为什么WriteProcessMemory函数没有设计成WriteProcessMemory(B_procID, p_B_addr, &p_A_buff, write_size)?

其中,B_procID是B进程的ID,因为每个进程都有唯一的ID。难道系统内核找不到B进程的虚拟地址可以通过这个B_procID映射的物理地址吗?为什么一定要传入A进程中B进程的进程句柄索引?

原因有很多,都在评论中提到了。

  1. 一生。进程 ID 只是一个数字,知道该 ID 并不能使进程保持活动状态。拥有进程的打开句柄意味着内核 EPROCESS 结构和进程地址 space 将保持不变,即使所述进程通过调用 ExitProcess 结束。 Windows 尝试不立即 re-use 新进程的 ID,但如果有足够的时间,它会在未来某个时间发生。
  2. Security/Access控制。在 Windows NT 中,访问控制是在您打开一个对象时执行的,而不是在您每次与该对象交互时执行的。在这种情况下,内核需要知道调用者对进程具有 PROCESS_VM_WRITE 和 PROCESS_VM_OPERATION 访问权限。这和第3点,效率有关。
  3. 速度。 Windows 当然可以实现一个 WriteProcessMemoryById 调用 OpenProcess+WriteProcessMemory+CloseHandle 的函数,但这会鼓励次优设计并使您面临竞争条件与第 1 点相关。这同样适用于“为什么没有 WriteFileByFilename 函数”(以及所有其他 Read/Write 函数)。