Windbg

本文详细介绍了Windbg的命令系统,包括注意事项、标准命令、元命令、扩展命令等。重点讲解了程序控制、断点设置、堆栈分析、反汇编、模块分析、内核调试和DUMP文件分析等内容,并提供了丰富的示例和技巧,帮助读者掌握Windbg的使用。

命令系统

注意事项

  • 只有暂停时可以输入命令
  • 直接回车可以重复上一条命令
  • 按上下方向键可以浏览之前输入过的命令
  • 当命令提示框为BUSY时,无法输入命令

标准命令

命令行输入后,可显示一些基本命令
在输入显示的命令,可以显示命令的具体说明

元命令

命令行输入.help后,可显示一些元命令

扩展命令

用于实现特定调试功能的一些命令,实现与DLL中,一般以开头。通常是一个单词。
扩展命令存在DLL被称之为扩展模块,使用.chain命令可以列出所有的扩展模块,大部分都有help命令来显示这个模块的基本信息以及所含有的命令。

常用基本命令

命令功能
lm查看当前模块和符号加载情况
.reload刷新符号路径,重新载入符号
ld加载某一个符号
.restart重新开始调试
.detach分离调试
q退出调试

程序控制相关命令

系列命令作用快捷键
g系列g恢复执行F5
gu执行的父函数
p系列p单步步过F10
pa执行到一个地址
pc执行到下一个Call
t系列t单步步入F11
ta执行到一个地址
tc执行到下一个call

断点控制相关命令

断点命令全是b系列命令

命令作用
bp设置软件断点
ba w\r\e设置硬件断点
bl列出所有断点
be\bd\bc启用\禁止\删除 断点
bc *清除所有断点
bu和bp类似,但不是一次性的
bm批量设置断点
  • 示例
    bm *!Messag* 下断所有Mssage开头的函数
    bm Myapp!MyClass::* 下断所有MyCalss 类中的函数

堆栈命令

命令功能
K显示简单的堆栈信息
Kb显示每个函数的前三个参数
Kp显示每个函数的全部参数
kv显示更具体的信息(调用约定)
.frame [堆栈序列号]切换局部环境上下文
  • 注意:假如想查看某个线程的堆栈,可以使用~n k(n代表线程号)

示例:

  1. k:查看堆栈序列
  2. .frame [序列号(#列)]:切换序列
  3. x:后面跟x命令可以显示局部变量

反汇编命令

命令作用
u将一个地址之后的内容反汇编显示
ub将某一个地址之前的内容反汇编
uf显示指定函数地址的反汇编代码(需要符号)
  • l+条数显示指定条数的反汇编代码
  • u | Address | count
  • uf命令自动识别函数结尾,将整个函数反汇编出来

模块分析

  • 常见的PE文件有 .exe .dll .sys后缀代表的文件
  • 内存中每一个可执行文件称之为一个模块。
命令作用
lm列出所有模块
lm vm 模块名列出某一个模块的详细信息
!dh查看某一个模块的PE信息

伪寄存器

命令作用
$exentry程序入口点
$peb程序PEB的入口点
$teb程序TEB的入口点
$ra当前函数的返回地址
$ip指针寄存器
$retreg当前函数的返回值

d系列结构

  • d系列命令一般为显示命令
命令作用
dt + 结构体 + 地址将地址解析为结构体
dd 地址四字节显示
db 地址单字节显示
dv显示当前函数变量信息(包括参数和局部变量)

搜索内存

命令作用
s -[flags]sa\su 范围搜索 Ascall\Unicode数据
s -[flags]type 范围搜索特定的数据类型的数据
flags含义
s保存搜索结果,供后续搜索筛选
r将当前搜索范围限定为上一次搜索中(上次搜索需要使用s)
i使用在sa\su中,表示搜索的字符长度
w只搜索可写入内存
l仅显示搜索到的数据地址,在foreach语法中很有用
类型说明
bByte
WWORD
dDWORD
qQWORD
aASC字符串
uUnicode字符串

示例

  1. 使用lm获取模块的地址范围
  2. 使用s -[flag]sa\su 起始地址 终止地址搜索数据
  3. 使用s -[flag]sa\su 起始地址 l+范围大小搜索指定大小区域数据
  4. 使用s -[flag] 范围 "数据"搜索指定类型的数据
    4.1 s -a 0x400000 0x41f000 "Hello" 搜索0x400000 0x41f000范围内 Ascall类型的字符 Hello
    4.2 s -b 0x400000 0x41f000 4d 5a 搜索0x400000 0x41f000范围内 按字节搜索 4d 5a

搜索符号

  • 使用x命令来进行符号搜索
  • 使用x进行模糊搜索,使用*号作为通配符

示例

  1. x *er*!MessageboxA 搜索模块名带有er中,MessageboxA函数的地址
  2. x KERNEL32!CloseConsoleHandle搜索KERNEL32模块中CloseConsoleHandle函数信息。

搜索调用

  1. # 模块名!函数名
  2. # 函数名
  3. # 函数名 + 范围

示例

  1. # user32!MessageBoxA搜索对user32模块中MessageboxA函数地址
  2. # MessageBoxA搜索所有对MessageBoxA的调用
  3. # MessageBoxA 0x400000 0x41f000

分析模块链

  • dt 结构体名称 -l 链表节点 地址
    地址结构体形式解析,并只将链表节点全部解析出来。

搭建双机调试环境

  1. 安装Virtual Kd,在其目录下启动对应vmmon.exe程序,点击debugger path,设置windbg调试器路径。
  2. Virtual Kd,目录下的Target文件夹拷贝至虚拟机中,启动Vminstall.exe并安装,重启虚拟机,以调试模式启动。
  3. 这时主机的vmmon.exe程序则可以接受虚拟机的的调试信号。

常见内核结构

SSDT(系统描述服务表)

  • 加载nt模块符号后 命令x nt!KiServiceTable 可获得服务表地址,使用dd + 地址可查看所有函数地址,使用u + 地址可查看具体函数反汇编

EPROCESS

dt _EPROCESS

ETHREAD

dt _ETHREAD

内核调试进程

  • !process 0 0
    枚举进程

  • .process /i 进程EPROCESS地址
    切入到一个进程的虚拟地址,就可以访问该进程的所有信息
    进程之间通过内存分页来隔离

分析DUMP文件

  1. 设置系统蓝屏时DUMP核心文件
  2. 使用Windbg!analyze -v分析dump文件

表达式

MASM 表达式

  • 使用特点总结
    -求值使用
    -默认进制为16进制
    -所有的符号均为地址(类似指针)
    -poi为取值内容

进制前缀

进制前缀
16进制0x
10进制0n
8进制0t
2进制0y

MASM常见运算符

系列运算符
算数运算符+ 、- 、* 、/ 、mod(或者%)
位移运算符<< 、>> 、>>>
比较运算=(或者==)、< 、 > 、 <= 、>= 、!=
位运算and(或者&)、xor(或者^)、or(或者丨)
逻辑运算not

=或者==都是比较运算符,赋值通常是通过r命令,r @eax = 1

MASM其他运算符

符号作用
hi取高16位 ? hi(@eax)
low取低16位 ? low(@eax)
by丨$pby取指定地址出的一个字节 ? by(地址)
wo丨$pwo取指定地址出的两个字节 ? wo(地址)
dwo丨$pdwo取指定地址出的四个字节 ? dwo(地址)
qwo$pqwo
poi丨$ppoi取指定地址出的指针大小数据 ? poi(地址)

$符号后的是解析的物理内存地址

C++ 表达式

  • 使用特点总结
    -默认使用??求值
    -符号根据它自身的类型解析
    -变量的数值就是它的实际值,不是地址

  • MASM表达式某一部分被圆括号括住并有两个@符号(@@),该部分会根据C++表达式规则来解析

  • C++表达式某一部分被圆括号括住并有两个@符号(@@),该部分会根据MASM表达式规则来解析

  • 也可以通过使用@@c++(…)或者@@masm(…)指定表达式求值

  • MASM不能直接解析结构体的元素,但是C++可以

  • MASM表达式默认是十六进制C++模式为10进制

  • 我们将表达式输入windbg命令中,求得数据

进制前缀

进制前缀
16进制0x
8进制0

不能直接使用二进制

运算符
支持C++大部分运算符

系列运算符
算数运算符+ - * / -(取负) ++ –
关系运算符> >= < <= == !=
位运算符& 丨 ~ ^ << >>
逻辑运算符! && 丨丨
赋值运算符= += -= *= /= %=
条件运算符? : 作用域符号(::)
逗号运算符, 注释(//)
指针运算符* &
求字节数运算符sizeof
分量运算符. ->
下标运算符[]

C++表达式中使用寄存器和伪寄存器必须带有@符号前缀
不能使用赋值运算符修改寄存器或伪寄存器,只能使用r命令修改他们

  • 切换默认表达式命令
    .expr /s c++/masm

流程控制语句

  • 选择结构

    • .if
    • .else
    • .elif
      示例
      .if (条件) {命令序列} .else {命令序列}
      .if (条件) {命令序列} .elif(条件) {命令序列} .else {命令序列}
  • 循环结构

    • .for
    • .while
    • .do
      示例
      .for (初始命令;条件;增量){命令序列}
      .while (条件) {命令序列}
      .do {命令序列}(条件)
  • continue与break
    C/C++一样的概念

Windbg脚本

  • 执行脚本 $$>< 路径
  • 注释 $$ 描述
g @$exentry

t
t
t
t

p
p
p

t

r @$t0 = @$ip+0x152 $$根据当前EIP计算下一个call的位置

g @$t0

t

r @$t1 = 0

.while(@$t1 != 4){
    p;
    .if(by(@$ip) == 0xe8){
        r @$t1= @$t1+1
    };
}$$循环查找第四个call的位置

t
t

就是一些命令的集合

线程命令

符号说明
~.当前线程
~#导致当前异常的线程
~*进程中的所有线程
~Number序号为Number的线程
~~[tid]线程ID为TID的线程
~{num}s切换线程;num为线程序列号

寄存器命令

  • 寄存器命令主要是r系列

    • r:直接打印出所有寄存器的值
    • r @eax:直接打印出eax寄存器的值
    • r @eax=表达式:直接修改寄存器的值
  • ~1 r查看1号线程的寄存器信息

  • ~2 k查看2号线程的堆栈信息

字符串通配语法(类似正则表达式)

符号含义
*表示零个或多个字符
表示任意单个字符
[]表示该列字符中的任意单个字符,可以使用-表示一个范围
#表示匹配零个或多个前字符列表
+匹配一个或者多个前字符列表
  • x *!m[a-z]+n搜索任意模块中,m开头,n结尾,中间是[a-z]的函数

条件断点

J命令

  • j表达式 命令1;命令2
    如果表达式的值时非0值,则执行命令1,否则执行命令2.

  • 示例
    J @eax>0 r @eax; r @eax=1

断点附加命令

  • bp $exentry “r @eax;r @ecx”
    当程序如上断下来后,还会执行后面引号中的内容。

伪寄存器

伪寄存器含义
$tpid当前进程的PID
$tid当前线程的PID
$proc当前进程的EPROCESS

Windbg脚本

  • 需要以下内容提供支持
    -数据类型(C++/MASM)
    -变量定义方式(伪寄存器)
    -运算符与表达式(C++/MASM)
    -流程控制语句(三大结构)
    -库函数功能的命令和语句

伪寄存器

  • 自定义伪寄存器 t 0   t0~ t0 t19,可以将其作为事先定义好的20个变量,直接使用。
    命令:
    r $t0 = 100为伪寄存器赋值
    ? $t0 + 200寄存器计算

别名

  • 固定别名:$u0 ~ $u9
    同样使用r命令修改固定别名所代表的内容。修改的时候需要在u前面加个.
    虽然在使用r命令,但是这些别名不是寄存器或伪寄存器,r命令只能修改他们,但不能显示他们的值。
  • 自动别名:调试器设置的别名
  • 自定义别名:可以由windbg使用者自己设置和命名
    • -as(aS) 定义别名
    • -ad 删除别名
    • -al 列出别名
    • 定义别名时的一些参数
      | 参数 | 含义 |
      | ------------ | ------------ |
      | -e | 把环境变量作为别名 |
      | -ma | 把一个内存地址中的字符串作为别名 |
      | -f | 把文件内容作为别名,只用用在(aS)中 |

伪寄存器相当于变量,而别名更像宏替换
as cmd bp user32!MessageBoxW "j eax=0 '';'gc'"
bp user32!MessageBoxW "j eax=0 '';'gc'"等效替换为cmd命令。

内存操作指令

命令作用
.dvalloc申请虚拟内存
.dvfree释放虚拟内存
.wirtemem写内存到文件
.readmem读内存到文件
!address内存信息查看
!vprot查看内存保护信息

修改内存

指令作用
e{a丨u丨za丨zu} address “String”ascll丨unicode丨以零结尾的ascall丨以零结尾的Unicode
e{a丨b丨d丨D丨f丨q丨u丨w} address {values}ascall丨byte丨dword丨double丨float丨8字节丨Unicode丨word

示例

  • eza 0x314342 “pediy”:向地址0x314342写入字符串pediy
  • eb 0x314342 70 65 64 69 79:向地址0x314342写入字符串70 65 64 69 79(字符pediy)

重定向命令输出

. logopen [输出文件路径]
. logclose

Windb脚本

  • 解析器
$<FilePath
$><FilePath
$$<FilePath
$$><FilePath
$$>a<FilePath

“<” 表示不会自动将脚本压缩成一行
“><” 会将脚本压缩成一行,并将换行替换为 “;”
“FilePath” 脚本路径

  • 数据类型
2进制        0x
8进制        0n
10进制    0t
16进制    0y
  • 字符串
"字符串"

使用 " " 括起来

  • 变量
;伪寄存器 $t0~$t19
r $t0=0x123
r $t0
  • 别名
    别名更像宏,解释时直接替换原始操作数
    固定别名: u 0 − u0- u0u9
r $.u0="123"
.echo $u0

自定义别名:as/ad/al

as: as [param1] ${/param2:Name} data
param1:
/ma 参数指定的内存地址当ASCII字符串
/mu 参数指定的内存地址当Unicode字符串
/msa 参数指定的内存地址当做ANSI_STRING字符串
/msu 参数指定的内存地址当做UNICODE_STRING字符串
/f 别名等于参数指定文件的内容
/e 别名等于参数指定的环境变量
param2:
/v 保持别名原样,不翻译,在定义和删除的时候使用
/n 如果别名已定义就翻译为内容,否则不做任何翻译
/f 如果别名已定义就翻译为内容,否则内容为空
/d 如果别名已定义,翻译为1,否则翻译为0,相当于#ifdef
  • 表达式
    汇编表达式(默认表达式)
    C++表达式 :需使用 @@c++() 将表达式括起来

  • 语句

.if
.else
.elif
.for
.while
.break
.continue
.do
.printf
.block    语句块,配合{}使用,与其等效
$$    注释

*内建函数

内核调试

准备工作

  1. 开启测试模式
    bcdedit /set testsigning on
  2. 开启调试模式
    bcdedit /debug on
  3. 禁用驱动签名
    bcdedit /set loadoptions DDISABLE_INTEGRIITY_CHECKS
  4. 生成秘钥
    set /dbgsettings net hostip:x.x.x.x(接受端IP) port:x(50010) key:x.x.x.x(1.2.3.4)

内核调试常用命令

  1. 获取EPROCESS
!process 0 0 [进程名.exe]
eg:
!process 0 0 notepad.exe
  1. 切换当前进程环境
.process /p [EPROCESS]
eg:
.process /p 00ffff86、00789564
  1. 强制加载用户态符号
.reload /f /user
  1. 附加到当前EPROCESS
侵入式:可下断点
.process /i
  1. 切换、附加、加载符号
.process /p /i /r
;小P仅仅切换内核态环境,大P切换内核和用户态环境
  1. 下断点
bp /p EPROCESS kernel32!createfilew
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值