[原] WinDBG 使用笔记

发布时间:2014-6-4 10:25
分类名称:Debug_Crack


Workspace

  1. Default Workspace (implicit)
    1. Base Workspace, 会话尚未建立,处于赋闲状态,会使用。
    2. Default Kernel-mode Workspace,开始内核调试,但尚未和目标建立连接时。
    3. Remote Default Workspace,通过调试服务器(DbgSrv/KdSrv)进行远程调试时。
    4. Processor-specific Workspace,和处理器相关联。
    5. Default User-mode Workspace,调试一个已经运行的进程时。
    6. WinDBG自动根据文件路径和文件名称为其建立一个默认工作空间,若此空间已经存在,则使用。
  2. Named Workspace (explicit) 手动保存

 

Workspace保存的信息:

 

WorkSpace默认保存位置:

HKEY_CURRENT_USER\Software\Microsoft\Windbg\Workspaces

下面有对应的四个子键:User, Kernel, Dump, Explicit

 

使用Themes可以加载4种经过定制的工作空间。(.reg, .wew).

 

心得:

Windbg工作空间的配置是一个叠加和继承的关系。使用正常方式启动Windbg后,对其空间所有的修改,会在HKEY_CURRENT_USER\Software\Microsoft\Windbg\Workspaces下创建一个Default(REG_BINARY)类型的键值,里面记录了工作空间(Base Workspace)的所有配置。当调试一个系统时,会在Workspace下创建一个kernel子键,子键下创建一个Default(REG_BINARY),它会继承Workspaces键下面的Default(REG_BINARY)键值,然后后续的所有的空间修改,都是针对Kernel的。当调试一个user mode程序时,Workspace下创建一个user子键,子键下创建一个以程序全路径为名称的(REG_BINARY)键值,它会继承Workspaces键下面的Default(REG_BINARY)键值,然后后续的所有的空间修改,都是针对此程序的。

命令

标准命令

WinDBG内置命令,大多数为一到二个字符,第一个字符不区分大小写,第二个字符可能区分。

控制调试目标执行:g, t, p, wt

寄存器:r, rdmsr/wrmsr, rm

IO: ib/iw/id 和 ob/ow/od

内存:d, e, s

栈: k

断点:bp, ba, bl, bc/bd/be

汇编:a, u

功能:~, |, ?, dg, $, sx, sq, so, ss, version, vertarget, x, ls, ld, ln, lm, q, qq, qd … …

 

元命令

WinDBG内置命令,补充标准命令,以(.)开始。大部分都是控制编译器的一些配置,例如

符号、源文件的选择,加载,修改等。

重新开始调试,放弃调试,附件调试,分离调试等。

扩展命令

在外部加载的扩展模块(DLL)中,以(!)开始。

![扩展模块名.]<扩展命令名>[参数]

使用元命令:.load, .loadby可以手动加载。当使用![扩展模块名.]<扩展命令名>[参数]执行命令时,如果指定的扩展模块没有被加载,WinDBG会自动加载。

.chain列出全部模块,.unlode, unloadall 卸载指定模块和全部模块

命令行窗口

[||system_index:]process_index:thread_index>        用户态调试

[||system_index:][processor_index:]kd>            双机内核调试

[||system_index:][processor_index:]lkd>            本地内核调试

*BUSY*    忙碌状态

NoTarget    .abondon所有的调试目标后

Input>

 

控制进程和线程 (User Mode)

||<system_index> s    切换当前系统

|<process_index> s        切换当前进程

~<thread_index> s        切换当前线程(仅在当前子系统中)

执行命令

  1. 一行多条命令,用(;)隔开。
  2. 直接回车,执行上次执行的命令。
  3. 上下键,可以浏览敲过的命令。
  4. 有的命令区分大小写,有的不区分。
  5. 元命令以(.)开始,扩展命令以(!)开始。
  6. Ctrl+break中断,如果是KD、CDB,使用Ctrl+C。
  7. Ctrl+Alt+V可以启动WinDBG详细输出,再次按,则关闭。
  8. Ctrl+Alt+D 让WinDBG显示与内核调试引擎之间的数据通信,再按停止。
  9. .hh 帮助。

语法

MASM Numbers and Operators

进制(Radix)

n (Set Number Base) set the default radix to 16, 10, or 8. All unprefixed numbers are then interpreted in this base. 0x prefix (hexadecimal)

0n prefix (decimal)

0t prefix (octal)

0y prefix (binary).

You can also specify hexadecimal numbers by adding an h after the number.

For example, "0x4AB3", "0X4aB3", "4AB3h", "4ab3h", and "4aB3H" have the same meaning.

 

符号(Symbol)

任何数字类型的符号都被视为地址在Masm中。address of a global variable, local variable, function, segment, module, or any other recognized label

 

When you perform arithmetic computations, the MASM expression evaluator treats all numbers and symbols as ULONG64 types.

 

MASM中,指定源文件行:

`[[Module!]Filename][:LineNumber(十进制)]` (两端是重音号),如:

Bp `d4dtest!drtest.cpp:196`

 

注释:*, $$. *后面的所有内容都是注释;而$$后面的内容截止到分号为止。这两个注释符号前面都要加分号。

 

伪寄存器

$ip, $peb, $teb, $frame, $thread, … …

在伪寄存器前加入@,标识是个寄存器,会更快执行。

C++ Numbers and Operators

Numbers in C++ expressions are interpreted as decimal numbers, unless you specify them in another manner. To specify a hexadecimal integer, add 0x before the number. To specify an octal integer, add 0 (zero) before the number.

 

The default debugger radix does not affect how you enter C++ expressions. You cannot directly enter a binary number (except by nesting a MASM expression within the C++ expression).

 

You can use the L, U, and I64 suffixes with integer values.

Evaluating Expressions

MASM expressions and C++ expressions

 

Default if MASM.

When Each Syntax is Used

You can select the default expression evaluator in one of the following ways:

 

.expr 可以设置和查看默认表达式设置。

显示指定表达式:@@masm(…) @@c++(…)

 

? Expression    评估表达式(evaluates and displays the value of an expression)

?? (Evaluate C++ Expression) 专门评估C++表达式

? @@c++(reinterpret_cast<int> (0xffffffee))

 

.formats (Show Number Formats)

Address and Address Range Syntax

通常所说的Address指的是Virtual Address,除非特别指出。

用户层,调试器使用当前进程的Page directory 解析地址。

内核层,调试器使用当前的Process context(或user-mode address context)解析地址。

 

You can specify an address range by a pair of addresses or by an address and object count.

a pair of addresses:            0x00001000 0x00001007

an address and object count:    0x00001000 L8

 

L Size,大小限制为256MB

L? Size 无大小限制

L- Size 负数,向上显示。

进程、线程和系统限定符

Thread Syntax

Many debugger commands have thread identifiers as their parameters. A tilde ( ~ ) appears before the thread identifier.

 

Thread identifier

Description

~.

The current thread.

~#

The thread that caused the current exception or debug event.

~*

All threads in the process.

~Number

The thread whose index is Number.

~~[TID]

The thread whose thread ID is TID. (The brackets are required And you cannot add a space between the second tilde and the opening bracket.)

~[Expression]

The thread whose thread ID is the integer to which the numerical Expression resolves.

 

Many debugger commands have process identifiers as their parameters. A vertical bar ( | ) appears before the process identifier.

Process identifier

Description

|.

The current process.

|#

The process that caused the current exception or debug event.

|*

All processes.

|Number

The process whose ordinal is Number.

|~[PID]

The process whose process ID is PID. (The brackets are required and you cannot add a space between the tilde (~) and the opening bracket.)

|[Expression]

The process whose process ID is the integer to which the numerical Expression resolves.

 

Many debugger commands have process identifiers as their parameters.

Two vertical bars ( || ) appear before the system identifier.

System identifier

Description

||.

The current system

||#

The system that caused the current exception or debug event.

||*

All systems.

||ddd

The system whose ordinal is ddd.

 

切换线程(user mode):~Thread s

切换进程(user mode):|Process s

切换系统(user mode):||System s

切换CPU(kernel mode):~Processor s 在kernel mode ~ 不用来表示thread,用来表示一个processor。

在Kernel Mode中,有切换上下文的概念,见下文。

上下文(Context)

此处的切换上下文是在kernel mode方式下切换,用户模式下的切换非此方式。

切换上下文钱,先禁用缓存功能:.cache forcedecodeuser 或 .cache forcedecodeptes

会话上下文    !session        (Kernel Mode)

进程上下文 .process        (Kernel Mode)

寄存器上下文 .thread        (Kernel Mode)配合!process使用。

局部变量上下文 .frame    (Kernel/user Mode)

别名

  1. User-named Alias    用户指定
  2. Fixed-named Alias    $u0~$u9
    1. Automatic Alias    $ntnsym, $ntwsym, $ntsym

 

用户指定别名:

as alias command, 如:

as v version

al 列出所有别名,ad删除别名

 

使用固定别名:

r $.u<0~9>=<别名实体>,如:

r $.u9=nt!KiServiceTable

 

用户别名如果和其他命令连在一起,需要使用${Alias}这种方式。固定的别名则不需要括号。

循环和条件

z循环

Command ; z( Expression )

!for_each_XXXX

j <条件表达式> [command1];[command2]

j <条件表达式> ['command1'];['command2']

 

.if .else .elseif

~0r; ~0k 显示0号线程的寄存器和栈回溯,可简写为:

~0e r; k; e表示为0线程的执行后面的所有commands。

记录到文件

.logopen .logclose .logfile

建立调试会话

Attach to a process

  1. (F6), –p PID, -pn Name(Process), .attach
  2. 设置WinDBG为JIT调试器(WinDBG.exe -I)

 

创建并调试新进程

  1. (Ctrl+E), windbg.exe path, .create
  2. HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options

    下,新建 appname.exe/Debugger(RGE_SZ)full path

 

非侵入式调试

不能收到任何调试事件,只能看,不能控制。

Noninvasive, -pv, .attach –v

 

终止调试

Stop Debug(menu), q命令

 

分离调试目标(XP以上版本)

Detach debuggee(menu), .detach

抛弃被调试的进程

.abandon和.detach的区别:

.detach 修改进程属性,使其脱离调试状态成为一个普通进程。

.abandon 被调试进程仍然处于挂起状态,只是和调试器相互脱离(调试器处于No target),被调试进程并没有恢复调试前的状态。使用 windbg –pe –p PID ,可以再次附加被abandon的进程。

 

杀死调试进程:.kill

重新开始调试:Restart(Ctrl+Shift+F5)(Menu), .restart

观察模块信息

lm, !lmi, Debug->Modules(menu)

检测符号

X [options] module!symbol

x /v module!symbol 显示符号类型(local,global,parameter,function,unknown)

搜索符号(最近的)

ln

控制流程

异常

gh 强制返回已经处理异常(Handled)

gn强制返回未处理异常(Not Handled)

继续运行

g[a] [= StartAddress] [BreakAddress ... [; BreakCommands]]

gu (Go Up)

gc (Go from Conditional Breakpoint)

单步

模式:源码和汇编。使用指令 l+/-t来切换

t [r] [= StartAddress] [Count] ["Command"]            Step Into

p[r] [= StartAddress] [Count] ["Command"]            Step Over

pa [r] [= StartAddress] StopAddress ["Command"]    Step to Address

ta [r] [= StartAddress] StopAddress ["Command"]        Trace to Address

pc [r] [= StartAddress] [Count]                    Step to Next Call

tc [r] [= StartAddress] [Count]                        Trace to Next Call

pt [r] [= StartAddress] [Count] ["Command"]        Step to Next Return

tt [r] [= StartAddress] [Count]                        Trace to Next Return

th [r] [= StartAddress] [Count]                    Trace to Next Branching Instruction

ph [r] [= StartAddress] [Count]                    Step to Next Branching Instruction

wt [WatchOptions] [= StartAddress] [EndAddress]    Trace and Watch Data

tb [r] [= StartAddress] [Count]                    Trace to Next Branch(x86 kernel / x64 user and kernel)

断点

软件断点(INT 3 0xcc)

bp[ID] [Options] [Address [Passes]] ["CommandString"]

bu[ID] [Options] [Address [Passes]] ["CommandString"]

bm [Options] SymbolPattern [Passes] ["CommandString"]

 

硬件断点 (DR0-DR7)

ba[ID] [erwi] Size [Options] [Address [Passes]] ["CommandString"]

 

条件断点,在CommandString中加入条件判断:

" j (condition) 'OptionalCommand'; 'gc' " 或 " .if (condition) { OptionalCommand} .else {gc} "

bl        Breakpoint List

bc        Breakpoint Clear

be        Breakpoint Enable

bd        Breakpoint Disable

控制线程

~Thread n        Suspend Thread

~Thread m        Resume Thread

~Thread f            Freeze Thread

~Thread u        Unfreeze Thread

~Thread s            Set Current Thread

~Thread g        

观察栈

函数的调用由下至上。

User-mode        [~Thread] k[b|p|P|v] [c] [n] [f] [L] [M] [FrameCount]

Kernel-mode        [Processor] k[b|p|P|v] [c] [n] [f] [L] [M] [FrameCount]

kb    显示前三个参数信息[ebp+0x08], [ebp+0x0C], [ebp+0x10],如果使用其他调用协议,或者FPO,这三个信息并不正确。

kp    如果是私有PDB,此命令会根据PDB中的信息,显示函数的参数声明。

kP    同kp,只是参数信息的显示会每个参数换一行

kv    在kb的基础上显示FPO(栈指针省略)

 

n    显示栈序号,从0开始。

f    显示相邻栈的距离,byte为单位,可以用来判断栈溢出。

L    不显示调试源码信息

观察栈变量

dv /i /t /V

epb+8    第一个参数

ebp+c    第二个参数

ebp+10    第三个参数

ebp+14    第四个参数

ebp+18    第五个参数

… …

ebp-4    VC7 and higher:Cookie

ebp-8    VC7 and higher:0xCCCCCCCC

ebp-C    第一个变量

… …

分析内存

显示内存区域

d{a|b|c|d|D|f|p|q|u|w|W} [Options] [Range]

dy{b|d} [Options] [Range]

d [Options] [Range]

 

字符串

da    ASCII characters

du    UNICODE characters

ds    ANSI_STRING

dS    UNICODE_STRING

 

字节,字,双字,四字,双精,单精

db    Byte values and ASCII characters.

 

dw    Word values (2 bytes).

dW    Word values (2 bytes) and ASCII characters.

 

dd    Double-word values (4 bytes).

dc    Double-word values (4 bytes) and ASCII characters.

 

dD    Double-precision floating-point numbers (8 bytes).

df    Single-precision floating-point numbers (4 bytes).

 

dq    Quad-word values (8 bytes).

dp    Pointer-sized values. Depending 32-bit or 64-bit.

 

dyb    Binary values and byte values.

dyd    Binary values and double-word values (4 bytes).

显示数据类型

dt [-DisplayOpts] [-SearchOpts] [module!]Name [[-SearchOpts] Field] [Address] [-l List]

dt [-DisplayOpts] Address [-l List]

dt –h

 

dt –b [module!]Name        Display blocks recursively.

dt –r[depth] [module!]Name    Recursively dumps the subtype fields. This recursion will stop after depth levels. 1-9

dt [module!]Name –ny member

搜索内存

搜索字符串

s -[[Flags]]sa Range     ASCII字符串

s -[[Flags]]su Range        UNICODE字符串

 

例子

s –[l5]sa poi(nt!PsInitialSystemProcess) l200    

搜索nt!PsInitialSystemProcess开始512(0x200)字节范围内长度不小于5的ASCII字符串;

 

搜索相同类型的对象(c++ class object)

s -[[Flags]]v Range Object

 

例子

s-v 0x12fc30 l100 0x12fe4c

 

搜索某一内存模式

s [-[[Flags]Type]] Range Pattern

Type 指定搜索内容的数据类型(宽度)。b(字节),w(字),d(双字),q(四字),a(ASCII),u(Unicode),如果不指定,b为默认。

 

例子

s-w 0x400000 l2a000 41 64 76 44 62 67

0041b954    0041 0064 0076 0044 0062 0067 0000 0000        A.d.v.D.b.g…..

 

s-u 0x400000 l2a000 'A' 'd' 'v' 'D' 'b' 'g'

0041b954    0041 0064 0076 0044 0062 0067 0000 0000        A.d.v.D.b.g…..

 

s-u 0x400000 l2a000 "AdvDbg"

0041b954    0041 0064 0076 0044 0062 0067 0000 0000        A.d.v.D.b.g…..

 

当前进程的所有模块中搜索:

!for_each_module s-a @#Base @#End "Debugger"

修改内存

e{b|d|D|f|p|q|w} Address [Values]

e{a|u|za|zu} Address "String"

e Address [Values]