您的位置:首页 > 运维架构

用Kernel Debugger验证Windows内存管理器的Copy-On-Write行为

2007-08-10 15:50 323 查看
写这篇东西的起源是MFC/VC论坛上MagicMoon朋友的一个问题:“DLL文件整个内存里只有一份?? ”(http://community.csdn.net/Expert/topic/5688/5688294.xml?temp=.6240198)。讨论的结果是对一个DLL,不管多少个进程装载它,如果它没有变动过(人为修改,Loader re-base, Debugger断点),那么在整个物理内存里面只有一个映象。这个映象被所有进程共享。当DLL在某一个进程中被修改后,系统的Memory Manager会实行Copy-On-Write,即对修改页在这个进程的存储空间里面另外分配空间,另外分配空间的大小是页的大小(4K)。MagicMoon进行了一系列测试,观察到了4K内存的增长,那么如何真正验证copy-on-write呢?下面是我自己做的一个小实验:

实验设想:如上所说,DLL被修改后,修改的页会由Memory Manager另外分页,也就是说系统会把此页搬到另外的物理内存页。如果我们能找到DLL修改部分真正占用的物理内存,就可以验证这个理论。查看物理内存只能用Kernel Debugger,市面上流行的Kernel Debugger有微软的KD,Numega(Compuware)的SoftIce等等,我们今天用免费的KD。(可以在微软网站下载)

KD以前需要两台机器中间用NULL Modem或者1394什么的连接。攒钱娶媳妇买房的朋友还有一个办法就是用Virtual PC(免费下载)通过Pipe来连接。具体方法不多罗嗦了,可以看 http://blogs.msdn.com/virtual_pc_guy/archive/2005/10/20/482413.aspx 。这样一台机器上就可以折腾了。

我的实验就是在对在Virtual PC上跑的Windows 2000进行Kernel Debug,手上的机器是Windows Vista,所以:
Target Machine:Win2k
Host Machine: Vista
以下就用Win2k和Vista简称。

KD连接好后,先在Win2k上用User Mode Debugger(cdb,windbg,ntsd, Visual Studio等等)随便起个进程,我随便用了个cdb, 进程是Notepad

E:/debuggers>cdb notepad.exe

Microsoft (R) Windows Debugger Version 6.7.0005.0
Copyright (c) Microsoft Corporation. All rights reserved.

CommandLine: notepad.exe
Symbol search path is: *** Invalid ***

...
ntdll!DbgBreakPoint:
77f9f9df cc int 3
0:000> !symfix <============== Fix symbol path
0:000> .reload -f kernel32.dll <============== Load symbols for kernel32.dll
0:000> lml <============== Make sure the symbol is loaded
start end module name
77e80000 77f36000 KERNEL32 (pdb symbols) E:/debuggers/sym/kernel32.pdb/384470951/kernel32.pdb

这个小实验我们用我们所熟知的CreateFileW来观察。

0:000> u Kernel32!CreateFileW
KERNEL32!CreateFileW:
77e895a3 55 push ebp
77e895a4 8bec mov ebp,esp
77e895a6 83ec5c sub esp,5Ch
77e895a9 8b4518 mov eax,dword ptr [ebp+18h]
77e895ac 53 push ebx
77e895ad 56 push esi
77e895ae 48 dec eax
77e895af 57 push edi

我们另外用dc直接Dump一下内存,以后对比用:(从a0处开始Dump,整齐,以利于以后比较)
0:001> dc 77e895a0
77e895a0 55c31840 ec83ec8b 18458b5c 57485653 @......./.E.SVHW
77e895b0 44aa840f 0f480000 ffeee984 850f48ff ...D..H......H..
77e895c0 0000f0c6 01f845c7 8b000000 458d087d .....E......}..E
77e895d0 ff5057e4 e8103c15 58016a77 e4453966 .WP..<..wj.Xf9E.
77e895e0 b70f1276 e9d1e44d 4f7c8366 840f5cfe v...M...f.|O./..
77e895f0 00018b73 7589f633 0c75fff0 50e4458d s...3..u..u..E.P
77e89600 0005cfe8 0fc63b00 003a2985 bc458d00 .....;...):...E.
77e89610 e4458d50 ff575056 e8112015 0fc08477 P.E.VPW.. ..w...

好了,现在我们需要到KD里面看看物理内存情况。

回到Vista机器上,KD里面Break掉。

kd>!symfix <=== 保证Symbol Path
kd>.reload -f nt <========= 我们需要装载ntoskrnl的Symbol
kd> lml
start end module name
80400000 80590900 nt # (pdb symbols) c:/debuggers/sym/ntoskrnl.pdb/38237D2054/ntoskrnl.pdb

kd> !process 0 0
**** NT ACTIVE PROCESS DUMP ****
PROCESS 8188dbe0 SessionId: 0 Cid: 0008 Peb: 00000000 ParentCid: 0000
DirBase: 00030000 ObjectTable: 818b2688 TableSize: 140.
Image: System

(中间省略)
PROCESS 81655cc0 SessionId: 0 Cid: 0130 Peb: 7ffdf000 ParentCid: 02dc
DirBase: 06876000 ObjectTable: 81658348 TableSize: 217.
Image: explorer.exe

PROCESS 8166f5e0 SessionId: 0 Cid: 0334 Peb: 7ffdf000 ParentCid: 02b8
DirBase: 07f03000 ObjectTable: 8165bcc8 TableSize: 23.
Image: notepad.exe <================= 我们的Notepad

有几种办法把Virtual Memory转换成物理内存,最简单的是!vtop命令(Virtual To Physical),具体用法如下:

!process会列出进程Page Directory的基地址,比如我们的NotePad的DirBase是07f03000, 把这个值左移12位(去3个0)==》7f03, 然后用!vtop (Virtual To Physical)来找对应的物理地址

kd> !vtop 7f03 77e895a3 (第一个参数 DirBase << 12,第二个是我们CreateFileW的地址)
Pdi 1df Pti 289
77e895a3 03948000 pfn(03948)

注意得到的结果03948000对应的是77e89000的地址,加上偏移5a3,那么CreateFileW的物理地址应该是: 0x039485a3

还可以用!pte或者手算,结果应该相同,有兴趣的去看看Windbg的帮助就可以了。

先看看我们物理地址的内容:
kd> !dc 039485a3 《============ 查看物理地址
# 39485a0 55c31840 ec83ec8b 18458b5c 57485653 @..U..../.E.SVHW
# 39485b0 44aa840f 0f480000 ffeee984 850f48ff ...D..H......H..
# 39485c0 0000f0c6 01f845c7 8b000000 458d087d .....E......}..E
# 39485d0 ff5057e4 e8103c15 58016a77 e4453966 .WP..<..wj.Xf9E.
# 39485e0 b70f1276 e9d1e44d 4f7c8366 840f5cfe v...M...f.|O./..
# 39485f0 00018b73 7589f633 0c75fff0 50e4458d s...3..u..u..E.P
# 3948600 0005cfe8 0fc63b00 003a2985 bc458d00 .....;...):...E.
# 3948610 e4458d50 ff575056 e8112015 0fc08477 P.E.VPW.. ..w...

KD从16位对齐的A0开始列,对比这个内容和我们在Win2k上的Dump,可以看出这个就是CreateFileW的代码。

好现在我们继续运行然后回到Win2k上:
kd> g

下面我们模拟Debugger,在CDB里面把CreateFileW的入口处放上人工断点int 3(cc)

0:001> e kernel32!CreateFileW
77e895a3 55 cc <==================== 55 换成 cc (int 3)
77e895a4 8b

好回到Vista,KD Break,重复劳动:
kd> !vtop 7f03 77e895a3
Pdi 1df Pti 289
77e895a3 08948000 pfn(08948)

08948000 + 5a3 = 0x89485a3

嗯,对应CreateFileW的物理地址从0x039485a3 变到了 0x89485a3 !!

先看看新的物理地址的内容:
kd> !dc 89485a0
# 89485a0 ccc31840 ec83ec8b 18458b5c 57485653 @......./.E.SVHW
# 89485b0 44aa840f 0f480000 ffeee984 850f48ff ...D..H......H..
# 89485c0 0000f0c6 01f845c7 8b000000 458d087d .....E......}..E
# 89485d0 ff5057e4 e8103c15 58016a77 e4453966 .WP..<..wj.Xf9E.
# 89485e0 b70f1276 e9d1e44d 4f7c8366 840f5cfe v...M...f.|O./..
# 89485f0 00018b73 7589f633 0c75fff0 50e4458d s...3..u..u..E.P
# 8948600 0005cfe8 0fc63b00 003a2985 bc458d00 .....;...):...E.
# 8948610 e4458d50 ff575056 e8112015 0fc08477 P.E.VPW.. ..w...

哈哈,头一个字节由55变成了cc。 再看看原来的页:

kd> !dc 039485a0
# 39485a0 55c31840 ec83ec8b 18458b5c 57485653 @..U..../.E.SVHW
# 39485b0 44aa840f 0f480000 ffeee984 850f48ff ...D..H......H..
# 39485c0 0000f0c6 01f845c7 8b000000 458d087d .....E......}..E
# 39485d0 ff5057e4 e8103c15 58016a77 e4453966 .WP..<..wj.Xf9E.
# 39485e0 b70f1276 e9d1e44d 4f7c8366 840f5cfe v...M...f.|O./..
# 39485f0 00018b73 7589f633 0c75fff0 50e4458d s...3..u..u..E.P
# 3948600 0005cfe8 0fc63b00 003a2985 bc458d00 .....;...):...E.
# 3948610 e4458d50 ff575056 e8112015 0fc08477 P.E.VPW.. ..w...

还是55,没有变。说明我们的修改是在新的页上。

实验到此可以验证我们的理论了。最后给有些坚持认为NT上每个进程都有一份自己的DLL的朋友再顺手加个实验,随便找个另外进程,看看CreateFileW的物理地址是什么:

PROCESS 81655cc0 SessionId: 0 Cid: 0130 Peb: 7ffdf000 ParentCid: 02dc
DirBase: 06876000 ObjectTable: 81658348 TableSize: 217.
Image: explorer.exe

这个是Explorer,重复劳动:

kd> !vtop 6876 77e895a3
Pdi 1df Pti 289
77e895a3 03948000 pfn(03948)

3948000 + 5a3 = 0x39485a3 <======= 对比一下Notepad,发现对应的物理地址相同。

验证完毕。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: