http://www.windbg.info/doc/1-common-cmds.html
1)内置帮助命令 CMD 变种/参数 描述 ?
? ?/ d
显示常规命令将常规命令 显示为DML
。救命
.help .help / D.help / D a *
显示。命令 显示。DML格式的命令(给出顶部链接栏) 显示。以*(通配符)作为DML开头的命令
。链
.chain .chain / D.
列出所有加载的调试器扩展将 所有加载的调试器扩展列为DML(扩展名链接到.extmatch)
.extmatch
.extmatch / e ExtDLL FunctionFilter .extmatch / D / e ExtDLL FunctionFilter
显示扩展DLL的所有导出函数。FunctionFilter =通配符字符串 以DML格式相同(函数链接到“!ExtName.help FuncName”命令) 示例:.extmatch / D / e uext * (显示uext.dll的 所有导出函数)
.hh
.hh .hh文字
打开WinDbg的帮助 文本=要在帮助文件索引中查找的文本 示例:.hh dt
上
2)General WinDbg的命令(显示版本,清除屏幕等) CMD 变种/参数 描述 版
转储调试器和加载的扩展DLL的版本信息
vercommand
用于启动调试器的转储命令行
vertarget
目标计算机的版本
CTRL + ALT + V
切换详细模式ON / OFF 在详细模式下,某些命令(例如寄存器转储)具有更详细的输出。
ñ
n [8 | 10 | 16]
设置数字基数
.formats
.formats Expression
显示数字格式=计算数值表达式或符号,并以多种数字格式显示(十六进制,十进制,八进制,二进制,时间等)。 示例1:。格式5 示例2:.formats poi(nLocal1)== .formats @@($!nLocal1)
.CLS
清除屏幕
.lastevent
显示最近发生的异常或事件(调试器等待的原因?)
.effmach
.effmach .effmach。 .effmach# .effmach x86 | amd64 | ia64 | EBC
转储有效机器(x86,amd64,..): 使用目标计算机的本机处理器模式 使用为最近事件执行的代码的处理器模式 使用x86,amd64,ia64或ebc处理器模式 此设置会影响许多调试器功能: - >哪个处理器的开卷用于堆栈跟踪 - >哪个处理器的寄存器组有效
。时间
显示时间(系统启动,处理,内核时间,用户时间)
上
3)调试会话(附加,分离,...) CMD 变种/参数 描述 。连接
PID
附加到一个过程
。分离
结束调试会话,但保持任何用户模式目标应用程序运行
q
q,qq
退出=结束调试会话并终止目标应用程序 远程调试:q =无效; qq =终止调试服务器
。重新开始
重启目标应用程序
上
4)表达式和命令 CMD 变种/参数 描述 ;
命令分隔符(cm1; cm2; ..)
?
?表达 ?? 表达
计算表达式(使用默认计算器) 评估c ++表达式
.expr
.expr .expr / q .expr / s c ++ .expr / s masm
选择默认表达式计算器 显示当前计算器 显示可用的计算器 将c ++ 设置为默认表达式计算器 将masm 设置为默认表达式计算器
*
* [任何文字]
注释行说明符 终止于:行尾
$$
$$ [任何文字]
注释说明符 终止于:行尾或分号
。回声
.echo String .echo“String”
Echo Comment - > comment text + echo it 终止于:行尾或分号 使用$$标记或*标记,调试器将忽略输入的文本而不回显它。
上
5)调试器标记语言(DML) 从6.6.07版本的调试器开始,包括一个增强调试器和扩展输出的新机制:DML。 DML允许输出以标记的形式包含指令和额外的非显示信息。 调试器用户界面解析出额外信息以提供新行为。 DML主要用于解决两个问题:
CMD 变种/参数 描述 .dml_start
踢其他DML命令
.prefer_dml
.prefer_dml [1 | 0]
全局设置:DML增强命令应该默认为DML吗? 请注意,许多命令如k,lm,..之后输出DML内容。
.help / D.
.help有一个新的DML模式,其中给出了一个顶部链接
.chain / D.
.chain有一个新的DML模式,其中扩展链接到.extmatch
.extmatch / D.
.extmatch有一种新的DML格式,其中导出的函数链接到“!ExtName.help FuncName”命令
LMD
lm有一个新的DML模式,其中模块名称链接到lmv命令
千米
k具有新的DML模式,其中帧编号链接到.frame / dv
.dml_flow
.dml_flow StartAddr TargetAddr
允许交互式探索函数的代码流。
从给定的起始地址开始为函数构建代码流图(类似于uf) 显示给定目标地址的基本块以及当前块引用的引用块和块的链接 示例:.dml_flow CreateRemoteThread CreateRemoteThread + 30
上
6)主要扩展 CMD 变种/参数 显示支持的命令.. !Ext.help
一般扩展
!Exts.help
- || -
!Uext.help
用户模式扩展(非特定于操作系统)
!Ntsdexts.help
用户模式扩展(特定于操作系统)
!logexts.help
记录器扩展
!clr10 \ sos.help
调试托管代码
!wow64exts.help
Wow64调试器扩展
!Wdfkd.help
内核模式驱动程序框架扩展
!Gdikdx.help
图形驱动扩展
..
!NAME.help
!NAME.help功能
显示有关导出函数的详细帮助 NAME =扩展DLL 占位符FUNCTION =导出函数的占位符 示例:!Ntsdexts.help句柄 (显示详细帮助!Ntsdexts.handle)
上
7)符号 CMD 变种/参数 描述 LD
ld ModuleName ld *
为所有模块加载模块 加载符号的符号
!符号
!sym !sym吵闹 !sym安静
获取符号加载状态 设置噪声 符号加载(调试器显示有关其符号搜索的信息) 设置安静 符号加载(=默认值)
X
x [选项] 模块!符号 x / t .. x / v .. x / a .. x / n .. x / z ..
检查符号 :显示与指定模式匹配的符号, 数据类型 详细(符号类型和大小) 按地址 排序按名称 排序按大小排序(函数符号的“大小”是内存中函数的大小)
LN
ln Addr
列出最近符号 =显示给定地址处或附近的符号。有用的:
确定指针指向的是什么 查看损坏的堆栈以确定哪个程序进行了调用
.sympath
.sympath .sympath +
显示或设置符号搜索路径 将目录附加到上一个符号路径
.symopt
.symopt .symopt + Flags .symopt- Flags
显示当前符号选项 添加选项 删除选项
.symfix
.symfix .symfix + DownstreamStore
将符号存储路径设置为自动指向http://msdl.microsoft.com/download/symbols + =将其附加到现有路径 DownstreamStore =将用作下游存储的目录。默认为WinDbgInstallationDir \ Sym。
.reload
.reload .reload [/ f | / v] .reload [/ f | / v]模块
重新加载所有模块的符号信息** f =强制立即符号加载(覆盖延迟加载); v =详细模式 Module =仅适用于模块 **注意:.reload命令实际上不会导致读取符号信息。它只是让调试器知道符号文件可能已经改变,或者应该将新模块添加到模块列表中。要强制执行实际符号加载,请使用/ f选项或ld(加载符号)命令。
坍方
X *! 列出所有模块 x ntdll!* 列出ntdll的所有符号 x / t / v MyDll!* 使用数据类型,符号类型和大小列出MyDll中的所有符号 x kernel32!* LoadLib * 列出kernel32中包含单词LoadLib的所有符号 .sympath + C:\ MoreSymbols 从C:\ MoreSymbols(文件夹位置)添加符号 .reload / f @“ntdll.dll” 立即重新加载ntdll.dll的符号。 .reload / f @“C:\ WINNT \ System32 \ verifier.dll” 重新加载验证者的符号。使用给定的路径。
还要检查“!lmi”命令。
上
8)来源 CMD 变种/参数 描述 .srcpath
.srcpath .srcpath + DIR
显示或设置源搜索路径 将目录添加到搜索到的源路径
.srcnoisy
{1 | 0}
控制噪声源负载
.lines
[-e | -d | -t]
切换源代码行支持:启用; 禁用; 切换
l(小写字母L)
l + l,ll l + o,lo l + s,ls l + t,lt
显示行数 除了[s] 源和行号 源模式与汇编模式之外的所有内容
上
9)例外,事件和崩溃分析 CMD 变种/参数 描述 G
g gH gN
Go Go异常处理 Go not handling
.lastevent
发生了什么?显示最近的事件或异常
!分析
!analyze -v !analyze -hang !analyze -f
显示有关当前异常或错误检查的信息; verbose 用户模式:分析线程堆栈以确定是否有任何线程阻塞其他线程。 即使调试器未检测到异常,也请参见异常分析。
SX
sx sxe sxd sxn sxi sxr
显示具有中断状态的所有事件过滤器并处理 中断第一次机会 中断第二次机会 通知; 不要将 忽略事件 重置过滤器设置中断 为默认值
.exr
.exr-1 .exr地址
在Addr上显示最近的异常记录 显示异常记录
.ecxr
显示与当前异常关联的异常上下文记录(寄存器)
!cppexr
地址
显示C ++异常的内容和类型
坍方
exr -1 显示最近的异常 .exr 7c901230 在地址7c901230处显示例外 !cppexr 7c901230 在地址7c901230处显示c ++异常
上
10)加载的模块和图像信息 CMD 变种/参数 描述 LM
lm [v | l | k | 你的 f] [m模式] lmD
列表模块; 详细| 加载符号| k-kernel或u-user only symbol info | 图像路径; 模块名称必须与 lm的DML模式匹配的 模式; 输出中包含lmv命令链接
!dll文件
!dlls !dlls -i !dlls -l !dlls -m !dlls -v !dlls -c ModuleAddr !dlls - ?
所有加载的模块按负载计数 按初始化顺序 按加载顺序(默认) 按内存顺序 , 只有版本信息 模块在ModuleAddr 简要帮助
!imgreloc
ImgBaseAddr
有关重新定位图像的信息
!LMI
模
有关模块的详细信息(包括确切的符号信息)
!DH
!dh ImgBaseAddr !dh -f ImgBaseAddr !dh -s ImgBaseAddr !dh -h
ImgBaseAddr的转储标头 f =仅文件标头仅 s =节标头 h =简短帮助 !lmi扩展从图像标头中提取最重要的信息并以简明的摘要格式显示。它通常比!dh更有用。
坍方
LM 显示所有已加载和已卸载的模块 lmv m kernel32 显示kernel32.dll的详细信息(所有可能的信息) LMD lm的DML变体 !dlls -v -c kernel32 显示kernel32.dll的信息,包括load-count !lmi kernel32 显示有关kernel32的详细信息,包括符号信息 !dh kernel32 显示kernel32的标头
上
11)过程相关信息 CMD 变种/参数 描述 !dml_proc
(DML)显示当前流程并允许钻取流程以获取更多信息
| (管)
打印正在调试的所有进程的状态
.tlist
列出系统上运行的所有进程
!PEB
显示进程环境块(PEB)的格式化视图
坍方
!PEB 转储进程PEB的格式化视图(仅一些信息) r $ peb 转储地址ob PEB。$ peb ==伪寄存器 dt ntdll!_PEB 转储PEB结构 dt ntdll!_PEB @ $ peb -r 递归(-r)转储我们进程的PEB
上
12)线程相关信息 CMD 变种/参数 描述 〜
~~ * [命令] 〜。[命令] 〜#[命令] 〜数字[命令] ~~ [TID] [命令] ~Ns
list threads 所有线程 当前线程 线程导致当前事件或异常 线程,其序数为Number 线程,其线程ID为TID(括号为必需) 切换到线程N(新当前线程) [命令]:适用于一些常规命令比如k,r
Ë〜
〜* e CommandString ~。e CommandString ~#e CommandString ~Number e CommandString
执行特定于线程的命令(CommandString =一个或多个要执行的命令): 所有线程 当前线程 线程导致当前事件 线程带序数
〜F
〜线程f
冻结线程(参见〜代表Thread语法)
〜U
〜线程你
解冻线程(参见〜用于线程语法)
〜n的
〜线程n
挂起thread =递增线程的挂起计数
-M
〜线程m
恢复线程=减少线程的暂停计数
!TEB
显示线程环境块(TEB)的格式化视图
!TLS
!tls -1 !tls SlotIdx !tls [-1 | SlotIdx] TebAddr
-1 =转储当前线程的所有槽 SlotIdx =转储仅指定槽 TebAddr =指定线程; 如果省略,则使用当前线程
.ttime
显示线程时间(用户+内核模式)
!逃跑
[标志:0 | 1 | 2]
显示每个线程消耗的时间信息(0-用户时间,1内核时间,自创建线程以来经过的2次)。快速找出哪些线程失控或消耗太多CPU时间
!GLE
!gle !gle -all
转储当前线程的 最后一个错误转储所有线程的最后一个错误 兴趣点: SetLastError(dwErrCode) 检查kernel32的值!g_dwLastErrorToBreakOn并可能执行DbgBreakPoint。 if ((g_dwLastErrorToBreakOn!= 0)&&(dwErrCode == g_dwLastErrorToBreakOn )) DbgBreakPoint(); 缺点是只能从KERNEL32.DLL中调用SetLastError。 其他对SetLastError的调用被重定向到位于NTDLL.DLL,RtlSetLastWin32Error中的函数。
!错误
!error ErrValue !error ErrValue 1
解码并显示有关错误值的信息 将ErrValue值视为NTSTATUS代码
坍方
〜* k 调用所有线程的堆栈〜!uniqstack ~2 f 冻结线程TID = 2 〜#f 冻结导致当前异常的线程 〜3你 解冻线程TID = 3 ~2e r; K表; KD == ~2r; 〜2K; 〜2KD 〜* e!gle 将重复每个扩展命令!gle为每个被调试的线程 !tls -1 转储当前线程的所有TLS插槽 逃亡7 1(用户时间)+ 2(内核时间)+ 4(自线程启动以来经过的时间) !TEB 转储我们的线程TEB的格式化视图(仅一些信息) dt ntdll!_TEB @ $ teb 转储当前线程的TEB
上
13)断点 CMD 变种/参数 描述 BL
列出断点
公元前
bc * bc#[#] [#]
清除所有断点 清除断点#
是
是* 是#[#] [#]
启用所有bps 启用bp#
BD
bd * bd#[#] [#]
禁用所有bps 禁用bp#
BP
bp [地址] bp [地址] [“CmdString”] [~thrd] bp [#] [选项] [地址] [通过] [“CmdString”]
在地址 CmdString = Cmd1 处设置断点 ; CMD2; ..每次BP被击中时执行。 ~Trd ==线程也表示bp适用。 #=断点ID 传递=在#Passes之后激活断点(之前忽略它)
BU
bu [地址] 见bp ..
设置未解决的断点。模块加载时设置bp
BM
bm SymPattern bm SymPattern [“CmdString”] [~thrd] bm [Options] SymPattern [#Passes] [“CmdString”]
设置符号断点。SymPattern可以包含通配符 CmdString = Cmd1; CMD2; ..每次BP被击中时执行。 ~Trd ==线程也表示bp适用。 Passes =在#Passes之后激活断点(之前被忽略) 语法bm SymPattern 等效于使用x SymPattern ,然后在每个结果上使用bu。
BA
ba [r | w | e] [Size]地址 [~thrd] ba [#] [r | w | e] [Size] [Options] [Addr] [Passes] [“CmdString”]
访问中断:[r =读/写,w =写,e =执行],大小= [1 | 2 | 4字节] [~Thrd] == bp也适用的线程。 #=断点ID 传递=在#Passes之后激活断点(之前忽略它)
BR
br OldID NewID [OldID2 NewID2 ...]
重新编号一个或多个断点
坍方
使用bp,断点位置始终转换为地址。相反,bu或bm断点始终与符号值相关联。 简单的例子
bp`mod!source.c:12` 在指定的源代码处设置断点 bm myprogram!mem * SymbolPattern等同于使用x SymbolPattern bu myModule!func 加载myModule后立即设置bp ba w4 77a456a8 打破写访问 bp @@(MyClass :: MyMethod) 中断方法(如果相同的方法被重载并因此存在于多个地址上,则非常有用)
Breakpoitns与选项
仅触发一次的断点 bp mod!addr / 1 在k-1传球后将开始击球的断点 bp mod!addr k
带命令的断点: 命令将在命中断点时执行。
每次遇到断点时都会生成一个日志 ba w4 81a578a8“k; g” 每次击中BP时都要创建转储 bu myModule!func“.dump c:\ dump.dmp; g” DllMain要求MYDLL - >检查原因 bu MYDLL!DllMain“j(dwo(@ esp + 8)== 1)'。echo MYDLL!DllMain - > DLL_PROCESS_ATTACH; kn';'g'” LoadLibraryExW(anyDLL)调用 - >显示anyDLL的名称 bu kernel32!LoadLibraryExW“.echo LoadLibraryExW for - >; du dwo(@ esp + 4); g” LoadLibraryExW(MYDLL)调用? - >仅在为MyDLL调用LoadLibrary时才中断 bu kernel32!LoadLibraryExW“; as / mu $ {/ v:MyAlias} poi(@ esp + 4); .if($ spat(\”$ {MyAlias} \“,\”* MYDLL * \“)!= 0 ){kn;} .else {g}“
LoadLibrary的第一个参数(在地址ESP + 4处 )是指向所讨论的DLL名称的字符串指针。 MASM $ spat 运算符会将此指针与预定义的字符串通配符进行比较,在我们的示例中为* MYDLL * 。 不幸的是,$ spat 可以接受别名或常量,但没有内存指针。这就是我们首先将我们的字符串存储到别名(MyAlias )的原因。 只有当$ spat 比较的模式匹配时,我们的kernel32!LoadLibraryExW断点才会命中。否则应用程序将继续执行。 跳过函数的执行 bu sioctl!DriverEntry“r eip = poi(@esp); r esp = @esp + 0xC; .echo sioctl!DriverEntry跳过; g”
在函数的入口点,堆栈顶部的值包含返回地址 r eip = poi(@esp) - >将EIP(指令指针)设置为偏移量0x0处的值 DriverEntry有2x4字节参数= 8字节+ 4字节用于返回地址= 0xC r esp = @esp + 0xC - >将0xC添加到Esp(堆栈指针),有效地展开堆栈指针 bu MyApp!WinMain“r eip = poi(@esp); r esp = @esp + 0x14; .echo WinSpy!WinMain进入; g”
WinMain有4x4字节参数= 0x10字节+ 4字节,返回地址= 0x14
如何以编程方式在代码中设置brekpoint?
KERNEL32!的DebugBreak NTDLL!DbgBreakPoint __asm int 3(仅限x86)
上
14)跟踪和步进(F10,F11) 每个步骤执行单个汇编指令或单个源代码行,具体取决于调试器是处于汇编模式还是源模式。 使用l + t和lt命令或WinDbg工具栏上的按钮在这些模式之间切换。 CMD 变种/参数 描述 g(F5)
g gu
Go(F5) Go up =执行直到当前函数完成 gu~ = g @ $ ra gu~ = bp / 1 / c @ $ csp @ $ ra; g - > $ csp =与x86上的esp相同 - > $ ra =当前堆栈上的返回地址
p(F10)
p PR p 计数 P [计数] “命令” P = StartAddress [COUNT] [ “命令”] [〜螺纹] P [= StartAddress] [COUNT] [ “命令”]
单步 - 执行单个指令或源代码行。子程序被视为一个步骤。 切换寄存器和标志的显示 Count =在停止之前 逐步执行的指令或源行的计数 在执行步骤后要执行的Command = debugger命令 StartAddress =使执行从指定的地址开始。默认是当前的EIP。 ~Thread =解冻指定的线程,冻结所有其他线程
t(F11)
t ..
单个跟踪 - 执行单个指令或源代码行。对于子程序,也跟踪每个步骤。
PT
pt ..
步骤到下一次返回 - 类似于GU(上行),但保留在当前函数的上下文中 如果EIP已经在返回 指令上,则执行整个返回。返回此返回后,将继续执行,直到达到另一个返回 。
TT
tt ..
跟踪下一个返回 - 类似于GU(上行),但保留在当前函数的上下文中 如果EIP已经在返回 指令上,则调试器将跟踪到 返回并继续执行,直到达到另一个返回 。
个人计算机
电脑 ..
步骤到下一个呼叫 - 执行程序直到达到呼叫指令 如果EIP已经在呼叫 指令上,则将执行整个呼叫。返回此调用后,将继续执行,直到达到另一个调用 。
TC
tc ..
跟踪下一个调用 - 执行程序直到达到调用指令 如果EIP已经在调用 指令上,调试器将跟踪调用并继续执行,直到达到另一个调用 。
PA
pa StopAddr par pa StopAddr “Command” pa = StartAddress StopAddr [“Command”]
步骤解决 ; StopAddr =执行将停止的地址 被调用的函数被视为单个单元 切换显示的寄存器和标志 Command =在执行步骤后要执行的调试器命令 StartAddress =使执行从指定的地址开始。默认是当前的EIP。
TA
ta StopAddr ..
跟踪解决 ; StopAddr =执行将停止的地址 跟踪被调用的函数
重量
wt wt [Options] [= StartAddr] [EndAddr] wt -l Depth .. wt -m Module [-m Module2] .. wt -i Module [-i Module2] .. wt -oa .. wt -or .. wt -oR .. wt -nc .. wt -ns .. wt -nw ..
跟踪和观察数据 。转到函数的开头并执行wt 。它将贯穿整个函数并显示统计信息。 StartAddr =执行开始; EndAddr =结束跟踪的地址(默认=当前函数的RET之后) l =跟踪调用的最大深度 m =限制跟踪模块 i =忽略模块中的代码 oa =转储调用站点的实际地址 或=转储返回寄存器值子函数的(EAX值) oR =适当类型的转储返回寄存器值(EAX值) nc =单个调用的无信息 ns =无摘要信息 ns =无警告
.step_filter
.step_filter .step_filter“FilerList” .step_filter / c
转储当前过滤器列表=跟踪时跳过的函数(t,ta,tc) FilterList = Filter 1; 过滤2; ...与要跳过的函数相关联的符号(跳过) 清除过滤器列表 .step_filter在汇编模式下不是很有用,因为每个函数调用都在不同的行上。
坍方
G 走 g`:123`; ?POI(计数器); G 执行当前程序到源行123; 打印计数器的值; 恢复执行 p 一小步 PR 切换显示寄存器 p 5“kb” 5x步骤,之后执行“kb” 个人计算机 步骤到下一个CALL指令 pa 7c801b0b 步骤直到达到7c801b0b 重量 跟踪和观察子功能 wt -l 4 -oR 跟踪子功能到深度4,显示其返回值
上
15)调用堆栈 CMD 变种/参数 描述 ķ
k [n] [f] [L] [#Frames] kb ... kp ... kP ... kv ...
转储栈; n =带帧#; f =相邻帧之间的距离; L =省略源线; 显示 前3个参数 的堆栈帧数 所有参数:参数类型+名称+值 所有参数格式化(新行) FPO信息,调用约定
KD
kd [WordCnt]
显示原始堆栈数据+可能的符号信息== dds esp
千米
链接到.frame#; dv的DML变体
.kframes
设置堆栈长度。默认值为20(0x14)。
。帧
.frame .frame# 。frame / r [#]
show current frame 指定帧 #show 寄存器值 .frame命令指定将使用哪个本地上下文(范围)来解释局部变量,或显示当前本地上下文。 当执行近程调用时,处理器将EIP寄存器的值(包含CALL指令之后的指令的偏移量)压入堆栈(稍后用作返回指令指针)。这是构建框架的第一步。每次进行函数调用时,都会创建另一个框架,以便被调用的函数可以访问参数,创建局部变量,并提供返回调用函数的机制。框架的组成取决于函数调用约定。
!uniqstack
!uniqstack !uniqstack [b | v | p] [n] !uniqstack - ?
显示所有线程的堆栈 [b =前3个参数,v = FPO +调用约定,p =所有参数:参数类型+名称+值],[n =带帧#] 简要帮助
!findstack
!findstack符号 !findstack符号[0 | 1 | 2] !findstack - ?
找到包含符号或模块的所有堆栈 [0 =仅显示TID,1 = TID +帧,2 =整个线程堆栈] 简要帮助
坍方
ķ 显示调用堆栈 KN 调用堆栈与帧号 KB 显示前3个参数的调用堆栈 kb 5 仅显示前5帧
从堆栈中获取3个以上的函数参数 dd ChildEBP + 8(参数从ChildEBP + 8开始) dd ChildEBP + 8(第X帧)== dd ESP(第X-1帧)
!uniqstack 获取我们进程的所有堆栈(每个线程一个) !findstack kernel32 2 显示包含“kernel32”的所有堆栈 。帧 显示当前帧 .frame 2 为本地上下文设置第2帧 .frame / r 0d 在帧0中显示寄存器
上
16)登记册 CMD 变种/参数 描述 [R
r r Reg1,Reg2 r Reg = 值 r Reg :类型 r Reg:[Num]类型 〜螺纹r [Reg:[Num] Type]
转储所有寄存器 仅转储指定的寄存器(即:r eax,edx ) 分配给寄存器的值(即:r eax = 5,edx = 6 ) 类型=显示寄存器的数据格式(即:r eax:uw ) ib =有符号字节 ub =无符号字节 iw =有符号字(2b) uw =无符号字(2b) id =有符号字(4b) ud =无符号双字(4b) iq =有符号qword(8b) uq =无符号qword(8b) ) f = 32位浮点 d = 64位浮点 Num =要显示的元素数量(即:r eax:1uw ) 默认值为完整寄存器长度,因此r eax:uw 将显示两个值,因为EAX是32位寄存器。 Thread =要从中读取寄存器的线程(即:~1 r eax )
R M
rM Mask rM Mask Reg1,Reg2 rM Mask Reg = Value ..
掩码 转储指定的转储寄存器类型 仅指定来自当前掩码 的寄存器值分配给寄存器 掩码的标志 0x1 =基本整数寄存器 0x4 =浮点寄存器== rF 0x8 =段寄存器 0x10 = MMX寄存器 0x20 =调试寄存器 0x40 = SSE XMM寄存器== rX
R f值
rF rF Reg1,Reg2 rF Reg =值 ..
转储所有浮点寄存器== rM 0x4 仅转储指定的浮点寄存器 要分配给寄存器的 值
RX
rX rX Reg1,Reg2 rX Reg =值 ..
转储所有SSE XMM寄存器== rM 0x40 仅转储指定的SSE XMM寄存器 分配给寄存器的 值
R M
rm rm? 面具
转储默认寄存器掩码。该掩码控制寄存器如何通过“r”显示。 转储可能的掩码位列表 指定显示寄存器时要使用的掩码。
坍方
R M ? 显示可能的位掩码 1 仅启用整数寄存器 [R 转储所有整数寄存器 r eax,edx 仅转储eax和edx r eax = 5,edx = 6 为eax和edx分配新值 r:1ub 只转储来自eax的第一个字节 rm 0x20 启用调试寄存器掩码 [R 转储调试寄存器 R f值 转储所有浮点寄存器 rM 0x4 转储所有浮点寄存器 rm 0x4; [R 转储所有浮点寄存器
上
17)有关变量的信息 CMD 变种/参数 描述 DT
dt -h dt [mod!] 名称 dt [mod!]名称字段 [字段] dt [mod!]名称[字段] 地址 dt [mod!]名称* dt [ -n | y ] [mod!]名称[ - n | y ] [Field] [Addr] dt [-n | y] [mod!]名称[-n | y] [Field] [Addr] -abcehioprsv
简要帮助 转储变量信息 仅转储'field-name(s)'(结构或联合) 要转储的结构的地址 列表符号(通配符) -n Name = param是一个名称(如果名称可以被误认为是地址,则使用) -y Name =部分匹配而不是默认完全匹配 -a =显示新行中的数组元素及其索引 -b = Dump仅连续块struct -c = Compact输出(一行中的所有字段) -i =不缩进子类型 -l ListField = Field是指向列表中下一个元素的指针 -o =忽略偏移值(struct的字段) -p =从物理地址转储 -r [l] =递归转储子类型/字段(最多l级) -s [size] =仅对于枚举,枚举仅给定大小的类型。 -v =详细输出。
DV
dv dv 模式 dv [ / i / t / V ] [模式] dv [/ i / t / V / a / n / z ] [模式]
显示局部变量和参数 vars匹配模式 i =类型(本地,全局,参数),t =数据类型,V =内存地址或寄存器位置 a =按地址排序,n =按名称排序,z =按大小排序
坍方
dt ntdll!_PEB * 列出包含单词_PEB的所有变量 dt ntdll!_PEB * -v 列表,详细输出(包括地址和大小) dt ntdll!_PEB * -v -s 9 仅列出大小为9个字节的符号 dt ntdll!_PEB dump _PEB info dt ntdll!_PEB @ $ peb 转储_PEB用于我们的流程 dt ntdll!_PEB 7efde000 在Addr 7efde000上转储_PEB 您可以使用“r @ $ peb”或“!peb”获取我们流程的PEB地址。 dt ntdll!_PEB Ldr SessionId 仅转储PEB的Ldr和SessionId字段 dt ntdll!_PEB Ldr -y OS * 转储Ldr字段+以OS *开头的所有字段 dt mod!var m_cs。 dump m_cs并扩展其子字段 dt mod!var m_cs .. 将其子字段扩展为2个级别 dt ntdll!_PEB -r2 递归转储(2级) dv / t / i / V. 使用类型信息(/ t),地址和EBP偏移量(/ V)转储局部变量,将它们分类为类别(/ i) 注意:dv还将显示使用“this calling-convention”调用的方法的THIS指针的值”。 BUG:在dv显示正确的值之前,您必须先执行一些命令。 在函数的入口点,THIS指针出现在ECX中,因此您可以从那里轻松获取它。
上
18)记忆 CMD 变种/参数 描述 d *
d [A | U | C | W | W | d | ç| q | F | D] [/ c#] [地址] dy [b | d] ..
显示内存 [#columns to display] a = ascii chars u = Unicode chars b = byte + ascii w = word(2b) W = word(2b)+ ascii d = dword(4b) c = dword(4b)+ ascii q = qword(8b) f =浮点(单精度 - 4b) D =浮点(双精度 - 8b) b =二进制+字节 d =二进制+双字
E *
e [b | w | d | q | f | D] Addr值 e [a | 你的 za | zu] Addr“String”
编辑存储器 b =字节 w =字(2b) d = dword(4b) q = qword(8b) f =浮点(单精度 - 4b) D =浮点(双精度 - 8b) a = ascii字符串 za = ascii string(以NULL结尾) u = Unicode字符串 zu = Unicode字符串(以NULL结尾)
ds,dS
ds [/ c#] [地址] dS [/ c#] [地址]
转储字符串结构 (struct!not null-delimited char sequence) s = STRING或ANSI_STRING S = UNICODE_STRING
d * S
dds [/ c#] [地址] dqs [/ c#] [地址]
显示单词和符号 (Addr中的内存假定为符号表中的一系列地址) dds = dwords(4b) dqs = qwords(8b)
dd *,dq *,dp *
dd * dq * dp * d * a d * u d * p
显示引用的内存 =在指定的Addr处显示指针,取消引用它,然后以各种格式显示结果位置的内存。 第二个char确定使用的指针大小: dd * - > 32位指针使用 dq * - > 64位指针使用 dp * - >标准大小:32位或64位,具体取决于CPU架构 第3个字符确定如何显示解除引用的内存: d * a - >取消引用mem作为asci chars d * u - >取消引用mem作为Unicode字符 d * p - >取消引用mem作为dword或qword,具体取决于CPU架构。如果此值与任何已知符号匹配,则也会显示此符号。
DL
dl [b] Addr MaxCount大小
显示链接列表 (LIST_ENTRY或SINGLE_LIST_ENTRY) b =以相反顺序转储(按照BLinks而不是FLinks) Addr =列表的起始地址 MaxCount = max要转储的元素 大小=每个元素的大小 使用!list为每个元素 执行一些命令列表中的元素。
!地址
!地址 -? !地址Addr !address -summary !address -RegionUsageXXX
显示有关目标进程使用的内存的信息 简要帮助 使用Addr Dump摘要信息 转储区域信息进程 转储指定区域(RegionUsageStack,RegionUsagePageHeap,..)
!vprot
!vprot - ? !vprot地址
简要帮助 转储虚拟内存保护信息
!将mapped_file
!mapped_file - ? !mapped_file地址
简要帮助 转储包含给定Addr的文件的名称
坍方
dd 0046c6b0 在0046c6b0显示dwords dd 0046c6b0 L1 在0046c6b0显示1 dword dd 0046c6b0 L3 在0046c6b0显示3个dword du 0046c6b0 在0046c6b0显示Unicode字符 du 0046c6b0 L5 在0046c6b0显示5个Unicode字符 dds esp == kd 在堆栈上显示单词和符号 !mapped_file 00400000 转储包含地址00400000的文件名 !地址 显示我们流程的所有内存区域 !address -RegionUsageStack 显示我们流程的所有堆栈区域 !地址尤其 显示我们的线程堆栈的已提交子区域的信息。 注意:对于堆栈溢出,SubRegionSize(已提交内存的大小)将很大,即: <span style="color:#4f6b72"><span style="color:#333333"><span style="color:#333333"><span style="color:#333333"> AllocBase:SubRegionBase - <strong>SubRegionSize</strong>
---------------------------------------------
001e0000:002d6000 - 0000a000</span></span></span></span>
确定线程的堆栈使用情况 <span style="color:#4f6b72"><span style="color:#333333"><span style="color:#333333">
堆栈标识符内存标识符^
-------------------------------------------------- -------
-------------- < - _TEB.StackBase SubRegionBase3 + SubRegionSize3
| |
| MEM_COMMIT |
| |
| ------------ | < - _TEB.StackLimit SubRegionBase3 ^,SubRegionBase2 + SubRegionSize2
| PAGE_GUARD |
| ------------ | SubRegionBase2 ^,SubRegionBase1 + SubRegionSize1
| |
| MEM_RESERVED |
| |
| ------------ | < - _TEB.DeallocationStack AllocationBase或RegionBase,SubRegionBase1 ^
DeallocationStack:dt ntdll!_TEB TebAddr DeallocationStack
</span></span></span>
从MSDN CreateThread> dwStackSize>“线程堆栈大小”: “每个新线程都接收自己的堆栈空间,包括已提交和已保留的内存。默认情况下,每个线程使用1 Mb的预留内存和一页已提交的内存。系统将根据需要从保留的堆栈内存中提交一个页面块。“
上
19)操作内存范围 CMD 变种/参数 描述 C
c范围DestAddr
比较记忆
米
m Range DestAddr
移动记忆
F
f范围模式
填充内存。Pattern =一系列字节(数字或ASCII字符)
小号
s 范围模式 s - [标志] b 范围模式 s - [标志] w 范围'模式' - [标志] d 范围'模式' - [标志] q 范围'模式' - [标志] 范围“模式“ s - [Flags] u 范围”模式“ s - [标志,l长度] sa 范围 s - [标志,l长度] su 范围 s - [标志] v 范围对象
搜索存储器 b =字节(默认值) 模式=一系列字节(数字或ASCII字符) w =字(2b) d = dword(4b) q = qword(8b) 模式=用单引号括起来(例如, 'Tag7') a = ascii字符串(不能以空值终止) u = Unicode字符串(不能以空值终止) Pattern =用双引号括起来(例如,“This string”) 搜索包含printable的任何内存ascii strings 搜索包含可打印Unicode字符串的任何内存 长度=此类字符串的最小长度; 默认值为3个字符 搜索相同类型的对象。 Object =指向Object或Object本身的指针的Addr 标志 ------- w =仅搜索可写内存 1 =仅输出搜索匹配的地址(如果使用.foreach,则非常有用) 标志必须包围通过一组没有空格的括号。 示例:s - [swl 10]类型范围模式
.holdmem
.holdmem -a Range .holdmem -o .holdmem -c Range .holdmem -D .holdmem -d {Range | 地址 }
保持并比较记忆。 比较是按字节逐字节 存储器范围到安全 显示所有已保存的存储器范围 比较所有已保存存储器范围的范围 删除所有已保存的存储器范围 删除指定的存储器范围(包含Addr或与Range重叠的任何已保存范围)
坍方
c Addr(Addr + 100)DestAddr 将Addr中的100个字节与DestAddr进行比较 c Addr L100 DestAddr - || - m Addr L20 DestAddr 从Addr移动20个字节到DestAddr f地址L20'A''B''C' 用模式“ABC”填充指定的内存位置,重复几次 f地址L20 41 42 43 - || - s 0012ff40 L20'H''''''''''o' 搜索内存位置0012FF40到0012FF5F的模式“Hello” s 0012ff40 L20 48 65 6c 6c 6f - || - s -a 0012ff40 L20“你好” - || - s - [w] a 0012ff40 L20“你好” 只搜索可写内存
上
20)记忆:堆 CMD 变种/参数 描述 !堆
!堆- ? !heap !heap -h !heap -h [HeapAddr | Idx | 0] !heap -v [HeapAddr | Idx | 0] !heap -s [HeapAddr | 0] !heap -i [HeapAddr] !heap -x [-v] Address !heap -l
简要帮助 索引和HeapAddr列表堆 列表满口具有索引和范围 (= startAddr(= HeapAddr),endAddr) 详细堆信息[IDX =堆IDX,0 =所有堆] 验证堆[IDX =堆IDX,0 =所有堆] 摘要信息,即保留和提交的内存 [Idx = heap Idx,0 =所有堆] 给定地址的块的详细信息 包含地址的 搜索堆块(v =搜索整个进程虚拟空间) 搜索可能泄漏的堆块
!heap -b,-B
!heap Heap -b [alloc | realloc | free] [Tag] !堆Heap -B [alloc | realloc | 自由]
在堆管理器中设置条件断点[Heap = HeapAddr | Idx | 0] 删除条件断点
!heap -flt
!heap -flt s Size !heap -flt r SizeMin SizeMax
转储与指定大小匹配的分配信息 按范围过滤
!heap -stat
!heap -stat !heap -stat -h [HeapHandle | 0]
转储堆句柄列表 每个AllocSize转储使用统计信息[HeapHandle =给定堆| 0 =所有堆]。 统计信息包括每个AllocSize的AllocSize,#blocks ,TotalMem。
!heap -p
!heap -p - ? !heap -p !heap -p -h HeapHandle !heap -p -a UserAddr !heap -p -all
扩展页堆帮助 NtGlobalFlag,HeapHandle + NormalHeap列表的摘要** 有关包含Handle的页面堆的详细信息 包含UserAddr的堆分配的详细信息。可用时打印回溯 。 流程中所有堆中所有分配的详细信息。 输出包括每个HeapAlloc调用的UserAddr和AllocSize 。
似乎以下适用于Windows XP SP2:a)正常堆
CreateHeap - >创建一个_HEAP AllocHeap - >创建一个_HEAP_ENTRY b)启用页面堆 (gflags.exe / i MyApp.exe + hpa)
CreateHeap - >创建一个_DPH_HEAP_ROOT(+ _HEAP + 2x _HEAP_ENTRY)** AllocHeap - >创建一个_DPH_HEAP_BLOCK **启用页面堆后,每个CreateHeap调用仍然会有一个带有两个常量_HEAP_ENTRY的_HEAP。
术语 描述 堆类型 HeapHandle = HeapCreate 或GetProcessHeap 返回的值 对于普通堆:HeapHandle == HeapStartAddr 普通和页面 HeapAddr = startAddr = NormalHeap 普通和页面 UserAddr,UserPtr =范围内的值[ HeapAlloc ... HeapAlloc + AllocSize] 对于正常堆,此范围进一步在Heap [startAddr-endAddr]内 普通和页面 UserSize = AllocSize(传递给HeapAlloc的值) 普通和页面 _堆 = HeapHandle = HeapStartAddr 对于每个HeapCreate ,都会创建一个_HEAP结构。 您可以使用“!heap -p -all”来获取这些地址。 正常堆 _HEAP_ENTRY 对于每个HeapAlloc ,都会创建一个_HEAP_ENTRY。 您可以使用“!heap -p -all”来获取这些地址。 正常堆 _DPH_HEAP_ROOT =通常HeapHandle + 0x1000 对于每个HeapCreate ,都会创建一个_DPH_HEAP_ROOT。 您可以使用“!heap -p -all”来获取这些地址。 页面堆 _DPH_HEAP_BLOCK 对于每个HeapAlloc ,都会创建一个_DPH_HEAP_BLOCK。 您可以使用“!heap -p -all”来获取这些地址。 页面堆
坍方
dt ntdll!_HEAP dump _HEAP struct dt ntdll!_DPH_HEAP_ROOT dump _DPH_HEAP_ROOT struct。 启用页面堆。然后,您可以使用“!heap -p -all”来获取进程中实际_DPH_HEAP_ROOT结构的地址。 dt ntdll!_DPH_HEAP_BLOCK dump _DPH_HEAP_BLOCK结构。 启用页面堆。然后,您可以使用“!heap -p -all”来获取进程中实际_DPH_HEAP_BLOCK结构的地址。 !堆 列出所有带索引和HeapAddr的堆 !堆-h 列出包含范围信息的所有堆(startAddr,endAddr) !heap -h 1 具有索引1的堆的详细堆信息 !heap -s 0 所有堆的摘要(保留和提交的内存,..) !heap -flt s 20 转储大小为20字节的堆分配 !heap -stat 转储HeapHandle列表。HeapHandle = HeapCreate或GetProcessHeap返回的值 !heap -stat -h 00150000 转储使用统计信息HeapHandle = 00150000 !heap 2 -b alloc mtag HeapAlloc上的断点使用索引2在堆中使用TAG = mtag进行调用 !heap -p 转储堆句柄列表 !heap -p -a 014c6fb0 堆分配的详细信息,包含地址014c6fb0 + call-stack(如果可用) !heap -p -all 转储流程中所有堆中所有分配的详细信息
谁分配了内存 - 谁叫HeapAlloc?
在GFlags中为您的图像选择“创建用户模式堆栈跟踪数据库”(gflags.exe / i MyApp.exe + ust) 从WinDbg的命令行执行!heap -p -a [UserAddr] ,其中[UserAddr]是您的分配地址***。 虽然!heap -p -a [UserAddr]将转储调用堆栈,但不会包含任何源信息。 要获取源信息,您还必须在步骤1中启用页堆(gflags.exe / i MyApp.exe + ust + hpa) 做一个dt ntdll!_DPH_HEAP_BLOCK StackTrace [MyHeapBlockAddr] ,其中[MyHeapBlockAddr]是在步骤3中检索到的DPH_HEAP_BLOCK地址。 执行dds [StackTrace] “,其中[StackTrace]是在步骤5中检索的值。 请注意,dds将转储包含源信息 的堆栈 。 谁创建了一个堆 - 谁叫HeapCreate?
在GFlags中为您的图像选择“创建用户模式堆栈跟踪数据库”和“启用页堆”(gflags.exe / i MyApp.exe + ust + hpa) a)从WinDbg的命令行执行!heap -p -h [HeapHandle] ,其中[HeapHandle]是HeapCreate 返回的值。您可以执行!heap -stat 或!heap -p 来获取进程的所有堆句柄。 b)或者你可以使用!heap -p -all 直接获取你进程的所有_DPH_HEAP_ROOT的地址。 做一个dt ntdll!_DPH_HEAP_ROOT CreateStackTrace [MyHeapRootAddr] ,其中是在步骤2中检索到的_DPH_HEAP_ROOT的地址 执行dds ,其中[CreateStackTrace]是在步骤3中检索的值。 发现内存泄漏
从WinDbg的命令行做一个!address -summary 。 如果RegionUsageHeap 或RegionUsagePageHeap 正在增长,那么堆上可能存在内存泄漏。继续以下步骤。
在GFlags中为您的图像启用“创建用户模式堆栈跟踪数据库”(gflags.exe / i MyApp.exe + ust) 从WinDbg的命令行执行!heap -stat ,获取所有活动的堆块及其句柄。 做一个!heap -stat -h 0 。这将列出每个AllocSize的句柄特定分配统计信息。 对于每个AllocSize,列出以下内容:AllocSize,#blocks和TotalMem。 使用最大TotalMem的AllocSize 。 做一个!heap -flt s [Size] 。[Size] =我们在上一步中确定的AllocSize。此命令将列出具有该特定大小的所有块。 做一个!heap -p -a [UserAddr] 来从你分配了那么多字节的地方获取堆栈跟踪。使用在步骤4中获得的[UserAddr]。 要获取源信息,您还必须在步骤1中启用页堆(gflags.exe / i MyApp.exe + ust + hpa) 做一个dt ntdll!_DPH_HEAP_BLOCK StackTrace [MyHeapBlockAddr] ,其中[MyHeapBlockAddr]是在步骤5中检索的DPH_HEAP_BLOCK地址。 执行dds [StackTrace] “,其中[StackTrace]是在步骤7中检索的值。 请注意,dds将转储包含源信息 的堆栈 。 ***什么是[UserAddr]?
[UserAddr]通常是HeapAlloc返回 的地址 : <span style="color:#4f6b72"><span style="color:#333333"><span style="color:#333333">int AllocSyze = 0x100000; // == 1 MB
BYTE * <strong>pUserAddr</strong> =(BYTE *)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,<strong>AllocSyze</strong>);</span></span></span>
通常,[UserAddr .... UserAddr + AlloSize]范围内的任何地址也是有效参数: <span style="color:#4f6b72"><span style="color:#333333"><span style="color:#333333">!heap -p -a [ <strong>UserAddr .... UserAddr + AlloSize</strong> ]</span></span></span>
上
21)应用程序验证程序 应用程序验证程序配置文件和跟踪Microsoft Win32 API(堆,句柄,锁,线程,DLL加载/卸载等),例外,内核对象,注册表,文件系统。使用!avrf扩展程序,我们可以访问此跟踪信息! CMD 变种/参数 描述 !avrf
显示Application Verifier选项。如果发生了应用程序验证程序停止,则显示停止的性质以及导致停止的原因。
!avrf
- ? -vs N -vs -a ADDR -hp N -hp -a ADDR -cs N -cs -a ADDR -dlls N -ex N -cnt -threads -trm -trace INDEX -brk [INDEX]
简要帮助 转储vspace日志中的最后N个条目(MapViewOfFile,UnmapViewOfFile,..)。 在vspace日志中搜索ADDR。 HeapAlloc,HeapFree,new和delete日志 在堆日志中搜索ADDR。 DeleteCriticalSection API日志(最后#Entries)。~CCriticalSection隐式调用它。 在关键部分删除日志中搜索ADDR。 LoadLibrary / FreeLibrary日志 异常日志 全局计数器(WaitForSingleObject,HeapAllocation调用,...) 线程信息+子线程的启动参数 TerminateThread API日志 转储堆栈跟踪与INDEX。 dump或set / reset break触发器。
上
22)记录扩展(logexts.dll) 你必须在GFlags中为你的图像启用以下选项: - >“创建用户模式堆栈跟踪数据库” - >“堆栈回溯:(Megs)” - > 10 - >看来你好像有时还需要检查并指定GFlags中的“Debugger”字段 CMD 变种/参数 描述 !logexts.help
显示所有Logexts.dll扩展命令
!LOGE
!loge [dir]
启用日志记录+可能会初始化它,如果尚未完成。输出目录可选。
!LOGI
初始化(=将Logger注入目标应用程序)但不启用日志记录。
!的logD
禁用日志记录
!商标
!logo !logo [e | d] [d | t | v]
列表输出设置 启用/禁用[d - 调试器,t - 文本文件,v - 详细日志]输出。使用logviewer.exe检查详细日志。
!logc
!logc !logc p# !logc [e | d] * !logc [e | d]#[#] [#]
列出所有类别 列出类别中的 API# 启用/禁用所有类别 启用/禁用类别#
!logb
!logb p !logb f
打印缓冲区内容到调试器 刷新缓冲区到日志文件
!10gm的
!logm !logm [i | x] [DLL] [DLL]
显示模块包含/排除列表 指定模块包含/排除列表
坍方
启用19-ProcessesAndThreads和22-StringManipulation日志记录:
!LOGE 启用日志记录 !logc d * 禁用所有类别 !logc p 19 显示类别19的API logc e 19 22 启用类别19和22 !logo dv 禁用详细输出 !logo dt 禁用文本输出 !logo ed 启用调试器输出
在2007年11月1日至2009年1月31日期间,本文发表在software.rkuster.com上 。