在X64位机器上捕捉32位程序的进程的内存镜像文件要点
在X64位机器上捕捉32位程序的进程的内存镜像文件要点
Capturing memory dumps for 32-bit processes on an x64 machine
翻译:Baal Lin
我们经常会遇到的一类问题是,很多人在做内存镜像文件抓取的时候,需要重新的来抓一次,第一次往往不会成功,那是因为我们使用了“错误”的方法来抓取,从而导致了失败。
故事场景是这样:如果在一个x64系统上运行一个x32位的程序,例如在x64位系统上运行的IIS为例,我们需要一个能抓取到32位进程的内存镜像文件的工作,而不是简单的拿一个调试工具双击来运行,你要确保的是了解该工具是否能在32位 或64位环境下正确工作。
如何知道一个进程是32位的?
如果你在一个64位的系统上,你可以通过任务管理器来查看某个进程是32位还是64位。
那些带有*32 字样的进程是32位程序的进程,其余的都是64位的。所以我们从图上可以看到w3wp.exe是一个32位进程。
为什么要用正确的工具来抓取那些进程?
如果你用一个抓取64位进程内存镜像文件的工具来抓取32位进程的内存镜像,你仍然会得到一个内存镜像文件,但你得到的是一个64位地址空间的镜像文件,但sos和psscor2工具都无法正确的解析,部分的功能还是会有效,但功能会限制,它可能会报很多错误,或者返回一个错误的堆栈。
通常,如果读取一个32位进程的64位内存镜像文件,你会得到一些类似下面的错误:
1、类似下面的警告:
WARNING: wkscli overlaps srvcli
..............WARNING: wship6 overlaps dnsapi
.WARNING: IPHLPAPI overlaps dsrole
...WARNING: FWPUCLNT overlaps rasadhlp
WARNING: FWPUCLNT overlaps dnsapi
.....WARNING: compstat overlaps iisres
2、堆栈显示64位进程的方法,带有wow64cpu:
0:000> kp
Child-SP RetAddr Call Site
00000000`000ce728 00000000`73a22bcd wow64cpu!CpupSyscallStub+0x9
00000000`000ce730 00000000`73a9d07e wow64cpu!Thunk0ArgReloadState+0x1a
00000000`000ce7f0 00000000`73a9c549 wow64!RunCpuSimulation+0xa
00000000`000ce840 00000000`76d684c8 wow64!Wow64LdrpInitialize+0x429
00000000`000ced90 00000000`76d67623 ntdll!LdrpInitializeProcess+0x17e2
00000000`000cf290 00000000`76d5308e ntdll! ?? ::FNODOBFM::`string'+0x2bea0
00000000`000cf300 00000000`00000000 ntdll!LdrInitializeThunk+0xe
3、可以看到所有的地址都是64位长度的,例如00000000`76d5308e 而不是 76d5308e,虽然是32位的进程,但依然用64位空间地址来表示。
4、当用sos命令时,提示下面的错误信息:(如果使用了错误的symbol文件,也有可能得到类似的信息,导致如下信息的错误原因不仅仅是因为本文主题所讲的原因)
0:000> !eeheap -gc
Failed to load data access DLL, 0x80004005
Verify that 1) you have a recent build of the debugger (6.2.14 or newer) 2) the file mscordacwks.dll
你可以使用 .cordll命令来控制调试器来加载mscordacwks.dll 命令:.cordll –ve –u –l 会进行一个冗长的加载过程。如果成功,sos命令会尝试重新工作。如果你抓取的是精简镜像文件,要确保可执行路径指向clr.dll路径。
应该使用什么工具?
在这类场景中,最好的抓取进程内存镜像文件的方式是使用32位的调试工具,例如32位的Debug Diag 或者32位的adplus+cdb。可以在64位系统上安装32位的工具,在下一个版本的Debug Diag中,64位的Debug Diag可以抓取32位进程的内存镜像文件。
以前曾今提到过,在Vista系统以上的版本,可以通过任务管理器来抓取内存镜像文件,但是如果是在64位的系统上,用任务管理器来抓取的话得到的还是一个64位的内存镜像文件。可以使用32位的任务管理器来抓取,位置是C:\Windows\SysWOW64\taskmgr.exe ,可以通过在任务管理器中检查taskmgr.exe 进程是否带有*32标记来判断该进程是否是32位的。
对于其他第三方的工具,你也首先阅读帮助文档来确认是否是32位版本。例如procmon 可以在后面带上 /run32参数。
让调试器用正确的“位”来加载内存镜像文件重要吗?
当然重要,无论是在32位或者64位os系统上,当加载32位的内存镜像,你必须用32位的windbg,针对64位的内存镜像,当然是在运行64位的os上用64位的windbg来抓取,(32位系统上,抓取不到64位内存镜像文件哦)。
记住,如果在调试一个64位内存镜像文件,你也必须保证组成该调试工具各个部分,例如64位的sos,64位的psscor2,64位的sosex或其他64位的扩展工具都是64位版本的。