Suppose we have process A and processB, both are using example.dll.
Now let's suppose that this dll was mapped to different addresses in process A and process B(say, it's due to ASLR or some other conflict).
Will the operating system map it twice or will it still be able to use the same physical page where the dll was mapped for both processes? I mean, that's the whole point of a DLL right? shared memory so we don't have to map things twice.
You already got all the right answers from the comments, I just want to demonstrate it from a kernel debugger (Windbg).
I have notepad.exe and explorer.exe running.
EPROCESS
structure (this is the structure that describes a process from the kernel point of view, this is the 64-bit number after PROCESS
):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
Notice the CR3 of the process which is given by DirBase, here: 0x16543002
.
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)
We have the module bases, ends and their names. On Windows, ASLR is per boot (not per process). So, in all processes ntdll
will be mapped at the same address until the system is rebooted and new random address is chosen.
ntdll
module: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....$.......
Typical PE module header (MZ
and This program cannot ...
).
!vtop
(Virtual to Physical) requires the base of the PML4 table - for the given process - and the virtual address to be translated (thus, we need to set the lower 12 bits of CR3 to 0 since there are not used for the address of the PML4 base):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....$.......
Now let's try with 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..............
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.
As you can see we get the same resulting physical address. Note that the table entries (PML4E, PDPTE, PDE and PTE) are not the same in both processes, but the resulting physical page is exactly the same.
Obviously, Windows has a CoW (Copy-on-Write) mechanisms that takes place if you'd write to one of those pages: it would be immediately copied and only the process where the write had happened would see the modified page.