x86 - Windows 是否将 dll 映射到不同进程中的同一物理页面?

问题描述 投票:0回答:1

假设我们有进程A和进程B,都使用example.dll。

现在让我们假设这个dll被映射到进程A和进程B中的不同地址(比如说,这是由于ASLR或其他一些冲突)。

操作系统是否会将其映射两次,或者仍然能够使用为两个进程映射 dll 的同一物理页?我的意思是,这就是 DLL 的全部意义,对吗?共享内存,因此我们不必映射两次。

windows dll x86 x86-64 windows-kernel
1个回答
0
投票

您已经从评论中得到了所有正确的答案,我只想通过内核调试器(Windbg)来演示它。

我正在运行 notepad.exe 和 explorer.exe。

  • 获取记事本
    EPROCESS
    结构体(这是从内核角度描述一个进程的结构体,这是
    PROCESS
    后面的64位数字):
0: kd> !process 0 0 notepad.exe
PROCESS ffffe28aca250080
    SessionId: 2  Cid: 0f58    Peb: 5903bde000  ParentCid: 1c60
    DirBase: 16543002  ObjectTable: ffffab8f834dac40  HandleCount: 240.
    Image: notepad.exe

注意 DirBase 给出的进程的 CR3,这里:

0x16543002

  • 切换到 notepad.exe 上下文(基本上,在 CPU 上调度其线程之一,以便我们访问它的内存,基本上从 CR3 映射其页表条目):
0: kd> .process /i ffffe28aca250080
  • 查看用户模式模块:
3: kd> lmu
start             end                 module name
; snip          
00007ff9`c6120000 00007ff9`c61cc000   ADVAPI32   (deferred)             
00007ff9`c6330000 00007ff9`c64d0000   USER32     (deferred)             
00007ff9`c6510000 00007ff9`c6705000   ntdll      (pdb symbols)

我们有模块 base、end 及其名称。在 Windows 上,ASLR 是“每次启动”(不是每个进程)。因此,在所有进程中,ntdll将被映射到相同的地址,直到系统重新启动并选择新的随机地址。


检查虚拟地址内容(针对
    ntdll
  • 模块的基地址):
    
    
  • 3: kd> db 00007ff9`c6510000 00007ff9`c6510000 4d 5a 90 00 03 00 00 00-04 00 00 00 ff ff 00 00 MZ.............. 00007ff9`c6510010 b8 00 00 00 00 00 00 00-40 00 00 00 00 00 00 00 ........@....... 00007ff9`c6510020 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 00007ff9`c6510030 00 00 00 00 00 00 00 00-00 00 00 00 e8 00 00 00 ................ 00007ff9`c6510040 0e 1f ba 0e 00 b4 09 cd-21 b8 01 4c cd 21 54 68 ........!..L.!Th 00007ff9`c6510050 69 73 20 70 72 6f 67 72-61 6d 20 63 61 6e 6e 6f is program canno 00007ff9`c6510060 74 20 62 65 20 72 75 6e-20 69 6e 20 44 4f 53 20 t be run in DOS 00007ff9`c6510070 6d 6f 64 65 2e 0d 0d 0a-24 00 00 00 00 00 00 00 mode....$.......
典型的 PE 模块头(
MZ

This program cannot ...
)。

将虚拟地址转换为物理地址。命令
    !vtop
  • 需要给定进程的PML4表的基址以及要转换的虚拟地址(因此,我们将CR3的低12位设置为0,因为没有用于PML4基址的地址):
    
    
  • 0: kd> !vtop 16543000 00007ff9c6510000 Amd64VtoP: Virt 00007ff9c6510000, pagedir 0000000016543000 Amd64VtoP: PML4E 00000000165437f8 Amd64VtoP: PDPE 000000012ce4ff38 Amd64VtoP: PDE 000000012cd52190 Amd64VtoP: PTE 0000000012d53880 Amd64VtoP: Mapped phys 00000002c1b98000 Virtual address 7ff9c6510000 translates to physical address 2c1b98000.
通过读取确认物理地址:
  • 0: kd> !db 2c1b98000 #2c1b98000 4d 5a 90 00 03 00 00 00-04 00 00 00 ff ff 00 00 MZ.............. #2c1b98010 b8 00 00 00 00 00 00 00-40 00 00 00 00 00 00 00 ........@....... #2c1b98020 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ #2c1b98030 00 00 00 00 00 00 00 00-00 00 00 00 e8 00 00 00 ................ #2c1b98040 0e 1f ba 0e 00 b4 09 cd-21 b8 01 4c cd 21 54 68 ........!..L.!Th #2c1b98050 69 73 20 70 72 6f 67 72-61 6d 20 63 61 6e 6e 6f is program canno #2c1b98060 74 20 62 65 20 72 75 6e-20 69 6e 20 44 4f 53 20 t be run in DOS #2c1b98070 6d 6f 64 65 2e 0d 0d 0a-24 00 00 00 00 00 00 00 mode....$.......
现在让我们尝试一下explorer.exe:

2: kd> !process 0 0 explorer.exe PROCESS ffffe28ac9c4f080 SessionId: 2 Cid: 1c60 Peb: 00568000 ParentCid: 1c3c DirBase: 1546ad002 ObjectTable: ffffab8f83851cc0 HandleCount: 2638. Image: explorer.exe 2: kd> .process /i ffffe28ac9c4f080 1: kd> db 00007ff9`c6510000 L10 00007ff9`c6510000 4d 5a 90 00 03 00 00 00-04 00 00 00 ff ff 00 00 MZ..............

翻译(V 到 P):
  • 1: kd> !vtop 1546ad000 00007ff9c6510000 Amd64VtoP: Virt 00007ff9c6510000, pagedir 00000001546ad000 Amd64VtoP: PML4E 00000001546ad7f8 Amd64VtoP: PDPE 0000000155db9f38 Amd64VtoP: PDE 0000000155dbf190 Amd64VtoP: PTE 0000000155dc0880 Amd64VtoP: Mapped phys 00000002c1b98000 Virtual address 7ff9c6510000 translates to physical address 2c1b98000.
如您所见,我们得到了相同的结果物理地址,但请注意,两个进程中的表条目(PML4E、PDPTE、PDE 和 PTE)并不相同,但结果物理页完全相同。

显然,Windows 有一种 CoW(写入时复制)机制,如果您写入其中一个页面,该机制会立即复制,并且只有发生写入的进程才能看到修改后的页面。

© www.soinside.com 2019 - 2024. All rights reserved.