출처 : http://skmagic.tistory.com/379
WinDbg란?!
마이크로 소프트에서 배포하는 마이크로 소프트 윈도우의 다목적 디버거
유져모드 어플리케이션, 드라이버 및 커널모드에서 자체 운영체제 디버깅을 할 수 있다.
난 보통 덤프 파일 분석을 위해 사용하기에 덤프파일 분석을 위한 디버깅을 소개한다.
[덤프 디버깅]
1.유져모드 덤프 디버깅
2.커널모드 덤프 디버깅
(언제 다 정리하지?!)
[디버깅 방법]
1.심볼을 연결한다 (pdb파일이 있는 경로로 설정) (tip:웬만하면 경로는 영문명으로 하자)
2.소스코드를 연결한다.(안해도 콜스택정도는 나옴)
3.각종 명령어를 통해 분석할 수 있다.
[명령어]
k : 콜스택 보기
.ecxr : 예외가 발생한 상황에 저장된 컨텍스트 레코드를 보여준다(eax, ebx, ecx 등등...)
!analyze -v : Windebug가 자동분석을 해서 많은 정보를 보여준다.
u 주소값: 어셈보기
Command | option | usage | Desc |
종료 | |||
q | 디버깅 종료 | ||
qd | 디버깅 종료;연결해제 | ||
디버깅 환경정보 | |||
vertarget | 타겟 컴퓨터 정보 표시 | ||
version | 디버그 환경 정보 표시 | ||
.lastevent | 마지막 디버그 이벤트 정보 표시 | ||
|| | 디버깅 세션 정보 표시 | ||
sumble & sorurce | |||
.symfix | MS 심볼경로 설정 | ||
.sympath | 심볼경로 확인/설정 | ||
.sym noisy | 심볼파일 검색 과정을 출력 | ||
.srcpath | 소스경로 설정 | ||
.srcnoisy | .srcnoisy 1 | 소스경로 검색 과정을 출력 | |
모듈 | |||
lm | l | 로드된 모듈만 표시 | |
m [pattern] | 패턴과 일치되는 모듈만 표시 | ||
v | 모듈 상세정보 표시 | ||
!lmi | !lmi ntdll.dll | 모듈 상세정보 표시 | |
.reload | /f [m_name] | 심볼을 즉시 로드 | |
x | X ntdll!* | /v | 심볼 타입을 표시. |
X *!*abc* | /t | 데이터 타입을 표시 | |
/n | 이름순으로 정렬 | ||
ln | ln [address] | 해당 주소에 근접한 심볼의 정보 표시 | |
레지스터 | |||
r | 레지스터 정보 표시 | ||
r $proc | 현재 프로세스의 PEB주소( user-mode) | ||
현재 프로세스의 EPROcESS주소( kernel-mode) | |||
r $thread | 현재 스레드의 TEB주소( user-mode) | ||
현재 스레드의 ETHREAD주소( kernel-mode) | |||
r $tpid | 현재 프로세스 ID(PID) | ||
r $tid | 현재 스레드 ID(TID) | ||
언어셈블 | |||
u | 언어셈블 | ||
f | 언어셈블(함수전체) | ||
b | 언어셈블(ip이전의 8개 명령어) | ||
콜스택 | |||
k | [n] | 콜스택 정보표시 | |
p | 함수정보 출력 | ||
b | 인자표시 | ||
n | 프레임번호 | ||
v | FPO정보 표시 | ||
f | 스택 사용량 표시 | ||
break point | |||
bp | bp 0x123456 | bp 설정 | |
bl | bp 리스트 출력 | ||
bc | bc * | [frame_no] | bp 삭제 | |
bd,be | bc * | [frame_no] | bp disable/enable | |
bm | bm notepad!*Win* | 패턴과 일치하는 모든심볼에 bp설정 | |
bu | bu aaa!bbb | 로드되지 않은 심볼에 대한 bp설정 | |
ba | 특정 주소에 access시 bp | ||
지역변수 | |||
dv | dv modulr!test* | ||
/i | 심볼유형과 인자유형 표시 | ||
/V | 변수저장 위치 표시( register or address ) | ||
데이터유형 | |||
dt | df _EPROCESS 0xaddr | 주소를 특정 데이터 형으로 변환해서 표시 | |
du | Unicode string 표시 | ||
da | Ansi string 표시 | ||
dc | |||
db | |||
dy | |||
!address | !address | ||
!address [address] | |||
프로세스 & 스레드 정보 | |||
!peb | PEB(Process Environment Block)표시 | ||
!teb | TEB(Thread Environment Block) 표시 | ||
!gle | API의 마지막 에러코드 표시 | ||
실행 제어 | |||
t | Trace | ||
~.t | 다른 스레드를 중지시킨 상태에서 하나의 statementt실행 | ||
g | |||
p | Step Over | ||
gu | gu | 현재함수가 복귀할 때 까지 실행 | |
~0 gu | 스레드 0을 제외한 모든 스레드를 freeze함 | ||
wt | 내부에서 호출된 함수와 함수호출 횟수등의 정보 표시 | ||
.cxr | 컨텍스트 변경 | ||
!ready | |||
.thread | |||
!thread | |||
.trap | |||
.process | |||
!process | |||
ed | |||
eb | eb .-6 90 90 90 90 90 90 | 6byte를 NOP(0x90)으로 변경 | |
!error | !error [error code] | 에러코드 정보표시 |
출처 : http://blog.naver.com/process3
[심볼관련 사용하는 주요 명령어]
심볼을 로드할 때 사용하는 명령입니다.
보통은 심볼패스를 설정한 후에 .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 처럼 모듈 이름을 줘서 로드합니다.
로드된 모듈 리스트 보기
lm 명령을 이용하면 된다.
lm k : Kernel Mode 모듈 표시
lm u : User Mode 모듈 표시
lm m : 패턴을 검사하여 해당하는 것만 보여줌 <lm m my*>
lkd> lm
start end module name
00c80000 00c90000 NateOnHook40u (export symbols) C:\Program Files\NATEON\BIN\NateOnHook40u.dll
00cb0000 00cb9000 MgHookDll C (export symbols) C:\Program Files\LG Software\On Screen Display\MgHookDll.dll
01000000 0106a000 windbg (pdb symbols) D:\Symbol\WebSymbol\windbg.pdb\D6EF677AA54441279479F0307F05A8941\windbg.pdb
016a0000 01784000 ext (export symbols) C:\Program Files\Debugging Tools for Windows\winext\ext.dll
01790000 017c1000 kext (pdb symbols) D:\Symbol\WebSymbol\kext.pdb\6B643FC4E9F94FF4ABA4CEF1FD6F89D61\kext.pdb
모듈의 심볼(Symbol) 검사
x 모듈!패턴 을 입력하면 된다.
lkd> x nt!Ke*
804f8c02 nt!KeQuerySystemTime = <no type information>
804f8c9e nt!KeEnableInterrupts = <no type information>
80500e38 nt!KeSwitchKernelStack = <no type information>
804fad32 nt!KeReadStateProcess = <no type information>
804f9188 nt!KeReleaseInterruptSpinLock = <no type information>
데이터 타입(Date Type) 표시
dt 데이터 타입 을 입력하면 된다.
lkd> dt _EPROCESS
+0x000 Pcb : _KPROCESS
+0x06c ProcessLock : _EX_PUSH_LOCK
+0x070 CreateTime : _LARGE_INTEGER
+0x078 ExitTime : _LARGE_INTEGER
+0x080 RundownProtect : _EX_RUNDOWN_REF
+0x084 UniqueProcessId : Ptr32 Void
+0x088 ActiveProcessLinks : _LIST_ENTRY
+0x090 QuotaUsage : [3] Uint4B
+0x09c QuotaPeak : [3] Uint4B
+0x0a8 CommitCharge : Uint4B
메모리 덤프(Memory Dump)
d* 명령들을 이용하면 된다.
db : Byte 형식 + Ascii 로 표시
dd : 데이터를 4Byte 형식으로 표시
lkd> db 8053db18
8053db18 8b ff 55 8b ec 8b 45 08-8b 4d 0c 8b 55 14 89 48 ..U...E..M..U..H
8053db28 0c 8b 4d 10 89 48 10 03-ca 89 48 14 8b 4d 18 83 ..M..H....H..M..
8053db38 c1 fe 89 48 18 8b 4d 1c-89 48 20 66 8b 4d 20 66 ...H..M..H f.M f
디스어셈블리(Disassembly)
u 주소 를 이용하면 된다. 특정 함수를 디스어셈블리 하고 싶으면 uf 주소 를 하면 된다.
u 주소 : 주소에서 일부분만 디스어셈블리
u 주소1 주소2 : 주소1에서 주소 2까지 디스어셈블리
lkd> u 8053db18 or uf nt!NtOpenProcess
nt!KeInitializeProfile:
8053db18 8bff mov edi,edi
8053db1a 55 push ebp
8053db1b 8bec mov ebp,esp
8053db1d 8b4508 mov eax,[ebp+0x8]
8053db20 8b4d0c mov ecx,[ebp+0xc]
메모리 영역 속성 보기(VA Dump)
!vadump 명령을 사용하면 된다. 만약 특정 메모리의 속성을 보고 싶다면 !vprot 주소 명령을 사용하면 된다.
0:000> !vadump
BaseAddress: 00000000
RegionSize: 00010000
State: 00010000 MEM_FREE
Protect: 00000001 PAGE_NOACCESS
BaseAddress: 00010000
RegionSize: 00001000
State: 00001000 MEM_COMMIT
Protect: 00000004 PAGE_READWRITE
Type: 00020000 MEM_PRIVATE
0:000> !vprot 30c191c
BaseAddress: 030c1000
AllocationBase: 030c0000
AllocationProtect: 00000080 PAGE_EXECUTE_WRITECOPY
RegionSize: 00011000
State: 00001000 MEM_COMMIT
Protect: 00000010 PAGE_EXECUTE
Type: 01000000 MEM_IMAGE
프로세스 관련
모든 프로세스를 보기위해서는 !process 0 0 를 입력하면 된다. 디버거를 특정 프로세스에 붙이고 싶으면 .process /i [pid] 를 입력하면 된다.
lkd> !process 0 0
**** NT ACTIVE PROCESS DUMP ****
PROCESS 8a3a3490 SessionId: none Cid: 0004 Peb: 00000000 ParentCid: 0000
DirBase: 00780000 ObjectTable: e1001c70 HandleCount: 521.
Image: System
PROCESS 8a184158 SessionId: none Cid: 03f0 Peb: 7ffdd000 ParentCid: 0004
DirBase: 17a40020 ObjectTable: e163dd70 HandleCount: 20.
Image: smss.exe
PROCESS 89df4da0 SessionId: 0 Cid: 0440 Peb: 7ffd5000 ParentCid: 03f0
DirBase: 17a40040 ObjectTable: e1c6cb18 HandleCount: 626.
Image: csrss.exe
구조체 내용 보기
!strct _KMUTANT ff93a330
이렇게 명령을 주면 자료구조랑 값들이 같이 출력이 된다.
WinDBG 디버깅 과정 파일로 저장하기
Windbg를 이용해서 디버깅을 하다보면,
디버깅과정을 저장할 필요가 생깁니다.
또는 아래와 같은 상황이 있을수 있을겁니다.
- 다른분의 도움을 통해 디버깅한 내용을 참고하고 싶은경우
- 수십시간동안 켜놓은 결과를 저장해야하는경우. -> 화면 버퍼를 넘어가면 그동안의 내용이 사라지죠~
- .cls 를 습관적으로 사용하는경우. -> 제경우입니다. T.T
이때 유용한 명령어가 바로.
.logxxx 계열 명령어입니다.
.logopen logfile
>> 디버깅 과정을 저장할 로그파일 명을 지정합니다.
ex) .logopen “c:\dbglog\logs.txt”
.logfile
>> 현재 기록중인 디버깅 로그파일의 상태를 표시합니다.
.logclose
>> 기록중이던 로그를 종료(완료)합니다.
유용하게 쓰세요~
(단, .logopen 이전의 내용은 저장되지 않습니다.` ^^)
참고하세요)
.logopen 정보 역시 Windbg WorkSpace 에 함께 저장됩니다.~ ^^
GUI환경의 디버깅툴인 windbg 사용법을 알아보자.
일단 각 필요파일들을 download해야겠지?
◎ 필요한 파일들
* windbg 다운로드
32bit버전 : http://www.microsoft.com/whdc/devtools/debugging/installx86.mspx
64bit버전 : http://www.microsoft.com/whdc/devtools/debugging/install64bit.mspx
* 심볼파일 다운로드
http://www.microsoft.com/whdc/devtools/debugging/symbolpkg.mspx
위의 링크에서 각 OS에 맞는 파일 다운로드하여 설치
◎ 설치할때 특별하게 주의할 점은 없다. 모르겠다 싶으면 그냥 "다음(Next)" 버튼만 눌러라.
단, 기억할것은 심볼파일을 설치할때 어디에 설치했는지 잘 봐두도록..
기본설치 위치는 해당 OS폴더 밑의 Symbols이다. 예를 들면 XP인 경우는
"C:\Windows\Symbols"에 설치된다.
◎ 실행방법 및 심볼파일 경로 설정
1. 실행창에서
시작 -> 실행 창 또는 명령프롬프트 창에서 아래와 같이 입력
windbg -y 심볼파일경로 -i OS이미지경로 -z 덤프파일경로
예> windbg -y SRV*C:\Windows\Symbols*http://msdl.microsoft.com/download/symbols -i d:\i386 -z c:\windows\memory.dmp
2. 시작 -> 모든 프로그램 -> Debugging Tools for Windows -> WinDbg 실행
File -> Symbol File Path... 실행
Symbol Search Path창이 뜨면 아래 경로 입력하고 확인 클릭
경로 : SRV*C:\Windows\Symbols*http://msdl.microsoft.com/download/symbols
File -> Image File Path... 실행
OS 이미지 경로입력 (OS CD의 i386에 있음)
File -> Open Crash Dump... 실행
Dump파일 경로 입력
◎ Remote Debugging 방법
* Debugger사용하는 방법
- 서버, 클라이언트 모두 windbg를 설치, 서버측에 심볼파일 설치
1. 서버(debug하려는 기계)셋팅 :
복수사용자(클라이언트) : 콘솔창 : WinDbg -server npipe:pipe=pipename
단일사용자 : WinDbg실행 -> 명령창: .server npipe=pipename
2. 클라이언트 셋팅:
1) WinDbg -remote npipe:server=Server, pipe=Pipename[,password=password]
2) WinDbg 실행 -> File-> Connect to Remote Session 선택
npipe:server=Server,pipe=PipeName[,password=Password]입력
* Remote.exe 사용하는 방법
- 서버, 클라이언트 모두 debugging tool 설치, 심볼파일은 클라이언트 설치
◎ 주요 명령어
참조 :
1. MSDN
2. 네이버 윈도우시스템프로그래밍 카페
Windbg Tutorial
http://www.codeproject.com/KB/debug/windbg_part1.aspx
Windows에서 디버깅을 위해 만든 작은 메모리 덤프 파일을 읽는 방법
http://support.microsoft.com/default.aspx?scid=kb;ko;315263
잊지 말아야 할 점은, windbg는 symbol과 source code의 매칭을 해주지 않는다.
반드시 Symbol File Path와, Source File Path 메뉴 에서 경로를 제대로 지정해주어야, 덤프 분석시 정보가 제대로 출력된다.
windbg shell command
덤프 생성
덤프 정보 분석
할당된 가상메모리 덤프
올리디버거의 Memory Map윈도의 기능
!vadump [-v]
해당메모리 주소가 어떤 속성인지 알려줌
!vprot [주소]
현재 프로세스내에 동작중인 스레드의 스택을 보여줌
!uniqstack [-b]
-b옵션을 주면 스택에 담긴 아규먼트까지 보여준다
현재 스레드에 할당된 권한(Privilege)를 보여줌
!token
각 스레드가 동작한 시간
!runaway
레지스트리 정보 확인
!dreg
예) 0:000> !dreg System\CurrentControlSet\Services\Tcpip!*
해당 주소를 UNICODE_STRING구조체 형식으로 살펴봄
!ustr [주소]
typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING;
해당 주소를 ANSI_STRING혹은 OEM_STRING구조체로 살펴봄
!str [주소]
typedef struct _STRING {
USHORT Length;
USHORT MaximumLength;
PCHAR Buffer;
} STRING;
typedef STRING ANSI_STRING;
typedef STRING OEM_STRING;
스레드 로컬 스토리지 슬롯을 살펴봄
!tls
모든 슬롯 출력
예) !tls -1
Specifies the thread environment block (TEB). If this is 0 or omitted, the current thread is used
예) !tls 0
현재 스레드의 TEB정보를 출력
!teb
현재 프로세스의 PEB정보를 출력
!peb
잘 알려진 몇몇 STL템플릿정보를 출력
!stl
로딩된 dll모듈의 베이스주소와 길이 모듈명을 출력한다
lm
해당모듈의 자세한 정보를 출력
!lmi [모듈]
예) !lmi 00400000
반복적인 디버거명령을 실행시키면서, 링크드리스트 정보를 출력함
!list
예) !list "-t ntdll!_LIST_ENTRY.Flink -e -x \"dd @$extret l4; dt ntdll!_RTL_CRITICAL_SECTION_DEBUG @$extret-0x8\" ntdll!RtlCriticalSectionList"
현재 Shared User-mode Page를 출력함
현재 타임존과 시스템루트, TickCount와 시간을 출력함
!kuser
로드된 모듈들의 리로케이션되기전의 주소를 출력한다
!imgreloc [주소]
최근 에러코드를 리턴한다
!gle
에러코드를 가지고 무슨 에러인지 설명을 보여준다
!error [에러코드번호]
글로벌 플래그를 설정 혹은 보여준다
!gflag
로드된 모듈들에 대한 커스터마이징(?)된 출력을 해준다.
!for_each_module ["명령어"]
예) !for_each_module .echo @#ModuleIndex : @#Base @#End @#ModuleName @#ImageName @#LoadedImageName
로드된 모듈에서 MZ로 시작되는것을 찾는다
예) !for_each_module s-a @#Base @#End "MZ"
가상메모리에서 이미지헤더를 검색한다 (MZ검색)
.imgscan
표현식을 헥사, 8진수, 2진수, 시간형, Float형, Double 형으로 변환한 형태로 보여준다
.formats [표현식]
디버그 레지스터 확인0:000> rm 0x20;r
dr0=00000000 dr1=00000000 dr2=00000000
dr3=00000000 dr6=00000000 dr7=00000000
ntdll!KiFastSystemCallRet:
7c93eb94 6a01 push 1
범용레지스터 확인
0:000> rm 0x01;r
eax=00000000 ebx=00000000 ecx=00000006 edx=7c9ac080 esi=7c93e88e edi=00000000
eip=7c93eb94 esp=0007fde8 ebp=0007fee4 iopl=0 nv up ei pl zr na pe nc
ntdll!KiFastSystemCallRet:
7c93eb94 6a01 push 1
레지스터 값 변경
r eip=7c931230
r eax = @ebx
r zf=0
특정 주소에 어셈블 코드 삽입
a <위치>
예) a eip
00401000 sub esp, 10
특정 주소에 원하는 값 삽입
e[옵션] <주소>
예) eb <주소>
00401000 90
00401001 90
00401002 90
현재 보여주는 숫자의 진수바꾸기
n <base>
예) n 8
예) n 16 # 16진수
예) n 10 #10진수로 보여줌
메모리가 참조하고 있는 데이터를 살펴보기
예) dpa esp 현재 스택을 아스키형태로 보여줌
예) dpu esp 현재 스택을 유니코드형태로 보여줌
메모리의 내용을 심벌과 매핑시켜서 보여줌
예) dds esp 현재 콜 스택을 보여줌
'UTIL > Debugging' 카테고리의 다른 글
Windbg를 이용한 메모리 릭 검사(영문) (0) | 2014.12.26 |
---|---|
Windows Wingdb를 이용한 MEMORY LEAK 대처법 (0) | 2014.12.26 |
gdb 사용법 안내 (0) | 2012.08.01 |
dbx와 core 파일 분석 및 사용법 (0) | 2012.08.01 |