.extpath 扩展模块搜索路径
.ecxr;kb
!analyze -v
~ - 列举出当前进程上下文中的所有线程
~* - 列举出当前进程上下文中的所有线程的详细信息
lm - 列举出所有加载的模块
!sym noice/quiet - 代码提示开关
.srcpath -设置源码路径
k - 显示当前堆栈
~*kb -显示出所有线程占用的堆栈
dv - 显示出本地变量(使用ctrl + alt + v切换模式)
.Frame - 调用堆栈
dt xxx - 显示出诸如PEB等的数据结构
dt ESAlertServer!* /v /s 14
!gle/!error - 显示出最新线程错误
!teb - 显示出当前线程执行块
!peb - 显示出当前进程执行块
r [@register] - 显示所有注册的值
ln [Address] - 显示地址类型
x [] -查询全局变量和全局函数
!locks - 显示所有死锁
exit (退出)
.kdfiles map.ini
map.ini
map
\Systemroot\system32\drivers\tag.sys
c:\host.sys
!handle ? f
!htrace [enable] - 显示并跟踪所有句柄!handle - 获取当前活动句柄
!handle ? f
!htrace [enable] - 显示并跟踪所有句柄
!htrace [Handle [Max_Traces]]
!htrace -enable [Max_Traces]
!htrace -snapshot
!htrace -diff
!htrace -diff
!htrace -disable
使用lsa 传递指定位置对应的代码,lsa ESCC!funn+0x0000002e 到这里,就找到了泄露句柄的函数。
for_each
vertarget 显示操作系统信息
u - 反汇编
uf
bp [Kernel!SetLastError] [value] - 设置断点
bl - 显示断点信息
ba - 数据断点
ba w4 0x4000000 "kb;g" - 显示出地址0x40000调用的所有堆栈
p,pa,t,ta - 控制命令
.time
!runaway 7
ContextsChangingContextsChanging
.frame /r 1 .frame /r 1
.cxr (Display Context Record)
.ecxr (Display Exception Context Record)
Other
.load C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\sos.dll
!dumpheap -stat
!eeversion
.chain
显示当前线程的错误值:!gle会显示当前线程的上一个错误值和状态值。!error命令可以解码hresult。
查看lock:!locks显示各线程的锁资源使用情况。对调试死锁很有用。
查看handle:!handle显示句柄信息。假如一段代码导致句柄泄漏,你只需要在代码执行前后使用!handle命令并比较两次输出的区别。有一个命令!htrace对调试与句柄有关的bug非常有用。在开始调试前输入:
!htrace –enable
然后在调试过程中使用!htrace handle_value 来显示所有与该句柄有关的调用堆栈。
显示当前线程,进程和模块信息:
!teb显示当前线程的环境信息。最常见的用途是查看当前线程堆栈的起始地址,然后在堆栈中搜索值。
!peb显示当前进程的环境信息,比如执行文件的路径等等。
lm显示进程中加载的模块信息。
?
1: kd> n 10
base is 10
1: kd> ? 0x123
Evaluate expression: 291 = 00000123
1: kd> ? 123
Evaluate expression: 123 = 0000007b
1: kd> n 10
base is 10
1: kd> ? 0x123
Evaluate expression: 291 = 00000123
1: kd> ? 123
Evaluate expression: 123 = 0000007b
0:001> !heap -s
Heap Flags Reserv Commit Virt Free List UCR Virt Lock Fast
(k) (k) (k) (k) length blocks cont. heap
-----------------------------------------------------------------------------
00150000 00000002 1024 52 52 5 1 1 0 0 L
00250000 00008000 64 12 12 10 1 1 0 0
00370000 00000002 64 36 36 5 2 1 0 0 L
00380000 00001002 64 16 16 0 0 1 0 0 L
003a0000 00001002 256 12 12 4 1 1 0 0 L
00030000 00001002 64 32 32 4 1 1 0 0 L
003e0000 00001002 64 32 32 24 1 1 0 0 L
Virtual block: 00aa0000 - 00aa0000 (size 00000000)
Virtual block: 00bc0000 - 00bc0000 (size 00000000)
00a80000 00001003 64 20 20 8 1 1 2 bad
-----------------------------------------------------------------------------
0:001> !heap -s
Heap Flags Reserv Commit Virt Free List UCR Virt Lock Fast
(k) (k) (k) (k) length blocks cont. heap
-----------------------------------------------------------------------------
00150000 00000002 1024 52 52 5 1 1 0 0 L
00250000 00008000 64 12 12 10 1 1 0 0
00370000 00000002 64 36 36 5 2 1 0 0 L
00380000 00001002 64 16 16 0 0 1 0 0 L
003a0000 00001002 256 12 12 4 1 1 0 0 L
00030000 00001002 64 32 32 4 1 1 0 0 L
003e0000 00001002 64 32 32 24 1 1 0 0 L
Virtual block: 00aa0000 - 00aa0000 (size 00000000)
Virtual block: 00bc0000 - 00bc0000 (size 00000000)
Virtual block: 00cd0000 - 00cd0000 (size 00000000)
Virtual block: 00de0000 - 00de0000 (size 00000000)
00a80000 00001003 64 20 20 8 1 1 4 bad
-----------------------------------------------------------------------------
0:001> !heap -stat -h 00a80000
heap @ 00a80000
group-by: TOTSIZE max-display: 20
size #blocks total ( %) (percent of total busy bytes)
100000 4 - 400000 (99.76)
1000 1 - 1000 (0.10)
800 1 - 800 (0.05)
280 1 - 280 (0.02)
20 12 - 240 (0.01)
30 9 - 1b0 (0.01)
40 6 - 180 (0.01)
160 1 - 160 (0.01)
50 4 - 140 (0.01)
110 1 - 110 (0.01)
100 1 - 100 (0.01)
d0 1 - d0 (0.00)
60 2 - c0 (0.00)
10 b - b0 (0.00)
0:001> !heap -flt s 100000
_HEAP @ 150000
_HEAP @ 250000
_HEAP @ 370000
_HEAP @ 380000
_HEAP @ 3a0000
_HEAP @ 30000
_HEAP @ 3e0000
_HEAP @ a80000
HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
00aa0018 20000 0000 [0b] 00aa0020 100000 - (busy VirtualAlloc)
00bc0018 20000 0000 [0b] 00bc0020 100000 - (busy VirtualAlloc)
00cd0018 20000 0000 [0b] 00cd0020 100000 - (busy VirtualAlloc)
00de0018 20000 0000 [0b] 00de0020 100000 - (busy VirtualAlloc)
0:001> !heap -p -a 00aa0018
address 00aa0018 found in
_HEAP @ a80000
HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
00aa0018 20000 0000 [0b] 00aa0020 100000 - (busy VirtualAlloc)
dt _DPH_BLOCK_INFORMATION
!address -summary
kd> !address -summary
804d8000 - 001f7000
Usage KernelSpaceUsageImage
ImageName ntkrnlpa.exe
806cf000 - 00021000
Usage KernelSpaceUsageImage
ImageName halaacpi.dll
81000000 - 001c1000
Usage KernelSpaceUsagePFNDatabase
811c1000 - 00818000
Usage KernelSpaceUsageNonPagedPool
bc000000 - 00400000
Usage KernelSpaceUsageSessionPool
bc400000 - 03400000
Usage KernelSpaceUsageSessionView
bf800000 - 00800000
Usage KernelSpaceUsageSessionImage
c1200000 - 1fe00000
Usage KernelSpaceUsageSystemCache
e1000000 - 0ca00000
Usage KernelSpaceUsagePagedPool
kd> !address -summary
804d8000 - 001f7000
Usage KernelSpaceUsageImage
ImageName ntkrnlpa.exe
806cf000 - 00021000
Usage KernelSpaceUsageImage
ImageName halaacpi.dll
81000000 - 001c1000
Usage KernelSpaceUsagePFNDatabase
811c1000 - 00818000
Usage KernelSpaceUsageNonPagedPool
bc000000 - 00400000
Usage KernelSpaceUsageSessionPool
bc400000 - 03400000
Usage KernelSpaceUsageSessionView
bf800000 - 00800000
Usage KernelSpaceUsageSessionImage
c1200000 - 1fe00000
Usage KernelSpaceUsageSystemCache
e1000000 - 0ca00000
Usage KernelSpaceUsagePagedPool
!pool
1: kd> !pool e7a88000
Pool page e7a88000 region is Nonpaged pool
e7a88000 is not a valid large pool allocation, checking large session pool...
e7a88000 is freed (or corrupt) pool
Bad allocation size @e7a88000, too large
***
*** An error (or corruption) in the pool was detected;
*** Attempting to diagnose the problem.
***
*** Use !poolval e7a88000 for more details.
***
Pool page [ e7a88000 ] is __inVALID.
Analyzing linked list...
Scanning for single bit errors...
None found
1: kd> !pool e7a88000-8
Pool page e7a87ff8 region is Nonpaged pool
e7a87000 size: be8 previous size: 0 (Free) Strg
e7a87be8 size: 160 previous size: be8 (Allocated) CcSc
e7a87d48 size: 128 previous size: 160 (Allocated) Ntfi
*e7a87e70 size: 190 previous size: 128 (Allocated) *Epos
Owning component : Unknown (update pooltag.txt)1: kd> !pool e7a88000
Pool page e7a88000 region is Nonpaged pool
e7a88000 is not a valid large pool allocation, checking large session pool...
e7a88000 is freed (or corrupt) pool
Bad allocation size @e7a88000, too large
***
*** An error (or corruption) in the pool was detected;
*** Attempting to diagnose the problem.
***
*** Use !poolval e7a88000 for more details.
***
Pool page [ e7a88000 ] is __inVALID.
Analyzing linked list...
Scanning for single bit errors...
WinDBG中设置条件断点
条件断点:断点指令 + “j(Excecute If-Else) 和 gc (Go from Conditional Breakpoint)”
形如:bp Address "j (Condition) 'OptionalCommands'; 'gc' "
这里仅简单说明该如何写后面的条件语句
1. 非结构体变量:
"j (poi(MyVar)>5) '';'gc'" 在代码中,MyVar是整数变量。默认的debug配置采用MASM语法,因此MyVar被当作指针看待,在做条件判断时,需要使用poi解引用。如果debug配置采用C++语法,MyVar会被解析为整数变量,可直接用于条件判断。条件为真时对应的语句为空,则当条件满足时,会断在此处。gc表示从断点处继续运行。
2. 结构体变量
"j (@@c++(MyStruct->field)>5) '';'gc'" 判断结构体变量中的某个成员变量时,采用C++语法解析表达式:@@c++(...)。因默认配置是masm语法,故对于结构体成员都用此种方法解析。
3. 寄存器
1 "j @eax = 0xa3 ''; 'gc'" <1>
2 "j @eax = 0xc0004321 '';'gc'" <2>
3 "j (@eax & 0x0`ffffffff) = 0x0`c0004321 '';'gc'" <3>
式<1>:当eax的值为0xa3时,触发该断点。
在masm表达式中,寄存器是做符号扩展的,即0xc0004321实际被当作是0xffffffff`c0004321,即便实际显示时是0xc00004321。这种符号扩展仅存在于kernel mode中。因此式<2>在kernel mode会失败。最好的改法则是按照式<3>的方式做条件比较,该方式可以同时用于kernel mode和user mode。
bu MSMPPEKey::insert "kb; .time; g"
bm /a iassam!Auth* "kb; g"
!sym noisy :开启符号打印. 这样符号加载的信息显示就非常多了
查看pe信息
!dh [Options] Address : 查看模块pe信息
!dh -f : display file headers
!dh -s : section headers
!dh -a : all header informations
!verifier:查看Verifier 检测统计信息
监视窗口:
@@(poi(0ffb6bae0))
显示0ffb6bae0指向的值. 具体可以参照windbg的命令语法写一个很复杂的命令.
@@(eax)
监视器窗口添加eax的值
@$peb @$teb @$ip
监视窗口添加peb teb eip的值
@$proc
监视窗口添加 eprocess的结构信息
条件断点:
bp kernel32!CreateFileW+0x5 “dU /c 50 poi(@ebp+8) ;gc”
断在CreateFileW, 然后打印第一个参数. 也就是文件名称了还可以这样
bp kernel32!OpenFileMappingW+5 “kv 10;dU /c 30 poi(@ebp+10)”
更可以这样
bp kernel32!CreateFileW+0x5 “dU /c 50 poi(@ebp+8) ;gu; r eax; gc”
更牛逼的是这样, 加个判断
bp kernel32!CreateFileW+0x5 “dU /c 50 poi(@ebp+8) ;gu; r eax; .if (@eax < 0 ) {.echo hit }.else{gc}”
字符串条件断点(OllyDbg):
使用快捷键:Shift+F2设置条件断点,在条件中输入。
ASCII字符集字符串设置方法:
STRING [eax] == "DDLX_CHAR" STRING [eax] == "DDLX_char" //不区分大小写 STRING [eax] == "DDLX" //不区分文本长度
UNICODE字符集字符串设置方法:
UNICODE [eax] == "DDLX_WCHAR" UNICODE [eax] == "DDLX_wchar" //不区分大小写 UNICODE [eax] == "DDLX" //不区分文本长度
字符串条件断点(Windbg):
//全字符串匹配,区分大小写 bp 0041141d "r @$t1 = eax; as /ma ${/v:pzString} $t1;.if ($scmp(\"${pzString}\",\"DDLX_CHAR\")==0) {} .else {gc}"
//全字符串匹配,不区分大小写 bp 0041141d "r @$t1 = eax; as /ma ${/v:pzString} $t1;.if ($sicmp(\"${pzString}\",\"DDLX_char\")==0) {} .else {gc}"
//字符串还可以模糊匹配,*表示0-?个模糊字符 bp 0041141d "r @$t1 = eax; as /ma ${/v:pzString} $t1;.if ($spat(\"${pzString}\",\"DDLX*\")==0) {} .else {gc}"
UNICODE字符集字符串设置方法:
bp 0041141d "r @$t1 = eax; as /mu ${/v:pzString} $t1;.if ($scmp(\"${pzString}\",\"DDLX_WCHAR\")==0) {} .else {gc}"
可以看到, 就是一个/mu /ma的区别. 看看windbg的帮助, 发现还有很多其他样式可供选择.
打印线程堆栈, 线程LastError值
~*e ? @$tid;!gle
~*e ? @$tid;kv
~* k( ~* kv ) 打印所有线程堆栈
显示进程中每个线程的的iD和LastError值.
调试运行相关:
gn 强制返回已经处理了异常
gh 跳过异常处理使用程序自带的异常处理.
ba 硬件断点
dl 遍历链表 如 dl nt!PsActiveProcessHead 1000
dt -r3 nt!_KPCR 显示结构遍历3层.
.call 调用目标程序的函数.
进程线程相关
.dml_start 以DML的方式显示一些自定义功能,默认情况下会显示各类命令帮助已经关于调试进程的一些基本信息。DML命令在命令浏览窗口将会得到更好的支持。你能使用CTRL+N打开该窗口并使用此指令
!dml_proc 也用来显示进程信息,不带参数时直接显示进程列表,比!process 0 0 命 令显示的格式要紧凑好看点, 是一条霸气侧漏的语句
!thread 列出当前线程信息
!cs 显示互斥量信息
.thread 地址 切换到某个线程
内存命令
!address 命令显示内存信息,如内存范围、内存权限等。
!vm 标号 命令显示虚拟内存信息
!memusage 命令显示物理内存信息
!pte 命令显示指定地址对应的页表项(PTE)和页目录项(PDE)。
!pfn 命令显示物理内存页的详细信息,指定页面帧编号为参数
!db/!eb 命令用来显示、修改物理内存,类似的还有!dd/!dc/!dq/!ed 等
!vprot address 显示某个地址所在的模块属性.
lm 列出模块信息.
lm m kern* 查找kern开头的模块信息.
lmf 显示模块的具体路径
lmv 显示模块的具体信息
写代码的时候记得列出标号是多么重要
!pool 命令显示内核内存池信息
!poolused 命令按照内存池 Tag 显示内存池信息。
!poolfind 命令显示所有指定 Tag 的内存信息
对象相关命令
!handle 命令显示句柄信息,包括句柄类型、句柄引用计数、句柄名等
!object 命令显示对象信息。
!object xxxxxxx 命令显示指定对象的信息,xxxxxxxx 表示对象地址
!drvobj 命令显示驱动信息,主要是显示 DRIVER_OBJECT 结构的信息
!devobj 命令显示驱动设备信息,主要是显示 DEVICE_OBJECT 结构信息。
蓝屏Dump相关命令
!analyze -v 命令是分析蓝屏 dump 时首先应该执行的命令,该命令会显示蓝屏原因、蓝屏上下文等,并会根据
蓝屏原因自动进行相关的分析,给出进一步分析的建议。
.ecxr 命令会回到异常产生的地方.
查看目标机(底层相关命令)
vertarget 命令可以显示目标系统的基本信息,如系统版本、计算机名、内核基址等
dg 命令主要显示选择子的详细信息
!cpuinfo 命令显示CPU 信息
!pcr 命令显示处理器控制域(Processor Control Region)信息,也就是KPCR 结构信息,每个CPU 对应一个KPCR 结构,可以在命令中指定需要显示的CPU 序号,不指定则显示当前CPU 的PCR 信息。
!prcb 命令显示处理器控制块(Processor Control Block)信息,也就是KPRCB 结构信息,同样,每个CPU对应一个KPRCB 结构,该结构紧接在KPCR 结 构后面,由KPCB 结构中的PrcbData 表示。命令中可以指定CPU 序号。
!idt 命令显示中断服务表,可以指定中断号显示,也可以显示全部的中断服务表
!irql 命令显示目标系统中断到WinDbg 时的中断请求级(IRQL),在 Windows2003 及以后的系统上可用,调试和IRQL 相关的程序时可能会用
!running 命令显示所有CPU 上正在运行的线程信息,便于了解系统当前的情况,如果 是分析蓝屏文件,则可以 看到蓝屏时系统正在执行什么线程。
!gflag 命令显示、设置系统全局标志,用于控制系统行为,和WinDbg 自带的gflags.exe 工具类似,不过设置 后只对当前调试会话有效。
句柄泄漏查找:
1)找到windbgs安装目录下的gflags.exe工具,该工具可用来打开windows自带的一些调试选项,具体gflags.exe的详细使用可以查看windbg帮助;这里我们设置勾上application verifiwer,该工具主要可用来对程序做一些稳定性的检测,本次调试主要用于保存栈的相关信息。同时设置stackbacktrace即栈的大小为10.
2)运行windbg,打开第一步编译的程序,并使其跑起来;此时你查看任务管理器中的句柄信息,会发行相应进程句柄一直在增加。
3)windbg用ctrl+break命令中断进程运行,用!htrace -enable命令开启句柄检测;htrace提供了进行句柄相关检测的命令,可查看windbg帮助。
4)再次中断进程,使用!htrace -snapshot命令,获得此时进程句柄的镜像。并再次让程序运行。
5)第三次中断进程运行,我们再使用!htrace -diff命令获得当前句柄状态与第4步 snapshot镜像句柄的差异;
6)我们使用lsa 传递指定位置对应的代码,lsa handlew2!fun4+0x0000002e
到这里,我们就找到了泄露句柄的函数,真是神奇啊。