WinDbg 디버깅2013. 5. 11. 01:00
반응형

특정 모듈이 어떤 문자열을 가지고 있는지 확인하고 싶은 경우가 있다.

 

예를 들면, 어떤 기능을 하는 것인지, 어느 회사에서 만든 모듈인지 확인하고 싶은 경우처럼 말이다.

 

먼저 특정 모듈의 주소를 확인한다.

이 예제에서는  Beep.sys를 확인해 본다.

 

kd> lm
start    end        module name
804d9000 806e4000   nt         (pdb symbols)         

806e4000 80704d00   hal        (deferred)            
...

f7afa000 f7afbf00   Fs_Rec     (deferred)            
f7afc000 f7afd080   Beep       (deferred)            
...

 

 

이 모듈에 포함된 ASCII 형태의 문자열을 다음과 같이 확인할 수 있다.

 

kd> s -sa f7afc000 f7afd080
f7afc04d  "!This program cannot be run in D"
f7afc06d  "OS mode."
f7afc0b8  "Rich"
f7afc1c8  ".text"
f7afc1ef  "h.rdata"
f7afc217  "HINIT"
f7afc240  ".rsrc"
f7afc267  "B.reloc"
f7afc30f  "N@Q"
f7afc323  "F%P"
f7afc331  "F%P"
f7afc357  "QQSVW"
f7afc3a3  "t)3"
f7afc3f6  "_^3"
f7afc470  "p(W"
f7afc4cd  "NHu%W"
f7afc524  "p(W"
f7afc5bb  "tQRP"
f7afc608  "p(j"
f7afc672  "SWhR"
f7afc697  "PjXW"
f7afc6b1  "p(Ph"
f7afc6cc  "@SP"
f7afc6d3  "F4P"
f7afc6f0  "G4 "
f7afc6f7  "G8j"
f7afc717  "^_["
f7afc780  "tin"
f7afc790  "@in"
f7afc7c0  "ngW"
f7afc80c  "RSDS"
f7afc815  "9LN"
f7afc824  "beep.pdb"
f7afc922  "IofCompleteRequest"
f7afc938  "IoReleaseCancelSpinLock"
f7afc952  "KeRemoveEntryDeviceQueue"
f7afc96e  "KeRemoveDeviceQueue"
f7afc984  "IoAcquireCancelSpinLock"
f7afc99e  "IoStartPacket"
f7afc9ae  "MmLockPagableDataSection"
f7afc9ca  "KeCancelTimer"
f7afc9da  "MmUnlockPagableImageSection"
f7afc9f8  "IoStartNextPacket"
f7afca0c  "KeSetTimer"
f7afca1a  "_allmul"
f7afca24  "IoDeleteDevice"
f7afca36  "KeInitializeEvent"
f7afca4a  "KeInitializeTimer"
f7afca5e  "KeInitializeDpc"
f7afca70  "IoCreateDevice"
f7afca82  "RtlInitUnicodeString"
f7afca98  "ntoskrnl.exe"
f7afcaa8  "HalMakeBeep"
f7afcab6  "KfLowerIrql"
f7afcac4  "KfRaiseIrql"
f7afcad2  "ExReleaseFastMutex"
f7afcae8  "ExAcquireFastMutex"
f7afcafc  "HAL.dll"
f7afcf89  "3(363K3`3f3"
f7afcf9f  "3I4V4`4z4"
f7afcfb9  "505@5U5"
f7afcfcb  "676I6u6"
f7afcfe9  "7 7"

 

 

이 모듈에 포함된 UNICODE 형식의 문자열은 다음과 같이 확인할 수 있다.

 

kd> s -su f7afc000 f7afd080
f7afc044  "됀촉렡䰁"
f7afc04e  "桔獩瀠潲牧浡挠湡潮"

...

f7afcad2  "硅敒敬獡䙥獡䵴瑵硥"

f7afcae8  "硅捁畱物䙥獡䵴瑵硥"
f7afcbe6  "VS_VERSION_INFO"
f7afcc42  "StringFileInfo"
f7afcc66  "040904B0"
f7afcc7e  "CompanyName"
f7afcc98  "Microsoft Corporation"
f7afccca  "FileDescription"
f7afccec  "BEEP Driver"
f7afcd0a  "FileVersion"
f7afcd24  "5.1.2600.0 (XPClient.010817-1148"
f7afcd64  ")"
f7afcd6e  "InternalName"
f7afcd88  "beep.sys"
f7afcda2  "LegalCopyright"
f7afcdc0  "© Microsoft Corporation. All rig"
f7afce00  "hts reserved."
f7afce22  "OriginalFilename"
f7afce44  "beep.sys"
f7afce5e  "ProductName"
f7afce78  "Microsoft® Windows® Operating Sy"
f7afceb8  "stem"
f7afceca  "ProductVersion"
f7afcee8  "5.1.2600.0"
f7afcf06  "VarFileInfo"
f7afcf26  "Translation"

 

문자열들을 보면 대충 어떤 모듈인지 파악할 수 있다.

 

반응형
Posted by GreeMate
WinDbg 디버깅2013. 5. 10. 00:04
반응형

특정 문자열이 어떤 모듈에 포함된 것인지 확인하고 싶은 경우가 있다.


예를 들면, ExAllocatePoolWithTag()로 할당한 메모리에 주어지는 Tag 문자열로 

어떤 드라이버 모듈이 이 메모리를 할당했는지 확인하고 싶은 경우처럼 말이다.


!for_each_module과 s -a 명령을 조합하면 쉽게 찾을 수 있다.


kd> !for_each_module s -a @#Base @#End "NtFE"

f73a878f  4e 74 46 45 50 6a 11 89-45 0c ff 15 14 0e 35 f7  NtFEPj..E.....5.

f73a8fce  4e 74 46 45 57 6a 11 ff-15 14 0e 35 f7 89 45 dc  NtFEWj.....5..E.

f73a92eb  4e 74 46 45 ff 75 d4 6a-11 ff 15 14 0e 35 f7 89  NtFE.u.j.....5..

f73a93de  4e 74 46 45 ff 75 a8 6a-11 ff 15 14 0e 35 f7 89  NtFE.u.j.....5..


kd> ln f73a878f

(f73a8745)   Ntfs!NtfsAppendEa+0x4a   |  (f73a885c)   Ntfs!NtfsDeleteEa


kd> ln f73a93de

(f73a91f4)   Ntfs!NtfsCommonSetEa+0x1e0   |  (f73a953a)   Ntfs!NtfsQueryCompressed


f73a878f와 f73a93de 사이에서 NtFE 문자열을 찾았다.

이 주소를 어떤 모듈이 사용하는지 조회해 보니 Ntfs가 사용하는 것으로 나타났다.

따라서 Ntfs에서 NtFE라는 메모리 태그를 사용한다는 것을 알 수 있다.


디버깅 환경이 아니라 실제 시스템에서도 이와 비슷한 작업을 할 수 있는데 

DOS 명령 중 findstr을 이용한 방법이다.


C:\WINDOWS\system32\drivers>findstr /M /L "NtFE" *.sys

ntfs.sys


이와 같이 간단하게 특정 문자열을 가진 모듈을 찾을 수도 있다.


반응형
Posted by GreeMate
WinDbg 디버깅2013. 3. 11. 23:38
반응형

실행중인 프로세스들은 디버거를 Attach하면 바로 디버깅할 수 있는데...

아직 실행 안된 프로세스를 실행하자마자 디버깅하려면 곤란한 때가 있다.


이 때 Image File Execution Options을 사용하면 편리한데 아래와 같이 잘 정리해 둔 사이트가 있어 링크해 둔다. ^^


http://byung.egloos.com/3572751


http://blogs.technet.com/b/askperf/archive/2008/12/12/two-minute-drill-configuring-a-debugger-using-image-file-execution-options.aspx


반응형
Posted by GreeMate
WinDbg 디버깅2012. 7. 17. 08:47
반응형

매우 기초적인 WinDbg 사용 방법에 대한 글이지만 간략히 잘 정리되어 있어 링크해 봅니다.

처음 시작하시는 분들이 참고하시기에 괜찮을 것 같네요. ^^


http://www.cmlab.csie.ntu.edu.tw/~cathyp/eBooks/WindowsNT/Driver/kernel_debugging_tutorial.pdf

반응형
Posted by GreeMate
WinDbg 디버깅2012. 3. 1. 00:15
반응형
Visual Studio 2008로 개발하면서 VMWare의 애플리케이션을 직접 디버깅하고 싶어서 설정하는 법을 좀 찾아 봤습니다.

많은 정보들이 있지만 세개만 링크해 봅니다. ^^

http://www.vmware.com/pdf/ws7_visualstudio_debug.pdf
http://thepassion.tistory.com/181
http://blog.naver.com/PostView.nhn?blogId=rantris&logNo=30082633729  
반응형
Posted by GreeMate
WinDbg 디버깅2010. 5. 25. 00:08
반응형
지금 감동의 눈물을 흘리고 있습니다. T_T

http://hexblog.com/2010/04/kernel_debugging_with_ida_pro_1.html

IDA로 커널 디버깅을 할 수 있다는 포스팅을 보고 따라해 보려고 했는데요.
IDA까지 안쓰더라도 VirtualKd를 설치해서 VMWare와 WinDbg를 연결해 커널디버깅을 할 수 있더군요.

그런데 이게 감동입니다.
분명 커널 디버깅인데 코드를 trace하는 속도가 거의 APP 디버깅과 같더군요.

이 좋은 걸 이제야 알다니... 흑흑
반응형
Posted by GreeMate
WinDbg 디버깅2010. 4. 28. 00:10
반응형

지난번 노가다 포스팅에 이어 태화님이 알려주신 깔끔 팁을 정리해 봅니다.

WinDbg는 Debug 메뉴에 Event Filters... 라는 항목이 있습니다.
각종 이벤트들을 디버거가 잡아주도록 하는 설정인데요.

여기에서 Load module을 enable해 놓으면 됩니다.


이렇게 설정해 놓고 드라이버를 로드하면 드라이버 이미지만 메모리에 로드하고 DriverEntry를 실행하기 전에 깔끔하게 브레이크 포인트가 걸립니다.

이 때 콜스택을 보면 아래와 같습니다.

kd> kb
ChildEBP RetAddr  Args to Child             
f9dffaa4 80528fce f9dffb3c f9dffab8 00000003 nt!DebugService2+0x10
f9dffac8 805a4cea f9dffb3c f9f90000 ffffffff nt!DbgLoadImageSymbols+0x42
f9dffc6c 80577254 f9dffcf0 00000000 00000000 nt!MmLoadSystemImage+0xa34
f9dffd4c 8057765f 00000528 00000001 00000000 nt!IopLoadDriver+0x370
f9dffd74 80535dd0 00000528 00000000 817ba020 nt!IopLoadUnloadDriver+0x45
f9dffdac 805c6a28 f7d18cf4 00000000 00000000 nt!ExpWorkerThread+0x100
f9dffddc 80542fa2 80535cd0 00000001 00000000 nt!PspSystemThreadStartup+0x34
00000000 00000000 00000000 00000000 00000000 nt!KiThreadStartup+0x16

여기서 DriverEntry의 주소를 어떻게 찾아야 하나 잠깐 당황했는데요. 
DbgLoadImageSymbols()의 인자로 ImageBase가 전달되므로 찾을 수 있습니다.

VOID
NTAPI
DbgLoadImageSymbols(
     IN PANSI_STRING Name,
     IN PVOID Base,
     IN ULONG_PTR ProcessId
)

콜스택에서 보이는 인자를 하나씩 확인해 보면

kd> ds f9dffb3c
816faf00  "\WINDOWS\System32\Drivers\Null.S"
816faf20  "YS"

kd> lmvm null
start    end        module name
f9f90000 f9f90b80   Null       (deferred)            
    Image path: Null.SYS
    Image name: Null.SYS
    ...

드라이버 이름에 대한 주소라는 것과 드라이버의 ImageBase 주소라는 것을 확인할 수 있습니다.

ImageBase를 알고 있으므로 !dh 명령으로 EntryPoint를 구합니다.

kd> !dh f9f90000

File Type: EXECUTABLE IMAGE
FILE HEADER VALUES
     14C machine (i386)
       6 number of sections
3B7D82EB time date stamp Sat Aug 18 05:47:39 2001

...

OPTIONAL HEADER VALUES
     10B magic #
    7.00 linker version
     300 size of code
     580 size of initialized data
       0 size of uninitialized data
     59A address of entry point
     300 base of code


ImageBase에 address of entry point를 더해 주면 DriverEntry의 주소가 됩니다.


kd> u f9f90000 + 59A
Null!DriverEntry:
f9f9059a 55              push    ebp
f9f9059b 8bec            mov     ebp,esp
f9f9059d 83ec0c          sub     esp,0Ch
f9f905a0 56              push    esi

깔끔하고 쉽게 구하는 방법이 있었네요. ^^

 

반응형
Posted by GreeMate
WinDbg 디버깅2010. 4. 21. 01:10
반응형

간혹 악성 드라이버를 분석할 일이 있는데 이 녀석의 시작점인 DriverEntry부터 보고 싶은 경우 어찌할 바를 몰라 고민하는 경우가 있었습니다.

그러다 생각한 것이 커널 내부함수인 IopLoadDriver로 부터 따라가서 들어가는 방법인데요. 노가다가 좀 심합니다. 그래도 정리해 보면 좋을 것 같아서 포스팅해 봅니다. (누가 좀 효율적인 방법 좀 알면 알려주세요. -_-a)

XP SP2 기준이구요 예제로 Null 드라이버를 로드해 봤습니다. 
먼저 IopLoadDriver에 브레이크 포인트를 겁니다.

kd> bp nt!IopLoadDriver
kd> bl
 0 e 805a5ba3     0001 (0001) nt!IopLoadDriver

g로 실행하고 나서 OsrLoader 같은 것으로 Null 드라이버를 로드합니다. 그러면 드라이버를 로드하는 과정에서 브레이크 포인트가 걸립니다.

Breakpoint 0 hit
nt!IopLoadDriver:
805a5ba3 8bff            mov     edi,edi

kd> k
ChildEBP RetAddr 
f9e93d4c 805a627c nt!IopLoadDriver
f9e93d74 804e626b nt!IopLoadUnloadDriver+0x45
f9e93dac 8057f16b nt!ExpWorkerThread+0x100
f9e93ddc 804fa27a nt!PspSystemThreadStartup+0x34
00000000 00000000 nt!KiThreadStartup+0x16

콜스택을 보면 시스템에서 드라이버를 로드하는 과정임을 볼 수 있습니다. IopLoadDriver 시작위치에서 멈췄네요.

이제 새로운 명령어인 pc(Step to Next Call)을 사용해 볼껀데요.
이 명령을 사용하면 현재 실행주소로부터 다음 call을 만날 때까지 쭉~ 실행됩니다.
다음 call에서 멈추지요. 자... 이제 pc를 수행합니다.

kd> pc
nt!IopLoadDriver+0x4b:
805a5bee e836b0fcff      call    nt!NtQueryKey (80570c29)

NtQueryKey를 호출하는 부분에서 멈췄네요.
앞뒤의 코드를 모두 보이면 아래와 같습니다.

805a5bde 66895d9a        mov     word ptr [ebp-66h],bx
805a5be2 895d9c          mov     dword ptr [ebp-64h],ebx
805a5be5 899d78ffffff    mov     dword ptr [ebp-88h],ebx
805a5beb 895da8          mov     dword ptr [ebp-58h],ebx
805a5bee e836b0fcff      call    nt!NtQueryKey (80570c29)
805a5bf3 3d05000080      cmp     eax,80000005h
805a5bf8 740b            je      nt!IopLoadDriver+0x6a (805a5c05)
805a5bfa 3d230000c0      cmp     eax,0C0000023h
805a5bff 0f856d330400    jne     nt!IopLoadDriver+0x5e (805e8f72)

코드에 특이사항이 없으므로 다시 pc를 실행하여 다음 call까지 실행하게 합니다.

kd> pc
nt!IopLoadDriver+0x78:
805a5c13 e8ac6ffaff      call    nt!ExAllocatePoolWithTag (8054cbc4)

메모리를 할당하는 부분이네요. 원하는 부분이 아니므로 또 pc를 합니다.
엔터만 쳐서 이전 명령을 그대로 수행하는 WinDbg의 기능을 사용해 보죠.

kd>
nt!IopLoadDriver+0x99:
805a5c34 e8f0affcff      call    nt!NtQueryKey (80570c29)

kd>
nt!IopLoadDriver+0xca:
805a5c65 e85a6ffaff      call    nt!ExAllocatePoolWithTag (8054cbc4)

kd>
nt!IopLoadDriver+0x114:
805a5caf e8cd46f5ff      call    nt!RtlAppendUnicodeToString (804fa381)

kd>
nt!IopLoadDriver+0x11f:
805a5cba e8d75af6ff      call    nt!HeadlessKernelAddLogEntry (8050b796)

kd>
nt!IopLoadDriver+0x1e6:
805a5cd8 e8c956f3ff      call    nt!ExAcquireResourceSharedLite (804db3a6)

kd>
nt!IopLoadDriver+0x1fd:
805a5cf5 e8ac26f6ff      call    nt!RtlEqualString (805083a6)

kd>
nt!IopLoadDriver+0x1fd:
805a5cf5 e8ac26f6ff      call    nt!RtlEqualString (805083a6)

관심있는 부분까지 계속 진행해야 하는데 이 쯤에서 RtlEqualString이 반복됩니다.
루프인 것 같아서 뒤부분의 코드를 살펴 봅니다.

805a5cf5 e8ac26f6ff      call    nt!RtlEqualString (805083a6)805a5cfa 84c0            test    al,al
805a5cfc 0f8531330400    jne     nt!IopLoadDriver+0x23a (805e9033)
805a5d02 8b3f            mov     edi,dword ptr [edi]
805a5d04 ebdd            jmp     nt!IopLoadDriver+0x208 (805a5ce3)
805a5d06 2e005300        add     byte ptr cs:[ebx],dl
805a5d0a 59              pop     ecx
805a5d0b 005300          add     byte ptr [ebx],dl
805a5d0e 0000            add     byte ptr [eax],al
805a5d10 0000            add     byte ptr [eax],al
805a5d12 8bce            mov     ecx,esi
805a5d14 e83779f3ff      call    nt!ExReleaseResourceLite (804dd650)

루프 바깥 부분에 브레이크 포인트를 걸어주고 그냥 go를 해버려서 루프를 빠져나가려고 합니다.

루프 바깥에 브레이크 포인트를 걸 지점을 찾아야 하는데 앞에서 call 한 흐름을 보면 다행히 RtlEqualString이 반복되기 직전에 ExAcquireResourceSharedLite를 호출한 것이 보이네요.

그러므로 ExReleaseResourceLite에 걸어주면 적당해 보입니다.

kd> bp 805a5d14
kd> bl
 0 e 805a5ba3     0001 (0001) nt!IopLoadDriver
 1 e 805a5d14     0001 (0001) nt!IopLoadDriver+0x212

kd> g
Breakpoint 1 hit
nt!IopLoadDriver+0x212:
805a5d14 e83779f3ff      call    nt!ExReleaseResourceLite (804dd650)

루프를 빠져나오면서 브레이크 포인트가 걸렸습니다.
이제부터는 다시 call을 확인하면서 진행합니다.

kd> pc
nt!IopLoadDriver+0x222:
805a5d24 e8dcfbffff      call    nt!IopBuildFullDriverPath (805a5905)

kd>
nt!IopLoadDriver+0x31a:
805a5d3e e806fdffff      call    nt!IopGetDriverNameFromKeyNode (805a5a49)

kd>
nt!IopLoadDriver+0x36b:
805a5d8f e8dff4ffff      call    nt!MmLoadSystemImage (805a5273)

kd>
nt!IopLoadDriver+0x428:
805a5da2 e82e4af5ff      call    nt!RtlImageNtHeader (804fa7d5)

kd>
nt!IopLoadDriver+0x43a:
805a5db4 e829200000      call    nt!IopPrepareDriverLoading (805a7de2)

kd>
nt!IopLoadDriver+0x47f:
805a5df0 e8590bfcff      call    nt!ObCreateObject (8056694e)

kd>
nt!IopLoadDriver+0x4c7:
805a5e3c e89449f5ff      call    nt!RtlImageNtHeader (804fa7d5)

kd>
nt!IopLoadDriver+0x4fb:
805a5e70 e8ae05fcff      call    nt!ObInsertObject (80566423)

kd>
nt!IopLoadDriver+0x536:
805a5ea0 e84301fcff      call    nt!ObReferenceObjectByHandle (80565fe8)

kd>
nt!IopLoadDriver+0x547:
805a5eb1 e8032ffcff      call    nt!NtClose (80568db9)

kd>
nt!IopLoadDriver+0x563:
805a5ecd e8f26cfaff      call    nt!ExAllocatePoolWithTag (8054cbc4)

kd>
nt!IopLoadDriver+0x5b1:
805a5f1b e8a46cfaff      call    nt!ExAllocatePoolWithTag (8054cbc4)

kd>
nt!IopLoadDriver+0x5e8:
805a5f3d e8fed7fdff      call    nt!NtQueryObject (80583740)

kd>
nt!IopLoadDriver+0x61e:
805a5f59 e8666cfaff      call    nt!ExAllocatePoolWithTag (8054cbc4)

kd>
nt!IopLoadDriver+0x669:
805a5fa4 ff572c          call    dword ptr [edi+2Ch]

뭔가 로드되고 있는 것처럼 보이지 않나요? ^^

마지막 call이 제가 찾던 부분입니다. 어떤 함수주소를 호출하는게 보이죠?
저는 이것이 로드될 드라이버의 DriverEntry이기를 바라고 있죠.
앞쪽 코드를 보면 push 두번이 보이므로 2개의 파라미터를 가진다는 것을 알 수 있습니다.

805a5f9a 8b7d80          mov     edi,dword ptr [ebp-80h]
805a5f9d ffb570ffffff    push    dword ptr [ebp-90h]
805a5fa3 57              push    edi
805a5fa4 ff572c          call    dword ptr [edi+2Ch]  ds:0023:81593884={Null!DriverEntry (fa13159a)}
805a5fa7 3bc3            cmp     eax,ebx

그런데 DriverEntry가 2개의 파라미터를 가지자나요.

NTSTATUS 
  DriverEntry
    __in struct _DRIVER_OBJECT  *DriverObject,
    __in PUNICODE_STRING  RegistryPath 
    )

그래서 현재 스택에 push된 파라미터를 확인해 보니 DriverObject와 RegistryPath가 확인됩니다.

kd> dd esp
f9e9bc84  814a9330 814fe000 00000000 f657bcf4

kd> !drvobj 814a9330
Driver object (814a9330) is for:
 \Driver\Null
Driver Extension List: (id , addr)

Device Object list:

kd> dS 814fe000
814fe008  "\REGISTRY\MACHINE\SYSTEM\Control"
814fe048  "Set001\Services\Null"

DriverEntry 진입점을 찾았네요.
그런데 역시 노가다는 심하네요. ^^

반응형
Posted by GreeMate
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
WinDbg 디버깅2008. 6. 17. 00:29
반응형

커널스택을 보여주는 명령입니다.
모든 프로세스의 모든 쓰레드를 보여주기 때문에 다음과 같이 명령하면 !process 0 7 과 같은 역할을 합니다.

!stacks 2

뒤의 숫자 2 를 1 이나 0 으로 사용할 수도 있는데 숫자가 작을 수록 더 간단한 정보를 보여줍니다.

!process 0 7 과 비슷한 출력을 보이는 명령어를 구지 설명하는 이유는 !stacks 만의 특출난 기능이 있기 때문인데요.

!stacks 2 FilterString

처럼 뒤에 FilerString 을 주면 FilterString 이 포함된 콜스택만 보여줍니다. XP 이상에서만 지원하는 기능이지만 매우 편리한 기능입니다. 예를 들어 시스템이 대드락이나 행에 빠져있을 경우 자신의 드라이버에서 행이 걸려 있는지 간단하게 확인할 수 있습니다. !process 0 7 을 사용하면 모든 쓰레드의 콜스택을 펼쳐놓고 찾아야 하지만 이렇게 하면 콜스택에 드라이버가 존재하는 쓰레드만 보여주기 때문에 출력 내용이 간단하고 찾기가 수월해 집니다.

예제)
NDIS 드라이버가 걸려있는 쓰레드만 찾아 봅니다.

kd> !stacks 2 NDIS
Proc.Thread  .Thread  Ticks   ThreadState Blocker

Max cache size is       : 1048576 bytes (0x400 KB)
Total memory in cache   : 0 bytes (0 KB)
Number of regions cached: 0
0 full reads broken into 0 partial reads
    counts: 0 cached/0 uncached, 0.00% cached
    bytes : 0 cached/0 uncached, 0.00% cached
** Prototype PTEs are implicitly decoded
                            [863a5490 System]
   4.00006c  863a75b8 0001015 Blocked    nt!KiSwapContext+0x2e
                                        nt!KiSwapThread+0x46
                                        nt!KeRemoveQueue+0x20e
                                        NDIS!ndisWorkerThread+0x30
                                        nt!PspSystemThreadStartup+0x34
                                        nt!KiThreadStartup+0x16

                            [8613eda0 smss.exe]

                            [85ff21c0 csrss.exe]

                            [8611d0a0 winlogon.exe]

                            [8610a1b8 services.exe]

                            [85ff91d8 lsass.exe]

                            [860f37c8 svchost.exe]

                            ...

깔끔하게 NDIS 가 생성해 놓은 WorkerThread 하나만 나왔네요. 현재 다른 쓰레드에서는 NDIS 드라이버의 기능이 호출되지 않고 있다는 것을 알 수 있습니다.


http://www.driveronline.org/bbs/view.asp?tb=tipbbs&GotoPage=1&s_bulu=&s_key=&no=102

반응형
Posted by GreeMate