windbg 使用与技巧
基本知识和常用命令
(1) Windbg下载地址http://msdn.microsoft.com/en-us/windows/hardware/gg463009.aspx
安装完后执行windbg –I将Windbg设置成默认调试器
(2) Windbg的命令分为标准命令,原命令和扩展命令,输入问号(?)可以显示所有的标准命令的帮助信息; 元命令以一个点(.)开始,输入.help可以显示所有的原命令的帮助信息;扩展命令以叹号(!)开始。
所有命令的具体用法可以通过F1查看Windbg的帮助文件。
(3) 通过设置符号文件路径,让Windbg自动从微软网站更新系统Dll的符号文件
SRV*d:\symbols* http://msdl.microsoft.com/download/symbols
(4) 用分号(;)作为分隔符,可以在一行输入多条命令
(5) 按上下箭头可以浏览和选择以前输入过的命令
(6) Ctrl+Break终止一个很长时间没有完成的命令, Ctrl+Break也可以让正在运行的程序暂停
(7) Windbg默认的数值进制一般是16, 可以通过n命令查看和设置当前进制,所以我们一般在数值里带上进制, 0n(十进制), 0x(十六进制), 0t(8进制), 0y(2进制), 比如0n20表示20, 0x14表示20等
(8) 可以通过问号命令(?)显示表达式值,双问号(??)显示C++表达式值, 通过.cls命令清屏
(9) 如果x表示的一个地址, 则可以通过以下方法获取x所指向的值
hi(x) 高16 bits
low(x) 低16 bits
by(x) 返回第一个byte
wo(x) 返回第一个word
dwo(x) 返回第一个dword
qwo(x) 返回第一个4 word(Quad-word)
poi(x) 返回第一个指针值
(10) 函数调用如果还没开始,即一般函数入口代码
push ebp
mov ebp, esp
还未执行,
则[esp+4]表示第一参数值, [esp+8]表示第二参数,以此类推, [esp]表示的是返回地址
如果上面的入口代码已经执行,则一般通过ebp来获取函数参数和局部变量
[ebp+8]表示第一参数, [ebp+0xC]表示第二个参数, 以此类推,[ebp+4]表示返回地址 [ebp]表示上一堆栈桢的基地址。
[ebp-4]表示函数第一个局部变量
(11) 条件表达式
j<条件表达式>[Command1];[Command2]
例如bp consoletest!add "j(dwo(esp+4)==0n10) 'kv;.echo \"break\"';'g'" 表示条件断点,如果consoletest!add的第一个参数是10, 则打印堆栈,输出”break”, 并暂停,否则继续执行
也可用元命令代替
bp consoletest!add ".if(dwo(esp+4)==0n10) {kv;.echo \"break\"} .else {g}"
(12) 上下文
上下文(Context)包括会话(Session)上下文, 进程上下文,寄存器上下文,局部变量上下文。
会话上下文和登陆用户帐号有关。进程上下文和当前调试的默认进程有关, 寄存器上下文和当前默认线程有关。
局部变量上下文和当前的堆栈桢有关, 比如可以通过.frame [index] 切换当前堆栈桢,然后通过dv 显示当前堆栈桢函数的局部变量(堆栈桢的index从0开始,可以通过kn命令显示堆栈桢索引)
(13) 保存dump文件
.dump /ma c:\test.dmp 保存full-dump
.dump /m c:\test.dmp 保存mini-dump
(14) 分析Dump
一般先 !analyze –v Windbg会根据上面命令自动分析,
然后 ~* kv 打印所有线程的堆栈
(15) 重新加载符号文件
.reload –f [name], 强制重新加载某个模块的符号文件
比如 .reload –f test.dll
(16) 察看模块信息
lm显示所有模块信息
lmf 显示所有模块及其路径
lmD 显示所有模块详细信息
!lmi [module name] 显示某一模块的详细信息
(17) 分析调试符号
X [选项] 模块名!符号名
比如x ntdll!dbg*显示所有ntdll模块中以dbg开头的符号
比如x test!cmyclass::init 显示test模块中cmyclass类中的init函数符号
(18) 搜索符号
ln [address] 搜索离address最近的符号名(list nearest symbols)
(19) 事件处理
可以通过菜单Debug->Event Filter…设置
sx 显示各个事件的代码和目前的处理选项
sx {e|d|i|n} [command] , e|d|i|n分别对应Enabled, Disabled,Output和Ignore
比如 sxe ld user32.dll 表示在加载user32.dll时设置的中断
sxr 恢复成默认设置
(20) 单步调试
g 继续运行(go), 热键F5
t 单步越过(step over), 热键F10
p 单步进入(step into), 热键 F11
(21) 设置断点(break point)
bp [address] [“command”] 设置软件断点。
比如 bp kernel32!CreateProcessW表示在调用这个CreateProcess时设置断点。
比如bp kernel32!CreateFileW "du poi(esp+4); g" 表示在调用CreateFile时打印出文件路径(第一个参数),然后继续执行
针对某线程设置断点,只要在命令前加~线程号:
比如 ~0 bp 0x441242, 表示0号线程执行到地址0x441242时中断
ba [access size] [command]设置硬断点。
其中,access指定访问方式(e执行指令, r读取数据,w写入数据)
size 表示监视数据的大小(1, 2, 4)
比如ba r4 0x414422, 表示在地址0x414422写入4字节数据是触发断点
(22) 管理断点
bl 列出所有当前断点的状态
bc 清除断点, bc * 清除所有断点, bc 0 清除0号断点
bd 禁用某个断点(disable)
be 打开某个断点(enable)
(23) 察看堆栈
kn [frame count]察看当前堆栈及其索引, frame count指定要显示多少桢
kb显示堆栈桢地址,返回地址,参数,函数名等
kv在kb的基础上增加了函数调用约定等信息, 所以推荐用kv命令察看堆栈.
.frame [frame index] 将当前堆栈切换到某个堆栈桢, 比如.frame 1 切换到第1桢
dv 命令察看当前堆栈桢的局部变量
(24) 察看和修改寄存器
r显示所有寄存器的值
r eax=0x100 将eax寄存器的改成0x100
(25) 显示内存区域(dump memory)
d{a|b|d|D|f|q|u|w} [range]
其中a表示ASCII码,b表示byte, d表示DWORD, D表示double, f表示float, q表示8字节, u表示Unicode String, w表示word
Range 表示地址范围,可以用2种表示:一是起始地址加终止地址, 二是起始地址加L长度(不是字节长度,是单位长度)。
比如 dw 77e0d827 L10 表示显示77e0d827开始的10个word
比如 dd 77e0d820 77e0d844, 表示显示 77e0d820 和77e0d844之间的所有dword
比如 du 77e0d820, 表示77e0d820开始的以0结尾的字符串
dps [range] 显示某一地址范围内的符号(display word and symobols)
(26) 显示数据类型(dump symbolic type information)
dt [模块名!]类型名
dt testApp!g_appInstance 表示显示testApp里全局变量g_appInstance的内存布局
dt 0x0458e850 test!CMyApp 表示将地址0x0458e850以test!CMyApp类地址解析,并打印内存布局, 所以只有私有符号才有这个功能
如果当前堆栈桢是在某个类函数内,可以通过dt this 打印当前类的内促布局。
(27) 搜索内存(search memory)
s –[type] range pattern
其中type, b表示byte, w表示word, d 表示dword, a表示ASCII string,u表示unicde string
Range 表示地址范围,可以用2种表示:一是起始地址加终止地址, 二是起始地址加L长度(不是字节长度,是单位长度)。如果搜索空间长度超过256M,用L?length。
Pattern指定要搜索的内容.
比如 s -u 522e0000 527d1000 "web"表示在522e0000 和527d1000之间搜索Unicode 字符串”web”
比如s -w 522e0000 L0x100 0x1212 0x2212 0x1234 表示在起始地址522e0000之后的0x100个单位内搜索0x1212 0x2212 0x1234系列的起始地址
(28) 修改内存 (edit memory)
e{a|u|za|zu} address “String”
其总za和zu表示以0结尾的Ascii和Unicode字符串, a和u则表示没有0结尾
比如 ezu 0x445634 “abc” 表示在0x445634地址写如unicode 字符串abc
比如ea 0x445634 “abc” 表示在0x445634地址写入Ascii字符串abc, 不包含结束符0
e{a|b|d|D|f|q|u|w} address [values]
其中a表示ASCII码,b表示byte, d表示DWORD, D表示double, f表示float, q表示8字节, u表示Unicode String, w表示word
比如eb 0x123432 0x41 0x41 0x41 表示在地址0x123432 写入3个0x41
(29) 观察内存属性
!address [address]
比如!address 0x414453, 显示地址0x414453所在区域的内存属性
!heap -h 显示所有的内存堆(heap)
(30) 反汇编某一地址
u address, 比如u 0x410040表示反汇编地址0x410040的代码
uf 反汇编某个函数, 比如uf test!main
ub 反汇编某地址之前的代码,比如ub 0x 0x410040 L20
(31) 进程线程控制
~*命令显示当前所有线程的详细信息
~[Index] n增加索引为Index的线程的挂起计数
~[Index] m减少索引为Index的线程的挂起计数
比如通过~2 n 增加2号线程的挂起计数后, 执行g命令(继续运行), 这时2号线程会依然暂停运行。
~[Index] f 冻结某一线程的执行
~[Index] u 解冻某一线程的执行
~[Index] g只运行线程号为index的线程
~[Index] s 切换当前线程
比如 ~2 kv; ~2 r 可以打印2号线程的当前堆栈和寄存器
~* kv可以打印所有线程堆栈。
!runaway 显示所有线程的CPU消耗
|. 显示当前调试进程
|* 显示当前调试中的所有进程
|[nIndex] s 切换当前调试进程
!peb 显示进程信息块(process environment block)
!teb 显示线程信息块(thread environment block)
(32) 线程死锁
!locks 显示死锁
!handle 列出当前进程所handle
!handle [index] f, 显示某个handle的详细信息
(33) 自动调试子进程
.childdbg 0
Disable child process debugging
.childdbg 1
Attach child process automatically
(34) 脚本支持
$$>< filename 加载脚本文件,并将脚本里的换行符自动换成;(分号)
$t0~$t19为伪寄存器,可用来存储临时值, 使用伪寄存器时前面尽量加@符号以加快搜索
.printf 可以输出格式化信息
as Name EquivalentLine 别名,类似define宏 , 比如 r $t0=poi(esp+4); as $filename $t0
ad Name 删除别名, ad*删除所有别名
al 列出所有别名
.block {…}重新开始替换里面的所有别名
${alias}强制要求替换里面的别名, ${/v:alias}不要替换里面的别名
运用别名的脚本样例:
FAQ
(1) 如何在某个窗口收到某个消息时设置断点? 比如在我想在某窗口收到系统最小化消息时设置断点,该怎么操作?
其实就是监视窗口处理函数MsgProc(hWnd, WM_SYSCOMMAND, SC_MINIMIZE, 0)消息:首先通过Spy察看窗口句柄, 比如为0x350d72; 通过Spy也可以看到窗口消息处理函数的地址,比如00E814DE; 察看WM_SYSCOMMAND的值(0x0112); 察看SC_MINIMIZE的值0xF020, 因此我们可以写入如下条件断点:
bp 0xE814DE
"j((dwo(esp+4)==0x350d72)&(dwo(esp+8)==0x0112)&(dwo(esp+0xc)==0xF020)) ‘kv’;’g’"
上面的命令表示在调用窗口函数时如果符合我们的条件,则打印堆栈(kv)并暂停,
否则继续执行(g).
(2) 堆栈桢的含义
堆栈生成原理:
堆栈从高地址向低地址生长,
__stcall和__cdecl调用约定都是从函数参数的右到左压栈.
因此调用某一函数比如int add(int a, int b) { return a + b;}
我们调用 add(1, 2)函数时,
从堆栈高地址到低地址依次入栈, 依次是参数2入栈, 参数1入栈,返回地址(ret address)入栈,然后跑到add函数执行入口代码push ebp , mov ebp, esp , 即上一函数桢的基址(ebp)入栈, 然后将当前的堆栈指针值赋给ebp(保存当前的堆栈指针给ebp, 这样可以用新的ebp操作当前函数的局部变量,该函数内部再调用某个函数时也能通过新ebp知道上一函数的基栈地址, 所有函数调用都以此类推)。
所以从堆栈低地址到高地址依次表示ebp(上一函数的堆栈桢基址), ret address, parameter 1, parameter 2…
(3) 如何用Windbg写高级脚本
参考http://blogs.msdn.com/b/debuggingtoolbox/archive/tags/windbg+scripts/default.aspx
(4) 如何将64位Dump转成32位
.load wow64exts 回车
!sw 回车
windbg 使用与技巧的更多相关文章
- WinDbg调试C#技巧,解决CPU过高、死锁、内存爆满
软件安装 安装问题:执行 .loadby sos clr 命令无效 解决办法: .load C:\Windows\Microsoft.NET\Framework64\v4.0.30319\SOS.dl ...
- Windows下软件调试
1. 视频: (1).VS下的C++调试方法.wnv (2).WinDbg高级调试技术.wmv (3).内存与句柄泄漏处理技巧.wmv 2. “WinDbg高级调试技巧” 中 [01:22]讲到“软件 ...
- 调试技巧 —— 如何利用windbg + dump + map分析程序异常
调试技巧 —— 如何利用windbg + dump + map分析程序异常 逗比汪星人2011-09-04上传 调试技巧 —— 如何利用windbg + dump + map分析程序异常 http ...
- windbg 调试技巧
技巧一:在加载名卸载的时候下断点 1. 加载某个DLL 的时候下断点的WinDBG 命令: sxe ld:[dll name] 然后按F5,进行刷新,再使用lmf 查看装载的Dll名称. 2. 卸载 ...
- Windbg对过滤驱动DriverEntry函数下断点技巧
方法1: 1> 先用DeviceTree.exe查看指定的过滤驱动的Load Address(加载地址) 2> 再用LordPE.EXE查看指定过滤驱动文件的入口点地址 3> 计算过 ...
- WinDBG 技巧:如何生成Dump 文件(.dump 命令)
程序崩溃(crash)的时候, 为了以后能够调试分析问题, 可以使用WinDBG要把当时程序内存空间数据都保存下来,生成的文件称为dump 文件. 步骤: 1) 打开WinDBG并将之Attach 到 ...
- Windbg SOS 加载技巧(.net framwork 2.0)
1.打开windbg,加载dump.使用命令确定dump的clr版本:lm vm mscorwks 或者lm vm clr(!eeversion可以查看加载后的sos版本) 2.找到对应的mscorw ...
- WinDBG 技巧:列出模块(DLL/EXE)里面所有的符号(symbol)
想对某个函数下断点,但是记不清楚的函数具体的名字,这个时侯可以使用x命令来列举所有的符号. 命令格式为: x [选项] 模块名字!符号匹配表达式 这里的符号匹配表达式类似dos的文件名匹配表达式,可以 ...
- Visual Studio高级调试技巧
1. 设置软件断点,运行到目标位置启动调试器 方法①:使用汇编指令(注:x64 c++不支持嵌入汇编) _asm 方法②:编译器提供的方法 __debugbreak(); 方法③:使用windows ...
随机推荐
- Java设计模式学习笔记(四) 抽象工厂模式
前言 本篇是设计模式学习笔记的其中一篇文章,如对其他模式有兴趣,可从该地址查找设计模式学习笔记汇总地址 1. 抽象工厂模式概述 工厂方法模式通过引入工厂等级结构,解决了简单工厂模式中工厂类职责太重的问 ...
- ~~核心编程(四):面向对象——单继承&复写~~
进击のpython 继承 继承的出现!就是一个作用! 为了节省代码! 为什么说节省代码? 你爸爸要是王健林 你是不是就不用愁怎么获得钱了? 为啥? 是不是钱已经有了! 直接拿来用就行了! 我们想一下奥 ...
- break使用不当引发的一个“血案”
最近在网上冲浪,读到一则新闻,摘抄下这则新闻: ======================= 以下文字摘抄自互联网==================== 1990年1月15日,AT&T电话 ...
- R035---偷个懒,用UiPath录制电脑操作过程,迅速实现流程自动化
一.缘起 UiPath可以录制你操作电脑的过程,从而实现自动化. 目前有点鸡肋,因为有些操作过程无法录制,例如: 键盘快捷键 修改键 右键点击 鼠标悬停 即便如此,录制功能有时候还是可以用一下,特别 ...
- 使用RabbitMQ做数据接收和处理时,自动关闭
场景:N个客户端向MQ里发送数据:服务器上有另一个控制台程序(假设叫ServerClient)来处理这里数据(往数据库保存).方向为Client * n→MQSERVER→ServerClient 问 ...
- 2015.11.27---Java
public class star{ public static void main(String[] args) { System.out.print("ha"); } }
- python找质数对
python找质数对 编写python脚本,输入一个正整数,输出有几对质数的和等于这个正整数. 例如输入一个正整数10,可以找出有“3+7=10”.“5+5=10”两个质数对的和为10. 要实现这个功 ...
- JasperReport报表
最近在做报表工作,公司要求使用正版免费的报表软件,想想还是用JasperReport. JasperReport是一个纯Java写的开源免费报表工具库,在java开源免费报表中,排在前列. 可是开源免 ...
- 实战SpringCloud响应式微服务系列教程(第一章)
前言 在当今互联网飞速发展的时代,业务需求不断的更新和产品的迭代给系统开发过程和编程模式也带来巨大挑战,Spring Cloud微服务也随之应用而生,从springboot1.x到springboot ...
- React躬行记(11)——Redux基础
Redux是一个可预测的状态容器,不但融合了函数式编程思想,还严格遵循了单向数据流的理念.Redux继承了Flux的架构思想,并在此基础上进行了精简.优化和扩展,力求用最少的API完成最主要的功能,它 ...