zoukankan      html  css  js  c++  java
  • windbg调试命令

     #调试命令窗口

     +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    #使用gflags.exe工具(在windbg所在目录下),让某个进程启动时,拉取windbg进行调试

    如下截图:当名称为captcomm.exe的进程启动时,拉起windbg调试

    也可通过脚本命令来实现:

    // 运行captcomm.exe时,启动windbg调试
    reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\captcomm.exe" /v Debugger /t REG_SZ /d "C:\Program Files\Debugging Tools for Windows (x86)\windbg.exe" /f
    // 解除启动时windbg调试
    reg delete "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\captcomm.exe" /f
    
    // 64位系统上,也可以设置以下注册表节点
    reg add "HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\captcomm.exe" /v Debugger /t REG_SZ /d "C:\Program Files\Debugging Tools for Windows (x86)\windbg.exe" /f
    // 解除启动时windbg调试
    reg delete "HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\captcomm.exe" /f
    
    // 测试发现:HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options和HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\Image File Execution Options指向的是同一数据,修改其中任何一个都可以

    安全软件可能会禁止修改注册表的Image File Execution项:

    -- 对于360安全卫士,在“设置”中去掉开启360自我保护”的勾选来关闭

    -- 对于McAfee,需要禁止IPS(Intrusion Prevension Systems)。

    -- 然而,电脑管家,则不会对该键值的注册表修改进行阻止。

    #打开dump文件,提示:Debuggee not connected

    解决方法:

    ① 去掉Symbol File Path、Source File Path、Image FilePath中配置的路径

    ② 升级windbg到最新版本

    当前只能从Windows 10 SDK中获取windbg了,详细请查看:下载Windows调试工具 - Windbg

    #重要说明

    (1) windbg命令分为标准命令元命令扩展命令

    标准命令提供最基本的调试功能,不区分大小写。如:bp g dt dv k等
    元命令提供标准命令没有提供的功能,也内建在调试引擎中,以.开头。如.sympath .reload等
    扩展命令用于扩展某一方面的调试功能,实现在动态加载的扩展模块中,以!开头。如!analyze等

    (2) 进入调试状态时,直接回车可重复执行上一条命令;按上下方向键可以浏览和选择以前输入过的命令

    (3) 神奇的Tab键,进行命令补全;ESC清除当前命令输入框中的文本

    (4) 选择Command窗口中的内容,然后右击进行复制

    (5) 使用;作为分隔符,可以在同一行输入多条命令

    (6) 上图红色框中的“0:000”。0当前调试会话的进程号000调试会话的线程号

    (7) 当命令提示符显示*BUSY*时,即使命令输入框可以输入命令,但输入的命令不会立即被执行,要等windbg空闲时才能执行。

         可使用Ctrl + Break来终止一个长时间未完成的命令

    (8) 一次可以执行多条命令,命令间用分号;分隔 【:bp main;bp `view.cpp:120`】,一次打2个断点

    (9)按Ctrl + Alt + V开启/关闭verbose Output(详细输出模式)

    (10) 为了保证windbg流畅运行,在调试时,尽量不要开启Watch、Locals、Registers、Call Stack、Processes and Threads窗口,直接用command来获取信息

    #启动调试

    windbg -I  // 将windbg设置成默认调试器

    windbg "notepad.exe" arguments  // 使用windbg启动调试notepad.exe

    windbg -p 4200  // 将windbg附加到一个正在运行的pid为4200的进程上

    windbg -pn "notepad.exe"  // 将windbg附加到一个正在运行的名为notepad.exe的进程上

    windbg -p 4200 -c "sxd av;sxi c0000005;sxi c0000008;g" // 将windbg附加到一个正在运行的pid为4200的进程上,附加成功后,执行sxd av;sxi c0000005;sxi c0000008;g命令

    windbg –z "c:\mydumpfile.dmp" // 调试mydumpfile.dmp文件

    .opendump "c:\mydumpfile.dmp"  // 调试mydumpfile.dmp文件

    windbg -y d:\mySymbols // 指示symbol路径

    windbg -srcpath d:\Src  // 指示源文件路径

    windbg -i  d:\myApp  //指示exe、dll等可执行模块路径

    .attach 0n4220  // 4220为十进制pid,使用该命令附加调试时,必须先存在一个调试会话

    .detach   // 分离调试

    .restart  // 重启并调试

    .kill  // 强制结束当前调试

    q  // 结束当前调试会话,回到基础工作空间,并结束调试进程

    qd  // 结束当前调试会话,回到基础工作空间,但不结束调试进程

    CTRL+ALT+V  // 打开或关闭 Verbose 模式开关,某些命令在此模式下可以给出更多详细信息

    .time // 调试会话时间信息

    .lastevent  // 显示最新的异常信息或事件信息

    version  // 显示windbg和已加载的调试器扩展相关的信息

    vercommand  // 显示windbg的启动路径及命令行信息

    .chain  // 显示已经加载进来的调试器扩展

    .extmatch /D /e wow64exts *  // 显示wow64exts调试器扩展中的命令

    #获取帮助

    ?   // 打印出所有标准命令

    .help  // 打印出所有元命令

    .hh  // 打开windbg的chm帮助文件

    .hh bp  // 打开windbg的chm帮助文件bp命令介绍页

    command /?  // 打印命令command具体参数用法

    #注释符

    *  // 注释整行

    $$ // 注释(遇到分号结束)

    #配置调试环境

    :如果被调试的模块(无论移动到本机的何处)是用本机代码编译产生的,都不需要进行符号和源代码的路径设置

    .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   注:必须勾选上菜单“Debug”-“Source Mode”;另外pdb须与exe、dll等执行模块匹配上

    .srcpath+ f:\src  // 将f:\src添加到源文件查找路径集合中

    .exepath // 查看可执行文件查找路径

    .exepath f:\bin // 将可执行文件查找路径设为:f:\bin

    .exepath+ f:\bin  // 将f:\bin添加到可执行文件查找路径集合中

    #系统信息

    vertarget // os信息

    !cpuid  // cpu信息

    #wow64模式  【x64版windbg调试win32程序】

    .load wow64exts  // [!load wow64exts] 加载wow64exts.dll模块  注:!sw就是wow64exts中的命令

    .unload wow64exts  // [!unload wow64exts] 卸载wow64exts.dll模块

    .effmach  // 查看当前调试mode:x86、x64等

    .effmach x86 // 切换到x86栈环境  注:需要先执行.load wow64exts来加载wow64exts.dll模块

    .effmach . // 切换回x64

    !sw  // [!wow64exts.sw]  在多个mode:x86、x64上进行循环切换  注:如果win32程序在x64的mode下,会看到地址是64位的

    !k  // [!wow64exts.k]  打印32位、64位堆栈

    !k 5 // [!wow64exts.k 5]  打印32位、64位堆栈,栈帧个数为5

    !info // [!wow64exts.info]  输出wow64相关的PEB、TEB和TLS基本信息

    !r // [!wow64exts.r]  输出处理器当前上下文信息

    !r dumpTest!main  // [!wow64exts.r dumpTest!main]  输出main函数地址的上下文信息

     -- 32位windbg无法打开64位应用程序,会提示如下错误:

    -- 32位windbg无法attach上64位应用程序,会提示如下错误:

    #符号加载与查看

    除了使用ld和.reload命令直接加载符号文件,某些使用符号的命令也可以触发调试器来加载符号,如:栈回溯命令(k*)和反汇编命令(u)等。

    值得说明的是,windbg缺省使用的是懒惰式符号加载策略,当它收到模块加载事件时,它通常是不会加载符号的,符号状态显示为deferred(延迟加载)。

    .symopt // 显示当前所有符号选项

    .symopt+ flags // 添加符号选项

    .symopt- flags // 删除符号选项

    !sym noisy   // 激活详细符号加载(noisy symbol loading)显示

    !sym quiet   // 禁止详细符号加载显示

    ld * // 为所有模块加载符号

    ld kernel32 // 加载kernel32.dll的符号

    .reload // 为所有已加载模块载入符号信息

    .reload /i // 重新加载不匹配符号的模块【dmp文件没有对应的pdb时使用

    .reload /i TGame.exe // 重新加载不匹配符号的TGame.exe

    .reload /f /v // f:强制立即模式(不允许延迟载入)  v:详细模式

    .reload /f @"c:\windows\System32\verifier.dll" // 为指定模块加载符号信息

    .reload /f TGame.exe // 为TGame.exe加载符号信息

    .reload /f UE4Editor_UnLuaInfiniteLoopWatcher_Win64_DebugGame.dll=0x00007ffa6ed90000  // 设置UE4Editor_UnLuaInfiniteLoopWatcher_Win64_DebugGame.dll模块基地址为0x00007ffa6ed90000,并为其加载符号信息

    .reload /u TGame.exe // 卸载TGame.exe及其载符号信息

    x *! // 列出所有模块对应的符号信息

    lm // 列出所有模块(加载和未加载)对应的符号信息

    lmv // 列出所有模块(加载和未加载)对应的符号信息

    lmvm ntdll  // 查看ntdll.dll的详细信息(注意exe、dll等都不要带后缀名)

    !lmi ntdll  // 查看ntdll.dll的详细信息(注意exe、dll等都不要带后缀名)

    !dlls -l  // 按照加载顺序(默认项)列出所有加载的模块

    !dlls -i  // 按初始化顺序列出所有加载的模块

    !dlls -v -c ntdll  // 查看ntdll.dll的详细信息(注意exe、dll等都不要带后缀名)

    ln 0x65777588  // 查看地址0x65777588处或附近的符号信息

    x ConsoleTest!* // 列出ConsoleTest模块中的所有符号

    x ConsoleTest!add* // 列出ConsoleTest模块中的所有add开头的符号

    x /t /v ConsoleTest!* // 带数据类型、符号类型和大小信息,列出ConsoleTest模块中的所有符号

    x kernel32!*LoadLib* // 列出kernel32模块中所有含LoadLib字样的符号

    !itoldyouso mono D:\mySymbols\mono.pdb  // 查看mono.dll与D:\mySymbols\mono.pdb符号是否匹配上

    0:000> !itoldyouso mono D:\mySymbols\mono.pdb

    mono.dll
    Timestamp: 559AAA60
    SizeOfImage: 230000
    pdb: C:\buildslave\mono-runtime-and-classlibs\build\builds\embedruntimes\win32\mono.pdb
    pdb sig: 728334C1-72C3-4A51-B310-C44087FC4B2E
    age: 1

    mono.pdb
    pdb sig: 728334C1-72C3-4A51-B310-C44087FC4B2E
    age: 1

    MATCH: mono.pdb and mono.dll

    -------------------------------------------------------------------------

    使用windbg提供的symchk.exe工具来查找模块的pdb

    symchk.exe Paladins.exe /v /s .\  //在当前目录查找Paladins.exe的pdb,/s后面指定搜索路径  带上/v会输出详细的log

    如果匹配上,会显示如下log:

    [SYMCHK] [ 0x00000000 - 0x001f0001 ] Checked "G:\TGame\symbols\ClientPackaging\Paladins.exe"
    
    SYMCHK: FAILED files = 0
    SYMCHK: PASSED + IGNORED files = 1

    没有匹配上,则显示log为:

    SYMCHK: Paladins.exe         FAILED  - ShippingPC-ChaosGameTencent.pdb mismatched or not found
    
    SYMCHK: FAILED files = 1
    SYMCHK: PASSED + IGNORED files = 0

    #进程

    |   // 列出调试进程

    |*  // 列出调试进程

    |N  // 参看序数为N的调试进程

    |Ns // 切换序数为N的进程为当前调试进程

    !dml_proc  // 显示当前进程信息 

    #线程

    ~   // 列出线程

    ~*  // 所有线程

    ~* k // 所有线程堆栈信息

    ~* r // 所有线程寄存器信息

    ~.  // 查看当前线程

    ~0s // 查看主线程

    ~# // 查看导致当前事件或异常的线程

    ~N  // 查看序数为N的线程

    ~~[n]  // 查看线程ID为n的线程  n为16进制

    ~Ns   // 切换序数为N的线程为当前调试线程

    ~~[n]s  // 切换线程ID为n的线程为当前调试线程  n为16进制

    ~N f  // 冻结序数为N的线程

    ~N u // 解冻序数为N的线程

    ~N n  // Suspend序数为N的线程

    ~N m // Resume序数为N的线程

    ~* e !gle // 显示所有线程最后的一个错误信息  e后可以为任意windbg命令

    .ttime  // 查看当前线程时间信息

    !runaway  //显示当前进程的所有线程用户态时间信息

    !runaway f  //显示当前进程的所有线程用户态、内核态、存活时间信息

    !locks // 显示死锁

    !cs  // 列出CriticalSection(临界段)的详细信息

    #断点

    bl   // 列出所有断点

    bc * // 清除所有断点

    bc 1 // 清除1号断点

    bc 1 2 5  // 清除1号、2号、5号断点

    be *  // 启用所有断点

    be 1  // 启用1号断点

    be 1 2 5 // 启用1号、2号、5号断点

    bd *  // 禁用所有断点

    bd 1  // 禁用1号断点

    bd 1 2 5 // 禁用1号、2号、5号断点

    bp 7c801b00  // 在7c801b00地址处放置一个断点

    bp MyDll+0x1032  // 在模块MyDll.dll偏移0x1032处放置一个断点

    bp `ConsoleTest.cpp:36`  // 在ConsoleTest.cpp的36行处放置一个断点

    bp main // 在main函数的起始处放置一个断点

    bp @$exentry  // 在进程的入口放置一个断点

    bp CSecondLoader::CSecondLoader  // 在CSecondLoader的构造函数处放置一个断点

    bp TestCommon! CTest::add  // 在TestCommon.dll的Test.cpp文件的CTest::add()函数起始处放置一个断点

    bp `ConsoleTest.cpp:40` ".if (poi(pVar)>5) {}; {g}" // ".if (Condition) {Optional Commands}; {g}"    条件断点 pVar指针指向的值>5,执行空语句;),断住  否则继续执行

    bp `ConsoleTest.cpp:40` "j (poi(pVar)>5) ' ''g'" // "j (Condition) 'Optional Commands'; 'g'"    j为条件表示式:条件断点 pVar指针指向的值>5,执行空语句;,断住  否则继续执行

    注:Condition表达式语法默认的是MASM表达式语法。使用复杂C++表达式时我们需要用@@c++()将表达式包围住;如:"j @@c++(*pVar>5) ' '; 'g'"

    ---------------------------------

    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) 返回第一个指针所指向的值

    ---------------------------------

    bp `ConsoleTest.cpp:40` "j @eax = 0xa3 ''; 'g'" // j为条件表示式:条件断点 寄存器eax的值为0xa3时断住

    bp kernel32!CreateFileA  // 在系统API的CreateFileA函数处放置一个断点

    bp kernel32!CreateFileA ".echo;.printf\"CreateFileA(%ma,%p,%p), ret=\",poi(esp+4),dwo(esp+8),dwo(esp+c);gu;.printf\"%N\",eax;.echo;g" // 不断住进程情况下,打印所有的CreateFileA调用

    bp kernel32!CreateFileW ".echo;.printf\"CreateFileW(%mu,%p,%p), ret=\",poi(esp+4),dwo(esp+8),dwo(esp+c);kn;g;"  // 不断住进程,打印所有的CreateFileW调用及堆栈信息

    bp advapi32!RegOpenKeyExA ".echo;.printf\"RegOpenKeyExW(%p,\\\"%ma\\\",%N,%N,%p) returned: \", dwo(esp+4), poi(esp+8), dwo(esp+c), dwo(esp+10), dwo(esp+14);gu;.printf\"%N\",eax;.echo;g"  // 不断住进程情况下,打印所有的RegOpenKeyExA调用(打开注册表键值)

    ---------------------------------

    注意:有些函数Symbol Name与导出函数名可能不一致,例如SetWindowPos,这时可以用Dependency查看相应的导出函数地址(Entry Point列):0x00018E5E,然后在windbg菜单“Debug”—〉“Modules...”对话框中获得user32.dll模块起始地址0x77d10000,在两个值相加后的绝对地址处直接设置断点:bp 77d28E5E;也可以通过x user32!*命令列出全部Symbols列表,查找77d28E5E,找到SetWindowPos对应的Symbol Name为“NtUserSetWindowPos”,然后通过符号设置断点:bp user32!NtUserSetWindowPos。通过符号设置断点的好处是当dll代码改变时,不需要修改,windbg会根据符号来自动匹配函数地址。

    ---------------------------------

    bu  // 保存断点,其用法和bp一样

    bm add_*  // 匹配add_开头的函数,并在这些函数起始处都打上断点

    ba w4 0x0483dfe0 // 当对0483dfe0地址写操作时停下,前面要带上0x,否则会报错

                              // ba [r|w|e] [Size] Addr      [r=read/write, w=write, e=execute], Size=[1|2|4 bytes]

    windbg无参脚本

    // 当CreateFileW读取UnityLockfile文件时断住进程,在命令输入框输入:$$><d:\CreateFileWNoArguScript.txt,CreateFileWNoArguScript.txt内容如下:

    bp kernel32!CreateFileW "
    r $t1=poi(esp+4)
    as /mu $FileName $t1
    .echo
    .printf\"File:%mu\",$t1
    .echo
    .block
    {
    .if($spat(\"${$FileName}\",\"*UnityLockfile\")) 
    {
      .echo 'find...';
      ad ${/v:$FileName}
    }
    .else 
    {
      .echo no find...
      ad ${/v:$FileName}
      gc
    }
    }"

    windbg有参脚本

    // 当CreateFileW读取mscorlib.dll文件时断住进程,在命令输入框输入:$$>a<d:\CreateFileWArguScript.txt mscorlib.dll,CreateFileWArguScript.txt内容如下:

    bp kernel32!CreateFileW "
    r $t1=poi(esp+4)
    as /mu $FileName $t1
    .echo
    .printf\"File:%mu\",$t1
    .echo
    .block
    {
    .if($spat(\"${$FileName}\",\"*${$arg1}\")) 
    {
      .echo 'find...';
      ad ${/v:$FileName}
    }
    .else 
    {
      .echo no find...
      ad ${/v:$FileName}
      gc
    }
    }"

    #调试执行控制

    g  // Go(F5)

    gH // 执行gH命令强制让调试器返回已经处理了这个异常。【Go with Exception Handled

         // 系统收到这个回复后会停止分发异常(因为调试器声称已经处理了异常),恢复调试目标继续执行,

         //  但由于异常条件仍在,所以还会产生异常,于是再次分发,WinDBG再次中断到命令模式。

    gN // Go with Exception Not Handled

         // 执行gN命令强制让调试器返回没有处理了这个异常,那么系统会进一步分发该异常,

         // 如果没有其他调试器也不处理,最后系统会弹出程序终止对话框。

    gu  // 执行到当前函数完成时停下Go Up

    Ctrl+Break  // 暂停正在运行的程序

    p    // 单步执行(F10)  【Step

    p 2 // 2为步进数目

    pc   // 执行到下一个函数调用处停下Step to  Next Call

    pa 7c801b0b // 执行到7c801b0b地址处停下  【Step to Adress

    t     // Step into(F11) 【Trace

    tc    // 执行到下一个进入点(Call指令)处停下 【Trace to Next Call

    tb  // 执行到分支指令停下【分支指令包括calls、returns、jumps、loops】

    ta 7c801b12  // 执行到7c801b12地址处停下 【Trace to Adress

    WT  Trace and Watch Data,一条强大指令,对执行流程做Profile

    # 查看句柄

    !handle  // 查看所有句柄的ID

    !handle 000007f8 1  // 查看ID为000007f8的句柄的类型

    !handle 000007f8 4  // 查看ID为000007f8的句柄的名称

    !handle 0 5  // 查看所有句柄的类型和名称

    !htrace -enable  // 使用windbg调试运行时,启用跟踪所有打开句柄或关闭句柄的调用以及相应的栈回溯

    !htrace  // 进程运行结束后,打印所有打开句柄或关闭句柄的调用以及相应的栈回溯

    !htrace -diff  // 只打印没有关闭的句柄的信息及栈回溯

    Handle = 0x00000038 - OPEN
    Thread ID = 0x00001f34, Process ID = 0x00000638

    0x049ca83c: +0x049ca83c
    0x049d5eb4: +0x049d5eb4
    0x046c8313: +0x046c8313
    0x76d2d90a: +0x76d2d90a
    0x7451c1ff: +0x7451c1ff
    0x7450d18f: +0x7450d18f
    0x74492776: +0x74492776
    0x7450d286: +0x7450d286
    0x7450c69e: +0x7450c69e
    0x76d210d6: +0x76d210d6
    0x76d7dc30: +0x76d7dc30
    0x76d0b17e: +0x76d0b17e
    0x76ee0166: ntdll!NtCreateFile+0x00000012
    0x7542c76b: KERNELBASE!CreateFileW+0x0000035e
    0x752c3f66: kernel32!CreateFileW+0x0000004a
    0x752c53c4: kernel32!CreateFileA+0x00000036

    --------------------------------------
    Parsed 0x1 stack traces.
    Dumped 0x1 stack traces.

    # 查看变量

    ===  0n(十进制)  0x(十六进制)  0t(8进制)  0y(2进制)    可以使用n [8|10|16]命令来修改数值进制表示方式(输入n可查看当前进制,默认为16进制)===

    -- VC6.0的Link选项需要将/pdbtype:sept改为/pdbtype:con, 否则生成的pdb文件中将不包含如自定义结构体,类等信息

    dt nRet  // 查看局部变量nRet的类型与值(函数参数变量请用dv命令) --注:编译器很多时候会把一些局部变量优化掉,这个时候就会出现找不到nRet符号的情况

    dt ntdll!* // 显示ntdll里的所有类型信息

    dt *!*IMAGE_DOS*  // 显示所有模块中含有IMAGE_DOS字符的类型信息

    test1!IMAGE_DOS_HEADER
    test1!PIMAGE_DOS_HEADER
    test1!_IMAGE_DOS_HEADER
    ntdll!_IMAGE_DOS_HEADER
    ntdll32!_IMAGE_DOS_HEADER
    MSVCR90D!IMAGE_DOS_HEADER
    MSVCR90D!PIMAGE_DOS_HEADER
    MSVCR90D!_IMAGE_DOS_HEADER

    dt myApp!g_app // 表示显示myApp进程里全局变量g_app的内存布局(注:vc6见上述说明)

    dt WindbgTest!CTest // 查看模块WindbgTest的CTest的内存布局,加上-b -r参数可以显示内部类及数组的信息(注:vc6见上述说明)

    dt WindbgTest!CTest 0x0041f8d4  // 将0x0041f8d4地址处内容按照模块WindbgTest的CTest的内存布局来解析(注:vc6见上述说明)

    Windbg默认会用寄存器ECX里面的值作为this指针地址,其实这样是有时候是错误的。
    有些C++编译器在做代码优化之后会把 this指针放在其他寄存器里面,比如ESI。
    所以在调试的时候还需要读一下汇编代码来确定this 在哪个寄存器里面。
    比如我们看到 MOV EAX, dword ptr [ESI + 0x48h](获取当前对象内存偏移为0x48h处的4字节成员变量),就可以判断ESI 是this 指针。
    这时可以通过如下命令打印this的内存结构:dt -b 模块名!类名 @esi

    dt tagMSG 0x0336e54c  // 类型要使用tagMSG,不能使用typedef产生出的MSG

    typedef struct tagMSG {
        HWND hwnd;
        UINT message;
        WPARAM wParam;
        LPARAM lParam;
        DWORD time;
        POINT pt;
    } MSG, *PMSG;

    dt this // 查看this指针的类型及成员变量(注:vc6见上述说明)

    dt -b this  // 查看this指针的类型及成员变量,如果某一成员变量为结构体,则把其结构成员也一一打印出来

                   // -b开关指定递归显示所有子类型信息,-r[n]指定递归显示的深度,如-r0表示不显示子类型信息

    dt -v _PEB @$PEB // 使用详细模式查看PEB(process's environment block)内存结构

    dt _TEB ny LastErrorValue // 只查看TEB(thread's environment block)结构成员LastErrorValue

    ?? this->m_nPen  // 查看成员变量的值(注:vc6见上述说明)

    ?? this // 查看this指针中的成员变量(注:vc6见上述说明)

    ?? sizeof(double)   // 获取double类型的大小

    ?? sizeof(this->m_nPen) // 获取this->m_nPen变量的大小

    ? nCount // 显示局部变量nCount的地址(前面4198608为10进制表示地址,004010d0为16进制表示地址) 形如:Evaluate expression: 4198608 = 004010d0

    ? HeapTest!CTest::Add  // 显示HeapTest模块中CTest类中的Add函数地址

    dv   // 显示当前函数内所有局部变量,函数参数的值

    dv n*  // 显示当前函数内n开头的所有局部变量,函数参数的值

    dv nCount // 查看局部变量nCount的值

    dv a // 查看函数参数变量a的值

    dv /t /i /V /a|/n|/z

    /***************************************** 

    更加详细地显示当前函数内所有局部变量,函数参数信息
    i = type (local, global, parameter)
    t = data type
    V = memory address or register location
    -----------------------
    a = sort by Addr, n = sort by name, z = sort by size

    *****************************************/

    x  // 用法和dv命令一致,显示当前函数内所有局部变量,函数参数变量的地址与值  --注:编译器很多时候会把一些局部变量优化掉,这个时候就会出现找不到符号的情况

    #调用堆栈

    k  // 显示当前调用堆栈

    kn // 带栈编号显示当前调用堆栈

    kb  // 打印出前3个函数参数的当前调用堆栈

    02a9ffec 00000000 01e511f9 0174c570 00000000 kernel32!BaseThreadStart+0x37
    ----------------------------------------------
    kernel32!BaseThreadStart+0x37 当前函数kernel32!BaseThreadStart执行的指令地址。
    01e511f9 0174c570 00000000  参数相关的数值【从左到右 -- 参数1  参数2:offset为sizeof(参数1)  参数3:offset为sizeof(参数1)+sizeof(参数2)  ...】。注:如果是成员函数,this指针通过ecx或其他寄存器来传递
    02a9ffec 00000000是 当前函数ebp 和 上层函数返回地址。

    ======================================================

    Windows 7 Ultimate Service Pack 1 [Build 6.1.7601]
    CPU: Intel(R) Core(TM) i3-2100 CPU @ 3.10GHz
    《Game》 20.15.1112 6EF76A43E6B1DD58907F3E066506E918
    ----------------------------------------
    Type: EXCEPTION_ACCESS_VIOLATION//非法地址访问异常
    Error: Read address 0x00074685//读取0x00074685地址出错(该地址对应的内存页,进程无读取权限)
    Address: 64DCAF68//崩溃发生的指令地址

    CallStack:

    //0x64D90000为模块MSVCR90.dll的基地址,3AF68为崩溃指令在模块中的偏移值,(0492B5D0,00074685,0000000C,00462482)为参数信息
    0x64D90000[3AF68] MSVCR90.dll: (0492B5D0,00074685,0000000C,00462482)
    0X00400000[11158A] tgame.exe: (0492B5D0,00074685,00000000,00000000)

    kb 5 // 只显示最上的5层调用堆栈

    kv   // 在kb的基础上增加了函数调用约定、FPO等信息

    kp  // 显示每一层函数调用的完整参数,包括参数类型、名字、取值(必须是完整符号的情况下,private symbols);注意:若程序被优化,这些值不一定对

    kd  // 打印堆栈的地址

    kD  // 从当前esp地址处,向高地址方向搜索符号(注:函数是符号的一种)

    dds 02a9ffec  // 从02a9ffec地址处,向高地址方向搜索符号(注:函数是符号的一种)

    dds  // 执行完dds 02a9ffec后,可通过dds命令继续进行搜索

    .frame // 显示当前栈帧

    .frame n  // 显示编号为n的栈帧(n为16进制数)

    .frame /r n // 显示编号n的栈帧(n为16进制数) 并显示寄存器变量

    .frame /c n // 设置编号n的栈帧为当前栈帧(n为16进制数)

    !uniqstack // 显示所有线程的调用堆栈

    !findstack kernel32 2 // 显示包含kernel32模块(用星号标出)的所有栈的信息

    +++++++++++++++++++++++++++++++++++++++++++

    案例:某个Unity游戏在关闭时的崩溃堆栈

    具体崩溃的原因:0x47e2740为游戏脚本中编写的新窗口处理函数地址,关闭程序时,游戏脚本从内存中被卸载,0x47e2740变成了野指针引发崩溃

    注:0x47e2740是游戏脚本新窗口处理函数被虚拟机JIT产生出来的地址,在线程的Native栈上是没有符号的,托管代码都有这个特点

    #查看汇编

    u .  // 反汇编当前eip寄存器地址的后8条指令

    u $eip  // 反汇编当前eip寄存器地址的后8条指令

    ub .  // 反汇编当前ip寄存器地址的前8条指令

    ub $eip  // 反汇编当前eip寄存器地址的前8条指令

    u main+0x29 L30 // 反汇编main+0x29地址的后30条指令

    u  // 反编译下8条指令

    uf CTest::add  // 反汇编CTest类的add函数

    uf /c main  // 反汇编main函数,通过/c可以查看main函数中的函数调用(call)都有哪些

    ub 000c135d L20  // 查看地址为000c135d指令前的20条指令内容

    #寄存器

    r // 显示所有寄存器信息及发生core所在的指令

    r eax, edx // 显示eax,edx寄存器信息

    r eax=5, edx=6  // 对寄存器eax赋值为5,edx赋值为6

    #内存

    -- 注:windbg不支持中文显示

    !address // 查看进程的所有内存页属性

    !address -summary  // 显示进程的内存统计信息  要为fulldmp才会准确

    !address -f:stack  // 查看栈的内存信息,红框为主线程、篮框为windbg注入的远程线程

    !address 7ffd8000  // 查看7ffd8000地址处内存页属性

    dd /c 5 7c801e02  // 从7c801e02内存处开始以dword为单位显示内存(宽度为:5)【默认显示128字节长度的内容】

    dd /c 5 7c801e02 L8  // 从7c801e02内存处开始以dword为单位显示内存(宽度为:5)【显示8个dword】

    da /c 100 7c80ff03  // 从7c80ff03内存处开始显示Ascii字符串(宽度为:100)

    du /c 100 7c8022f5  // 从7c8022f5内存处开始显示Unicode字符串(宽度为:100)

    /*****************************************

    d[a| u| b| w| W| d| c| q| f| D] [/c 列数] [地址]

    a = ascii chars
    u = Unicode chars
    b = byte + ascii   -- 和UE一样,左边为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)

    *****************************************/

    dyb /c 3 7c801e02  // 从7c801e02内存处开始,显示byte及二进制(宽度为:3)

    /*****************************************

    dy[b | d] ..   // b = binary+byte     d = binary+dword

    *****************************************/

    s -w 522e0000 L0x100  0x1212 0x2212 0x1234 // 表示在起始地址522e0000之后的0x100个单位内搜索0x1212 0x2212 0x1234系列的起始地址

    s -u 522e0000 527d1000 "web"  //表示在522e0000 和527d1000之间搜索Unicode 字符串”web”

    ea 0x445634 "abc"  // 表示在0x445634地址写入Ascii字符串abc, 不包含结束符0

    eza 0x445634 "abc"  // 表示在0x445634地址写入Ascii字符串abc, 包含结束符0

    eu 0x445634 "abc"  // 表示在0x445634地址写入Unicode字符串abc, 不包含结束符0

    ezu 0x445634 "abc"  // 表示在0x445634地址写入Unicode字符串abc, 包含结束符0

    ed nCounter 80  // 将变量nCounter的值修改为80(注:80为10进制还是16进制,还是其他,取决于当前进制)

    .writemem D:\Test\0041a5e4.bin 0041a5e4 L1000  // 将内存地址处0x0041a5e4后面0x1000长度的内容拷贝存储到D:\Test\0041a5e4.bin中

    #查看堆(Heap)

    !heap -s  // 显示进程堆的个数(每一项是一个堆,也就是_HEAP结构指针,对应的API是HeapCreate)

    Heap Flags Reserv Commit Virt Free List UCR Virt Lock Fast
    (k) (k) (k) (k) length blocks cont. heap
    -----------------------------------------------------------------------------
    00140000 50000062 1024 12 12 1 1 1 0 0 L
    00240000 50001062 64 24 24 15 1 1 0 0 L
    00250000 50008060 64 12 12 10 1 1 0 0
    00380000 50001063 64 12 12 4 2 1 0 bad
    -----------------------------------------------------------------------------

    dt _HEAP 00140000  // 选取一个堆的地址,打印该堆的内存结构

    ntdll!_HEAP
    +0x000 Entry : _HEAP_ENTRY
    +0x008 Signature : 0xeeffeeff
    +0x00c Flags : 0x50000062
    +0x010 ForceFlags : 0x40000060
    +0x014 VirtualMemoryThreshold : 0xfe00
    +0x018 SegmentReserve : 0x100000
    +0x01c SegmentCommit : 0x2000
    +0x020 DeCommitFreeBlockThreshold : 0x200
    +0x024 DeCommitTotalFreeThreshold : 0x2000
    +0x028 TotalFreeSize : 0xaf
    +0x02c MaximumAllocationSize : 0x7ffdefff
    +0x030 ProcessHeapsListIndex : 1
    +0x032 HeaderValidateLength : 0x608
    +0x034 HeaderValidateCopy : (null)
    +0x038 NextAvailableTagIndex : 0
    +0x03a MaximumTagIndex : 0
    +0x03c TagEntries : (null)
    +0x040 UCRSegments : (null)
    +0x044 UnusedUnCommittedRanges : 0x00140598 _HEAP_UNCOMMMTTED_RANGE
    +0x048 AlignRound : 0x17
    +0x04c AlignMask : 0xfffffff8
    +0x050 VirtualAllocdBlocks : _LIST_ENTRY [ 0x140050 - 0x140050 ]
    +0x058 Segments : [64] 0x00140640 _HEAP_SEGMENT
    +0x158 u : __unnamed
    +0x168 u2 : __unnamed
    +0x16a AllocatorBackTraceIndex : 0
    +0x16c NonDedicatedListLength : 1
    +0x170 LargeBlocksIndex : (null)
    +0x174 PseudoTagEntries : (null)
    +0x178 FreeLists : [128] _LIST_ENTRY [ 0x142a90 - 0x142a90 ]
    +0x578 LockVariable : 0x00140608 _HEAP_LOCK
    +0x57c CommitRoutine : (null)
    +0x580 FrontEndHeap : 0x00140688 Void
    +0x584 FrontHeapLockCount : 0
    +0x586 FrontEndHeapType : 0x1 ''
    +0x587 LastSegmentIndex : 0 ''

    !heap -a 00140000 // 选取一个堆的地址,打印该堆的信息,比上面打印内存命令更详细直观

    Index Address Name Debugging options enabled
    1: 00140000
    Segment at 00140000 to 00240000 (00003000 bytes committed)
    Flags: 50000062
    ForceFlags: 40000060
    Granularity: 8 bytes
    Segment Reserve: 00100000
    Segment Commit: 00002000
    DeCommit Block Thres: 00000200
    DeCommit Total Thres: 00002000
    Total Free Size: 000000af
    Max. Allocation Size: 7ffdefff
    Lock Variable at: 00140608
    Next TagIndex: 0000
    Maximum TagIndex: 0000
    Tag Entries: 00000000
    PsuedoTag Entries: 00000000
    Virtual Alloc List: 00140050
    UCR FreeList: 00140598
    FreeList Usage: 00000000 00000000 00000000 00000000
    FreeList[ 00 ] at 00140178: 00142a90 . 00142a90
    00142a88: 00050 . 00578 [14] - free
    Segment00 at 00140640:
    Flags: 00000000
    Base: 00140000
    First Entry: 00140680
    Last Entry: 00240000
    Total Pages: 00000100
    Total UnCommit: 000000fd
    Largest UnCommit:000fd000
    UnCommitted Ranges: (1)
    00143000: 000fd000

    Heap entries for Segment00 in Heap 00140000
    00140000: 00000 . 00640 [01] - busy (640)
    00140640: 00640 . 00040 [01] - busy (40)
    00140680: 00040 . 01818 [07] - busy (1800), tail fill - unable to read heap entry extra at 00141e90
    00141e98: 01818 . 00040 [07] - busy (22), tail fill - unable to read heap entry extra at 00141ed0
    00141ed8: 00040 . 00050 [07] - busy (36), tail fill - unable to read heap entry extra at 00141f20
    00141f28: 00050 . 002f0 [07] - busy (2d8), tail fill - unable to read heap entry extra at 00142210
    00142218: 002f0 . 00330 [07] - busy (314), tail fill - unable to read heap entry extra at 00142540
    00142548: 00330 . 00330 [07] - busy (314), tail fill - unable to read heap entry extra at 00142870
    00142878: 00330 . 00040 [07] - busy (24), tail fill - unable to read heap entry extra at 001428b0
    001428b8: 00040 . 00028 [07] - busy (10), tail fill - unable to read heap entry extra at 001428d8
    001428e0: 00028 . 00058 [07] - busy (40), tail fill - unable to read heap entry extra at 00142930
    00142938: 00058 . 00058 [07] - busy (40), tail fill - unable to read heap entry extra at 00142988
    00142990: 00058 . 00060 [07] - busy (44), tail fill - unable to read heap entry extra at 001429e8
    001429f0: 00060 . 00020 [07] - busy (1), tail fill - unable to read heap entry extra at 00142a08
    00142a10: 00020 . 00028 [07] - busy (10), tail fill - unable to read heap entry extra at 00142a30
    00142a38: 00028 . 00050 [07] - busy (36), tail fill - unable to read heap entry extra at 00142a80
    00142a88: 00050 . 00578 [14] free fill
    00143000: 000fd000 - uncommitted bytes.

    #虚拟内存

    !vadump  // 查看虚拟内存布局 

    #设置事件发生时windbg行为

    sx // 显示windbg遇到每个异常和事件时的行为

    sxr // 将所有异常和事件过滤器的状态重设为默认值

    sxe  ld // 当加载模块时,立即中断(Break)到调试器中(First-Chance)

    sxe ld mono.dll  // 当加载mono.dll模块时,立即中断(Break)到调试器中(First-Chance)

    sxd ud // 当卸载模块时,windbg不会在第一次处理机会时中断(虽然会显示信息)。如果其他错误处理器没有处理掉该异常,执行会停止下来并中断(Break)到windbg中(Second-Chance)

    sxd av // 所有异常和事件只有Second-Chance才中断到调试器

    sxn et // 当线程退出时,windbg会打印出一条消息

    sxi ct // 当线程创建时,windbg不中断也不打印消息

    sxi c0000005  // 不中断也不打印code码为c0000005的异常

    #dump输出

     .dump /ma "d:\mydmpfile.dmp" // 将当前调试进程输出Dump文件

    #其他元命令

    .tlist  // 显示所有进程

    .cls  // 清除屏幕

    .shell config.bat  // 执行config.bat批处理文件

    .shell tasklist  // 列出所有进程信息

    .formats 'a'  // 显示字母a的各种类型对应的信息

    .logopen c:\1.log   // 将command内容输出到c:\1.log文件中

    .logclose  // 关闭当前打开的日志

    #其他扩展命令

    !analyze -v  // 详细显示当前异常信息

    !analyze -hang  // 诊断线程调用栈上是否有任何线程阻塞了其他线程

    !analyze -f  // 查看异常分析信息,尽管调试器并未诊断出异常

    !tls -1 // 显示当前线程所有的slot信息

    !tls 2   // 显示当前线程索引为2的slot信息

    !peb // 格式化输出PEB信息(process's environment block)

    PEB at 7efde000
    InheritedAddressSpace: No
    ReadImageFileExecOptions: No
    BeingDebugged: No
    ImageBaseAddress: 00f20000
    Ldr 76fa0200
    Ldr.Initialized: Yes
    Ldr.InInitializationOrderModuleList: 003a4d78 . 003e4a00
    Ldr.InLoadOrderModuleList: 003a4ce8 . 003e49f0
    Ldr.InMemoryOrderModuleList: 003a4cf0 . 003e49f8
    Base TimeStamp Module
    f20000 54772f74 Nov 27 22:04:36 2014 C:\Program Files (x86)\Citrix\ICA Client\wfcrun32.exe
    76ea0000 5684255b Dec 31 02:41:31 2015 C:\windows\SysWOW64\ntdll.dll
    74790000 568425ff Dec 31 02:44:15 2015 C:\windows\syswow64\kernel32.dll
    75b00000 56842600 Dec 31 02:44:16 2015 C:\windows\syswow64\KERNELBASE.dll
    ... ...
    71d40000 55a5cad6 Jul 15 10:52:06 2015 C:\windows\System32\msxml6.dll
    71d20000 4a5bdb38 Jul 14 09:11:20 2009 C:\windows\System32\bcrypt.dll
    71ce0000 5600ce51 Sep 22 11:43:13 2015 C:\windows\SysWOW64\bcryptprimitives.dll
    SubSystemData: 00000000
    ProcessHeap: 003a0000
    ProcessParameters: 003a2188
    CurrentDirectory: 'C:\windows\system32\'
    WindowTitle: '"C:\Program Files (x86)\Citrix\ICA Client\wfcrun32.exe"'
    ImageFile: 'C:\Program Files (x86)\Citrix\ICA Client\wfcrun32.exe'
    CommandLine: '"C:\Program Files (x86)\Citrix\ICA Client\wfcrun32.exe" -Embedding'
    DllPath: 'C:\Program Files (x86)\Citrix\ICA Client;C:\windows\system32;C:\windows\system;C:\windows;
    Environment: 003a07f0
    =::=::\
    ALLUSERSPROFILE=C:\ProgramData
    APPDATA=C:\Users\kekec\AppData\Roaming
    CommonProgramFiles=C:\Program Files (x86)\Common Files
    CommonProgramFiles(x86)=C:\Program Files (x86)\Common Files
    CommonProgramW6432=C:\Program Files\Common Files
    COMPUTERNAME=KEKEC-PC1
    ComSpec=C:\windows\system32\cmd.exe
    DXSDK_DIR=D:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\
    FP_NO_HOST_CHECK=NO
    HOMEDRIVE=C:
    HOMEPATH=\Users\kekec
    include=D:\Program Files (x86)\Microsoft Visual Studio\VC98\atl\include;D:\Program Files (x86)\Microsoft Visual Studio\VC98\mfc\include;
    lib=D:\Program Files (x86)\Microsoft Visual Studio\VC98\mfc\lib;D:\Program Files (x86)\Microsoft Visual Studio\VC98\lib
    LOCALAPPDATA=C:\Users\kekec\AppData\Local
    LOGONSERVER=\\GM-HEIJI
    MSDevDir=D:\Program Files (x86)\Microsoft Visual Studio\Common\MSDev98
    NUMBER_OF_PROCESSORS=8
    OS=Windows_NT
    Path=C:\ProgramData\Oracle\Java\javapath;C:\windows\system32;C:\windows;C:\Program Files\Intel\Intel(R) Management Engine Components\DAL;
    PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC
    PROCESSOR_ARCHITECTURE=x86
    PROCESSOR_ARCHITEW6432=AMD64
    PROCESSOR_IDENTIFIER=Intel64 Family 6 Model 60 Stepping 3, GenuineIntel
    PROCESSOR_LEVEL=6
    PROCESSOR_REVISION=3c03
    ProgramData=C:\ProgramData
    ProgramFiles=C:\Program Files (x86)
    ProgramFiles(x86)=C:\Program Files (x86)
    ProgramW6432=C:\Program Files
    PSModulePath=C:\windows\system32\WindowsPowerShell\v1.0\Modules\
    PUBLIC=C:\Users\Public
    SESSIONNAME=Console
    SystemDrive=C:
    SystemRoot=C:\windows
    TEMP=C:\Users\kekec\AppData\Local\Temp
    TMP=C:\Users\kekec\AppData\Local\Temp
    USERDNSDOMAIN=TENCENT.COM
    USERDOMAIN=TENCENT
    USERNAME=kekec
    USERPROFILE=C:\Users\kekec
    VS120COMNTOOLS=D:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\Tools\
    VS80COMNTOOLS=D:\Program Files (x86)\Microsoft Visual Studio 8\Common7\Tools\
    VS90COMNTOOLS=d:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\Tools\
    windir=C:\windows

    !gle  // 打印当前线程最近的错误信息LastError

    !gle -all  // 打印所有线程的最近的错误信息

    !error  897// 显示错误码为897的详细描述信息

    #帮助

    中文在线帮助:http://www.dbgtech.net/windbghelp/index.html

    windbg cmd: http://www.slideshare.net/kewuc/windbg-cmds 【下载

    WinDbg 命令三部曲:(一)WinDbg 命令手册

  • 相关阅读:
    学习第57天
    学习第56天
    学习第55天
    学习第54天
    学习第53天
    学习第52天
    学习第51天
    学习第50天
    MVVM模式
    css盒模型
  • 原文地址:https://www.cnblogs.com/kekec/p/2798020.html
Copyright © 2011-2022 走看看