1:64位可以加载32为进行调试,!wow64exts.sw 切换到32位,再输一次切换到64位
2:x*! 查看哪些模块的符号文件已经被加载,
F9:设置断点,只要在光标定位的位置(上图中灰色条)按F9键即可,再按一次F9键则会删除断点。(相当于OllyDbg 中的 F2)
F10:单步步过。每按一次这个键执行一条反汇编窗口中的一条指令,遇到 CALL 等子程序不进入其代码。(相当于 OllyDbg中的 F8)
F8 or F11:单步步入。(相当于 OllyDbg 中的 F7)。
F7:运行到选定位置。作用就是直接运行到光标所在位置处暂停。(相当于 OllyDbg 中的 F4)。
Shift+F11:运行到跳出函数。
F5:运行。按下这个键如果没有设置相应断点的话,被调试的程序将直接开始运行。(相当于 OllyDbg 中的 F9)
windbg命令分为标准命令,(.开头的)元命令和(!开头的)扩展命令。
以.开头的元命令提供标准命令没有提供的功能,也内建在调试引擎中。
以!开头的扩展命令用于扩展某一方面的调试功能,实现在动态加载的扩展模块中。
.hh 查看指定命令的帮助手册
.help 打印出所有元命令
.reload 重新加载符号文件
.restart 重新启动调试目标
.ecxr 当前异常的上下文信息
.effmach x86 命令.effmach表示Effective Machine Type,即有效的机器类型。此
命令将当前的处理器模式设置为x86模式。可用处理器模式值有:
x86、X86-64、adm64、ia64、ebc。
.detach 分离调试
.writemem 路径 内存地址 将内存中某个地址打印出来。
.kill 强制结束当前调试
.frame 显示当前栈帧
.frame n 设置编号n的栈帧为当前栈帧
.frame /r n 设置编号n的栈帧为当前栈帧 并显示寄存器变量
!uniqstack 显示所有线程的调用堆栈
.attach 0n4220 4220为十进制pid,使用该命令附加调试时,必须先存在一个调试会话
.dump /m C:\Users\Administrator\Desktop\test.txt 生成较小的dump文件 /ma带有尽量多选项的包括
完整的内存内容、句柄、未加载的模块等),文件很大,/mFhutwd是一种折中分析
dump 文件的 指令 !analyze -v
.sympath 查看当前符号查找路径
.sympath c:\symbols 将符号查找路径设为:c:\symbols
.sympath+ c:\symbols 将c:\symbols添加到符号查找路径集合中
.symfix 将符号查找路径设为:SRV*WinDbg安装目录
\Sym*http://msdl.microsoft.com/download/symbols.symfix f:\symbols // 将符号查找路径设为:SRV*f:\symbols*http://msdl.microsoft.com/download/symbols
.symfix+ f:\symbols 将SRV*f:\symbols*http://msdl.microsoft.com/download/symbols添加到符号
查找路径集合中
.srcpath 查看当前源文件查找路径
.srcpath f:\src 将源文件查找路径设为:f:\src
.srcpath+ f:\src 将f:\src添加到源文件查找路径集合中
.exepath 查看可执行文件查找路径
.exepath f:\bin 将可执行文件查找路径设为:f:\bin
.exepath+ f:\bin 将f:\bin添加到可执行文件查找路径集合中
.symopt 显示当前所有符号选项
.symopt+ flags 添加符号选项
.symopt- flags 删除符号选项
.reload 为所有模块加载符号信息
.reload /f /v f:强制立即模式 v:详细模式
.reload /f @"c:\windows\System32\verifier.dll" 为指定模块加载符号信息
.tlist 显示所有进程
.cls 清除屏幕
.formats 0x123abc 将一个整数以各种格式显示,包括:16进制、10进制、8进制、二进制、字
符串、日期、浮点数等。
!peb 格式化输出PEB信息(process's environment block)
!gle 打印当前线程最近的错误信息
!gle -all 打印所有线程的最近的错误信息
!error 897 显示错误码为897的详细描述信息
!teb 线程环境块
!analyze -v 详细显示当前异常信息,常用于分析dmp文件
!address 400000 查看指定内存地址的信息
!locks 查看进程中有些锁处于锁定状态
!cs -l 查看处于锁定状态的关键区
!handle 000000c0 f 查看句柄000000c0的信息
~ 查看调试进程中的线程信息
~. 当前线程信息
~* 所有线程
~# 导致当前异常或调试事件的线程信息
~[Number]s 线程切换
~* k 所有线程堆栈信息
~* r 所有线程寄存器信息
~# 查看导致当前事件或异常的线程
~N 查看序数为N的线程
~~[n] 查看线程ID为n的线程
~Ns 切换序数为N的线程为当前调试线程
~N f 冻结序数为N的线程
~N u 解冻序数为N的线程
~N n Suspend序数为N的线程
~N m Resume序数为N的线程
| 所有进程列表
|. 当前进程信息
|# 导致当前异常或调试事件的进程信息
|* 列出调试进程
|[Number]s 进程切换
!peb 进程环境块
|N 参看序数为N的调试进程
|Ns 切换序数为N的进程为当前调试进程
ld * 为所有模块加载符号
ld kernel32 加载kernel32.dll的符号
a 修改当前指令,输入修改的指令按Enter结束
s –a 00400000 L53000 “Wrong” 以ASCII码的形式从00400000处开始往后53000个字节搜索字符
串“Wrong”
bp $exentry 在程序入口点设置断点,$exentry是一个伪寄存器
bp 0x00401030 在地址0x00401030处设置断点
bp MyTestModule!MyTestFunc 在MyTestModule模块中的MyTestFunc函数处设置断点,前提是该模
块符号已经加载
bp MyTestModule!MyTestClass::SetValue 在模块MyTestModule的MyTestClass类成员函数
SetValue处设置断点
bp @@C++(MyTestModule!MyTestClass::SetValue) 与上面一样,语法不同,C++语法,上面的为
MASM语法
bp `ConsoleTest.cpp:40` "j (poi(MyVar)>5) ''; 'g'" 条件断点 MyVar>5,执行空语句(;),断住
否则继续执行
bp `ConsoleTest.cpp:40` "j @eax = 0xa3 ''; 'g'" 条件断点 寄存器eax的值为0xa3时断住
bu 保存断点,其用法和bp一样
bm add_* 匹配add_开头的函数,并在这些函数起始处都打上断点
ba w4 0483dfe0 当对0483dfe0地址写操作时停下
bl 查看设置的断点
be 激活断点
bd 禁用断点
bc 删除某个断点
bc * 清除所有断点
bc 1 清除1号断点
bc 1 2 5 清除1号、2号、5号断点
ba 设置访问断点
ba r 1 0044108c 在内存0044108c的位置开始的下一个字节的读断点
ba w4@@C++(&i) 给变量i地址下4个字节的写断点
dt 用于查看结构体内容
dv 查看当前作用域下局部变量的类型和值
db 400000 以二进制的方式显示内存地位为400000开始的内容
dd 400000 以DWORD类型查看
da /c 5 7c801e02 从7c801e02内存处开始,显示5个ascii字符
d[a| u| b| w| W| d| c| q| f| D] [/c 列数] [地址]
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 = floating point (single precision - 4b)
D = floating point (double precision - 8b)
dt nRet 查看变量nRet的类型与值
dv 显示当前函数内所有局部变量,函数参数
dv n* 显示当前函数内n开头的所有局部变量,函数参数
dv /t /i /V /a|/n|/z 更加详细地显示当前函数内所有局部变量,函数参数信息
d 按上一次的d命令的方式来显示,如果不带参数,则从上一次显示结束的地方继续显示
?i 查看局部变量i的值,会以10进制和16进制同时显示
g 运行程序,相当于F5
gu 返回函数调用处,相当于shift+F11
gH 执行gH命令强制让调试器返回已经处理了这个异常,系统收到这个回复后会停止分发
异常(因为调试器声称已经处理了异常),恢复调试目标继续执行,但由于异常条件仍
在,所以还会产生异常,于是再次分发,WinDBG再次中断到命令模式。
gN 执行gN命令强制让调试器返回没有处理了这个异常, 那么系统会进一步分发该异常,
如果没有其他调试器也不处理,最后系统会弹出程序终止对话框。
u 查看当前正要执行的代码 (反编译)
k 查看当前调用堆栈
~*kb 显示所有进程调用堆栈
k 显示当前调用堆栈
kn 带栈编号显示当前调用堆栈
kb 打印出前3个函数参数的当前调用堆栈
kb 5 只显示最上的5层调用堆栈
q 退出windbg
? 打印出所有标准命令
command /? 打印命令command具体参数用法
# 注释符
* 注释整行
$$ 注释(遇到分号结束)
eb 0012ff78 'a' 'b' 从内存地址0012ff78开始依次写入后面的值
r $peb $peb是一个伪寄存器,调试器将它定义为当前进程的进程环境块地址
r 显示所有寄存器信息
r eax, edx 显示eax,edx寄存器信息
r eax=5, edx=6 对寄存器eax赋值为5,edx赋值为6
x *! 列出所有模块对应的符号信息
lm 列出所有模块对应的符号信息
x ConsoleTest!* 列出ConsoleTest模块中的所有符号
x ConsoleTest!add* 列出ConsoleTest模块中的所有add开头的符号
x /t /v ConsoleTest!* 数据类型、符号类型和大小信息,列出ConsoleTest模块中的所有符号
x kernel32!*LoadLib* 列出kernel32模块中所有含LoadLib字样的符号
p 单步执行(F10) 【Step】
p 2 2为步进数目
pc 执行到下一个函数调用处停下
pa 7c801b0b 执行到7c801b0b地址处停下 【Step to Adress】
t Step into(F11)
tc 执行到下一个进入点处停下 【Trace to Next Call】
ta 7c801b12 执行到7c801b12地址处停下 【Trace to Adress】
一些技巧:
tab键 自动完成命令
ESC清除当前命令输入框中的文本
使用;作为分隔符,可以在同一行输入多条命令
可使用Ctrl + Break来终止一个长时间未完成的命令
.attach PID
Windbg –p PID
Windbg -pn 进程名 以上三种方式可以将windbg挂载到崩溃程序
比如挂载到记事本就可以这样:windbg –pn notepad.exe
.opendump 文件名 此命令打开一个dump文件,并建立一个DUMP调试会话。
.detach 此命令结束当前调试会话, Windbg解除和被调试进程之间的调 试关系 (不管是通过挂载,还是通过创建方式建立的调试关系),解挂后,被调试进程能够独立运行;如果当前的调试会话是一个Dump文件,此命令直接结束对dump文件的调试,即结束调试会话。
如果需要彻底结束调试,下面的命令更有用:
q | qq | qd
q是Quit的缩写。结束当前调试会话,并返回到最简单的工作空间,甚至把命令行界面也关闭掉。q和qq两个命令将结束(close)被调试的进程,qd不会关闭调试进程,而是进行解挂操作。
双机调试的时候,如果你感觉调试已经陷入僵局,比如目标机Hang住了动都动不了,此时通过主机让目标机强制宕机或重启,不失为一个好主意。
.crash
.reboot
crash命令能引发一个系统蓝屏,并生成dump文件;而.reboot使系统重启,不产生dump文件。
调试器根据模块的加载情况加载符号。有几个命令可以用来列举模块列表,分别是:
lm、 lm v a 模块地址
!dlls、 -i/-l/-m:排序方式,分别按照初始化顺序、加载顺序、内存起始地址顺序排列。
-a:列出镜像文件PE结构的文件头、Section头等详细信息,是分析PE结构的好帮手(更好
的帮手是利用自如PEView或Stud_PE等UI工具)。
-c:指定函数所在的模块。比如我想知道NtCreateFile函数是哪个模块暴露出来的接口,如
下:0:000> !dlls -c ntcreatefile
.reload /l、
!imgreloc 模块地址
!lmi 模块地址 此命令通过指定模块地址查找模块并获取其信息
!dh [标志] 模块地址 可以查看更详细、丰富的模块信息
多个命令可显示进程列表,但一般只能在特定情况下使用,它们是:| 、.tlist 、!process和!dml_proc
查看指定线程的信息,用下面的命令:
- ~ 线程号
线程号是由调试器软件内部维护的线程ID值,是一个从0开始的整数,和线程ID不是一回事。
线程信息中包括有线程环境块地址,可通过!teb命令查看环境块信息:
- !teb [teb地址]
如要在多线程间作切换,需使用~命令的s参数:
- ~ 线程号 s
由于线程号在外部是没有太大意义的,所以另一个线程切换命令是以线程ID来标识一个线程的。这个命令比较奇怪,以双波浪线打头,格式如下:
- ~*k
显示所有线程栈信息(此命令意指:对所有线程执行k指令)
使用下面的命令查看线程时间:
- .ttime
- !runaway 7
在!runaway命令中加入标志值7,将显示线程的全部三种时间值。这两个命令的区别之处是,.ttime只能显示当前线程的时间信息,!runaway能显示当前进程的所有线程时间。
异常与事件
sxr 此命令将当前所有对调试事件的设置,恢复到调试器的默认设置。最后一个字母r表示Reset。
sx{e|d|n|i}
这4个命令分别代表了图8-38中Execution组(中断属性)中的四个按钮,即Enable、Disable、Output、Ignore。Enable是开启中断,Disable是禁止事件中断(但对于异常,只禁止第一轮机会,第二轮机会到来时仍会中断到调试器),Output是禁止中断但会输出相关信息,Ignore表示完全忽略这个事件(对于异常,Output和Ignore两选项使得两轮机会都不会中断到调试器)。
sx{e|d|n|i} -h
上述命令如果带上-h选项,就不是设置中断属性,而是设置中断属性了。对应了图8-38中的Continue组。其中sxe –h表示Handled,se{d|n|i} –h都表示Not Handled。
.lastevent
显示最近发生的一个调试事件,往往是导致中断发生的那个。下图显示的是一个很典型的初始化断点引发的中断事件。
.exr 此命令显示一个异常记录的详细内容,传入一个异常记录地址:
- .exr 记录地址
如果仅仅为了显示最近的一条异常记录,可以用-1代替异常记录地址:
- .exr -1
由于异常是事件的一种,所以使用.exr -1命令得到的异常,可能和使用.lastevent命令获取的事件(其实是异常)
0:009> .lastevent Last event: 4f0.1538: Break instruction exception - code 80000003 (first chance) debugger time: Fri Aug 23 16:58:02.995 2013 (UTC + 8:00)
还有一个类似的命令:!cppexr,他分析并显示一个C++异常信息。
.bugcheck
此命令不带参数。在内核环境下,显示当前bug check的详细信息;可用于活动调试或者crash dump调试环境中。用户环境不可用。
!analyze
此命令分析当前最近的异常事件(如果在进行dump分析,则是bug check),并显示分析结果。这个异常事件,就是上面.lastevent命令对应的事件。
- -v:显示异常的详细信息,这个选项在调试错误的时候,最有用。
- -f:f是force的缩写。强制将任何事件都当作异常来分析,即使仅仅是普通的断点事件。将因此多输出一些内容。
- -hang:这个选项很有用,对于遇到死锁的情况,它会分析原因。在内核环境中,它分析内核锁和DPC栈;在用户环境中,它分析线程的调用栈。用户环境中,调试器只会对当前线程进行分析,所以一定要将线程环境切换到最可能引起问题的那个线程中去,才有帮助。这个参数非常有用,当真的遇到死锁时,它可以救命(另一个分析死锁的有效命令是!locks)。
- -show bug-check-代码 [参数]:在内核环境下,显示指定的bug check的详细信息。
!error
有免费的软件e-look,功能类似
!gle:
此命令是Get Last Error的缩写。它调用Win32接口函数GetLastError()取得线程的错误值,并打印分析结果。如果带有-all选项,则针对当前进程的所有线程(内核环境下为所有用户线程)执行GetLastError()操作;否则仅针对当前线程。
内存信息
系统的内核空间很大的,想知道这么广大的内存空间里面都有些什么东西吗?想要知道一个内存地址,到底是被一个内核栈使用着,亦或被堆管理器使用着吗?我们这一节就领大家看看内存的地理概况。首先看Address命令:
- !address [地址]
用户环境下可使用下面的命令显示内存统计信息,包括内存用途、内存类型、内存状态。
- !address -summary
和!address命令类似的,用户模式下还有下面两个命令可用:
- !vprot [地址]
- !vadump [-v]
命令!vprot显示指定内存块的信息,侧重于内存保护信息;命令!vadump显示整个内存空间信息。
在内核环境下显示内存的统计信息:
- !memusage
此命令从物理内存角度显示内存统计信息。无数个页表信息将被打印出来,可以说是“最内存”的信息。此命令会查看所有的页帧,所以运行时会非常地耗时。
- !vm
此命令从虚拟内存的角度显示内存统计信息,不仅能从全局角度显示虚拟内存的使用情况,还能以进程为单位显示内存使用情况。
上图分别以内存使用、内存类型、内存状态显示用户空间内存统计信息。
和!address命令类似的,用户模式下还有下面两个命令可用:
- !vprot [地址]
- !vadump [-v]
命令!vprot显示指定内存块的信息,侧重于内存保护信息;命令!vadump显示整个内存空间信息,dump者倾泻也,开启-v选项将显示详细(Verbose)信息。
上面讲过,用户环境下使用“!address –summary”可显示用户空间的内存统计信息;现在再看两个内核命令,在内核环境下显示内存的统计信息:
- !memusage
此命令从物理内存角度显示内存统计信息。无数个页表信息将被打印出来,可以说是“最内存”的信息。此命令会查看所有的页帧,所以运行时会非常地耗时。
- !vm
此命令从虚拟内存的角度显示内存统计信息,不仅能从全局角度显示虚拟内存的使用情况,还能以进程为单位显示内存使用情况。
用户模式下查看堆信息,命令格式如下:
- !heap
- !heap -a
安装与配置windbg的symbol(符号)
第二步 双击下载的文件安装windbg.安装时注意记住安装到那里了.
第三步 windbg访问符号需要两个文件(SYMSRV.DLL 和 SYMSTORE.EXE)所以添加主path环境变量中它们的路径进去,即:你的windbg安装目录.
操作方法:在桌面我的电脑点右键--属性--高级--环境变量,在系统变量列表框中找到path双击,在变量值最后面加一个分号再把你的安装目录写上.点确定. 这一步是告诉windbg那两个文件放在什么地方.
第四步 新建一个环境变量_NT_SYMBOL_PATH 值为: SRV*c:\mysymbol* http://msdl.microsoft.com/download/symbols
还有一种方法新的方法是:设置值为 cache*c:\mysymbol;srv*http://msdl.microsoft.com/download/symbols这两个的不同点在于 第一个只能缓存符号服务器形式的符号文件,但是第二种可以缓存远程共享形式的符号文件。
操作方法:桌面我的电脑点右键--属性--高级--环境变量 ,点击新建,把上面的变量名和变量值填上.这一步的意思是说告诉windbg,我的符号文件存放在c:mysymbol中(当然其实里面什么也没有,甚至这个文件夹也不存在,不过没关系,系统找不到的话会给你创建一个,并在上面的网址中去帮你下载符号文件放在里面)
第五步 重启计算机,再运行运行windbg 打开一个exe文件或者附加到一个进程里去, 你会看到
Symbol search path is: SRV*c:\mysymbol* http://msdl.microsoft.com/download/symbols
打开c盘看到有一个新目录mysymbol,里面有windbg新下载的文件.
恭喜说明配置成功了.