Windbg 命令 总结

基本调试:
        0. 内置的帮助命令:
        ? 显示常用的命令
        ? /D 显示常用命令和DML
        .help 显示.命令
        .help /D   以DML形式显示'.'命令(顶部会给出链接)
        .help /D a* 以DML形式显示a开头的'.'命令 (*为通配符)
        .hh 打开帮助文件
        .hh dt 打开帮助文件,并在索引定位到 dt命令

        version 显示调试器以及加载扩展版本信息
        vertarget 显示目标计算机的版本
        n [8|10|16] 设置调试器数基,8进制,10进制等

        .cls 清空界面

1. 常用'.'命令
        .srcpath 显示或设置源码的检索路径
        .srcpath+ 目录 将目录添加到检索到的源码路径
        .lines [-e|-d|-t] 切换源码行的支持,可用,禁用,切换
        
        .srcnoisy 1 显示源码的搜索过程  .srcnoisy 0 不显示源码的搜索过程。
        
        小写'L'的命令
                l+l,l-l 显示行数
                l+o, l-o 除了[s]隐藏一切
                l+s, l-s 源码和行数
                l+t, l-t 源码模式对汇编模式

        例如:
                .srcpath C:\Users\Administrator\Desktop\WinDbug\TestDebug1 
                添加源码的路径,模块可以与源码结合,看到源码中的调试过程

                .exepath C:\Users\Administrator\Desktop\exefiles
                在调试dump文件时才会用得上可执行映像路径。需要将这个路径设置为调试的exe,dll,sys等可执行文件的路径。

        调试日志
                .logopen /t d:\logs\mylogfile.txt 打开日志文件 
                .logappend /t d:\logs\mylogfile.txt 向日志文件中追加 日志
                .logclose 关闭日志文件
                注:在关闭一次调试时,要关闭日志文件。

        调试会话:
                .attach  PID (在调试一个进程中),附加到一个进程
                .detach 结束调试会话,但是保留用户模式目标程序运行
                q / qq 结束调试会话,并终止目标程序
                .restart 重启目标程序

2. 符号相关
        ld 模块名 加载指定模块符号
        ld * 加载所有模块的符号
        !sym 获取符号加载情况( !sym noisy 显示搜索符号过程,!sym quiet 默认)

        x 可以列举模块的名字
                x [选项] 模块!符号
                选项: /t 带数据类型
                             /v 详情,包括符号类型与大小
                             /a 按照地址分类
                             /n 按照名称分类
                             /z 按照大小分类(函数在内存中的大小)

                x [选项]模块名字!符号匹配表达式   可以查找一些函数名字,以方便下断点
                比如: x  user32!GetWindowT*   列举出 USER32.dll中的 GetWindowT开头的所有的函数。

                x /t /v notepad!*  用于列举出notepad模块的public函数以及变量

        ln 地址 列出最近的符号,显示给出地址附近的符号,用于确定指针指向位置以及在损坏栈中,确定栈的调用程序。
                ln 01001b90 列举出地址01001b90附近的符号

        .sympath  路径 设置符号路径
        .sympath+ 路径 添加符号路径
        .symfix 路径 设置符号存储路径
        .symfix+ 保存路径 附加到现有路径,当作符号下载流存储位置

        .reload 为所有模块重载符号信息
        .reload [/f|/v] /f 强制立即加载符号, /v 详细模式
        .reload [/f|/v] 模块 同上,只是针对特定模块
        .reload /d 重新加载调试器中的所有模块符号
                      /l 列出所有的模块但是不重新加载符号
                      /n 重新加载内核符号
                      /user 重新加载用户模式符号
                      /u 卸载指定模块和它的符号
        例如:
                .sympath C:\Users\Administrator\Desktop\WinDbug
                设置程序的符号路径为 C:\Users\Administrator\Desktop\WinDbug
                .symfix+  D:\Symbols 
                添加系统模块的符号路径,即微软公共符号的本地存储位置(会被WinDbg自动添加为 D:\Symbols;SRV*http://msdl.microsoft.com/download/symbols)

        .reload  /u ntdll.dll   卸载ntdll.dll
        .reload  /s /f ntdll.dll 加载ntdll.dll

        注:添加完符号路径后,可以使用 .reload 命令重新加载符号


        命令的扩展:
                x *!*   列出所有的模块
                x ntdll!*   列出ntdll的所有符号
                x /t /v MyDll!* 列出MyDll的所有符号的数据类型,符号类型和大小

                .reload /f @"ntdll.dll" 立刻从ntdll.dll重载符号

3. 命令窗口
        0:000>  这个提示符号:
        第一个0,表示当前的进程号,冒号后的 000表示当前的线程号。
        *BUSY*这样的字符串,表示调试器正忙。

        单核的内核调试为 kd>,而多核的系统以0:kd> 表示内核调试,0表示处理器号

        输入命令:
                Esc 可以消除当前行
                Tab 键可以自动补充命令
                鼠标点击右键,可以将剪切板上的内容粘贴到命令行输入框
                直接按Enter键,可以重复上一条命令
                Ctrl-Break来中断一条没有执行完毕的命令

        伪寄存器:
                $ip = eip / rip x86/x64上的ip寄存器
                $ra = 当前函数的返回地址
                $retreg  返回值  eax - rax - ret0 分别针对x86/x64/Itanium
                $csp  当前栈指针, esp - rsp - bsp
                $proc  用户态的进程环境块PEB地址
                $thread 线程环境块 TEB
                $tpid 当前进程的标识 PID
                $tid 当前线程的标识TID

4. 反汇编:
        u 反汇编当前IP寄存器位置的内容
        u $ip  反汇编当前 $ip上的8条命令

        uf $ip 反汇编当前$ip地址上的整个函数
        uf addr 反汇编addr地址上的整个函数

        ub
                ub $ip  反汇编$ip之前的8条指令
                ub $ip L2a  反汇编$ip 地址之前的42条指令

        u $ip  $ip+a 反汇编两个地址之间的指令其中不包括$ip+a地址处的指令

5. 线程与进程相关:
        |         显示所有正在被调试的进程的状态
        .tlist   列出系统正运行的所有进程
        !peb 显示进程环境块 PEB 的标准视图

        ~ 列出线程
                ~* [命令] 所有线程
                ~. [命令] 当前线程
                ~# [命令] 当前时间或异常引发的线程
                ~ns 转到线程n,n为线程id
                ~n f|u|n|m 将线程n  冻结|解冻|挂起|恢复

        例如:
                ~ 字符用于查看被调试进程中的线程信息
                比如: 0  Id:  1998.1358  Suspend: 1  Teb: 7ffde000  Unfrozen
                表示一条线程的信息,0表示该线程的编号(区分所有列出的);1998.1358,前者是进程进程ID,后者是线程ID。再后面的信息室线程的状态和Teb地址。在 0 之前的一个点号”.”表示是当前线程。

                一旦WinDbg中Ctrl+Break之后,会在调试目标的进程中创建一个远线程,并在远线程中执行ntdll!DbgBreakPoint函数,在目标进程中产生一次int3异常,中断到调试器中。

        ~线程编号 s :可以在线程之间进行切换。 ~0s  则切换到当前进程的0号线程中。
        |进程编号 s :可以再进程之间切换。 |1s 则切换到1号进程中去。

        !teb 显示线程环境块 TEB的标准视图
        !peb 显示进程环境块的信息,PEB的标准视图

        !gle 当前线程的最终错误 GetLastError()值
        !gle -all 所有线程的最终错误

        !error 错误值 解码并显示一个错误值的信息
        !error 错误值 l 将错误值作为NTSTATUS代码处理

死锁调试:
        !runaway 列举出当前所有线程的执行时间
        !runaway 7 列举出执行时间的详细信息
        !locks 列举出死锁的信息

        ~*kb 查看当前在进程中运行的所有的线程堆栈,结合 !cs 命令就可以查到那些线程死锁了
        !cs addr 可以显示内存处临界区的内容        
        !cs -s  显示每个临界区的初始堆栈回溯
        !cs -l 仅显示锁定的临界区
        !cs -? 显示 !cs 的帮助信息

        ~~[tid] tid为线程id,查看当前线程等待的锁是什么

6. 控制命令
        调试源码或汇编:
                F5 运行或运行到断点,F10逐过程单步执行,F11逐语句单步
                汇编模式和源码模式的单步执行不同,汇编模式,每次执行一条汇编语句,源码模式,每次执行一句源码。 l-t 来启用 汇编模式, l+t 启用源码模式。

        g*类的命令:直接运行目标,
                g 与F5同等,
                gu 执行到当前函数完成 ××××
                gc 条件断点之后恢复运行
                gh 当前异常当做已处理,继续执行
                gn 当前异常当做未处理,继续执行

        p*类的命令:单步执行,
                p  step over,等同于F10
                pa 执行到制定的地址
                pc 执行到遇到下一条 call指令
                pct 执行到遇到一条call指令或一个return指令
                ph 执行到一条分支指令:条件分支,call调用,函数返回,系统调用等
        
        p 计数    计数为走过的指令或源代码的数量

        t*类的命令: 类似p*类的命令,但是遇到call时会跟踪进去。
                t   等同于 F11
                ta  执行到制定地址,本函数和被调用函数的每一步都会显示
                tb  执行到下一条分支指令
                tct  执行到下一条call 或 return指令
                th  类似ph
                tt  遇到return指令
                wt  目标执行,直到制定的函数执行完成,显示统计信息

7. 断点
        bp  : 打一个断点。
        0:000> bp TestDebug!main 叹号前面指明了模块,main为模块内的函数名,指明模块可以减少符号的搜索时间。

        在源码窗口,可以使用 F9 设置断点(同VS中)
        bl  列出当前的所有断点。
        1  e  0040105d[TestDebug1.cpp@27]  1表示断点id,e表示断点启用,如果是d表示断点金庸,u表示断点未定。后面是断点的地址,以及断点的文件以及行数。

        bd id  禁用编号为id的断点
        be id  重新启用编号为id的断点
        bu 与bp一样,用于在一些没有被加载的模块中设置断点,一旦模块加载即可断到断点处。
        bc id   删除编号为id的断点

        bp 给C++类成员函数加断点: 
                bp TestDebug1.exe!CTestClass::SetChar
                bp TestDebug1.exe!CTestClass__SetChar
                bp @@C++( TestDebug1.exe!CTestClass::SetChar)
                两种语法表达式 @@C++表示C++语法,@@masm表示MASM语法,默认使用的是MASM语法。

        ba 用于给某个内存地址设断点,当这个内存地址被执行,读取,或写入时中断下来。
        ba w4 @@C++(&i)  &i 是表示变量i的地址,w表示写入,4表示只处理&i地址处的4个字节的写入。

        ba [r|w|e] [大小] 地址 访问时中断 r为读写,w为写入,e为执行。 大小可设置 1|2|4三个值(64位机器可以设置为8)

        bm 符号型 设置符号断点,符号型可包含通配符

        例如:
                bp '模块!source.c:12' 在指定源码处设置断点
                bm myprogram!mem* 符号型等同使用x,在所有mem开头符号加断点
                bu mymodule!func ".dump C:\dump.dmp;g" 触发断点后执行指令  属于 bu [地址] ["命令串"]

        ~0 bp sample!main 针对0号线程,设置断点

        条件断点,后续再学习使用,太庞大了有木有???

        DLL调试的断点:
                在调试dll时,需要断在dll加载或卸载时加断点,中断下来。
                sxe ld:[dll name]  加载某个DLL的时候中断
                sxe ud:[dll name]  卸载某个dll时中断下来

                sxe ld:wininet  表示 在wininet.dll被装载的时候断点
                bu wininet!DllMain  表示在wininet模块的DllMain上断下来

        技巧:
                在编程代码中设置一个断点:
                kernel32!DebugBreak
                ntdll!DbgBreakPoint
                __asm int 3 仅用于x86

8. 访问内存和寄存器
        以d开头的命令用于查看内存值:
                d[a|u|b|w|W|d|c|q|f|D] [/c #] [地址]
                        a Ascii字符
                        u unicode字符
                        b 字节+ASCII
                        w 字(两个字节)
                        W 字(2字节)+ASCII
                        d 双字 4字节
                        c 双字 + ASCII
                        q 四字 8字节

                        f 浮点,单精度 4字节
                        D 浮点,双精度 8字节

                        yb 二进制和字节的值
                        yd 二进制和双字节值

                        s 查看String,ANSI_STRING的内容,非da查看的0结尾
                        S 查看一个UNICODE_STRING的内容,非du的0结尾的字符串

                db addr 按照BYTE类型查看
                dd addr 按照DWORD类型查看
                d 不带地址 会按照上一次 d*命令的方式,接着上一次的显示继续显示
        例如:
                dd 0046c6b0 显示0046c6b0处的双字
                dd 0046c6b0 L3 显示0046c6b0处的三个双字
                du 0046c6b0 显示0046c6b0处的Unicode字符

        dt nt!_PEB  7ffda000 用于显示结构体,数组,和类对象的内容
        dt argv  可以显示argv的内容
        dt -v  结构名称 用于显示结构体的信息内容。

        dv 显示当前作用域下的局部变量的类型和值

        dd*,dq*,dp*:
        第二位表示指针大小
                dd* 使用32位指针
                dq* 使用64位指针
                dp* 标准大小,32位或64位,取决于CPU
        第三位表示如何解引用内存:
                d*a 以ASCII字符形式显示解引用内存
                d*u 以Unicode字符形式显示解引用内存
                d*p 双字或四字显示解引用内存

        dds 查看四字节地址处的符号(dqs,dps)

        ? 表达式 : 表达式求值命令,用来查看符号所代表的值 比如 ? i 显示 i的值是多少



        e*命令可以将值写入内存,和d*类似。
                e[b|w|d|q|f|D] addr  value 同 d×,修改addr处的内存,值为value
                e[a|u|za|zu] addr "chars" 修改addr处内存,值为 chars

                eb  0012ff78 ‘a’ ‘b’ ‘c’ ‘d’ 从地址开始一次写入后面的数值。

        r 命令用于查看或修改寄存器和伪寄存器的值
                r 显示所有寄存器值
                r reg1,reg2 显示寄存器reg1,寄存器reg2的值
                r reg1=value 设置寄存器reg1为value
                ~0 r 显示0号线程的寄存器
                ~* r 显示所有线程的寄存器

        !address addr  用于显示指定的内存地址的信息。 
                !address -? 显示帮助信息
                !address -summary 显示进程的摘要信息
        例如:
                !address 400000 用于显示当前进程模块的PE文件头。

9. 进程模块的查看命令
        lm[v|l|k|u|f] [m 模式]  列出模块:详细|带加载符号|进内核符号信息|仅用户符号信息|映像路径  (m 模式 匹配)

        lm  列举当前进程加载的模块,其实地址,模块名称等
        lmf  显示每个DLL/EXE的具体路径
        lm命令列表比较长,如果过滤出自己感兴趣的模块,使用lm m 表达式 命令

        lm m *theme* 列举出包含了 theme字符串的模块


        lm vm *theme*  列举出模块的详细信息,比如版本,日期等

        lm a addr  显示addr地址所在的模块

        !lmi 模块 模块详细信息,包括准确符号信息
                !lmi uxtheme 列举出 uxtheme.dll的详细调试信息

        !dlls 列出所有加载的的模块
                -i  按照初始化顺序
                -l  按照加载顺序
                -m  按照内存数序
                -v  显示详细信息
                -c 模块地址  仅显示地址处的模块

        例如:
                lmv m kernel32  显示kernel32.dll的详细信息
                lmD   DML型的lm

        !dh 显示pe文件的头信息
                -a  显示所有的信息
                -f  文件头,不显示区块信息

                -s  显示区块信息


10. 堆栈的查看命令
        k 查看堆栈的内容
        kp 能看到各个函数的输入参数,kp 5 显示5个函数的调用栈 (前提是有私有符号,微软的公有符号不行)
        kP 比kp看起来更加舒服,所有项格式化
        kn(callstack with index number)显示调用栈的栈号

        kb 5 显示前5个函数以及他们的前三个参数
        kf 5 显示前五个函数栈,以及他们所使用的栈大小
        kv FPO信息,调用协议

        .frame 显示当前帧
        .frame id   切换到堆栈id处,可以查看这个地方的一些值与变量

        在.frame n  命令后,切换到指定栈帧,使用 x 可以显示当前函数里面的局部变量值

11. 使用Windbug分析dump文件
        !analyze -v  分析命令,自动分析dump

                !analyze !analyze -v  显示当前异常或故障检查信息:详细
                !analyze -hang 用户模式:分析线程栈,以确认是否那个线程正阻塞其他线程
                !analyze -f  查看异常分析,即便是调试器没有检测到异常 

        .lastevent 显示最近的事件或异常,可以看到发生异常的线程

        !heap 分析出错的堆栈

        !for_each_frame  dv  /t 显示每一个堆栈函数处的所有变量。

        .opendump 文件名  打开dump文件

        .dump 文件名      生成dump文件
        .dump -? 显示dump的帮助命令
        .dump /mf 或 .dump /ma 将创建一个比.dump /f 更大更完整的文件

        .ecxr  定位当前异常的上下文信息,并显示重要的寄存器。 !analyze -v 命令后,可以使用这个命令查看异常发生位置的信息。

12. 变量信息:
        dt -h 显示dt帮助
        dt [模块!]名称 显示变量信息
        dt [模块!]名称 字段 [字段] 仅显示"字段"的值,结构或集合
        dt [模块!]名称 [字段] 地址 显示的结构的地址
        dt [模块!]名称* 列出符号(通配符)

        dv 显示本地变量与参数
        dv 样式 变量匹配样式
        dv [/i /t /V] [样式] i为类型(本地,全局,参数) t为数值类型 V为内存位置或寄存器地址

        例如:
                dt ntdll!_PEB* 列出所有包含_PEB的变量
                dt ntdll!_PEB* -v 以详细输出方式列出,包含地址与大小

13. 内存操作:
        对比内存
        搜索内存

        s –a 00400000 L53000 "Wrong"
        从 0040000 地址开始,向后 L53000 范围内搜索 Wrong字符串

        移动内存

14. 调试子进程

        .childdbg 1 开启子进程调试(从主进程中启动的子进程被调试)
        .childdbg 0 关闭子进程调试

内核调试:
        待补充

你可能感兴趣的:(Windbg 命令 总结)