'메모리 검색'에 해당되는 글 1건

  1. 2008.07.07 [WinDbg 분석] BugCheck 0x8E 9
WinDbg 디버깅2008. 7. 7. 00:05
반응형

이번 예제는 BugCheck 0x8E 이지만 0x8E 자체에 집중하는 예제는 아닙니다. 오히려 새로운 접근 방법에 초점을 맞추고 있습니다. 이런 식으로 분석을 진행할 수도 있다는 방법을 적어보려 합니다.
Dmitry 아저씨 말대로 하면 일종의 분석패턴이라고나 할까요?

오늘의 주제는 모래사장에서 바늘찾기 신공입니다.

0: kd> !analyze -v
*******************************************************************************
*                                                                             *
*                        Bugcheck Analysis                                    *
*                                                                             *
*******************************************************************************

KERNEL_MODE_EXCEPTION_NOT_HANDLED (8e)
This is a very common bugcheck.  Usually the exception address pinpoints
the driver/function that caused the problem.  Always note this address
as well as the link date of the driver/image that contains this address.
Some common problems are exception code 0x80000003.  This means a hard
coded breakpoint or assertion was hit, but this system was booted
/NODEBUG.  This is not supposed to happen as developers should never have
hardcoded breakpoints in retail code, but ...
If this happens, make sure a debugger gets connected, and the
system is booted /DEBUG.  This will let us see why this breakpoint is
happening.
Arguments:
Arg1: c0000005, The exception code that was not handled
Arg2: 8092e20b, The address that the exception occurred at
Arg3: f3a4ea60, Trap Frame
Arg4: 00000000

Debugging Details:
------------------

EXCEPTION_CODE: (NTSTATUS) 0xc0000005 - 0x%08lx

FAULTING_IP:
nt!ObpLookupDirectoryEntry+ee
8092e20b 394608          cmp     dword ptr [esi+8],eax

TRAP_FRAME:  f3a4ea60 -- (.trap 0xfffffffff3a4ea60)
ErrCode = 00000000
eax=0000e470 ebx=e1fdb600 ecx=e1753c2c edx=00000011 esi=00740065 edi=e1753be8
eip=8092e20b esp=f3a4ead4 ebp=f3a4eaec iopl=0         nv up ei pl nz na pe nc
cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00010206
nt!ObpLookupDirectoryEntry+0xee:
8092e20b 394608          cmp     dword ptr [esi+8],eax ds:0023:0074006d=????????
Resetting default scope

DEFAULT_BUCKET_ID:  DRIVER_FAULT
BUGCHECK_STR:  0x8E
PROCESS_NAME:  iexplore.exe
CURRENT_IRQL:  0
LAST_CONTROL_TRANSFER:  from 8085bba7 to 8087c480

STACK_TEXT: 
f3a4e62c 8085bba7 0000008e c0000005 8092e20b nt!KeBugCheckEx+0x1b
f3a4e9f0 808346b4 f3a4ea0c 00000000 f3a4ea60 nt!KiDispatchException+0x3a2
f3a4ea58 80834668 f3a4eaec 8092e20b badb0d00 nt!CommonDispatchException+0x4a
f3a4ea78 80935a06 00000000 f3a4eb67 f3a4eb7c nt!Kei386EoiHelper+0x186
f3a4eaec 8092c2ab e1753b98 f3a4eb14 00000050 nt!SepAccessCheck+0x41d
f3a4eb58 80939f97 00000000 f3a4ec3c 00000000 nt!ObpLookupObjectName+0x45f
f3a4ec48 809305c8 00000000 00000000 00000000 nt!ObReferenceObjectByName+0x8e
f3a4ed10 80920300 0559cd88 0315b948 0315b954 nt!NtSecureConnectPort+0x1d6
f3a4ed3c 80833bdf 0559cd88 0315b948 0315b954 nt!NtConnectPort+0x24
f3a4ed3c 7c9685ec 0559cd88 0315b948 0315b954 nt!KiFastCallEntry+0xfc
...

STACK_COMMAND:  kb

FOLLOWUP_IP:
nt!ObpLookupDirectoryEntry+ee
8092e20b 394608          cmp     dword ptr [esi+8],eax

SYMBOL_STACK_INDEX:  0
SYMBOL_NAME:  nt!ObpLookupDirectoryEntry+ee
FOLLOWUP_NAME:  MachineOwner
MODULE_NAME: nt
IMAGE_NAME:  ntkrnlmp.exe
DEBUG_FLR_IMAGE_TIMESTAMP:  45ec14ca
FAILURE_BUCKET_ID:  0x8E_nt!ObpLookupDirectoryEntry+ee
BUCKET_ID:  0x8E_nt!ObpLookupDirectoryEntry+ee

Followup: MachineOwner
---------

메시지에서는 이 BugCheck 는 익셉션에 의한 것이므로 흔한 것이라고 하고 익셉션 주소를 보고
잘 확인해 보라고 하지만 콜스택을 봐도 내가 만든 모듈은 흔적도 없고 전부 커널함수만 보이니
한숨이 절로 나오고 맙니다.

메시지 마지막 부분에서 nt!ObpLookupDirectoryEntry+ee 에서 죽었음을 강조하면서 MODULE_NAME: nt 를 운운하지만 별로 위안이 되지 않습니다. nt 잘못으로 nt 코드에서 죽는 경우는 거의 없기 때문입니다. 제가 잘못했기 때문인 경우가 대부분이죠.

그렇다고 벌써 포기할 순 없죠. 문제가 발생한 지점으로 되돌리기 위하여 .trap 을 수행합니다.

0: kd> .trap 0xfffffffff3a4ea60
ErrCode = 00000000
eax=0000e470 ebx=e1fdb600 ecx=e1753c2c edx=00000011 esi=00740065 edi=e1753be8
eip=8092e20b esp=f3a4ead4 ebp=f3a4eaec iopl=0         nv up ei pl nz na pe nc
cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00010206
nt!ObpLookupDirectoryEntry+0xee:
8092e20b 394608          cmp     dword ptr [esi+8],eax ds:0023:0074006d=????????

8092e20b 주소에서 0074006d 이라는 주소를 참조하다가 시스템이 죽었습니다.
이 메모리 주소는 참조할 수 없는 유효하지 않은 메모리 주소입니다.

어떻게 이런 주소를 참조하게 되었는지 확인하기 위하여 8092e20b 까지 수행된 내용을 확인합니다.

0: kd> ub eip
nt!ObpLookupDirectoryEntry+0xd1:
8092e1eb f00fb111        lock cmpxchg dword ptr [ecx],edx
8092e1ef 85c0            test    eax,eax
8092e1f1 0f8554ccfdff    jne     nt!ObpLookupDirectoryEntry+0xd9 (8090ae4b)
8092e1f7 c746103412dddd  mov     dword ptr [esi+10h],0DDDD1234h
8092e1fe 8b33            mov     esi,dword ptr [ebx]    <=== esi 에 00740065 를 채운 지점
8092e200 85f6            test    esi,esi
8092e202 0f848a470000    je      nt!ObpLookupDirectoryEntry+0x122 (80932992)
8092e208 8b45f8          mov     eax,dword ptr [ebp-8]
0: kd> u eip
nt!ObpLookupDirectoryEntry+0xee:
8092e20b 394608          cmp     dword ptr [esi+8],eax    <=== 문제발생 지점
8092e20e 0f851a690000    jne     nt!ObpLookupDirectoryEntry+0x112 (80934b2e)
8092e214 8b4604          mov     eax,dword ptr [esi+4]
8092e217 0fb648f4        movzx   ecx,byte ptr [eax-0Ch]
8092e21b ff75f4          push    dword ptr [ebp-0Ch]
8092e21e 83e818          sub     eax,18h
8092e221 2bc1            sub     eax,ecx
8092e223 83c004          add     eax,4

이 때 레지스터 값들도 확인합니다.

0: kd> r
Last set context:
eax=0000e470 ebx=e1fdb600 ecx=e1753c2c edx=00000011 esi=00740065 edi=e1753be8
eip=8092e20b esp=f3a4ead4 ebp=f3a4eaec iopl=0         nv up ei pl nz na pe nc
cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00010206
nt!ObpLookupDirectoryEntry+0xee:
8092e20b 394608          cmp     dword ptr [esi+8],eax ds:0023:0074006d=????????

문제발생 지점에서 esi 가 00740065 이었기 때문에 00740065+8 = 0074006d 를 참조하다가
문제가 발생했습니다.

esi 가 어떻게 0074006d 를 가지게 되었는지 확인하기 위하여 조금 위쪽을 보면 esi 에 00740065 를 채운 지점이 있습니다. [ebx] 에서 읽어온 값이 00740065 입니다.

현재 ebx 는 e1fdb600 이고 이 주소에는 커널모드에서 사용가능한 메모리 포인터가 있어야 하는데 00740065 와 같은 이상한 값이 존재하고 있어서 발생한 문제입니다.

e1fdb600 는 어떤 메모리인지 확인하기 위하여 !pool 명령을 수행합니다.

0: kd> !pool e1fdb600
Pool page e1fdb600 region is Paged pool
 e1fdb000 size:  290 previous size:    0  (Allocated)  Gla:
 e1fdb290 size:   10 previous size:  290  (Free)       9.0.
 ...
 e1fdb490 size:  168 previous size:   a0  (Allocated)  MyMm
e1fdb5f8 is not a valid large pool allocation, checking large session pool...
e1fdb5f8 is freed (or corrupt) pool
Bad previous allocation size @e1fdb5f8, last size was 2d

***
*** An error (or corruption) in the pool was detected;
...
None found

e1fdb600 메모리의 정보를 보여주기 전에 e1fdb5f8 부터 메모리가 손상되었다고 나옵니다. 원래 e1fdb600 에는 정상적인 메모리 포인터가 들어있었을 것 같은데 메모리가 손상되어 이상한 값(00740065)으로 변경된 것으로 보입니다.

보통 메모리가 손상되는 경우는 손상된 메모리 앞쪽의 메모리를 사용하는 드라이버가 메모리 경계를 넘겨서 손상시키는 경우가 많습니다. 앞쪽의 메모리인 e1fdb490 을 보면 mydrv.sys 가 사용하는 MyMm 이라는 메모리 태그를 가지고 있습니다. 따라서 mydrv.sys 가 MyMm 이라는 태그를 가지는 메모리를 조작하다가 e1fdb600 메모리를 손상시켰을 가능성이 있습니다.

e1fdb490 메모리가 mydrv.sys 에서 어떤 용도로 사용되는지를 찾으면 문제의 실마리를 찾을수 있습니다. 이런 건 어떻게 찾으면 좋을까요? 메모리 주소만 가지고 소스코드의 어디에서 사용하는 건지 알 수 있을까요?

일단 문제를 단순화하기 위하여 e1fdb490 주소가 mydrv.sys 드라이버 영역 어디엔가 저장되어 있지 않을까 가정해 봅니다. mydrv.sys 의 전역변수에 저장되어 있을 거라는 가정입니다.

따라서 e1fdb490 주소가 mydrv.sys 의 전역변수에 저장되어 있지는 않은지 메모리 검색을 해 봅니다.
mydrv.sys 의 주소 범위는

0: kd> lmvm mydrv
start    end        module name
f3fa3000 f400ba00   mydrv   (deferred)            
    Image path: \??\C:\WINDOWS\system32\drivers\mydrv.sys
    Image name: mydrv.sys
    Timestamp:        Fri Jun 20 16:04:15 2008 (486490EF)
    CheckSum:         001758C6
    ImageSize:        00168A00
    Translations:     0000.04b0 0000.04e0 0409.04b0 0409.04e0

f3fa3000 부터 f400ba00 까지 입니다.

이 영역에 e1fdb490 이라는 주소값을 저장하고 있는 전역변수가 있는지 검색합니다. 실제 드라이버가 사용하는 메모리 주소는 e1fdb498 이기 때문에 e1fdb498 로 검색합니다. e1fdb490 에서 e1fdb498 까지는 커널에서 메모리헤더로 사용하고 드라이버는 e1fdb498 이라는 주소를 커널로부터 넘겨받아 사용하는 것이기 때문입니다.

0: kd> s f3fa3000 f400ba00 98 b4 fd e1

아무런 결과가 나오지 않았습니다.
mydrv.sys 영역에는 이 메모리 주소가 존재하지 않는 것입니다.

다음엔 어떤 가정이 있을 수 있을까요? 이번엔 메모리를 통채로 뒤져 봅시다. 그야말로 모래사장에서 바늘찾기가 되어 버렸네요.

커널의 메모리 할당영역에서 이 주소값을 찾아봅니다. mydrv.sys 는 PagedPool 만 사용하므로 PagedPool 영역의 범위에서 찾아봅니다. PagedPool 영역의 범위는 파라미터 없이 !pool 명령을 수행하면 나옵니다.

0: kd> !pool
Paged Pool: e1000000 .. eb7fffff
e1000000: 1000 - busy
e1001000: 1000 - busy
e1002000: 1000 - busy
...
...
...
e3e74000: 22000 - busy
e3e9d000: 15000 - free
e3eb2000: 41000 - free
e3ef3000: 22000 - busy
e3f15000: a0c000 - free
e4921000: 6edf000 - free

범위는 e1000000 부터 eb7fffff 까지이지만 뒤부분은 모두 free 상태이고 e3ef3000 까지만 사용중입니다.

e1000000 부터 e3f15000 까지의  영역이 PagedPool 메모리로 사용중입니다.
이 영역에서 e1fdb498 을 저장하고 있는 메모리 영역이 있는지 검색합니다.

0: kd> s e1000000 e3f15000 98 b4 fd e1
e115aec8  98 b4 fd e1 00 00 00 00-05 06 26 0c 42 63 4d 63  ..........&.MyMm

앗싸~ e115aec8 에서 발견되었습니다.
어떤 메모리인지 확인하기 위하여 !pool 명령으로 확인합니다.

0: kd> !pool e115aec8
Pool page e115aec8 region is Paged pool
 e115a000 size:  9d0 previous size:    0  (Allocated)  MyMm
 e115a9d0 size:   18 previous size:  9d0  (Allocated)  Ntf0
 ...
 e115ae20 size:   48 previous size:   68  (Allocated)  Ntfc
 e115ae68 size:   40 previous size:   48  (Allocated)  MyMm
*e115aea8 size:   28 previous size:   40  (Allocated) *MyMm
  Owning component : Unknown (update pooltag.txt)

e115aea8 에 포함된 영역이고 MyMm 메모리 태그를 가졌으므로 역시 mydrv.sys 가 사용하는 메모리입니다.

같은 방법으로 e115aea8 주소를 사용하는 영역이 있는지 확인해 봅니다.
메모리 헤더 크기(8)를 더한 e115aeb0 을 검색해야 합니다.

0: kd> s e1000000 e3f15000 b0 ae 15 e1
e18407e4  b0 ae 15 e1 a0 b4 fd e1-32 00 00 00 c4 ea a4 f3  ........2.......

e18407e4 에 존재하는 것이 확인되었습니다.
어떤 메모리인지 확인하기 위하여 !pool 명령으로 확인합니다.

0: kd> !pool e18407e4
Pool page e18407e4 region is Paged pool
 e1840000 size:   b8 previous size:    0  (Allocated)  Port (Protected)
 e18400b8 size:   10 previous size:   b8  (Allocated)  Glnk
  ...
 e1840720 size:   30 previous size:   18  (Allocated)  CMVa
 e1840750 size:   18 previous size:   30  (Allocated)  Uspi Process: 85b31c88
*e1840768 size:   98 previous size:   18  (Allocated) *MyMm
  Owning component : Unknown (update pooltag.txt)
 e1840800 size:   50 previous size:   98  (Allocated)  LStb
 ...

e1840768 에 포함된 영역이고 MyMm 메모리 태그를 가졌으므로 역시 mydrv.sys 가 사용하는
메모리입니다.

e1840768 주소를 사용하는 영역이 있는지 확인해 봅니다.
메모리 헤더 크기(8)를 더한 e1840770 을 검색해야 합니다.

0: kd> s e1000000 e3f15000 70 07 84 e1
e2f3f874  70 07 84 e1 48 21 13 e2-01 00 00 00 00 00 00 00  p...H!..........

e2f3f874 에 존재하는 것이 확인되었습니다.
어떤 메모리인지 확인하기 위하여 !pool 명령으로 확인합니다.

0: kd> !pool e2f3f874
Pool page e2f3f874 region is Paged pool
 e2f3f000 size:  100 previous size:    0  (Allocated)  IoNm
 e2f3f100 size:   98 previous size:  100  (Allocated)  NtFs
 ...
 e2f3f760 size:  108 previous size:   38  (Allocated)  CM39
*e2f3f868 size:   58 previous size:  108  (Allocated) *MySt
  Owning component : Unknown (update pooltag.txt)
 e2f3f8c0 size:   80 previous size:   58  (Allocated)  IoNm
 ...

e2f3f868 에 포함된 영역이고 MySt 메모리 태그를 가졌습니다.
MySt 메모리 태그도 역시 mydrv.sys 가 사용하는 메모리이지만 특정 구조체를 할당할 때만 사용하는 메모리 태그입니다. 운이 좋았네요. 이것부터 추적이 가능해 보입니다.

mydrv.sys 소스코드에서 이 구조체는 다음과 같습니다.

typedef struct _MY_STRUCT {
 ULONG            ulType;
 DRV_STRUCT  *pDrvStruct1;
 DRV_STRUCT  *pDrvStruct2;
 ...
} MY_STRUCT;

MY_STRUCT 는  TYPE_ID 가 0x10 입니다.
메모리 헤더크기를 더한 e2f3f870 주소의 내용을 보면 첫번째 필드인 ulType 을 확인할 수 있습니다.

0: kd> db e2f3f870
e2f3f870  10 00 00 00 70 07 84 e1-48 21 13 e2 01 00 00 00  ....p...H!......
e2f3f880  00 00 00 00 00 00 00 00-65 73 00 00 00 00 00 00  ........es......
e2f3f890  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................

0x10 으로 일치하네요.

어떤 부분이 메모리를 손상시켰는지 MY_STRUCT 로 부터 역추적해 봅니다.
이제는 e2f3f870 이 MY_STRUCT 라는 것을 알기 때문에 그 내용을 확인해 봅니다.

0: kd> dt mydrv!MY_STRUCT e2f3f870
   +0x000 ulType          : 16
   +0x004 pDrvStruct1    : 0xe1840770
   +0x008 pDrvStruct2    : 0xe2132148
   ...

앞에서 추적하던 메모리 주소 0xe1840770 가 보입니다.
pDrvStruct1 은 DRV_STRUCT 타입이므로 다음과 같이 확인합니다.

0: kd> dt mydrv!DRV_STRUCT e1840770
   +0x000 id               : 64
    ...
   +0x074 pPathStruct   : 0xe115aeb0
   +0x078 pOsPath   : 0xe1fdb4a0  -> 0x5c
   ...

역시 앞에서 추적하던 주소 0xe115aeb0 가 보입니다.
pPathStruct 는 PATH_STRUCT 타입이므로 다음과 같이 확인합니다.

0: kd> dt mydrv!PATH_STRUCT e115aeb0
   +0x000 id               : 6d
   ...
   +0x018 pPathData     : 0xe1fdb498

역시 앞에서 추적하던 주소 0xe1fdb498 이 보입니다.
pPathData 는 PATH_DATA 타입이므로 다음과 같이 확인합니다.

0: kd> dt mydrv!PATH_DATA e1fdb498
   +0x000 pPrev            : (null)
   +0x004 pLimit           : 0xe1fdb5f2  "u"
   +0x008 Data             : []  "\"

0xe1fdb498 의 메모리 내용을 직접 확인합니다.

0: kd> db e1fdb498
e1fdb498  00 00 00 00 f2 b5 fd e1-5c 00 44 00 65 00 76 00  ........\.D.e.v.
e1fdb4a8  69 00 63 00 65 00 5c 00-48 00 61 00 72 00 64 00  i.c.e.\.H.a.r.d.
e1fdb4b8  64 00 69 00 73 00 6b 00-56 00 6f 00 6c 00 75 00  d.i.s.k.V.o.l.u.
e1fdb4c8  6d 00 65 00 32 00 5c 00-57 00 49 00 4e 00 44 00  m.e.2.\.W.I.N.D.
e1fdb4d8  4f 00 57 00 53 00 5c 00-73 00 79 00 73 00 74 00  O.W.S.\.s.y.s.t.
e1fdb4e8  65 00 6d 00 33 00 32 00-5c 00 6f 00 6c 00 65 00  e.m.3.2.\.o.l.e.
e1fdb4f8  33 00 32 00 2e 00 64 00-6c 00 6c 00 00 00 6c 00  3.2...d.l.l...l.
e1fdb508  6c 00 00 00 6c 00 6c 00-00 00 74 00 6f 00 72 00  l...l.l...t.o.r.
e1fdb518  5c 00 4c 00 6f 00 63 00-61 00 6c 00 20 00 53 00  \.L.o.c.a.l. .S.
e1fdb528  65 00 74 00 74 00 69 00-6e 00 67 00 73 00 5c 00  e.t.t.i.n.g.s.\.
e1fdb538  54 00 65 00 6d 00 70 00-6f 00 72 00 61 00 72 00  T.e.m.p.o.r.a.r.
e1fdb548  79 00 20 00 49 00 6e 00-74 00 65 00 72 00 6e 00  y. .I.n.t.e.r.n.
e1fdb558  65 00 74 00 20 00 46 00-69 00 6c 00 65 00 73 00  e.t. .F.i.l.e.s.
e1fdb568  5c 00 43 00 6f 00 6e 00-74 00 65 00 6e 00 74 00  \.C.o.n.t.e.n.t.
e1fdb578  2e 00 49 00 45 00 35 00-5c 00 39 00 46 00 4c 00  ..I.E.5.\.9.F.L.
e1fdb588  4b 00 4f 00 4d 00 4a 00-31 00 5c 00 6d 00 61 00  K.O.M.J.1.\.m.a.
e1fdb598  70 00 5b 00 31 00 5d 00-2e 00 67 00 69 00 66 00  p.[.1.]...g.i.f.
e1fdb5a8  00 00 5d 00 2e 00 67 00-69 00 66 00 00 00 69 00  ..]...g.i.f...i.
e1fdb5b8  66 00 00 00 00 00 69 00-66 00 00 00 69 00 63 00  f.....i.f...i.c.
e1fdb5c8  65 00 5c 00 48 00 61 00-72 00 64 00 64 00 69 00  e.\.H.a.r.d.d.i.
e1fdb5d8  73 00 6b 00 56 00 6f 00-6c 00 75 00 6d 00 65 00  s.k.V.o.l.u.m.e.
e1fdb5e8  32 00 5c 00 44 00 6f 00-63 00 75 00 6d 00 65 00  2.\.D.o.c.u.m.e.
e1fdb5f8  6e 00 74 00 73 00 53 00-65 00 74 00 74 00 69 00  n.t.s.S.e.t.t.i.
e1fdb608  6e 00 67 00 73 00 5c 00-41 00 64 00 6d 00 69 00  n.g.s.\.A.d.m.i.
e1fdb618  6e 00 69 00 73 00 74 00-72 00 61 00 74 00 6f 00  n.i.s.t.r.a.t.o.
e1fdb628  72 00 5c 00 4c 00 6f 00-63 00 61 00 6c 00 20 00  r.\.L.o.c.a.l. .
e1fdb638  53 00 65 00 74 00 74 00-69 00 6e 00 67 00 73 00  S.e.t.t.i.n.g.s.
e1fdb648  5c 00 54 00 65 00 6d 00-70 00 6f 00 72 00 61 00  \.T.e.m.p.o.r.a.
e1fdb658  72 00 79 00 20 00 49 00-6e 00 74 00 65 00 72 00  r.y. .I.n.t.e.r.
e1fdb668  6e 00 65 00 74 00 20 00-46 00 69 00 6c 00 65 00  n.e.t. .F.i.l.e.
e1fdb678  73 00 5c 00 43 00 6f 00-6e 00 74 00 65 00 6e 00  s.\.C.o.n.t.e.n.
e1fdb688  74 00 2e 00 49 00 45 00-35 00 5c 00 39 00 46 00  t...I.E.5.\.9.F.
e1fdb698  4c 00 4b 00 4f 00 4d 00-4a 00 31 00 5c 00 62 00  L.K.O.M.J.1.\.b.
e1fdb6a8  30 00 32 00 5f 00 6f 00-6e 00 5f 00 6f 00 66 00  0.2._.o.n._.o.f.
e1fdb6b8  66 00 2d 00 4c 00 5b 00-31 00 5d 00 2e 00 67 00  f.-.L.[.1.]...g.
e1fdb6c8  69 00 66 00 00 00 01 00-88 20 c6 85 88 a8 cd 85  i.f...... ......

e1fdb498 부터 e1fdb6c8 까지 모두 파일경로 문자열로 차있습니다.
하지만 e1fdb498 메모리는 e1fdb5f7 까지만 사용하도록 할당된 영역입니다.

0: kd> !pool e1fdb498
Pool page e1fdb498 region is Paged pool
 e1fdb000 size:  290 previous size:    0  (Allocated)  Gla:
 ...
 e1fdb3f0 size:   a0 previous size:    8  (Allocated)  Gla8
*e1fdb490 size:  168 previous size:   a0  (Allocated) *MyMm
  Owning component : Unknown (update pooltag.txt)
e1fdb5f8 is not a valid large pool allocation, checking large session pool...
e1fdb5f8 is freed (or corrupt) pool

e1fdb5f8 자리에 nt 커널에서 사용하는 어떤 메모리가 할당되어 있었는데 mydrv.sys 가
e1fdb498 메모리를 사용하다가 경계를 넘어서 덮어 쓰는 바람에 nt 커널이 사용하던 내용이
모두 지워지고 파일 경로 문자열이 덮어진 것입니다.

이번 문제는 PATH_DATA 를 다루는 코드에서 할당된 크기보다 더 많은 문자열을 써넣는 버그로 밝혀졌습니다.

메모리를 깨먹는 문제라서 처음부터 너무 겁먹고 시작한 감은 있었는데요.
이번 분석을 하면서 제가 얻은 교훈은 다음과 같이 정리되네요.

1. 아무리 어려워 보여도 일단 부딪혀 봐라.
2. 깨진 메모리 영역을 찾아라.
3. 깨진 메모리 영역 앞의 메모리 주인을 찾아라. (그것이 나의 것이라면 더 말할것도 없이 나의 문제이다.)
4. 메모리 검색을 십분 활용하라.

이제 메모리 깨지는 문제에 살짝 자신감이 붙기 시작하네요. ^^

반응형
Posted by GreeMate