!chkimg扩展命令通过将可执行文件的映像与符号存储库或其他文件存储库上的副本进行比较来检测可执行文件映像中的损坏。
语法
!chkimg[Options][-mmw LogFile LogOptions] [Module]
参数
- Options
以下选项的任意组合:
- -pSearchPath
在访问符号服务器之前,递归地搜索SearchPath路径。
- -f
修复Image中的错误。每当扫描检测到符号存储中的文件与内存中的图像之间存在差异时,符号存储中的文件内容将复制到Image上。如果正在执行实时调试,则可以在执行!chkimg-f扩展之前创建一个转储文件。
- -nar
- 防止移动符号服务器上文件的映射。默认情况下,当文件副本位于符号服务器上并映射到内存时!chkimg移动符号服务器上文件的Image。但是,如果使用-nar选项,则不会移动服务器上的文件映像。已在内存中的可执行映像(即正在扫描的映像)将被移动,因为调试器总是重新定位它加载的映像。仅当操作系统已移动原始映像时,此开关才有用。如果Image没有被移动!chkimg和调试器将移动Image。很少使用这个开关。
- -ssSectionName
将扫描限制为名称包含字符串SectionName的节。扫描将包括名称中包含此字符串的任何不可丢弃部分。SectionName区分大小写,不能超过8个字符。
- -as
使扫描包括除可丢弃部分以外的Image的所有部分。默认情况下,(如果不使用-as或-ss),扫描将跳过可写的部分、不可执行的部分、名称中有“PAGE”的部分以及可丢弃的部分。
- -rStartAddressEndAddress
将扫描限制为以StartAddress开始、以EndAddress结束的内存范围。在此范围内,将扫描通常要扫描的任何部分。如果部分与此范围重叠,则只扫描与此范围重叠的部分。即使您也使用-as或-ss开关,扫描也限制在该范围内。
- -nospec
使扫描包括的保留部分Hal.dll 和 Ntoskrnl.exe. 默认情况下!chkimg不检查这些文件的某些部分。
- -noplock
显示字节值0x90(nop指令)和字节值0xF0(锁定指令)不匹配的区域。默认情况下,不显示这些不匹配项。
- -np
使修补的指令被识别。
- -d
扫描时显示所有不匹配区域的摘要。
- -db
以类似于db debugger命令的格式显示不匹配的区域。因此,每个显示行显示该行中第一个字节的地址,后跟最多16个十六进制字节值。字节值后面紧跟着相应的ASCII值。所有不可打印的字符,如回车符和换行符,都显示为句点(.)。不匹配的字节用星号(*)标记。
- -lolines
将-d或-db显示的输出行数限制为行数。
- -v
显示详细信息。
- -mmw
创建日志文件并记录!chkimg在这个文件里的活动。日志文件的每一行都表示一个不匹配项。
- LogFile
指定日志文件的完整路径。如果指定相对路径,则该路径相对于当前路径。
- LogOptions
指定日志文件的内容。LogOptions是一个由多个字母串联而成的字符串。日志文件中的每一行包含多个用逗号分隔的列。这些列包括以下选项字母指定的项,顺序是字母在LogOptions字符串中的出现顺序。可以多次包含以下选项。必须至少包含一个选项。
Log option | Information included in the log file |
v |
The virtual address of the mismatch |
r |
The offset (relative address) of the mismatch within the module |
s |
The symbol that corresponds to the address of the mismatch |
S |
The name of the section that contains the mismatch |
e |
The correct value that was expected at the mismatch location |
w |
The incorrect value that was at the mismatch location |
LogOptions还可以包括以下附加选项中的一些,或者不包括。
Log option | Effect |
o |
If a file that has the name LogFile already exists, the existing file is overwritten. By default, the debugger appends new information to the end of any existing file. |
tString |
Adds an extra column to the log file. Each entry in this column contains String. The tString option is useful if you are appending new information to an existing log file and you have to distinguish the new records from the old. You cannot add space between t and String. If you use the tIString option, it must be the final option in LogOptions, because String is taken to include all of the characters that are present before the next space. |
例如,如果LogOptions是rSewo,则日志文件的每一行都包含不匹配位置的相对地址和节名以及该位置的预期值和实际值。此选项还会导致覆盖以前的任何文件。如果要创建多个具有不同选项的日志文件,可以多次使用-mmw开关。最多可以同时创建10个日志文件。
- Module
指定要检查的模块。Module可以是模块的名称、模块的起始地址或模块中包含的任何地址。如果省略模块,调试器将使用包含当前指令指针的模块。
DLL
Windows 2000 |
Ext.dll |
Windows XP and later |
Ext.dll |
备注
当你使用!它将内存中可执行文件的映像与驻留在符号存储中的文件副本进行比较。比较文件的所有部分,除了可丢弃、可写、不可执行、名称中有“PAGE”或来自INITKDBG的节除外。可以通过使用-ss、-as或-r开关来更改此行为。!chkimg将映像和文件之间的任何不匹配显示为映像错误,但以下情况除外:
- 不检查由导入地址表(IAT)占用的地址。
- 某些特定地址哈尔.dll以及Ntoskrnl.exe文件未选中,因为加载这些节时会发生某些更改。要检查这些地址,请包含-nospec选项。
- 如果文件中存在字节值0x90,并且如果值0xF0出现在图像的相应字节中(反之亦然),则将这种情况视为匹配。通常,符号服务器保存单处理器和多处理器版本中都存在的二进制文件的一个版本。在基于x86的处理器上,锁指令是0xF0,而该指令对应于单处理器版本中的nop(0x90)指令。如果你愿意的话!chkimg要将此对显示为不匹配,请设置-noplock选项。
注意,如果您使用-f选项来修复Image不匹配!chkimg只修复那些它认为是错误的不匹配。例如!除非包含-noplock,否则chkimg不会将0x90字节更改为0xF0字节。
当您包含-d选项时!当扫描发生时,chkimg显示所有不匹配区域的摘要。每个不匹配显示在两行上。第一行包括范围的开始、范围的结束、范围的大小、与范围开始相对应的符号名称和偏移量,以及自上一个错误以来的字节数(在括号中)。第二行的十六进制值中包含了一个十六进制值。如果范围大于8个字节,则只有前8个字节显示在冒号之前和冒号之后。下面的示例显示了这种情况。
be000015-be000016 2 bytes - win32k!VeryUsefulFunction+15 (0x8)
[ 85 dd:95 23 ]
有时,驱动程序会使用钩子、重定向或其他方法来更改Microsoft Windows内核的一部分。即使是不再在堆栈中的驱动程序也可能改变了内核的一部分。你可以用!chkimgextension是一个文件比较工具,用于确定驱动程序正在更改Windows内核(或任何其他映像)的哪些部分,以及这些部分是如何更改的。这种比较对完全转储文件最有效。
你也可以用!chkimg和!for_each_module他在一起用于检查每个加载模块的映像。下面的示例显示了这种情况。
!for_each_module !chkimg @#ModuleName
例如,假设您遇到了一个bug检查,并使用 !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显示Win32 K模块的所有错误。
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 -fto修复内存。
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