为何Windows下不同进程同虚拟地址的MessageBoxW修改互不可见
底层原理说明
1 DLL共享机制的实际规则
你对DLL共享的认知存在偏差,Windows通过*写时复制(Copy-On-Write, COW)*机制平衡内存利用率和进程隔离性:
- 多个进程加载同一个DLL时,DLL的只读代码段默认会被映射到同一块物理内存页面,所有进程的对应虚拟地址都指向这个共享物理页,实现同一份DLL实例全局共享。
- 此时DLL代码段的内存属性为只读,任何写入操作都会触发系统的COW机制。
2 修改DLL代码触发写时复制
你在代码中执行的修改操作触发了COW,使得修改仅对当前进程生效:
- 你调用
VirtualProtect将user32.dll中MessageBoxW所在的内存页属性修改为PAGE_EXECUTE_READWRITE,为写入操作做好准备。 - 执行
memcpy写入跳转指令时,系统检测到对原本只读的共享代码页执行写入操作,立刻触发COW流程:- 为当前进程单独分配一块新的私有物理内存页
- 将原共享代码页的完整内容复制到新的私有物理页
- 修改当前进程的页表映射关系,将
MessageBoxW对应的虚拟地址从指向共享物理页,改为指向新分配的私有物理页
- 后续你对该虚拟地址的所有修改,都只会作用在当前进程的私有物理页上,完全不会触及其他进程的内存映射。
3 同虚拟地址内容不同的原因
每个进程都拥有独立的虚拟地址空间,虚拟地址需要通过进程专属的页表转换才能得到真实的物理内存地址:
- 第一个进程的
MessageBoxW虚拟地址,经过自身页表转换后指向被修改过的私有物理页,所以读取到的是你写入的跳转指令。 - 第二个进程的同虚拟地址,页表仍然指向未被修改的原始共享DLL物理页,所以读取到的是原生代码,也能正常弹出消息框。
内容的提问来源于stack exchange,提问作者pazdinho_
相关产品推荐
相关产品推荐

