最新文章专题视频专题问答1问答10问答100问答1000问答2000关键字专题1关键字专题50关键字专题500关键字专题1500TAG最新视频文章推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37视频文章20视频文章30视频文章40视频文章50视频文章60 视频文章70视频文章80视频文章90视频文章100视频文章120视频文章140 视频2关键字专题关键字专题tag2tag3文章专题文章专题2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章专题3
当前位置: 首页 - 正文

windbg简明教程

来源:动视网 责编:小OO 时间:2025-09-25 13:54:08
文档

windbg简明教程

Windbg简明教程2008年10月08日星期三09:10Windbg是Microsoft公司免费调试器调试集合中的GUI的调试器,支持Source和Assembly两种模式的调试。Windbg不仅可以调试应用程序,还可以进行KernelDebug(新版本对于XP+操作系统支持Livekerneldebug),同时结合Microsoft的SymbolServer调试应用程序和Kernel非常得利。Windbg支持x86,IA,AMD。Windbg下载地址:http://www.micr
推荐度:
导读Windbg简明教程2008年10月08日星期三09:10Windbg是Microsoft公司免费调试器调试集合中的GUI的调试器,支持Source和Assembly两种模式的调试。Windbg不仅可以调试应用程序,还可以进行KernelDebug(新版本对于XP+操作系统支持Livekerneldebug),同时结合Microsoft的SymbolServer调试应用程序和Kernel非常得利。Windbg支持x86,IA,AMD。Windbg下载地址:http://www.micr
Windbg简明教程

2008年10月08日 星期三 09:10

Windbg是Microsoft公司免费调试器调试集合中的GUI的调试器,支持Source和Assembly两种模 式的调试。Windbg不仅可以调试应用程序,还可以进行Kernel Debug(新版本对于XP+操作系统支持Live kernel debug),同时结合Microsoft的Symbol Server调试应用程序和Kernel非常得利。Windbg支持x86,IA,AMD。

Windbg下载地址:http://www.microsoft.com/whdc/devtools/debugging/default.mspx

下面我来说一下Windbg的基本用法:

基本设置

由于Windbg是GUI调试器,所以在设置方面可以通过菜单,也可以通过命令。我只说明最方便的办法:),那请先打开Windbg吧

符 号路径设置,Ctrl+S在弹出的窗口中输入你的符号路径,路径的格式只要符合Windows操作系统路径格式即可,路径可以多个,中间以分号间隔,如: d:\\symbols\\win2k3_en;个人感觉Windbg的强大功能之一在于Windbg会自动到Microsoft的服务器上下载符号表文件 (.dbg或.pdb,有时DLL和EXE也会下载),只要在符合表路径里做如下设置:srv*d:\\symbolslocal*http: //msdl.microsoft.com/download/symbols,这样如果相关符号表在d:\\symbolslocal目录没有找到的话, Windbg会自动在Microsoft的Symbol Servers上下载。如果你是调试自己的应用程序的话,建议你将自己应用程序的*.pdb文件的路径放在前面这样对Windbg来说查找起来比较快。

源文件路径设置:Ctrl+P在弹出的窗口里指定你的源代码文件的路径,路径格式只要符合Windows操作系统的格式即可,可以指定多个,中间以分号间隔。

可以将你的设置进行保存,File->Save Workspace。

开始调试

可以创建一个子进程进行调试,也可以对正在运行的程序进行调试,方法如下:Ctrl+E打开一个应用程序并可指定运行参数进行调试;F6从对话框中选择当前正在运行的进程调试。

对于调试子进程,通常Windbg会在应用程序运行之前中断,此时你可下一些想要的断点:

以Notepad.exe 为例,如果你还没有符号表文件的而又设置了MicrosoftSymbol Servers的话,你得先等一下,因为Windbg会自己自动到Microsoft上下载相关的符号表,在命令提示符的位置如果没有出现0: 000>这个标记表示Windbg正在忙。

表达式格式:

无论在那条指定里都会涉及这个问题:数制,语法。Windbg支持C++和 MASM两个表达式格式,@@用于即时改变语法格式,即在MASM下使用@@指令来使用C++的语法解释器,反之亦然。Windbg数制的表示0x表示 16进制,0n表示10进制,0t表示8进制,0y表示2进制;Windbg默认数制为16进制,n指认用于设置数制;默认表达式语法是MASM,. expr 指令用于设置表达式语法解释器。本文均使用MASM为默认语法解释器。大小问题,通常如果不特别说明,Windbg对指令不区分大小

断点指令:BP,BM,BA,BL,BC,BD,BE

BP 在指定的地址设置断点

bp notepad!WinMain,在Notepad的WinMain函数处下断点。

断 点的位置可以用符号表示,也以直接使用地址及Windbg的Pseudo-Register(虚拟寄存器),如$exentry表示进程的入口点,可以使 用bp @$exentry在进程的入口点设置断点,对于Notepad当前入口点为010020,也可以直接 bp 010020,等效于bp notepad!WinMainCRTStartup.

BM 使用模式匹配设置断点,需要符号表支持

bm 值一提,在符号表合法的情况下(符号表中包含私有符号的时候),bm可能通过模式一次下多个断点,bm mydriver!FastIo*指定可以将所有与FastIo*模式相匹配的函数下断点,如FastIoRead,FastIoWrite等。但是bm 需要full or export symbols支持,Microsoft的提供的符号表不是都支持的,通常我们自己编译的程序的符号表(Windbg显示为private pdb symbols)默认是支持的。

BA (Break on Access)

顾名思义,对内存访问下断点。对于在多核或多处理器调试的时候 很有用,对于调试多线程也很有用,应该说用处很多,比如对一个全局变量设置断点,ba mydriver!gMonitoredDevices,如果如果你认为这个变量的值被莫名的修改了,相信通过BA设置的断点,你很快就能找到是谁修改 的。

BL(List),BC(Clear),BE(Enable),BD(Disable)

   这四个指令是分别用于列表,清除,开启和禁用断点,也是使用非常频繁的指令。

条件断点

   以上所提到的断点指令通过与J指令很容易形成条件断点。比如:

bp USER32!GetMessageW "r $t1=poi(esp+4);r $t2=poi(@$t1+4); j(@$t2 = 0x102 ) 'du @$t1+8 L2;gc';'gc'"

这个条件断点,截取WM_CHAR消息,并将字符(包括中文)显示出来。

条件断点的最简形式:bp Address "j (Condition) 'OptionalCommands'; 'gc' "

Address是指令的地址,Condition是一个条件表达式,如果@eax=1,'OptionalCommands'是在断点被击中并且表达式成立时要执行的指令;gc指定是从一个条件断点返回,是不可少的一部分。

数据查看指令 d{a|b|c|d|D|f|p|q|u|w|W}

d{b|c|d|D|f|p|q}分别是显示:

byte&ASCII, double-word&ASCII,double-word,double-precision,float,pointer-sized,quad-word数据;

DA用于显示ASCII,DU用于显示UNICODE;

BYB,BYD,显示binary和Byte及binary和DWORD

补充一个DV,用于查看本地变量用的

这些指令区分大小。

栈指令k[b|p|P|v]

这 四条指令显示的内容类似,但是每个指令都有特色,KB显示三个参数,Kp显示所有的参数,但需要Full Symbols或Private PDBSymbols支持。KP与Kp相似,只是KP将参数换行显示了。Kv用于显示FPO和调用约定,KD,用于显示Stack的Dump,在跟踪栈时 比较有用。

这些指令区分大小。

KD显示的内容:

0012fbd0   0012fbf0

0012fbd4   77e2158f USER32!UserCallWinProc+0x18

0012fbd8   0016011e

0012fbdc   00000030

0012fbe0   750a0c3f

0012fbe4   00000000

0012fbe8   00000000

0012fbec   dcbaabcd

0012fbf0   0012fc2c

0012fbf4   77e1279c USER32!DefDlgProcWorker+0xbf

0012fbf8   004018e0 DGGuarder!MainDLGproc [j:\\mydriver\\dgguarder2\\dgguarder.c @ 350]

0012fbfc   0016011e

0012fc00   00000030

0012fc04   750a0c3f

0012fc08   00000000

0012fc0c   00629d08

0012fc10   00000030

0012fc14   00619828

0012fc18   77e0f626 USER32!__ClientLoadMenu+0x38

0012fc1c   77e0f635 USER32!__ClientLoadMenu+0x47

   KP显示的内容:

ChildEBP RetAddr  

0012fbd0 77e2158f DGGuarder!MainDLGproc(

struct HWND__ * hwnd = 0x0016011e, 

unsigned int message = 0x30, 

unsigned int wParam = 0x750a0c3f, 

long lParam = 0)+0x227 [j:\\mydriver\\dgguarder2\\dgguarder.c @ 415]

0012fbf0 77e1279c USER32!UserCallWinProc+0x18

0012fc5c 77e0b981 USER32!DefDlgProcWorker+0xbf

0012fd14 77e140bb USER32!InternalCreateDialog+0x695

0012fd44 77e1410f USER32!InternalDialogBox+0xaa

0012fd 77df41ec USER32!DialogBoxIndirectParamAorW+0x34

0012fd90 00401cdc USER32!DialogBoxParamA+0x4a

0012fe88 00408684 DGGuarder!WinMain(

struct HINSTANCE__ * hInstance = 0x00400000, 

struct HINSTANCE__ * hPrevInstance = 0x00000000, 

char * lpCmdLine = 0x00132902 "", 

int nCmdShow = 10)+0x5c [j:\\mydriver\\dgguarder2\\dgguarder.c @ 469]

0012ffc0 77e8 DGGuarder!WinMainCRTStartup(void)+0x194 [f:\\vs70builds\\3077\\vc\\crtbld\\crt\\src\\crt0.c @ 251]

0012fff0 00000000 KERNEL32!BaseProcessStart+0x3d

数据修改指令e{b|d|D|f|p|q|w} 

   请参见文档吧:)

反汇编指令u,uf

u @$exentry L10

0:001> u @$exentry L10

notepad!WinMainCRTStartup:

010020 55             push ebp

010021 8bec          mov     ebp,esp

010023 6aff          push 0xff

010025 6888180001    push 0x1001888

01002a 68d0650001    push 0x10065d0

01002f a100000000     mov     eax,fs:[00000000]

010035 50             push eax

010036 2500000000 mov     fs:[00000000],esp

01003d 83c498           add     esp,0xffffff98

010040 53             push ebx

010041 56             push esi

010042 57             push edi

010043 65e8           mov     [ebp-0x18],esp

010046 c745fc00000000 mov     dword ptr [ebp-0x4],0x0

01004d 6a02          push 0x2

01004f ff1560110001 call dword ptr [notepad!_imp____set_app_type (01001160)]

uf (Unassemble Function)指令对整个函数进行反汇编

uf GetLanguageCount

0:000> uf GetLanguageCount

DGGuarder!GetLanguageCount [j:\\mydriver\\dgguarder2\\language.c @ 54]:

54 00403c00 55             push ebp

54 00403c01 8bec          mov     ebp,esp

54 00403c03 81ecc0000000     sub     esp,0xc0

54 00403c09 53             push ebx

54 00403c0a 56             push esi

54 00403c0b 57             push edi

54 00403c0c 8dbd40ffffff     lea     edi,[ebp-0xc0]

54 00403c12 b930000000    mov     ecx,0x30

54 00403c17 b8cccccccc    mov     eax,0xcccccccc

54 00403c1c f3ab          rep     stosd

56 00403c1e 6a00          push 0x0

56 00403c20 6828b44100    push 0x41b428

56 00403c25 6820b44100    push 0x41b420

56 00403c2a e8b1edffff    call DGGuarder!ReadInt (004029e0)

56 00403c2f 83c40c           add     esp,0xc

58 00403c32 5f             pop     edi

58 00403c33 5e             pop     esi

58 00403c34 5b             pop     ebx

58 00403c35 81c4c0000000     add     esp,0xc0

58 00403c3b 3bec          cmp     ebp,esp

58 00403c3d e85e0f0000    call DGGuarder!_RTC_CheckEsp (00404ba0)

58 00403c42 8be5          mov     esp,ebp

58 00403c44 5d             pop     ebp

58 00403c45 c3             ret

跟踪指令T,TA,TB,TC,WT,P,PA,PC

   T指令单步执行,在源码调试状态下,可指源码的一行,根据不同的选项也可以为一行ASM指令;

TA单步跟踪到指定地址,如果没有参数将运行到断点处。

TB执行到分支指令,分支指令包括calls, returns, jumps, counted loops, and while loops

TC执行到Call指令

WT Trace and Watch Data,一条强大指令,对执行流程做Profile,执行一下看看结果吧

P,PA,PC相信不用多做解释,大家也都明白了

源代码操作指令 .,lsf,lsc,ls,l,lsp

.指令打一个源文件,可以打开一个全路径的文件,也可以通过函数地址来打开并定位到源文件中函数的位置,如. –a myapp!main,. j:\\mydriver\\mydriver.c

lsf指定一个源文件为当前源文件,使用lsc可显示当前指定的源文件ls可显示源文件的代码。Lsf可以使用全路径,如果源路径已经设置,也可以直接指定源文件名称。如lsf mydriver.c,lsf j:\\mydriver\\mydriver.c

lsc显示当前源文件

ls显示当前源文件的代码,如ls 200显示第200行

l 用于设置源文件选项

lsp 设置源文件行在调试时显示范围比如,显示当前行的前50,后50,lsp 100

但通常使用Windbg时,可以直接用Ctrl+O来打开并查看源文件

寄存器指令 r

相 信大家对这个指令都很熟悉,在Windbg中r指令除了可以显示修改CPU寄存器之外,Pseudo-Register可使用这个命令来修改。对eax 操作,r eax 显示其值,r eax=2,修改其值;r $t2=10,修改Pseudo-Register的值,r @$t2显示其值。

Search 指令 s,#

S 指令对内存区别进行查找,可用于查找数字,字符串,但不支持模式查找。s -d @esp L100 8187bc40,从esp指向的内存地址0x100个字节内查找 DWORD   8187bc40。查找字符串 s -a 0012ff40 L20 "Hello" 。s -sa 和 s -su 显示内存可打印的ASCII和Unicode字符串。

#指令可以查询汇编指令模式, # "call[ ]+esp" kernel32 L1000

查找call esp 指令。

其他常用指令 lm,!peb,x,dt

lm 查看当前载入的模块

!peb 查看当前进程环境块(PEB)

x 查看模块的符号,如x mydriver!*FastIo*,显示所有与*FastIo*匹配的符号列表

dt 查看类型数据,还可用于查看模块类型的符号列表,如 dt dgguarder!_IMAGE_DOS_HEADER 00400000

从00400000处查看_IMAGE_DOS_HEADER类型的数据

上下文的概念

   Windbg下上下文的概念很重要,根据文档中说明有多种上下文概念,

Session Context,

Process Context

Register Context(其实也就是线程上下文)

Local Context(这个关系的本地如果解析本地变量的问题)

调 试Win32应用程序,Session Context和Process Context是确定的,主要是Register Context,也即Thread Context,可以使用~指令来查看,改变当前的Thread Context 。~*显示所有线程列表,~xs用于切换上下文(x是数字),如:~1s,将上下文切换到1号线程。

.frame用来设置Local Context。

PAUSE

好了,基本的指令都已经列出了来了,Kernel Debug现在先不写了,其实跟Win32也差不多。如果再有时间再写吧。本文对指令没有说的太细,详细说明见Windbg文档,希望见谅。

windbg

Windbg的命令都是一点号(.)来开始的,它不同于叹号开始的命令(!),叹号开始的命令都是sos.dll中的命令。

.load sos

每次打开windbg调试.net程序的dump时,我们首先要输入此命令。它的用途是使得windbg可以支持托管代码(managed code)的调试。

.time

查看dump文件生成时的时间,其中包括系统当前时间,开机总时间,程序运行总时间,程序运行在内核态总时间以及用户态总时间。

sos.dll

最强大的功能还要数sos.dll中的命令,它是我们调试.net程序的基础。下面介绍一些基本命令:

!help

它用来查看每个命令的用法。如!help !threads,用来查看!threads 命令的具体用法。如果直接使用!help,它将列出sos的基本信息。

!threadpool

通过这个命令,我们可以很容易的看出在dump文件生成时的确切CPU使用率,同时,我们也可以看到队列中等待的work requests,timers以及completion port threads等信息。Timers,work requests以及completion port threads都是CLR的线程种类,在以后的文章中我会详细介绍。

!runaway

它是用来罗列所有正在运行的线程以及它们的CPU占用率。通过这个命令,我们可以很容易的去trouble shooting一些CPU占用率过高的问题。

!threads

它是用来罗列所有正在运行的托管(managed)线程的详细信息,如CLR线程所在的appdomain等等。如果线程的ID显示XXXX,说明这个线程已经结束,等待被回收。

~[id]s

此命令用来切换到某一特定线程。如 ~20s 代表切换到ID为20的线程。

!clrstack

此命令用来显示此线程的managed code 的callstack。我们可以加上-p参数来得到更加详细的信息。

!dumpobject(!do)

通过这个命令,我们可以查看某个特定address的object信息。如果这个address指向一个string,我们就可以看到这个string内存储了什么值。

!dumpstackobjects(!dso)  

此命令用来查看被当前线程堆栈引用的所有托管对象。

!dumparray(!da)

当我们查看线程堆栈上的object时,我们可以使用!do命令。但是如果该object是一个array的话,!do只能得到array本身的信息,并非其存储的内容。此时!da就发挥了用场。

!objsize

如果我们想查看一个object的total size的时候,我们需要使用!objsize命令。比如当我们!da一个array时,它显示的size仅仅是包含的type的size,并非实际的size。我们可以使用!objsize address来查看这个array的实际size。

!dumpheap

它是用来查看堆上所有的object。通常我们加上 –stat参数来帮我们做个归类,否则它会罗列出许多繁杂的信息。同时,它还有几个比较常用的参数,如-type,-mt。-type用来列出某一特定类型的所有object,如!dumpheap –type System.String将列出堆上所有的string。-mt是用来列出某一特定MethodTable的所有object。大家知道,每一个引用类型都对应一个MethodTable,假设System.String类型的MethodTable是02c39310,那么我们还可以通过!dumpheap –mt 02c39310来找到堆上所有的string。

这些是一些基本命令的用法,大家需要先有点印象。在后面的文章中,我们会经常遇到这些命令。同时,在后面的文章中,我也会和大家介绍遇到的每一个命令。

http://kb.cnblogs.com/a/1370703/

文档

windbg简明教程

Windbg简明教程2008年10月08日星期三09:10Windbg是Microsoft公司免费调试器调试集合中的GUI的调试器,支持Source和Assembly两种模式的调试。Windbg不仅可以调试应用程序,还可以进行KernelDebug(新版本对于XP+操作系统支持Livekerneldebug),同时结合Microsoft的SymbolServer调试应用程序和Kernel非常得利。Windbg支持x86,IA,AMD。Windbg下载地址:http://www.micr
推荐度:
  • 热门焦点

最新推荐

猜你喜欢

热门推荐

专题
Top