커널 메모리가 손상되면 분석하기 매우 곤란한 경우가 많은데요.
그중에서 분석이 가능한 한 가지 상황에 대해 분석을 진행해 보겠습니다.
이번 분석의 초식은 "깨진 메모리 앞쪽 메모리를 의심하라" 입니다.
MyDrv.sys가 사용중인 메모리가 손상돼 발생한 덤프입니다.
0: kd> !analyze -v
*******************************************************************************
* *
* Bugcheck Analysis *
* *
*******************************************************************************
DRIVER_IRQL_NOT_LESS_OR_EQUAL (d1)
An attempt was made to access a pageable (or completely invalid) address at an
interrupt request level (IRQL) that is too high. This is usually
caused by drivers using improper addresses.
If kernel debugger is available get stack backtrace.
Arguments:
Arg1: 00000008, memory referenced
Arg2: 00000002, IRQL
Arg3: 00000000, value 0 = read operation, 1 = write operation
Arg4: 8c032fa5, address which referenced memory
Debugging Details:
------------------
READ_ADDRESS: 00000008
CURRENT_IRQL: 2
FAULTING_IP:
MyDrv!GetListEntry+85
8c032fa5 3b5108 cmp edx,dword ptr [ecx+8]
DEFAULT_BUCKET_ID: WIN7_DRIVER_FAULT
BUGCHECK_STR: 0xD1
PROCESS_NAME: SomeProcess.exe
TRAP_FRAME: bdf939b4 -- (.trap 0xffffffffbdf939b4)
ErrCode = 00000000
eax=00000000 ebx=8c0344b0 ecx=00000000 edx=c339fdc0 esi=0101ed94 edi=bdf93b60
eip=8c032fa5 esp=bdf93a28 ebp=bdf93a4c iopl=0 nv up ei pl nz na pe cy
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00010207
MyDrv!GetListEntry+0x85:
8c032fa5 3b5108 cmp edx,dword ptr [ecx+8] ds:0023:00000008=????????
Resetting default scope
LAST_CONTROL_TRANSFER: from 8c032fa5 to 83248b7f
STACK_TEXT:
bdf939b4 8c032fa5 badb0d00 c339fdc0 00000000 nt!KiTrap0E+0x1b3
bdf93a4c 8c03331d c339fdc0 a0fa8b08 bdf93a68 MyDrv!GetListEntry+0x85
bdf93a5c 8c0325fc c339fdc0 bdf93a7c 8c0364e5 MyDrv!GetEntryTable+0xd
...
bdf93c10 76e270f4 0101f08c 00020019 0101eda0 nt!KiSystemServicePostCall
WARNING: Frame IP not in any known module. Following frames may be wrong.
0101ef94 00000000 00000000 00000000 00000000 0x76e270f4
STACK_COMMAND: kb
FOLLOWUP_IP:
MyDrv!GetListEntry+85
8c032fa5 3b5108 cmp edx,dword ptr [ecx+8]
SYMBOL_STACK_INDEX: 1
SYMBOL_NAME: MyDrv!GetListEntry+85
FOLLOWUP_NAME: MachineOwner
MODULE_NAME: MyDrv
IMAGE_NAME: MyDrv.sys
DEBUG_FLR_IMAGE_TIMESTAMP: 5099ff75
FAILURE_BUCKET_ID: 0xD1_MyDrv!GetListEntry+85
BUCKET_ID: 0xD1_MyDrv!GetListEntry+85
Followup: MachineOwner
---------
.trap 명령으로 죽은 시점을 복원합니다.
0: kd> .trap 0xffffffffbdf939b4
ErrCode = 00000000
eax=00000000 ebx=8c0344b0 ecx=00000000 edx=c339fdc0 esi=0101ed94 edi=bdf93b60
eip=8c032fa5 esp=bdf93a28 ebp=bdf93a4c iopl=0 nv up ei pl nz na pe cy
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00010207
MyDrv!GetListEntry+0x85:
8c032fa5 3b5108 cmp edx,dword ptr [ecx+8] ds:0023:00000008=????????
GetListEntry 함수에서 죽었는데 변수를 살펴보면 pListEntry 가 NULL이어서 문제가 발생했습니다.
0: kd> dv
pListHead = 0x8c038d00 [ 0x89e95988 - 0x864f3ea8 ]
pListEntry = 0x00000000
pListEntry는 pListHead에서 연결되는 리스트이므로 pListHead를 살펴봅니다.
0: kd> dl 0x8c038d00
8c038d00 89e95988 864f3ea8 8c038d08 8c038d08
89e95988 00000000 00000000 00000000 00000000
pListHead가 가리키는 89e95988의 내용은 더블 링크드 리스트라서 00000000이면 안되고 어떤 포인터가 들어 있어야 하는데 00000000 이 들어 있습니다.
기존에 있던 포인터 값이 0으로 덮어써진 것으로 추정됩니다.
0: kd> db 89e95988
89e95988 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
89e95998 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
89e959a8 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
89e959b8 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
89e959c8 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
89e959d8 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
89e959e8 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
89e959f8 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
어떤 모듈이 이 영역을 덮어쓰는지 추적합니다.
일단 메모리 정보를 확인합니다.
0: kd> !pool 89e95988
Pool page 89e95988 region is Nonpaged pool
89e95808 doesn't look like a valid small pool allocation, checking to see
if the entire page is actually part of a large page allocation...
89e95808 is freed (or corrupt) pool
Bad previous allocation size @89e95808, last size was 0
...
Pool page [ 89e95000 ] is __inVALID.
Analyzing linked list...
[ 89e95000 ]: invalid previous size [ 0x43 ] should be [ 0x0 ]
[ 89e95000 --> 89e95c10 (size = 0xc10 bytes)]: Corrupt region
Scanning for single bit errors...
None found
메모리 헤더까지 손상되어 정보가 나오지 않습니다.
바로 앞 페이지의 정보를 확인합니다.
보통은 앞의 메모리를 사용하는 모듈이 뒤 부분의 메모리를 손상시키기 때문입니다.
0: kd> !pool 89e94378
Pool page 89e94378 region is Nonpaged pool
*89e89000 : large page allocation, Tag is Ddk , size is 0xc808 bytes
Pooltag Ddk : Default for driver allocated memory (user's of ntddk.h)
Ddk 태그를 가진 메모리가 확인됩니다. 이 부분은 손상되지 않았습니다.
이 메모리를 사용하는 모듈이 메모리를 손상했을 가능성이 높습니다.
89e89000 메모리를 들여다보면 특정한 패턴을 가지고 있고 이 패턴이 0xc808 길이를 넘어서 이어집니다.
따라서 이 메모리를 사용하던 모듈이 메모리 경계를 넘어서 메모리를 손상시켰다고 가정할 수 있습니다.
Ddk는 디폴트 태그라서 태그로는 어떤 모듈이 사용중인지 알 수 없으니...
시스템에 로드된 모듈중에서 89e89000 라는 메모리 포인터를 가지고 있는 모듈을 검색합니다.
0: kd> !for_each_module s @#Base @#End 00 90 e8 89
Page 69a9 not present in the dump file. Type ".hh dbgerr004" for details
Page 6414d not present in the dump file. Type ".hh dbgerr004" for details
Page 63b60 not present in the dump file. Type ".hh dbgerr004" for details
bebb5424 00 90 e8 89 21 00 00 00-00 00 00 00 01 00 00 00 ....!...........
다행히 bebb5424 하나만 찾아지네요.
bebb5424 위치에서 89e89000 포인터를 보관하고 있습니다.
bebb5424 은 어떤 모듈인지 확인합니다.
0: kd> u bebb5424
NotMyDrv+0x6424:
bebb5424 0090e8892100 add byte ptr [eax+2189E8h],dl
bebb542a 0000 add byte ptr [eax],al
bebb542c 0000 add byte ptr [eax],al
bebb542e 0000 add byte ptr [eax],al
bebb5430 0100 add dword ptr [eax],eax
bebb5432 0000 add byte ptr [eax],al
bebb5434 0800 or byte ptr [eax],al
bebb5436 0000 add byte ptr [eax],al
NotMyDrv.sys 모듈의 내부로 나옵니다.
NotMyDrv.sys 내부의 어떤 위치인지 확인합니다.
0: kd> lmvm NotMyDrv
start end module name
bebaf000 bebbe780 NotMyDrv (no symbols)
Loaded symbol image file: NotMyDrv.sys
Image path: \??\C:\Windows\system32\Drivers\NotMyDrv.sys
Image name: NotMyDrv.sys
0: kd> !dh bebaf000
File Type: EXECUTABLE IMAGE
FILE HEADER VALUES
14C machine (i386)
5 number of sections
4D880A01 time date stamp Tue Mar 22 11:31:29 2011
0 file pointer to symbol table
0 number of symbols
E0 size of optional header
10E characteristics
Executable
Line numbers stripped
Symbols stripped
32 bit word machine
OPTIONAL HEADER VALUES
10B magic #
6.00 linker version
6300 size of code
9200 size of initialized data
0 size of uninitialized data
50D3 address of entry point
280 base of code
----- new -----
00010000 image base
80 section alignment
80 file alignment
1 subsystem (Native)
5.00 operating system version
5.00 image version
1.10 subsystem version
F780 size of image
280 size of headers
16350 checksum
00040000 size of stack reserve
00001000 size of stack commit
00100000 size of heap reserve
00001000 size of heap commit
0 DLL characteristics
0 [ 0] address [size] of Export Directory
E680 [ 3C] address [size] of Import Directory
EC00 [ 4A8] address [size] of Resource Directory
0 [ 0] address [size] of Exception Directory
0 [ 0] address [size] of Security Directory
F100 [ 4F8] address [size] of Base Relocation Directory
370 [ 1C] address [size] of Debug Directory
0 [ 0] address [size] of Description Directory
0 [ 0] address [size] of Special Directory
0 [ 0] address [size] of Thread Storage Directory
0 [ 0] address [size] of Load Configuration Directory
0 [ 0] address [size] of Bound Import Directory
280 [ F0] address [size] of Import Address Table Directory
0 [ 0] address [size] of Delay Import Directory
0 [ 0] address [size] of COR20 Header Directory
0 [ 0] address [size] of Reserved Directory
SECTION HEADER #1
.text name
5D18 virtual size
280 virtual address
5D80 size of raw data
280 file pointer to raw data
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
68000020 flags
Code
Not Paged
(no align specified)
Execute Read
Debug Directories(1)
Type Size Address Pointer
cv 8d 0 f780 [Debug data not mapped]
SECTION HEADER #2
.data name
8680 virtual size
6000 virtual address
8680 size of raw data
6000 file pointer to raw data
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
C8000040 flags
Initialized Data
Not Paged
(no align specified)
Read Write
SECTION HEADER #3
INIT name
556 virtual size
E680 virtual address
580 size of raw data
E680 file pointer to raw data
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
E2000020 flags
Code
Discardable
(no align specified)
Execute Read Write
SECTION HEADER #4
.rsrc name
4A8 virtual size
EC00 virtual address
500 size of raw data
EC00 file pointer to raw data
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
42000040 flags
Initialized Data
Discardable
(no align specified)
Read Only
SECTION HEADER #5
.reloc name
61E virtual size
F100 virtual address
680 size of raw data
F100 file pointer to raw data
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
42000040 flags
Initialized Data
Discardable
(no align specified)
Read Only
bebb5424은 bebaf000 + 6000 에서 시작하는 data SECTION에 위치하는 메모리입니다.
NotMyDrv.sys의 데이터 영역에 있으므로 이 드라이버에서 사용하는 전역변수로 추정됩니다.
결국 NotMyDrv.sys라는 드라이버가 MyDrv.sys가 사용하는 메모리를 overwrite해서 발생하는 문제로 볼 수 있습니다.