WinDbg 디버깅2007. 9. 23. 02:27
반응형

ds, dS는 문자열을 볼 때 유용한 명령어입니다.

ds 는 ANSI_STRING 구조체에 들어있는 문자열을 보여줍니다.
dS 는 UNICODE_STRING 구조체에 들어있는 문자열을 보여줍니다.

예제1) ds

PANSI_STRING pAStr = f9e9f608;

위와 같은 변수가 있었다면 다음과 같이 볼 수 있습니다.

kd> db f9e9f608
f9e9f608  0c 00 0d 00 6a 1d ae f9-00 10 ae f9 00 10 ae f9  ....j...........

구조체의 형태는 다음과 같으므로

typedef struct _STRING {
  USHORT  Length;
  USHORT  MaximumLength;
  PCHAR  Buffer;
} ANSI_STRING *PANSI_STRING;

네번째 바이트부터 보이는 6a 1d ae f9 가 Buffer 포인터입니다. 여기에 문자열이 들어있습니다.
보통 아래와 같이 Display Memory 명령으로 확인합니다.

kd> db f9ae1d6a
f9ae1d6a  6e 74 6f 73 6b 72 6e 6c-2e 65 78 65 00 00 51 01  ntoskrnl.exe..Q.

복잡하게 이렇게 하지 않고 이를 한방에 해결해 주는 것이 ds 입니다.
그냥 f9e9f608 를 주면 불필요한 것은 보여주지도 않고 문자열만 예쁘게 보여줍니다.

kd> ds f9e9f608
f9ae1d6a  "ntoskrnl.exe"


예제2) dS

PUNICODE_STRING pUStr = f9e97c80;

위와 같은 변수가 있었다면 다음과 같이 볼 수 있습니다.

kd> db f9e97c80
f9e97c80  1c 00 1e 00 80 7a e9 f9-00 00 00 00 00 00 00 00  .....z..........

구조체의 형태는 다음과 같으므로

typedef struct _UNICODE_STRING {
  USHORT  Length;
  USHORT  MaximumLength;
  PWSTR  Buffer;
} UNICODE_STRING *PUNICODE_STRING;

네번째 바이트부터 보이는 80 7a e9 f9 가 Buffer 포인터입니다. 여기에 문자열이 들어있습니다.
보통 아래와 같이 Display Memory 명령으로 확인합니다.

kd> db f9e97a80
f9e97a80  49 00 53 00 41 00 50 00-4e 00 50 00 5c 00 54 00  I.S.A.P.N.P.\.T.
f9e97a90  42 00 41 00 30 00 33 00-62 00 30 00 00 00 2a 00  B.A.0.3.b.0...*.

역시 위와 비슷하게 dS 한방으로 예쁘게 볼 수 있습니다.

kd> dS f9e97c80
f9e97a80  "ISAPNP\TBA03b0"


추가로 Display Memory 명령중 문자열을 보는데 편리한 명령어가 있습니다.

da, du 명령어 입니다.

da 는 PCHAR 포인터가 가리키는 문자열을 보여줍니다.
du 는 PWSTR 포인터가 가리키는 문자열을 보여줍니다.


예제3) da

ds 예제에서

PCHAR  Buffer = f9ae1d6a;

이므로 다음과 같이 볼 수 있습니다.

kd> da f9ae1d6a
f9ae1d6a  "ntoskrnl.exe"


예제4) du

dS 예제에서 

PWSTR  Buffer = f9e97a80;

이므로 다음과 같이 볼 수 있습니다.

kd> du f9e97a80
f9e97a80  "ISAPNP\TBA03b0"


문자열 보기좋게 보시기 바랍니다. ^^
Happy Debugging!!!

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

반응형
Posted by GreeMate
WinDbg 디버깅2007. 9. 23. 02:26
반응형

MS에서 제공하는 웹심볼 서버를 간단히 심볼패스로 지정할 수 있는 명령입니다.

다음과 같은 형태로 사용하구요.

.symfix[+] [DownstreamStore]

이 명령을 모르면 다음과 같이 적어줘야 합니다.

.sympath[+] srv*DownstreamStore*http://msdl.microsoft.com/download/symbols

두개는 같은 의미 입니다.
저렇게 긴 URL 을 외우고 있을 필요가 없겠죠.
그냥 .symfix 를 사용하면 됩니다.

명령어 뒤에 [+] 는 + 를 붙여도 되고 붙이지 않아도 된다는 의미입니다.
.symfix+ 와 같이 +를 붙이면 기존에 존재하는 sympath 뒤에 웹심볼 패스가 추가됩니다.
.symfix 와 같이 +를 붙이지 않으면 기존에 존재하는 sympath 는 무시됩니다.

그 뒤에 보이는 [DownstreamStore] 역시 [] 표시가 있으므로 생략 가능합니다.
이것을 생략하면 WinDbg 설치 폴더 밑에 심볼패스가 지정됩니다.

예제)

.sympath 로 현재 상태를 확인해 봅니다.

kd> .sympath
Symbol search path is:

아무것도 없네요.
대충 하나를 지정해 봅니다.

kd> .sympath c:\Symbol
Symbol search path is: c:\Symbol

여기에 .symfix+ 를 사용해서 웹심볼을 추가합니다.

kd> .symfix+ c:\WebSym

다시 .sympath 로 확인해 봅니다.

kd> .sympath
Symbol search path is: c:\Symbol;SRV*c:\WebSym*http://msdl.microsoft.com/download/symbols

처음에 지정했던 c:\Symbol 뒤에 웹심볼 패스가 추가된 것을 볼 수 있습니다.

.symfix 로 간편하게 웹심볼을 활용하시기 바랍니다. ^^

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

반응형
Posted by GreeMate
WinDbg 디버깅2007. 9. 23. 02:25
반응형
Virtual PC 2004 를 실행하고 이에 연결하여 디버깅하는 방법에 대하여 간단히 정리합니다.

VMWare 에 연결하는 방법에 대해서 이미 여러 곳에서 다룬 내용이긴 합니다. ^^
다음과 같이 하라고 하죠.

windbg.exe -k com:port=\\.\pipe\com1,pipe

커맨드 라인에서 위와 같이 하거나 등록정보에 위와 같이 등록해 놓고 사용하라고 합니다.

하지만 저는 그냥 WinDbg UI 에서 하는게 더 편하더군요. (최신 WinDbg ^^ 제껀 6.6.0007.5)



Pipe 체크를 해서 pipe 로 연결할 것임을 알립니다.
Port 에 pipe 이름을 적어줍니다. 일반 시리얼 디버깅과는 이부분이 달라지죠.
\\.\pipe\com1 이라고 지었습니다.
Reconnect 체크를 해야 Virtual PC 가 아직 실행되지 않아서 pipe 가 생성되지 않았을 경우에도 대기합니다.

'확인' 을 누르면 다음과 같이 대기합니다.



자.... 이제 Virtual PC 2004 를 보실까요.

Settings 에서 COM1 을 다음과 같이 Named pipe 로 설정합니다.
제가 위에서 지어준 이름으로요.



OK 해서 설정하시고 Virtual PC 를 실행시키면 됩니다.

물론 Virtual PC 의 boot.ini 는 다음과 같이 시리얼 디버깅 설정이 되어 있어야죠.
이건 뭐 우리가 늘 하던 일반 시리얼 디버깅 설정과 다른 것이 전혀 없습니다.

[boot loader]
timeout=30
default=multi(0)disk(0)rdisk(0)partition(1)\WINDOWS
[operating systems]
multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Microsoft Windows XP Professional" /noexecute=optin /fastdetect /debug /debugport=COM1 /baudrate=115200

최신 PC 에서 위와 같은 환경으로 돌려보신 분의 무용담을 빌리자면 마치 SoftICE 사용하는 기분이었답니다.
소스라인 디버깅을 하면서 한줄씩 넘기는데 SoftICE 처럼 거의 실시간으로 넘어갔다는...
전혀 WinDbg 스럽지 않죠. WinDbg 는 WinDbg 고유의 갑갑스러움이 있어야 하는데 말이죠. ^^

저도 느껴보고자 제 PC 에서 해 봤습니다. 1년 정도 전에 구입한 PC 구요. ( CPU: 3.2GHz, RAM: 1GB )
오... 사실이었습니다. 이 정도면 아주 쓸만 한데요.
WinDbg 의 갑갑스러움을 다소 떨쳐버릴 수 있을 것 같습니다.

좋은 PC 구입하셔서 Virtual PC 띄워놓고 시원한 디버깅을 즐겨 보시기 바랍니다. ^^

http://www.driveronline.org/bbs/view.asp?tb=tipbbs&GotoPage=5&s_bulu=&s_key=&no=42
반응형
Posted by GreeMate
WinDbg 디버깅2007. 9. 23. 02:24
반응형

심볼을 로드할 때 사용하는 명령입니다.

보통은 심볼패스를 설정한 후에 .reload 와 같이 사용합니다.

kd> .symfix e:\symbols

kd> .reload
Connected to Windows XP 2600 x86 compatible target, ptr64 FALSE
Loading Kernel Symbols
........................
Loading User Symbols

lm 을 사용하여 심볼이 로드된 상태를 봅니다.

kd> lm
start    end        module name
804d9000 806ede00   nt         (pdb symbols)          e:\symbols\ntoskrnl.pdb\8592B6763F344B562\ntoskrnl.pdb
806ee000 80701d80   hal        (deferred)            
f9871000 f988b580   Mup        (deferred)   
f996f000 f998e780   fltMgr     (deferred)
...

nt 는 심볼이 로드된 것이 보이는데 나머지는 deferred 라고 나옵니다.
이것은 WinDbg 의 lazy symbol loading (deferred symbol loading) 이라는 특징 때문에 그렇습니다.

WinDbg 는 심볼을 로드할 때 꼭 필요한 심볼만 올려놓고 나머지는 deferred 로 해놓고 심볼을 올리지 않습니다. deferred 로 된 녀석들은 나중에 해당 모듈이 WinDbg 상에서 실제 사용되는 순간이 발생해야만 로드가 됩니다. 필요한 것만 그때 그때 올려주는 나름대로 효율적인 방법입니다. ^^

WinDbg Help 에 보면 .reload 는 다양한 옵션을 가지고 있는데요.
제가 유용하게 사용하는 것만 몇가지 설명합니다.

.reload /i mydrv.sys (심볼이 맞지않아도 강제로 심볼 로드하기)

예를 들어 어제 빌드한 드라이버가 BSOD 를 발생시켜서 덤프가 만들어 졌는데 심볼은 보관하지 않아서 덤프분석을 할 수 없는 문제를 만났다고 가정합시다. 다행히도 어제 소스 코드를 그대로 보관하고 있었다고 하면 그것을 그대로 빌드하여 pdb 파일을 생성할 수 있습니다. 문제는 이 pdb 파일을 로드하려고 해도 WinDbg가 TimeStamp 등을 체크하여 symbol mismatch 에러를 내면서 심볼로드를 하지 않는다는 겁니다. 이런 경우에 심볼이 맞는지 확인하지 말고 강제로 올려달라는 /i 옵션을 사용하면 심볼이 올라갑니다.

.reload /f (심볼 모두 올리기)

보통 lazy symbol loading 상태로 그냥 사용하시면 되지만 혹시 모든 모듈의 심볼을 모두 올려 놓아야 할 경우가 있다면 /f 옵션을 사용해서 모든 모듈의 심볼을 올릴 수 있습니다.

.reload /u (심볼 모두 내리기)

반대로 모든 심볼을 모두 내려야 할 경우가 있다면 /u 옵션을 사용해서 모든 모듈의 심볼을 내릴 수 있습니다.

.reload /u mydrv.sys (특정모듈 심볼 내리기)

mydrv.pdb 를 로드하여 사용하고 있는데 새로 빌드한 mydrv.pdb 를 심볼패스에 복사하면 mydrv.pdb 가 사용중이라서 복사가 실패합니다. 이런 경우 /u mydrv.sys 옵션을 줘서 특정 모듈의 심볼만 내릴 수 있습니다.

.reload mydrv.sys (특정모듈 심볼 로드하기)

위와 같이 내려진 특정 모듈의 심볼만 다시 올리려면 mydrv.sys 처럼 모듈 이름을 줘서 로드합니다.

급하게 정리하느라 뭐가 좀 빠진 느낌이지만... 도움이 되셨기를 바라겠습니다. ^^

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

반응형
Posted by GreeMate
WinDbg 디버깅2007. 9. 23. 02:21
반응형

s (Search Memory)

메모리에서 원하는 문자열이나 메모리 패턴을 찾을 때 사용하는 명령입니다.
디버깅할 때 종종 아주 유용하게 사용하는 경우가 있으므로 알아두시면 좋습니다.

WinDbg Help 를 보면 아주 다양한 옵션을 사용할 수 있다는 것을 알 수 있습니다.
다 알면 유용한 것들일텐데 안타깝게도 제가 다 알지를 못하고 있습니다. -_-a

유용하게 자주 사용하는 것들만 간단히 설명합니다.

[Syntax]
s [-Type] Range Pattern

Type Description
b Byte (8 bits) (default)
w WORD (16 bits)
d DWORD (32 bits)
q QWORD (64 bits)
a ASCII string(not necessarily null-terminated)
u Unicode string(not necessarily null-terminated)

Type 을 생략하면 Byte 단위로 메모리를 검색합니다.
Range 는 시작주소와 끝주소를 표시합니다.
Pattern 은 찾아야 할 패턴입니다.

WinDbg Help 에 있는 예제를 그대로 가져와서 설명합니다.

0:000> s 0012ff40 0012ff60 'H' 'e' 'l' 'l' 'o'

위 예제는 0012ff40 부터 0012ff60 까지 범위에서 H,e,l,l,o 문자패턴을 가지고 있는 메모리를 찾아 달라는 뜻입니다.
Range 를 지정하는 방법을 '시작주소 L길이' 를 사용할 수도 있는데 다음은 위에서 보인 예제와 같은 의미입니다.

0:000> s 0012ff40 L20 'H' 'e' 'l' 'l' 'o'

패턴을 다음과 같이 ASCII 코드 값으로 적어줘도 같은 의미입니다.

0:000> s 0012ff40 L20 48 65 6c 6c 6f

이와 같은 형식은 메모리에서 특정 숫자들이 나열되어 있는 것을 찾을 때도 사용할 수 있습니다.

옵션을 사용하여 다음과 같이 사용해도 위와 같은 의미입니다.

0:000> s -a 0012ff40 L20 "Hello"

-a 라는 Type 옵션을 주고 패턴은 "Hello" 처럼 문자열 형식으로 적어줄 수 있습니다.

예제1)

제가 작성한 드라이버를 적용한 시스템에서 메모리가 부족한 문제가 발생한 경우가 있었습니다.
문제를 검토하다 보니 가장 많이 사용될 만한 메모리 할당의 내용은 50 00 50 00 43 00 32 00 3a 00 로 시작하는 패턴을 가지고 있었습니다. 정말 이것이 과도하게 할당된 것인지 확인해 보기 위해서 NonPagedPool 시작위치부터 0x10000000 길이(대충 무지 길게 잡은 겁니다 ^^)만큼 이 패턴에 대한 검색을 수행했습니다.

kd> s 810c7000 L10000000 50 00 50 00 43 00 32 00 3a 00
810c7154  50 00 50 00 43 00 32 00-3a 00 3a 00 4e 00 65 00  P.P.C.2.:.:.N.e.
810c72b4  50 00 50 00 43 00 32 00-3a 00 3a 00 4e 00 65 00  P.P.C.2.:.:.N.e.
810c7414  50 00 50 00 43 00 32 00-3a 00 3a 00 4e 00 65 00  P.P.C.2.:.:.N.e.
810c7574  50 00 50 00 43 00 32 00-3a 00 3a 00 4e 00 65 00  P.P.C.2.:.:.N.e.
810c76d4  50 00 50 00 43 00 32 00-3a 00 3a 00 4e 00 65 00  P.P.C.2.:.:.N.e.
...
...
...

그러자 그 패턴과 일치하는 메모리 위치가 수도 없이 나열되었습니다. (정말 셀 수 없었답니다. -_-;)
이것이 버그임을 s 명령으로 검증하고 메모리를 해제하도록 버그를 수정한 사례였습니다.

예제2)

수 년전에는 프로그램을 개발할 때 Easter Egg 를 삽입하는 것이 꽤 유행했었습니다. 개발자 이름이 리스트업 된다던가 화려한 그래픽이 나온다던가 하는 식으로 유명한 프로그램들은 저마다 고유한 Easter Egg 를 가지고 있었습니다.
그 때 생각한 것이 드라이버도 Easter Egg 를 가질 수 있지 않을까 하는 것이었습니다. 그래서 V3의 드라이버는 Easter Egg 를 가지고 있답니다.
자... 한번 찾아보실까요?

먼저 lmvm 으로 V3 필터 드라이버의 시작 주소를 찾습니다.

lkd> lmvm v3flt2k
start    end        module name
ebcf6000 ebd10400   V3Flt2K    (no symbols)          
    Loaded symbol image file: \??\C:\PROGRA~1\AhnLab\V3\V3Flt2K.sys
    Image path: \??\C:\PROGRA~1\AhnLab\V3\V3Flt2K.sys
    Image name: V3Flt2K.sys
    Timestamp:        Wed Jul 12 02:55:27 2006 (44B3E60F)
    CheckSum:         000258D1
    ImageSize:        0001A400
    Translations:     0000.04b0 0000.04e0 0409.04b0 0409.04e0

s 명령으로 시작주소부터 끝주소 사이에서 VIEWEGG 라는 문자열을 찾습니다.

lkd> s -a ebcf6000 ebd10400 "VIEWEGG"
ebd0ca98  56 49 45 57 45 47 47 20-20 20 2c 25 25 25 20 20  VIEWEGG   ,%%% 

찾아진 주소 ebd0ca98 가 Easter Egg 의 시작주소입니다.
이 드라이버의 Easter Egg 는 16 x 11 의 그림입니다.
db 명령으로 볼 수 있습니다.

lkd> db ebd0ca98 L10*b
ebd0ca98  56 49 45 57 45 47 47 20-20 20 2c 25 25 25 20 20  VIEWEGG   ,%%% 
ebd0caa8  20 20 20 20 20 20 20 20-2c 25 25 25 60 25 3d 2d          ,%%%`%=-
ebd0cab8  20 20 20 20 20 20 20 2c-25 25 60 28 20 27 7c 20         ,%%`( '|
ebd0cac8  20 20 20 20 20 20 20 25-25 40 20 2f 5c 5f 2f 20         %%@ /\_/
ebd0cad8  2c 25 2e 2b 2d 25 25 20-22 40 5f 5f 20 20 20 20  ,%.+-%% "@__   
ebd0cae8  25 2f 20 20 20 20 20 20-20 20 7c 5f 5f 60 5c 20  %/        |__`\
ebd0caf8  25 5c 20 20 7c 20 5c 20-20 20 2f 20 20 2f 2f 20  %\  | \   /  //
ebd0cb08  20 3e 20 40 2d 2d 2d 5c-20 7c 20 20 5b 2f 20 20   > @---\ |  [/ 
ebd0cb18  3c 20 3c 60 20 20 20 20-7c 7c 20 20 20 20 20 20  < <`    ||     
ebd0cb28  20 60 5c 5c 20 20 20 20-7c 7c 20 20 20 20 20 20   `\\    ||     
ebd0cb38  5e 5e 5e 22 22 5e 5e 5e-22 22 5e 5e 5e 5e 5e 5e  ^^^""^^^""^^^^^^

크엇... 뭐가 보이시나요? ^^
귀여운 유니콘이 잘 보이시나요?

V3 필터 드라이버의 Easter Egg 를 찾는 방법이었습니다.
여러분의 PC 에 V3 를 사용하고 계신다면 지금 당장 한번 찾아보시지요. ^^

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

반응형
Posted by GreeMate
WinDbg 디버깅2007. 9. 23. 02:19
반응형

dt (Display Type)

타입을 보여주는 명령인데 주로 구조체 타입을 확인할 때 사용합니다.

이 명령 역시 WinDbg Help 에는 무지 다양하고 복잡한 옵션들이 있습니다.
하지만 제가 주로 사용하는 구조체 확인에 대한 내용만 다루도록 하겠습니다.

1) dt 구조체타입이름
- 구조체의 멤버 필드를 확인합니다.

kd> dt _IO_STACK_LOCATION
   +0x000 MajorFunction    : UChar
   +0x001 MinorFunction    : UChar
   +0x002 Flags            : UChar
   +0x003 Control          : UChar
   +0x004 Parameters       : __unnamed
   +0x014 DeviceObject     : Ptr32 _DEVICE_OBJECT
   +0x018 FileObject       : Ptr32 _FILE_OBJECT
   +0x01c CompletionRoutine : Ptr32   
   +0x020 Context          : Ptr32 Void

구조체타입이름은 다음과 같이 선언된 구조체의 경우 맨 앞에 선언한 구조체 이름을 사용합니다.

typedef struct _IO_STACK_LOCATION {
    ...
} IO_STACK_LOCATION, *PIO_STACK_LOCATION;

2) dt 구조체타입이름 구조체주소
- 구조체의 멤버 필드와 실제 내용을 확인합니다.

kd> dt _IO_STACK_LOCATION 816441c0
   +0x000 MajorFunction    : 0xe ''
   +0x001 MinorFunction    : 0 ''
   +0x002 Flags            : 0x1 ''
   +0x003 Control          : 0 ''
   +0x004 Parameters       : __unnamed
   +0x014 DeviceObject     : 0x815d2030 _DEVICE_OBJECT
   +0x018 FileObject       : 0x8166b288 _FILE_OBJECT
   +0x01c CompletionRoutine : (null)
   +0x020 Context          : (null)

3) dt 구조체타입이름 멤버필드이름 [구조체주소]
- 구조체에서 특정한 멤버필드만 확인합니다.

kd> dt _IO_STACK_LOCATION MajorFunction
   +0x000 MajorFunction : UChar

kd> dt _IO_STACK_LOCATION MajorFunction 816441c0
   +0x000 MajorFunction : 0xe ''

4) dt -r 구조체타입이름 [구조체주소]
- 구조체의 멤버필드중 구조체가 있으면 펼쳐서 보여줍니다.

kd> dt -r _IO_STACK_LOCATION 816441c0
   +0x000 MajorFunction    : 0xe ''
   +0x001 MinorFunction    : 0 ''
   +0x002 Flags            : 0x1 ''
   +0x003 Control          : 0 ''
   +0x004 Parameters       : __unnamed
      +0x000 Create           : __unnamed
         +0x000 SecurityContext  : (null)
         +0x004 Options          : 0
         +0x008 FileAttributes   : 0x18
         +0x00a ShareAccess      : 0x22
         +0x00c EaLength         : 0
      +0x000 CreatePipe       : __unnamed
         +0x000 SecurityContext  : (null)
         +0x004 Options          : 0
      ...

5) dt -r[숫자] 구조체타입이름 [구조체주소]
- 구조체의 멤버필드중 구조체가 있으면 숫자만큼만 펼쳐서 보여줍니다.

kd> dt -r1 _IO_STACK_LOCATION 816441c0
   +0x000 MajorFunction    : 0xe ''
   +0x001 MinorFunction    : 0 ''
   +0x002 Flags            : 0x1 ''
   +0x003 Control          : 0 ''
   +0x004 Parameters       : __unnamed
      +0x000 Create           : __unnamed
      +0x000 CreatePipe       : __unnamed
   ...

6) dt 변수이름
- 심볼이 맞춰져 있다면 변수이름에 해당하는 타입과 정보를 보여줍니다.

kd> dt pIrpStack
Local var @ 0xf9c8bc30 Type _IO_STACK_LOCATION*
0x816441c0
   +0x000 MajorFunction    : 0xe ''
   +0x001 MinorFunction    : 0 ''
   +0x002 Flags            : 0x1 ''
   +0x003 Control          : 0 ''
   +0x004 Parameters       : __unnamed
   +0x014 DeviceObject     : 0x815d2030 _DEVICE_OBJECT
   +0x018 FileObject       : 0x8166b288 _FILE_OBJECT
   +0x01c CompletionRoutine : (null)
   +0x020 Context          : (null)

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

반응형
Posted by GreeMate
WinDbg 디버깅2007. 9. 23. 02:19
반응형

아래에서 핸들에 대한 주제를 올려주셨으니 !handle 명령에 대해서 알아보도록 하겠습니다. ^^

!handle은 특정 또는 모든 핸들에 대한 정보를 보여주는 명령입니다.

유저모드의 형식
!handle [Handle [UMFlags [TypeName]]]

커널모드의 형식
!handle [Handle [KMFlags [Process [TypeName]]]]

플래그의 자세한 설명은 언제나 그렇듯이 WinDbg Help 를 참조하시기 바랍니다. ^^
진행하면서 필요한 것만 간단히 설명하겠습니다.

아래의 예제들은 WinDbg Help !handle 에 있는 예제입니다.
WinDbg Help 에 쓸만한 예제도 있더군요. ^^

유저모드 먼저 간단히 살펴봅니다.

아래와 같이 명령어만 주고 인자를 생략하면 현재 프로세스의 핸들 테이블을 모두 보여주고
UMFlags는 기본값인 0x1 이 적용되어 handle type 만 보여주게 됩니다.

0:000> !handle
Handle 4
  Type          Section
Handle 8
  Type          Event
Handle c
  Type          Event
Handle 10
  Type          Event
Handle 14
  Type          Directory
Handle 5c
  Type          File
6 Handles
Type            Count
Event           3
Section         1
File            1
Directory       1

아래는 특정 핸들 8 을 보여주는 예제입니다.
UMFlags 에 f 를 주어 가능한 모든 Flag 를 다 켰습니다. 이 핸들에 대한 모든 정보를 보여줍니다.

0:000> !handle 8 f
Handle 8
  Type          Event
  Attributes    0
  GrantedAccess 0x100003:
         Synch
         QueryState,ModifyState
  HandleCount   2
  PointerCount  3
  Name         
  Object Specific Information
    Event Type Auto Reset
    Event is Waiting


커널모드에 대해서 살펴봅니다.

아래 예제는 Handle 에 0 을 주어 모든 핸들을 보이게 하고 KMFlags 에 4 를 주어 해제된 핸들도 포함하여 보이게 합니다.

kd> !handle 0 4
processor number 0
PROCESS 80559800  SessionId: 0  Cid: 0000    Peb: 00000000  ParentCid: 0000
    DirBase: 00039000  ObjectTable: e1000d60  TableSize: 380.
    Image: Idle

New version of handle table at e1002000 with 380 Entries in use

0000: free handle, Entry address e1002000, Next Entry fffffffe
0004: Object: 80ed5238  GrantedAccess: 001f0fff
0008: Object: 80ed46b8  GrantedAccess: 00000000
000c: Object: e1281d00  GrantedAccess: 000f003f
0010: Object: e1013658  GrantedAccess: 00000000
......
0168: Object: ffb6c748  GrantedAccess: 00000003 (Protected)
016c: Object: ff811f90  GrantedAccess: 0012008b
0170: free handle, Entry address e10022e0, Next Entry 00000458
0174: Object: 80dfd5c8  GrantedAccess: 001f01ff
......

사실 해제된 핸들을 특별히 볼 일은 별로 없으니 위와 같이 사용하는 경우는 없을 것 같네요.

좀 더 현실적인 예로 제 자리에서 그냥 !handle 을 사용한 결과를 보여드립니다.
현재 프로세스의 핸들 테이블을 모두 보고 싶을 때 사용하면 좋습니다.
KMFlags 의 기본값은 0x3 이라 좀 더 자세한 내용을 볼 수 있습니다.

lkd> !handle
processor number 0, process 80562f00
PROCESS 80562f00  SessionId: none  Cid: 0000    Peb: 00000000  ParentCid: 0000
    DirBase: 00039000  ObjectTable: e1003e60  HandleCount: 275.
    Image: Idle

Handle table at e16a9000 with 275 Entries in use
0004: Object: 867b5a00  GrantedAccess: 001f0fff Entry: e1004008
Object: 867b5a00  Type: (867b5040) Process
    ObjectHeader: 867b59e8
        HandleCount: 2  PointerCount: 72

0008: Object: 867b5340  GrantedAccess: 00000000 Entry: e1004010
Object: 867b5340  Type: (867b5e70) Thread
    ObjectHeader: 867b5328
        HandleCount: 1  PointerCount: 1

000c: Object: e1010478  GrantedAccess: 00000000 Entry: e1004018
Object: e1010478  Type: (867ab980) Key
    ObjectHeader: e1010460
        HandleCount: 1  PointerCount: 3
        Directory Object: 00000000  Name: \REGISTRY

0010: Object: e13aa168  GrantedAccess: 000f003f Entry: e1004020
Object: e13aa168  Type: (867ab980) Key
    ObjectHeader: e13aa150
        HandleCount: 1  PointerCount: 1
        Directory Object: 00000000  Name: \REGISTRY\MACHINE\SYSTEM\CONTROLSET001\CONTROL\SESSION MANAGER\MEMORY MANAGEMENT\PREFETCHPARAMETERS

...

보통 10 이라는 핸들이 어떤 Object 인지 궁금할 때 다음과 같이 사용합니다.

lkd> !handle 10
processor number 0, process 80562f00
PROCESS 80562f00  SessionId: none  Cid: 0000    Peb: 00000000  ParentCid: 0000
    DirBase: 00039000  ObjectTable: e1003e60  HandleCount: 275.
    Image: Idle

Handle table at e16a9000 with 275 Entries in use
0010: Object: e13aa168  GrantedAccess: 000f003f Entry: e1004020
Object: e13aa168  Type: (867ab980) Key
    ObjectHeader: e13aa150
        HandleCount: 1  PointerCount: 1
        Directory Object: 00000000  Name: \REGISTRY\MACHINE\SYSTEM\CONTROLSET001\CONTROL\SESSION MANAGER\MEMORY MANAGEMENT\PREFETCHPARAMETERS

모든 핸들을 보였던 바로 위 예제에 이 내용이 포함되어 있는 것을 볼 수 있습니다.

아래는 KMFlags 의 0x10 플래그(커널 핸들 테이블 보이기 플래그)를 사용하여 커널 핸들 테이블의 핸들 0x14 를 보는 예제입니다.

kd> !handle 14 13
processor number 0
PROCESS 80559800  SessionId: 0  Cid: 0000    Peb: 00000000  ParentCid: 0000
    DirBase: 00039000  ObjectTable: e1000d60  TableSize: 380.
    Image: Idle

Kernel New version of handle table at e1002000 with 380 Entries in use
0014: Object: e12751d0  GrantedAccess: 0002001f
Object: e12751d0  Type: (80ec8db8) Key
    ObjectHeader: e12751b8
        HandleCount: 1  PointerCount: 1
        Directory Object: 00000000  Name: \REGISTRY\MACHINE\SYSTEM\CONTROLSET001\CONTROL\SESSION MANAGER\EXECUTIVE


!handle 의 마지막 인자인 [Process [TypeName]] 을 활용하면 특정 프로세스의 핸들을 볼 수도 있고 특정 타입의 핸들을 볼 수도 있습니다.
필요할 때 활용하시면서 익혀 보시기 바랍니다.

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

반응형
Posted by GreeMate
WinDbg 디버깅2007. 9. 23. 02:17
반응형

시스템 오브젝트의 정보를 보여주는 명령어입니다.

형식은 다음과 같이 사용할 수 있습니다.

!object Address
!object Path
!object 0 Name

아래 예제에서 각각의 경우에 대하여 설명합니다.

1) !object Address

오브젝트의 주소를 알고 있을 때 주소를 주면 오브젝트의 정보가 자세히 나옵니다.

아래 예제는 WinDbg Help 의 예제입니다.
!handle 의 결과를 보면 핸들이 어떤 오브젝트를 가리키는지 나옵니다.

kd> !handle
processor number 0
PROCESS 80a02920  Cid: 0002    Peb: 00000000  ParentCid: 0000
    DirBase: 0006c805  ObjectTable: 80a03788  TableSize:  54.
    Image: System
006c: Object: 80967768  GrantedAccess: 00100003
Object: 80967768  Type: (809d5c20) File
    ObjectHeader: 80967750
        HandleCount: 1  PointerCount: 1
        Directory Object: 00000000  Name: \WINNT\system32\config\software {Partition1}

이 정보는 !object 에서 나오는 결과와 동일합니다.

kd> !object 80967768
Object: 80967768  Type: (809d5c20) File
    ObjectHeader: 80967750
    HandleCount: 1  PointerCount: 1
    Directory Object: 00000000  Name: \WINNT\system32\config\software {Partition1}

오브젝트 주소를 알고 있다면 위와 같이 바로 !object 명령으로 자세한 정보를 볼 수 있습니다.


2) !object Path

!object 명령을 이용해서 오브젝트들의 구성을 볼 수 있습니다.
마치 winobj 유틸리티를 사용하는 것과 같은 느낌입니다.
먼저 Root 를 봅니다.

kd> !object \
Object: e1001690  Type: (81586490) Directory
    ObjectHeader: e1001678
    HandleCount: 0  PointerCount: 40
    Directory Object: 00000000  Name: \
    109 symbolic links snapped through this directory

    Hash Address  Type          Name
    ---- -------  ----          ----
     00  e1006850 Directory     ArcName
         81570218 Device        Ntfs
     01  e16839b8 Port          SeLsaCommandPort
     02  812d2818 Device        FatCdrom
     03  e1007160 Key           \REGISTRY
     05  e1711db8 Port          ThemeApiPort
     06  e1782888 Port          XactSrvLpcPort
     09  e14c4c38 Directory     NLS
     10  e1000150 SymbolicLink  DosDevices
     13  e135aa38 Port          SeRmCommandPort
     14  e16cdf18 Port          LsaAuthenticationPort
         814e8030 Device        Dfs
         813fdf18 Event         LanmanServerAnnounceEvent
     16  e1289f58 Directory     Driver
     19  e1006778 Directory     Device
     20  e13d8bb8 Directory     Windows
     21  813b1fc0 Event         SAM_SERVICE_STARTED
         e13d8a08 Directory     Sessions
     22  e13d8ae0 Directory     RPC Control
         e12e3400 Port          SmApiPort
         8131b400 Device        Fat
     23  e14c3030 Directory     BaseNamedObjects
         e1001510 Directory     KernelObjects
     24  e1289e80 Directory     FileSystem
         e1000308 Directory     GLOBAL??
     25  8129faa0 WaitablePort  NLAPublicPort
     26  e18cc1d0 Port          SmSsWinStationApiPort
         e1001428 Directory     ObjectTypes
     ...

Type 이 Directory 라고 되어 있는 것들은 하위에 다른 오브젝트들을 포함하고 있는 것입니다.
ObjectTypes 라는 Directory를 들여다 봅니다.

kd> !object \ObjectTypes
Object: e1001428  Type: (81586490) Directory
    ObjectHeader: e1001410
    HandleCount: 0  PointerCount: 25
    Directory Object: e1001690  Name: ObjectTypes

    Hash Address  Type          Name
    ---- -------  ----          ----
     00  81586490 Type          Directory
     01  8154d858 Type          Mutant
         81552ca0 Type          Thread
     03  81570a80 Type          FilterCommunicationPort
     05  8153c040 Type          Controller
     07  8154c040 Type          Profile
         8154dbf8 Type          Event
         81586660 Type          Type
     09  8154c880 Type          Section
         8154da28 Type          EventPair
         815862c0 Type          SymbolicLink
     10  8154cad0 Type          Desktop
     11  8154d2e8 Type          Timer
     12  8153c900 Type          File
         8154cca0 Type          WindowStation
     16  8153cca0 Type          Driver
     ...
     34  8154d4b8 Type          Semaphore

시스템에 존재하는 오브젝트 Type 들이 모두 보여집니다.

이번에는 FileSystem 이라는 Directory를 들여다 봅니다.

kd> !object \FileSystem
Object: e1289e80  Type: (81586490) Directory
    ObjectHeader: e1289e68
    HandleCount: 0  PointerCount: 23
    Directory Object: e1001690  Name: FileSystem

    Hash Address  Type          Name
    ---- -------  ----          ----
     00  81570340 Driver        Ntfs
     01  812d2040 Driver        Fastfat
         813c9040 Driver        NetBIOS
     02  815707c0 Driver        sr
     05  814284b0 Driver        Rdbss
     15  81425cc0 Driver        Msfs
     17  813c3cc0 Driver        MRxSmb
     18  8142a340 Device        UdfsCdRomRecognizer
     19  812d72e0 Driver        Srv
     24  81519628 Driver        Mup
         81537f38 Driver        RAW
     25  813bbf38 Driver        Npfs
         8149a368 Driver        Fs_Rec
     26  e1289da8 Directory     Filters
     30  813a0970 Driver        MRxVPC
     31  813d8bf8 Driver        Cdfs
     32  8137c138 Device        FatCdRomRecognizer
         813730e0 Device        CdfsRecognizer
         81570f38 Driver        FltMgr
     34  81382138 Device        FatDiskRecognizer
     35  812b9330 Driver        MRxDAV
     36  81456030 Device        UdfsDiskRecognizer

파일시스템으로 등록된 것들이 보이네요.
Filters Directory 로 한번 더 들어가 볼까요?

kd> !object \FileSystem\Filters
Object: e1289da8  Type: (81586490) Directory
    ObjectHeader: e1289d90
    HandleCount: 0  PointerCount: 4
    Directory Object: e1289e80  Name: Filters

    Hash Address  Type          Name
    ---- -------  ----          ----
     11  81570958 Device        FltMgrMsg
     31  81570698 Device        SystemRestore
     32  81570e10 Device        FltMgr

Filter Manager Device 인 FlgMgr 도 보이네요.

이처럼 시스템에 존재하는 Object 들의 구성을 마음대로 볼 수 있으므로 필요한 정보를 확인할 때 유용하게 사용할 수 있습니다.


3) !object 0 Name

Name 은 오브젝트의 Type 이름입니다.
특정 오브젝트를 찾을 때 사용할 수 있습니다.

File Type 인 것들을 찾아봅니다.

kd> !object 0 File
Scanning 1571 objects of type 'File'
Object: 8153be70  Type: (8153c900) File
    ObjectHeader: 8153be58
    HandleCount: 0  PointerCount: 1
Object: 815659a0  Type: (8153c900) File
    ObjectHeader: 81565988
    HandleCount: 0  PointerCount: 1
    Directory Object: 00000000  Name: \WINDOWS\system32\ntdll.dll {HarddiskVolume1}
Object: 814a2758  Type: (8153c900) File
    ObjectHeader: 814a2740
    HandleCount: 0  PointerCount: 1
    Directory Object: 00000000  Name: \WINDOWS\system32\drivers\vpc-8042.sys {HarddiskVolume1}
Object: 814a0090  Type: (8153c900) File
    ObjectHeader: 814a0078
    HandleCount: 0  PointerCount: 1
    Directory Object: 00000000  Name: \WINDOWS\system32\drivers\vpc-s3.sys {HarddiskVolume1}
Object: 81499918  Type: (8153c900) File
    ObjectHeader: 81499900
    HandleCount: 0  PointerCount: 1
    Directory Object: 00000000  Name: \WINDOWS\system32\drivers\vmsrvc.sys {HarddiskVolume1}
Object: 814991c0  Type: (8153c900) File
    ObjectHeader: 814991a8
    HandleCount: 0  PointerCount: 1
    Directory Object: 00000000  Name: \WINDOWS\system32\ntdll.dll {HarddiskVolume1}
Object: 8148a8e8  Type: (8153c900) File
    ObjectHeader: 8148a8d0
    HandleCount: 0  PointerCount: 1
    Directory Object: 00000000  Name: \WINDOWS\system32\drivers\vpc-8042.sys {HarddiskVolume1}
...

File Type 을 가진 모든 것들이 뿌려지므로 이 중에서 찾으려고 했던 특정 파일이 있는지 확인할 수 있습니다.

Driver Type 을 가지는 것들도 찾아봅니다.

kd> !object 0 Driver
Scanning 84 objects of type 'Driver'
Object: 8153c780  Type: (8153cca0) Driver
    ObjectHeader: 8153c768
    HandleCount: 0  PointerCount: 57
    Directory Object: e1289f58  Name: PnpManager
Object: 81581cf8  Type: (8153cca0) Driver
    ObjectHeader: 81581ce0
    HandleCount: 0  PointerCount: 4
    Directory Object: e1289f58  Name: ACPI_HAL
Object: 815819a0  Type: (8153cca0) Driver
    ObjectHeader: 81581988
    HandleCount: 0  PointerCount: 4
    Directory Object: e1289f58  Name: WMIxWDM
Object: 81537f38  Type: (8153cca0) Driver
    ObjectHeader: 81537f20
    HandleCount: 0  PointerCount: 5
    Directory Object: e1289e80  Name: RAW
Object: 81537a88  Type: (8153cca0) Driver
    ObjectHeader: 81537a70
    HandleCount: 0  PointerCount: 26
    Directory Object: e1289f58  Name: ACPI
Object: 81522948  Type: (8153cca0) Driver
    ObjectHeader: 81522930
    HandleCount: 0  PointerCount: 8
    Directory Object: e1289f58  Name: PCI
Object: 81575bd8  Type: (8153cca0) Driver
    ObjectHeader: 81575bc0
    HandleCount: 0  PointerCount: 6
    Directory Object: e1289f58  Name: isapnp
Object: 8151b518  Type: (8153cca0) Driver
    ObjectHeader: 8151b500
    HandleCount: 0  PointerCount: 5
    Directory Object: e1289f58  Name: IntelIde
...

시스템에 로드된 드라이버들의 리스트를 볼 수 있습니다.

몇가지 다른 타입의 오브젝트들에 대해서 해봤는데 다음과 같은 오류가 발생했습니다.

kd> !object 0 Process
Scanning 21 objects of type 'Process'
*** objects of the same type are only linked together if the 4000 flag is set in NtGlobalFlags
Total of 0 objects of type 'Process'

kd> !object 0 Thread
Scanning 312 objects of type 'Thread'
*** objects of the same type are only linked together if the 4000 flag is set in NtGlobalFlags
Total of 0 objects of type 'Thread'

kd> !object 0 Timer
Scanning 29 objects of type 'Timer'
*** objects of the same type are only linked together if the 4000 flag is set in NtGlobalFlags
Total of 0 objects of type 'Timer'

gflags.exe 를 사용해서 0x4000 플래그를 켜주면 정상적으로 보일 것 같기는 하지만 실제로 해 보지는 않았습니다.

사실 위에서 정상적으로 볼 수 있었던 File 과 Driver 같은 경우도 verifier 를 켰기 때문에 나오는 것이지 verifier 가 설정되지 않았다면 위와 같은 오류가 발생합니다.
이 점 때문에 일반적인 경우는 잘 써먹지 못하겠지만 특별히 이와 같은 디버깅이 필요할 경우를 만나시면 gflags.exe 로 플래그를 켜서 응용해 보시기 바랍니다. ^^

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

반응형
Posted by GreeMate
WinDbg 디버깅2007. 9. 23. 02:16
반응형

오늘은 대드락 디버깅을 해 보겠습니다.

대드락이라함은 두 개의 쓰레드가 두 개의 동기화 객체를 엇갈리게 소유하고 있어서 교착상태에 빠진것을 의미합니다.

한 프로세스에 있는 두 개의 쓰레드가 대드락인 경우는 그 프로세스가 '응답없음' 상태일 꺼구요.
두 프로세스에 각각 존재하는 두 개의 쓰레드가 대드락인 경우는 두 프로세스가 '응답없음' 상태일 겁니다.

더욱 좋지 않는 경우는 대드락인 두 개의 동기화 객체중 하나라도 시스템(OS 또는 파일시스템 등)에서 사용하는 동기화 객체라면 이것이 풀리지 않음으로 인해서 시스템이 멈추는 현상이 발생합니다. (어떤 경우는 마우스 마저 움직이지 않고 화면이 완전히 얼어버립니다. ^^)

일반적으로 대드락의 원인을 찾는 것은 어려운 분석에 속하지만 쉬운 예제를 통해서 가볍게 접근해 보겠습니다. 이번 예제의 시나리오는 MyApp.exe 프로세스가 '응답없음' 상태인 것이 발견되어 원인을 찾아가는 과정입니다.
먼저 MyApp.exe 의 프로세스 정보를 찾아봅니다.

kd> !process 0 0 MyApp.exe
PROCESS 81570b90  SessionId: 0  Cid: 01e4    Peb: 7ffdf000  ParentCid: 01e8
    DirBase: 0bc9c000  ObjectTable: e20a9d60  HandleCount:  44.
    Image: MyApp.exe

프로세스 주소로 프로세스 정보를 확인합니다.

kd> !process 81570b90 
PROCESS 81570b90  SessionId: 0  Cid: 01e4    Peb: 7ffdf000  ParentCid: 01e8
    DirBase: 0bc9c000  ObjectTable: e20a9d60  HandleCount:  44.
    Image: MyApp.exe
    VadRoot 813898a8 Vads 58 Clone 0 Private 175. Modified 81. Locked 0.
    ...
        THREAD 8158c9f8  Cid 1e4.3b0  Teb: 7ffde000 Win32Thread: e1a53660 WAIT: (Executive) KernelMode Non-Alertable
            f9fdf480  Mutant - owning thread 81116030
        IRP List:
            81397b90: (0006,0094) Flags: 00000000  Mdl: 00000000
        Not impersonating
        ...

ChildEBP RetAddr 
f2208bac 804f82e4 nt!KiSwapContext+0x2e (FPO: [EBP 0xf2208be0] [0,0,4])
f2208bb8 804f24b2 nt!KiSwapThread+0x44 (FPO: [0,0,2])
f2208be0 f9fdf9e4 nt!KeWaitForSingleObject+0x1c0 (FPO: [Non-Fpo])
f2208c34 804e8185 MyDrv!MyDrvDeviceControl+0xe4 (FPO: [Non-Fpo]) (CONV: stdcall) [d:\project\test\mydrv\mydrv.c @ 272]
f2208c44 8055887c nt!IopfCallDriver+0x31 (FPO: [0,0,1])
f2208c58 805595a7 nt!IopSynchronousServiceTail+0x5e (FPO: [Non-Fpo])
f2208d00 80552468 nt!IopXxxControlFile+0x5a5
f2208d34 8052a421 nt!NtDeviceIoControlFile+0x28 (FPO: [Non-Fpo])

쓰레드가 하나 있는데 이 녀석이 깨어나지 않는 것이로군요.
콜스택의 마지막 부분에서 KeWaitForSingleObject 를 호출한 것이 보입니다.
KeWaitForSingleObject 를 호출한 MyDrv.sys 의 MyDrvDeviceControl 함수를 확인해 봅니다.

265: case MYDRV_IOCTL_MUTEX1:
266: KeWaitForSingleObject( &MutexA, Executive, KernelMode, FALSE, NULL );
267:
268: interval1.QuadPart = -30000000;
269: KeDelayExecutionThread( KernelMode, FALSE, &interval1 );
270: KeWaitForSingleObject( &MutexB, Executive, KernelMode, FALSE, NULL );
271:
272: KeReleaseMutex( &MutexA, FALSE ); // LINE 272
273: KeReleaseMutex( &MutexB, FALSE );

콜스택에서 표시하는 소스라인 272 는 KeWaitForSingleObject 가 리턴했을 때의 위치입니다. 따라서 현재 상태는 270 라인을 호출하고 있는 상태입니다. MutexB 를 얻어야 하는데 다른 쓰레드가 획득하고 있어서 얻지 못하고 있는 상황입니다.

우리는 어떤 쓰레드가 MutexB 를 획득하고 있는지를 찾아야 합니다.
이번 예제가 간단한 예제가 될 수 있는 이유는 KMUTEX 의 속성을 이용하기 때문입니다.
KMUTEX 는 내부에 자신을 소유한 쓰레드 정보를 포함하고 있습니다. 따라서 MutexB 의 내용을 보면 이 뮤텍스를 소유하고 있는 쓰레드를 알 수 있습니다.

kd> dd mydrv!MutexB
f9fdf480  00080002 00000000 8158ca68 8158ca68
f9fdf490  81116040 81116040 81116030 00000100

MutexB 의 주소는 f9fdf480 이네요.
dt 명령으로 내용을 자세히 봅니다.

kd> dt KMUTEX f9fdf480 
   +0x000 Header           : _DISPATCHER_HEADER
   +0x010 MutantListEntry  : _LIST_ENTRY [ 0x81116040 - 0x81116040 ]
   +0x018 OwnerThread      : 0x81116030
   +0x01c Abandoned        : 0 ''
   +0x01d ApcDisable       : 0x1 ''

중간에 OwnerThraed 라는 정보가 보입니다.
이것이 바로 이미 이 뮤텍스를 소유하고 있는 쓰레드를 나타냅니다.
쓰레드 정보를 봅니다.

kd> !thread 0x81116030
THREAD 81116030  Cid 428.60c  Teb: 7ffde000 Win32Thread: e20f6cb8 WAIT: (Executive) KernelMode Non-Alertable
    f9fdf4a0  Mutant - owning thread 8158c9f8
IRP List:
    81396c10: (0006,0094) Flags: 00000000  Mdl: 00000000
...
ChildEBP RetAddr  Args to Child             
f26ddbac 804f82e4 811160a0 81116030 804f24b2 nt!KiSwapContext+0x2e
f26ddbb8 804f24b2 81116240 817b6bd8 81396c10 nt!KiSwapThread+0x44
f26ddbe0 f9fdfa59 00000000 00000000 00000000 nt!KeWaitForSingleObject+0x1c0
f26ddc34 804e8185 8120ec98 81396c10 8069f2f0 MyDrv!MyDrvDeviceControl+0x159 (CONV: stdcall) [d:\project\test\mydrv\mydrv.c @ 287]
f26ddc44 8055887c 81412ac0 81396c80 81396c10 nt!IopfCallDriver+0x31
f26ddc58 805595a7 8120ec98 81396c10 81412ac0 nt!IopSynchronousServiceTail+0x5e
f26ddd00 80552468 000000a0 00000000 00000000 nt!IopXxxControlFile+0x5a5
f26ddd34 8052a421 000000a0 00000000 00000000 nt!NtDeviceIoControlFile+0x28

앞서 봤던 콜스택과 비슷한 콜스택이 보입니다.
하지만 소스라인이 다르네요. 소스코드를 확인해 봅니다.

280: case MYDRV_IOCTL_MUTEX2:
281: KeWaitForSingleObject( &MutexB, Executive, KernelMode, FALSE, NULL );
282:
283: interval2.QuadPart = -30000000;
284: KeDelayExecutionThread( KernelMode, FALSE, &interval2 );
285: KeWaitForSingleObject( &MutexA, Executive, KernelMode, FALSE, NULL );
286:
287:  KeReleaseMutex( &MutexB, FALSE ); // LINE 287
288: KeReleaseMutex( &MutexA, FALSE );

소스코드도 비슷해 보이지만 약간 다른 내용을 가지고 있습니다.
281 라인에서 이 쓰레드가 MutexB 를 얻은 것을 확인할 수 있습니다.
285 라인에서 MutexA 를 얻으려고 하지만 획득하지 못하고 대기하는 모습을 볼 수 있습니다.

MutexA 는 이미 앞의 쓰레드 8158c9f8 이 획득한 것을 266 라인에서 보이고 있습니다.
MutexA 의 OwnerThread 에 8158c9f8 이 들어있는지 확인해 봅니다.

kd> dd mydrv!MutexA
f9fdf4a0  00080002 00000000 811160a0 811160a0
f9fdf4b0  8158ca08 8158ca08 8158c9f8 00000100

kd> dt KMUTEX f9fdf4a0 
   +0x000 Header           : _DISPATCHER_HEADER
   +0x010 MutantListEntry  : _LIST_ENTRY [ 0x8158ca08 - 0x8158ca08 ]
   +0x018 OwnerThread      : 0x8158c9f8
   +0x01c Abandoned        : 0 ''
   +0x01d ApcDisable       : 0x1 ''

정확하게 0x8158c9f8 이 들어있네요.

말 그대로 대드락 이지요.
쓰레드 8158c9f8 는 MutexA 를 획득하고 MutexB 를 요청하고 있고
쓰레드 81116030 은 MutexB 를 획득하고 MutexA 를 요청하고 있습니다.
영원히 풀릴 수가 없겠죠.

대드락 분석은 여기까지 하고 나면 위와 같은 구조가 나오지 않도록 코드를 수정하는 일만 남습니다.
대드락이 발생하지 않도록 코드를 작성하는 한가지 팁은 동기화 객체를 두개 이상 획득하는 코드를 만들지 않는 것입니다.
동기화 객체를 하나 획득했으면 얼른 일을 처리하고 풀어주고 다른 동기화 객체를 요청하는 식으로 처리하는 것이지요.

이번 대드락 분석은 KMUTEX 의 속성을 이용해서 간단하게 해 볼 수 있었습니다.
뮤텍스에 이런 쓰레드 정보가 없었다면 훨씬 복잡한 분석을 해야 하는 상황으로 갔을 것입니다.
모든 쓰레드를 펼쳐놓고 콜스택을 일일히 봐가면서 대드락의 가능성을 점검해야 하는 분석이죠.
동기화 객체로 세마포어, 이벤트, 스핀락 등을 사용했다면 이런 분석을 해야 할 것입니다.
내부에 소유한 쓰레드 정보가 없기 때문입니다.

ERESOURCE 같은 경우도 내부에 쓰레드 정보가 있기 때문에 KMUTEX 와 비슷한 접근방법을 취할 수가 있습니다. !locks 명령어가 일부 분석을 도와 주기도 하구요.
하지만 왠지 기억에 분석이 쉽지 않았던 것 같은 기분이 드는데요. ^^
나중에 적절한 예제가 만들어지면 분석하는 시간을 가지도록 해 보겠습니다.

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

반응형
Posted by GreeMate
WinDbg 디버깅2007. 9. 23. 02:14
반응형

멋진 글을 써야만 한다는 중압감을 벗어버리고 가벼운 글을 올려봅니다. ^^

.hh (Open HTML Help File)

이 명령어는 제가 늘 언급하는 WinDbg Help 를 띄워주는 일을 해 줍니다.
저도 예전에는 일일이 WinDbg Help 메뉴를 마우스로 클릭했었으나 이 명령을 알고난 다음부터 노가다 안하기로 했습니다.

.hh 알고 싶은 명령어

형식으로 사용하시면 WinDbg Help 가 뜨면서 "찾을 키워드 입력" 창에 제가 적어준 명령어가 적혀있습니다.
Enter 만 치면 바로 명령어의 사용법을 볼 수 있죠.

예제를 보겠습니다.

kd> .hh !object

위와 같이 명령하면 아래와 같은 화면이 나타납니다.


여기서 단지 Enter 만 한번 더 쳐 주시면 바로 내용이 나타납니다.

WinDbg 메뉴의 Help-Index 클릭하고 !object 쳐주는 일을 .hh 명령어 한방으로 처리한 것입니다.
빠르고 간편하죠.

그래서 고수일수록 WinDbg 에 Command 창 하나만 띄워놓고 사용하나 봅니다.
전 아직도 3~4개 띄워놓고 사용합니다만...
Command 창 하나만 남겨놓는 그날까지 열심히 공부해 봅시다. ^^

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

반응형
Posted by GreeMate