Debugging Tools for Windows

!chkimg

!chkimg 扩展通过比较可执行文件映像和符号存储或者其他地方的拷贝,来检测其中被改动过的内容。

语法

!chkimg [Options] [-mmw LogFile LogOptions] [Module

参数

Options
下面这些选项的任意组合:
-p SearchPath
在访问符号服务器之前先在SearchPath中递归搜索文件。
-f
修正映像中的错误。当检测到内存映像和符号存储中的文件有不同时,会将符号存储中的文件内容覆盖掉内存映像中的。如果在进行活动调试,可以在执行!chkimg -f 之前先创建一个dump文件。
-nar
避免符号服务器上文件的映射的映像被移动。默认情况下,当文件的拷贝位于符号服务器上并且被映射到内存中时,!chkimg 会移动符号服务器上的文件的映像。但是,如果使用了-nar 选项,则不会移动服务器上的文件映像。 

已经在内存中的可执行映像(即被扫描的那个)会被移动,因为调试器总是会重定位它所加载的映像。

该开关仅在操作系统已经移动了原始映像的时候才有用。如果映像并没有被移动,!chkimg和调试器会移动它。一般都不需要使用这个开关。

-ss SectionName
将扫描限制在名字包含字符串SectionName 的节中。会扫描名字中包含该字符串的任何不可丢弃的节。SectionName 区分大小写,并且不能超过8个字符。
-as
扫描映像中除了可丢弃节之外的所有节。默认情况下,(如果没有使用-as或者-ss),扫描会跳过可写的节、不可执行的节、名字中有"PAGE"的节、以及可丢弃的节。
-r StartAddress EndAddress
将扫描限制在从StartAddress 开始,EndAddress 结尾的范围内。在该范围中,任何可以被扫描的节都会扫描。如果某个节和该范围只是部分重叠,则只扫描范围中的那部分。即使使用了-as或者-ss 开关,扫描还是被限制在指定范围中。
-nospec
使得扫描包括Hal.dll Ntoskrnl.dll 中的保留节。默认情况下, !chkimg不会检查这些文件的这部分节。
-noplock
显示字节值为0x90(nop指令)和0xF0(lock指令)的不匹配的位置。默认情况下,这些不匹配的位置不会被显示出来。(详见注释部分,— 译者)
-np
识别被修改过的指令。
-d
扫描时显示不匹配的区域的摘要信息。该摘要文本的详细信息,查看注释部分。
-db
以类似db 调试器命令的格式显示不匹配的区域。因此,每个显示行的开头是该行第一个字节的地址,后面跟最多16个16进制字节值。字节值后面跟相应的ASCII值。所有的不可打印字符,如回车和换行,都显示为点号(.)。不匹配的字节以星号(*)标识。
-lo lines
-d-db 显示的最大行数限制为lines
-v
显示详细信息。
-mmw
创建一个日志文件,并记录!chkimg 的活动情况。日志文件的每一行都对应单个不匹配的项。
LogFile
指定日志文件的完整路径。如果指定相对路径,则是相对于当前路径的。
LogOptions
指定日志文件的内容。LogOptions 是由各个字母组合起来的字符串。日志文件的每一行都包含由逗号分隔的几个列。这些列包含由选项字母指定的项,按照这些字母在LogOptions 中出现的顺序。可以包含下面这些选项多次,但是必须至少包含一个选项。
日志选项 日志文件中包含的信息
v 不匹配的内容的虚拟地址
r 不匹配内容在模块中的偏移(相对地址)
s 和不匹配内容地址对应的符号
S 包含不匹配内容的节的名字
e 不匹配位置的原始值
w 不匹配位置的当前值

LogOptions 也可以包含下面这些附加选项的一个、多个或者0个。

日志选项 作用
o 如果LogFile 名字的文件已经存在,则覆盖该文件。默认情况下,调试器会将新信息添加到已存在的文件末尾。
tString 在日志文件中添加一个额外的列。该列中每一项都包含StringtString 选项在将新信息添加到已存在的日志文件时,可以用来和旧的纪录区分开。在tString之间不能有空格。如果使用tIString选项,它必须是LogOptions 的最后一个选项,因为String包括下一个空格之前的所有字符。

例如,如果 LogOptionsrSewo,则日志中每一行包括不匹配项的相对地址、节名、该地址的原始值和实际值。该选项也使得任何先前的文件都会被覆盖。如果想创建多个具有不同选项的日志文件,可以使用-mmw多次。一次最多创建10个日志文件。

Module
指定要检查的模块。Module 可以是模块名、模块的开始地址,或者包含在模块中的任何地址。如果省略Module,调试器使用包含当前指令指针的模块。

DLL

Windows 2000 Ext.dll
Windows XP 和之后 Ext.dll

只能在基于x86的目标机上使用!chkimg 扩展命令。

注释

使用!chkimg时,它会比较内存中的可执行映像和符号存储中的文件拷贝。

文件中除了可抛弃的、可写得、不可执行的、名字中有"PAGE"的或者INITKDBG 中的节之外,所有节都会被比较。可以使用-ss-as、或-r 开关来改变这个行为。

!chkimg 会显示文件和内存映像中所有不匹配的地方,除了下面的例外:

注意 如果使用了-f选项来修正不匹配的内容,!chkimg 仅修正被认为是不匹配的地方。例如,没有包含-noplock时,!chkimg不会将0x90改为0xF0。

包含-d选项时,!chkimg 显示扫描中遇到的不匹配内容的摘要。每个不匹配位置都显示为两行。第一行包含该位置的起始地址、大小、和起始地址对应的符号名和偏移、以及和上一个错误位置之间有多少个字节(圆括号中)。第二行用中括号括起来,包含原始的16进制值、一个冒号、以及当前映像中实际的16进制值。如果该区域大于8个字节,在冒号前后都只会显示8个字节。下面是一个例子。

be000015-be000016  2 bytes - win32k!VeryUsefulFunction+15 (0x8)
     [ 85 dd:95 23 ]

有时候,驱动程序会通过hook、重定向或其它方法改变Microsoft Windows内核的一部分。即使是不在堆栈上的驱动也可能改变内核。可以使用!chkimg 扩展作为文件比较工具来查看Windows内核(或任何其它映像)被某些驱动改变了,以及具体是怎么改变的。这种比较在完整dump文件上非常有效。

也可以将!chkimg!for_each_module扩展一起使用来检查所有已加载模块的映像。下面是这种情况的示例。

!for_each_module !chkimg @#ModuleName 

例如,假设遇到了bug check,以使用!analyze开始。

kd> !analyze 
....
BugCheck 1000008E, {c0000005, bf920e48, baf75b38, 0}
Probably caused by : memory_corruption
CHKIMG_EXTENSION: !chkimg !win32k
....

例中 !analyze 的输出提示可能遇到了内存错误,并且包含了一个CHKIMG_EXTENSION 行提示被破坏的模块可能是Win32k.sys。(即使不存在这一行,也应该考虑可能调用堆栈顶部的模块被破坏了。)不带任何参数使用!chkimg ,如下。

kd> !chkimg win32k
Number of different bytes for win32k: 31

下面的例子说明确实有内存错误。使用!chkimg -d 来显示模块Win32k 中的所有错误。

kd> !chkimg win32k -d
    bf920e40-bf920e46  7 bytes - win32k!HFDBASIS32::vSteadyState+1f
        [ 78 08 d3 78 0c c2 04:00 00 00 00 00 01 00 ]
    bf920e48-bf920e5f  24 bytes - win32k!HFDBASIS32::vHalveStepSize (+0x08)
        [ 8b 51 0c 8b 41 08 56 8b:00 00 00 00 00 00 00 00 ]
Number of different bytes for win32k: 31

当尝试反汇编列出来的第二个被破坏的映像位置时,可能会有下面这样的输出。

kd> u  win32k!HFDBASIS32::vHalveStepSize
win32k!HFDBASIS32::vHalveStepSize:
bf920e48 0000             add     [eax],al
bf920e4a 0000             add     [eax],al
bf920e4c 0000             add     [eax],al
bf920e4e 0000             add     [eax],al
bf920e50 7808            js win32k!HFDBASIS32::vHalveStepSize+0x12 (bf920e5a)
bf920e52 d3780c           sar     dword ptr [eax+0xc],cl
bf920e55 c20400           ret     0x4
bf920e58 8b510c           mov     edx,[ecx+0xc]

然后,使用!chkimg –f来修正内存错误。

kd> !chkimg win32k -f
Warning: Any detected errors will be fixed to what we expect!
Number of different bytes for win32k: 31 (fixed)

现在可以反汇编正确的内容并且查看有些什么改变。

kd> u  win32k!HFDBASIS32::vHalveStepSize
win32k!HFDBASIS32::vHalveStepSize:
bf920e48 8b510c           mov     edx,[ecx+0xc]
bf920e4b 8b4108           mov     eax,[ecx+0x8]
bf920e4e 56               push    esi
bf920e4f 8b7104           mov     esi,[ecx+0x4]
bf920e52 03c2             add     eax,edx
bf920e54 c1f803           sar     eax,0x3
bf920e57 2bf0             sub     esi,eax
bf920e59 d1fe             sar     esi,1

Build machine: CAPEBUILD