WINDBG配置和使用.docx
《WINDBG配置和使用.docx》由会员分享,可在线阅读,更多相关《WINDBG配置和使用.docx(38页珍藏版)》请在冰豆网上搜索。
WINDBG配置和使用
WinDbg配置和使用基础
WinDbg是微软发布的一款相当优秀的源码级(source-level)调试工具,可以用于Kernel模式调试和用户模式调试,还可以调试Dump文件。
1.WinDbg介绍:
DebuggingToolsandSymbols:
GettingStarted
AwordforWinDbg
2.WinDbg下载:
InstallDebuggingToolsforWindows32-bitVersion
InstallDebuggingToolsforWindows64-bitVersions
3.配置WinDbg:
运行WinDbg->菜单->File->SymbolFilePath->按照下面的方法设置_NT_SYMBOL_PATH变量:
在弹出的框中输入“C:
\MyCodesSymbols;SRV*C:
\MyLocalSymbols*Server上下载Symbols)。
另一种做法是从这个Symbol下载地址中,下载相应操作系统所需要的完整的Symbol安装包,并进行安装,例如我将其安装在D:
\WINDOWS\Symbols,在该框中输入“D:
\WINDOWS\Symbols”。
(这里要注意下载的Symbols的版本一定要正确,在我的Win2003+Sp1上,我曾经以为安装Win2003+Sp2的Symbols可能会牛×点,但结果证明我错了,用WinDbg打开可执行文件时,提示“PDBsymbolformscorwks.dllnotloaded;Defaultedtoexportsymbolsforntdll.dll”的错误,我有重新装上Win2003+Sp1的Symbols,现在一切运行正常^_^)
4.使用WinDbg:
WinDbg提供了图形界面和命令行两种运行方式。
这里介绍使用图形界面的WinDbg来调试应用程序:
File->OpenExecutable->可以选择一个可执行文件进行调试;
File->AttachetoaProcess->可以选择一个运行中的进程,并对其进行调试;
至此,我们就可以在上图中用红色方框标记的文本框中输入各个功能指令了(有关指令的帮助文档,可以参考:
Help->Contents->DebuggingToolsforWindows->Debuggers->DebuggerReference,该目录下列集了所有指令机器功能说明!
)。
Hihappyhippy,
我是这样调试的,但是始终没成功的。
1.生成符号信息
更改Relase版的设置(2处):
一、ProjectSetting->C/C++
Debuginfo:
选择ProgramDatabase
二、ProjectSetting->Link
选中Generatedebuginfo
重新编译
2.安装Windbg
下载安装最新的Windbg
c:
\iknow\docshare\data\cur_work\t
3.设定环境变量
对于user32.dll等系统文件,Windbg可以自动从微软网站下载所需的符号信息.我们只需设定_NT_SYMBOL_PATH
这个环境变量告诉Winddbg.方法如下:
我的电脑>右键菜单>属性>高级选项卡>环境变量>系统变量>新建
变量名:
_NT_SYMBOL_PATH
变量值:
SRV*C:
\websymbols*
解释一下:
C:
\websymbols用来存储系统符号.你可以指定其他的路径.Windbg会自动创建该文件夹
4.设定符号路径
新建一个文件夹,譬如C:
\MyAppSymbols
将第一步中生成的Release目录下.pdb文件拷贝到该文件夹,该pdb文件包含了调试所需的符号信息.
打开Windbg,选择File>Symbolfilepath>将C:
\MyAppSymbols路径添加进去
5.调试程序
选择File>OpenExecutable然后选择你需要调试的Exe文件,就显示
WARNING:
Whitespaceatendofpathelement
CommandLine:
C:
\test\Release\test.exe
Symbolsearchpathis:
SRV*C:
\websymbols*
Executablesearchpathis:
ModLoad:
0040000000405000test.exe
ModLoad:
77f8000077ffd000ntdll.dll
ModLoad:
6bc400006bd3b000C:
\WINNT\system32\MFC42.DLL
ModLoad:
7800000078045000C:
\WINNT\system32\MSVCRT.dll
ModLoad:
77e6000077f33000C:
\WINNT\system32\KERNEL32.dll
ModLoad:
77f4000077f7c000C:
\WINNT\system32\GDI32.dll
ModLoad:
77df000077e4f000C:
\WINNT\system32\USER32.dll
(318.430):
Breakinstructionexception-code80000003(firstchance)
eax=00000000ebx=00131f04ecx=00000009edx=00000000esi=7ffdf000edi=00131f70
eip=77f813b1esp=0012f984ebp=0012fc98iopl=0nvupeiplnznaponc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000202
***ERROR:
Symbolfilecouldnotbefound.Defaultedtoexportsymbolsforntdll.dll-
ntdll!
DbgBreakPoint:
77f813b1ccint3
然后我就用BP来设置断点用F5来执行,显示
ModLoad:
75e0000075e1a000C:
\WINNT\system32\IMM32.DLL
ModLoad:
796d000079732000C:
\WINNT\system32\ADVAPI32.DLL
ModLoad:
786f00007875f000C:
\WINNT\system32\RPCRT4.DLL
ModLoad:
6bc200006bc2d000C:
\WINNT\system32\MFC42LOC.DLL
ModLoad:
7171000071794000C:
\WINNT\system32\COMCTL32.DLL
ModLoad:
6dd300006dd36000C:
\WINNT\system32\INDICDLL.dll
ModLoad:
1000000010055000C:
\ProgramFiles\Tencent\RTXC\RTXOLAss.dll
ModLoad:
76af000076b2e000C:
\WINNT\system32\comdlg32.dll
ModLoad:
772a000077306000C:
\WINNT\system32\SHLWAPI.DLL
ModLoad:
78f90000791d6000C:
\WINNT\system32\SHELL32.DLL
ModLoad:
777c0000777de000C:
\WINNT\system32\WINSPOOL.DRV
ModLoad:
79b2000079b30000C:
\WINNT\system32\MPR.DLL
ModLoad:
7cf000007cfef000C:
\WINNT\system32\ole32.dll
ModLoad:
68e9000068eb9000C:
\WINNT\system32\OLEPRO32.DLL
ModLoad:
7799000077a2b000C:
\WINNT\system32\OLEAUT32.dll
Breakpoint0hit
eax=00000001ebx=00000001ecx=0012fac0edx=00130608esi=00402300edi=0012fe94
eip=004014eeesp=0012f99cebp=0012f9a8iopl=0nvupeingnzacpenc
cs=001bss=0023ds=0023es=0023fs=0038gs=0000efl=00000296
test!
CTestDlg:
:
OnButton1+0xe:
004014eec3ret
不知道这样操作有没有什么错误的,
如果是对的,那怎么看它的调试信息?
如果不对,还请各位赐教。
***ERROR:
Symbolfilecouldnotbefound.Defaultedtoexportsymbolsforntdll.dll-
这上面的这个提示对调试有没有影响?
谢谢!
@Jim
"C:
\websymbols用来存储系统符号.你可以指定其他的路径.Windbg会自动创建该文件夹",你可以先查看下,windbg有没有从ms的网站上把symbols下载回来?
刚开始我也尝试过让windbg从ms下载symblos,试了几次没有成功,最后我自己的做法是:
从,下载相应操作系统所对应的完整的Symbol安装包,并进行安装。
Hihappyhippy,
1.生成符号信息
更改Relase版的设置(2处):
一、ProjectSetting->C/C++
Debuginfo:
选择ProgramDatabase
二、ProjectSetting->Link
选中Generatedebuginfo
我这样操作后就生成了个.pdb符号文件的。
我将这个文件COPY到C:
\websymbols中的。
应该不会提示说找不到符号文件的啊,还请赐教。
谢谢。
Jim
WinDbg设置断点
在windbg中,断点设置的地址形式有好多种,可以是以下几种:
1.虚拟地址:
即给出直接地址,如12345678
2.函数偏移量:
如DriverEntry+5c.
3.源代码+行数:
`[[Module!
]Filename][:
LineNumber]`
4.对C++可以对模块中的某个类的方法设置断点:
设置断点语法:
1:
无条件设置断点:
bp Address
例如:
kd>bp0040108c
kd>bpmain+5c
kd>bp`source.c:
31`
kd>bpMyClass:
:
MyMethod
kd>bpMyClass__MyMethod
kd>bp@@(MyClass:
:
MyMethod)
2:
设置有条件断点
kd> bp Address "j (Condition) 'OptionalCommands'; 'gc' "kd> bp Address ".if (Condition) {OptionalCommands} .else {gc}"
这两种设断点语法是等价的。
bp,bu,bm的区别:
bu:
SetUnresolvedBreakpoint
bp和bu的区别:
1:
bp是立即生效,且马上被转化为内存中的某个地址,如果调式模块被改变,bp指向的地址不会变,而bu只是和symbol文件相关联,模块改变的时候,指向的symbol的offset或者plus是不变的
2:
bp指定的断点在模块unload之后从bl列表中删除,而bu的断点是永远存在的。
3:
在windbg的可视源码或者可视的反汇编代码中所设的断点都是bu模块的断点
bm:
SetSymbolBreakpoint
使用bm设置断点支持正则表达式的模式匹配,所以可以使用他来设置多个断点
如果正则表达式被匹配的话,他的效果将和bu设置的是一样的
例如:
0:
000>bmdbgtest!
*main*
1:
00413530@!
"dbgtest!
wmain"
2:
00411810@!
"dbgtest!
__tmainCRTStartup"
3:
004117f0@!
"dbgtest!
wmainCRTStartup"
使用bp和bm/a的风险:
当wndbg在设置软件断点在代码段的时候,windbg将程序指令替换为断点指令,但是当断点设置在数据段的时候,将会将程序数据替换为断点指令,从而导致数据被修改,因此在设置断点在数据段的时候,推荐使用ba(ba(BreakonAccess).)指令
控制断点的方法
使用下面一些方法来控制或显示断点:
∙bl (BreakpointList)命令列出当前存在的断点和他们的状态。
∙bp (SetBreakpoint)命令设置新断点。
∙bu (SetUnresolvedBreakpoint)命令设置新断点。
使用bu设置的断点和bp设置的断点特点不同,详细信息查看后面的内容。
∙bm (SetSymbolBreakpoint)在匹配指定格式的符号上设置断点。
∙ba (BreakonAccess)命令设置数据断点。
这种断点在指定内存被访问时触发。
(可以在写入、读取、执行或发生内核I/O时触发,但不是所有处理器都支持所有的内存访问断点。
更多信息,查看ba (BreakonAccess)。
)
∙bc (BreakpointClear)命令移除一个或多个断点。
∙bd (BreakpointDisable)命令暂时禁用一个或多个断点。
∙be (BreakpointEnable)命令重新启用一个或多个断点。
∙br (BreakpointRenumber)命令修改一个已存在的断点的ID。
∙(仅WinDbg)反汇编窗口(Disassemblywindow)和源码窗口(Sourcewindows)会将设置了断点的行高亮。
已启用的断点为红色,禁用的断点为黄色,如果当前程序计数器(EIP)位置是断点位置则显示为紫色。
∙(仅WinDbg)Edit | Breakpoints命令或ALT+F9快捷键打开Breakpoints对话框。
该对话框会列出所有断点,所以可以用它来禁用、启用、删除已存在的断点或设置新断点。
∙(仅WinDbg)如果光标在反汇编窗口或源码窗口中,可以按下F9或点击工具栏上的Insertorremove按钮(
)来在光标所在行上设置断点。
如果在当前窗口不是反汇编窗口或源码窗口时按下快捷键或点击上述按钮,则和使用Edit | Breakpoints具有相同效果。
每个断点都有一个关联的10进制数字称为断点ID。
该数字在各种命令中用于指定断点。
未定断点:
BUvs.BP
如果一个断点是设置在某个还未加载的函数名上,则称为延迟、虚拟或未定断点。
(这些术语可交替使用。
)未定断点没有被关联到任何具体被加载的模块上。
每当一个新的模块被加载时,会检查该函数名。
如果这个函数出现,调试器计算虚拟断点的实际位置并启用它。
使用bu设置的断点自动被认为是未定断点。
如果断点在一个已加载模块中,则会启用并正常生效。
但是,如果模块之后被卸载并重新加载,这个断点不会消失。
而使用bp设置的断点会立即绑定到某个地址。
bp和bu断点有以下三个主要的不同点:
∙bp断点的位置总是被转换成地址。
如果某个模块改变了,并且bp设置的地址位置改变,断点还是在原来的位置。
而bu断点仍然和使用的符号值关联(一般是符号加上偏移),它会一直跟踪符号的地址,即使这个地址已经改变。
∙如果bp的断点地址在某个已加载模块中找到,并且该模块之后被卸载,则该断点会从断点列表中移除。
而bu断点经过反复的卸载和加载仍然存在。
∙用bp设置的断点不会保存到WinDbg工作空间(workspaces)中,而使用bu设置的断点会保存。
当在WinDbg反汇编窗口或源码窗口中使用鼠标设置断点时,调试器创建的是bu断点。
初始断点
当调试器启动一个新的目标程序时,初始断点在主映像和所有静态加载的DLL被加载、DLL初始化例程被调用之前自动触发。
调试器附加到一个已存在的用户模式程序时,初始断点立即触发。
-g命令行选项使得WinDbg或CDB跳过初始断点。
在这时可以自动执行命令。
更多信息,查看控制异常和事件。
如果想启动新调试目标并在实际的程序即将开始执行的时候中断下来,就不要使用-g选项。
应该让初始断点被触发。
当调试器激活之后,在main或winmai函数上设置断点并使用g (Go)命令。
之后所有初始化过程都会运行并且程序在main函数即将执行时停止。
关于内核模式的自动断点的更多信息,查看崩溃和重起目标机。
断点中的地址
断点支持几种地址语法,包括虚拟地址、函数偏移和源码行号。
例如,可以使用下面的方法之一来设置断点:
0:
000> bp 0040108c
0:
000> bp main+5c
0:
000> bp `source.c:
31`
关于这些语法的更多信息,查看数值表达式语法,源码行语法,以及各个命令的主题。
断点的数量
在内核模式下,最多可以使用32个断点。
在用户模式下,可以使用任意数量的断点。
数据断点的数量由目标处理器架构决定。
方法的断点
如果要在MyClass类的MyMethod方法上设置断点,可以使用两种不同语法:
∙用MASM表达式语法,可以用双冒号或者双下划线来指定一个方法。
0:
000> bp MyClass:
:
MyMethod
0:
000> bp MyClass__MyMethod
∙用C++表达式语法,必须用双冒号指定方法。
0:
000> bp @@( MyClass:
:
MyMethod )
如果要使用更复杂一些的断点命令,应该使用MASM表达式语法。
表达式语法的更多信息,查看表达式求值。
用户空间和系统空间
每个用户模式应用程序在虚拟内存0x00000000到0x7FFFFFFF的地址称为用户空间。
当WinDbg或CDB在小于0x80000000的地址上下断时,断点是在单个进程的指定的用户空间的地址设置。
用户模式调试时,当前进程决定了虚拟地址的意义。
更多信息,查看控制进程和线程。
在内核模式,可以使用bp、bu、ba命令和Breakpoints对话框在用户空间设置断点。
必须首先使用.process/i(或在一些内核空间的函数上的指定进程的断点)来将目标切换成当前进程上下文,并使用该进程上下文来指定拥有目标地址空间的用户模式进程。
用户模式的断点总是和设置该断点时进程上下文为激活状态的进程关联起来。
如果有用户模式调试器在调试该进程,而还有一个内核模式调试器在调试进程运行的机器,即使断点由内核调试器设置,它中断时也是进入用户模式调试器。
这时可以从内核模式调试器中断系统,或使用.breakin (BreaktotheKernelDebugger)命令来将控制权交给内核调试器。
注意 如果目标机运行在MicrosoftWindows NT 4.0上,则不能使用内核调试器在用户空间中设置断点。
断点伪寄存器(Pseudo-Registers)
如果在某个表达式中想引用某个断点的地址,可以使用一个$bpNumber语法的伪寄存器,Number是断点ID。
关于该语法的更多信息,查看伪寄存器语法。
设置断点时的风险
当使用内存地址或符号加偏移的方式设置断点时,一定不能将断点设置到一条指令的中间。
例如,有下面一段汇编代码。
770000f1 5e pop esi
770000f2 5b pop ebx
770000f3 c9 leave
770000f4 c21000 ret 0x10
770000f7 837ddc00 cmp dword ptr [ebp-0x24],0x0
前三条指令只有1个字节长。
但是第四条指令有3字节长。
(包含在0x770000F4,0x770000F5,和0x770000F6三个地址的字节)如果要在该指令上使用bp、bu或ba设置断点,则必须将地址指定为0x770000F4。
如果使用ba命令在0x770000F5地址设置了断点,处理器将在该位置设置断点。
但是该断点永远不会被触发,因为处理器认为0x770000F4才是这条指令的实际地址。
如果使用bp或bu命令在0x770000F5设置断点,调试器在这个位置会写入断点。
但是由于调试器使用如下方法设置断点,它可能造成目标运行错误:
1.调试器保存0x770000F5地址的内容,并用一条断点指令写入该地址。
2.如果用调试器显示这段内存的内容,并不会显示被写入的断点指令,而是显示那里原来"应该是"的内容。
即调试器显示原来的内存,或者断点设置之后该内存被修改的内容。
3.如果使用BC命令删除断点,调试器将断点位置的内存恢复成原始值。
当在0x770000F5设置断点时,调试器保存它的值并写入断点指令。
但是当程序运行时到达0x770000F4时,会将它视为一条多字节指令的第一个字节。
处理器将0x770000F4、0x770000F5可能还有后面的一些字节当作一条指令。
这会产生各种非正常的行为。
因此,当使用bp、bu或ba命令设置断点时,要确定断点在合适的地址上。
如果使用WinDbg图形界面来添加断点就不用在意这样的情况,因为它会自动选择正确的地址。
断点命令
可以在断点中包含一条命令用于在断点触发时自动执行。
也可以包含一条用于执行的命令字符串。
但是,其中任何恢复程序执行的命令(例如g和t)都会终止命令列表的执行。
例如下面的命令在MyFunction+0x47中断,写入一个dump文件并恢复执行。
0:
000> bu MyFunction+0x47 ".dump c:
\mydump.dm