Maze
2020-03-21 23:32:39 Author: bbs.pediy.com(查看原文) 阅读量:222 收藏

windbg中文文档:

windbg官网:

b断点命令:

1.bl

列出当前所有中断

2.bp+地址/bp+MyModel!Function

在某个地址下断点,windbg不会把bp断点保存在工作空间中

3.bu+MyModel!Function

针对某个符号下断点,在代码修改后,该断点可以随着函数地址改变而更新,而且bu断点会保存在windbg工作空间中,下次启动windbg会自动设置上去

4.bm+MyModel!Function

针对符号下断点,它支持匹配表达式

例如bm MyModel!sb*CreateFile、bm MyModel!Dispatch*

5.ba access size 地址

针对内存访问下硬件断点(内存断点),access可以为e(执行)、r(读)、w(写),size以字节为单位,可以是1/2/4,在64为机器上还可以是8

access和size之间不能有空格,如果access是e(执行),那么size必须是1

例如ba w4 0x804ef129,一旦在该地址执行写操作,那么系统就会停下来

查看当前堆栈:

1.kv

提示FPO信息,ChildEBP、retaddr、前三个参数

2.kb

ChildEBP、retaddr、前三个参数

3.kp

全参数(需要所有符号)

dt查看数据结构,如果是查询nt模块中的数据结构,nt模块名可以省略

1.dt _EPROCESS

显示EPROCESS的数据结构 _EPROCESS中的DebugPort:调试程序与被调试程序之间的桥梁,将它设为0,可以进行反调试,有的反调试

_EPROCESS中的Token:进程的权限,可以通过修改该值来获得权限

_EPROCESS中的SectionObject:可以通过该值获得全路径

_EPROCESS中的ImageFileName:进程名称

2.dt _EPROCESS -r

显示EPROCESS包含子项的详细数据结构

3.dt nt!_P*

显示nt模块中所有以_P为开头的结构体的名称

4.x nt!zw*

显示nt模块中所有以Zw为开头的函数名

5.dt _DRIVER_OBJECT 0x87c07bc0

显示地址0x87c07bc0开始的结构体_DRIVER_OBJECT的成员值

6.dt _DRIVER_OBJECT DriverName 0x87c07bc0

显示地址0x87c07bc0开始的结构体_DRIVER_OBJECT的成员值DriverName的值

7.自己在帮助文档中查看dt命令的具体使用

d命令打印值:

1.

db 以一个字节显示值和ASSCII字符

dw 显示2字节的值

dd 显示4字节的值

dq 显示8字节的值

dp 显示指针长度的值(32等同于dd,64等同于dq)

dD 显示double(8字节)的值(内核中不存在浮点数)

df 显示float(4字节)的值(内核中不存在浮点数)

2.

da 显示ascii值

du 显示unicode值

ds 显示ANSI_STRING值

dS 显示UNICODE_STRING值

3.

db 0x87c07bc0 La8(十六进制):显示地址0x87c07bc0处开始的a8个单字节的数据

dw 0x87c07bc0 L2:显示地址0x87c07bc0处开始的2个双字节的数据

4.

dpp 以DWORD或者QWORD显示地址处的指针所指向的值

dpu 以UNICODE显示地址处的指针所指向的UNICODE字符串

dpa 以ASSCII显示地址处的指针所指向的ASSCII字符串

(指针长度随操作系统而定,32位系统则指针为32位,64位系统则指针为64位)

5.

dpu 0x86c6e030+0x1c+0x4 L1:显示地址0x86c6e030+0x1c+0x4开始的指针所指向的UNICODE字符串

e命令修改内存:

eb/ed/eq address

ea address ASCII字符串

eu address UNICODE字符串

获取进程信息(内核调试使用):

!process 0x79c 获取进程号为0x79c的进程信息

!process -1 0 获取当前进程的简略信息

!process 0 0 SoftMgr.exe 获取进程名为SoftMgr.exe的信息

!process 0 0 查看所有进程信息,包括进程块地址

!process 0 7 查看所有进程的详细信息

!process EPROCESS地址 查看进程信息

!process EPROCESS地址 0 获取进程简略信息

!process EPROCESS地址 7 查看进程详细信息

例子:

!process 852fbd40 7:显示进程块地址为852fbd40的进程的详细信息,包括所有线程和线程栈

切换进程/线程(内核调试使用):

.process /p EPROCESS地址:进入进程上下文

.thread ETHREAD地址:进入线程上下文

将windbg中命令的输出保存到文本文件中:

1. .logopen d:/dump.txt 将显示结果放到文件中

2. 运行你想要输出到文本中的命令

3. .logclose d:/dump.txt 关闭文件

4. .logfile 查看是否还有打开的日志记录

在查看ssdt表和shadowssdt表之前一定要加载好符号

查看ssdt和shadowssdt:

1.x nt!kes*des*table*:得到ssdt和shadowssdt的地址

2.dd 地址:查看表数据

3.dds 地址:查看符号表

u 地址:进行反汇编

ub 地址:倒着反汇编

uf 函数地址:对nt模块的函数进行反汇编

uf 模块名!函数地址:反汇编函数

uf /i 函数地址/模块名!函数地址:反汇编并显示共有多少条指令

例如:

u IofCallDriver L5:显示五行的IofCallDriver的反汇编代码

uf /i nt!PspProcessOpen

反调试方法:

1._EPROCESS中的DebugPort-->清零可以反调试

反反调试:ba w4 debugport_addr找到篡改DebugPort的程序

2.KdDisableDebugger-->在内核层检测调试器是否存在

反反调试:bp KdDisableDebugger;eb xxxx修改关键代码让它返回不存在调试器

3.IsDebuggerPresent和CheckRemoteDebuggerPresent-->在用户层检测调试器是否存在

4.Hook一些调试时使用的函数

5.花指令:无用指令或者干扰指令

蓝屏分析:

1.打开虚拟机的dump功能:

右键“我的电脑”->属性->高级系统设置->启动和故障恢复 设置->写入调试信息 核心内存转储->确定->确定->退出

2.这时,如果电脑蓝屏,会转储核心内存为C:\Windows\MEMORY.DMP文件,在蓝屏的最后一行显示转储进度(Dumping physical memory to disk: 80),并在重启后可以发现该文件。

如果sys文件在系统开机时启动,为防止蓝屏,可以开机时,按f8,进入安全模式,然后查看C:\Windows\MEMORY.DMP文件

3.将dmp文件拷贝到实机

4.打开Windbg,菜单栏File->Open Crash Dump...,选择dmp文件

5.设置Windbg的符号链接

6.在windbg命令行中输入!analyze -v,即可分析出问题的原因

7.在windbg命令行中输入.open -a 自己的引发错误的模块名!引发错误的函数+偏移,即可定位到引起错误的源代码位置

例如:.open -a MyModel!OperUnicodeStr+0x2a    .open -a DriverToDump!DriverEntry+2b

8.kv/kp/kb

R0与R3联调:

1.!process 0 0获取用户空间进程块地址或者!process 0 0 SoftMgr.exe就可以直接得到进程SoftMgr.exe的信息

2.输入.process /p + EProcesss地址 切换到应用程序的地址空间

3.如果是x64的系统上调试x86的程序,则输入.effmach x86切换到x86模式,也可以.effmach amd64切换回x64模式,直接输入.effmach可以查看当前模式

4.在符号链接中添加user程序的PDB文件,但不要点击重新加载选择框,然后在命令行输入.reload /f /user

就算没有符号表,也要输入.reload来加载和同步当前用户层内容

5.在windbg中打开应用层源文件

6.下应用层断点,打开R3程序的源代码,按F9下断点

查看局部变量和全局变量:(前提:加载了对应的符号表)

dv 查看局部变量

dv /i 查看局部变量, 并显示符号的类型和参数类型

dv /V 查看局部变量, 并显示变量的存储位置

dv /V VariableName 指定需要查看的变量的名字

dv MyModule!g* dv命令可以带有通配符, 来查看具有某命名模式的变量

查看符号

x MyModule!GlobalVariableName 查看模块MyModule中名为GlobalVariableName的全局变量

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

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

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

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

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

查看模块

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

2.lmf 显示所有模块的信息(包含模块的文件路径)

2.lm m *nt* 显示名字中包含nt的模块的信息

3.lmvm *nt* 显示名字中包含nt的模块的详细信息(注意exe、dll等都不要带后缀名)

4.!lmi uxtheme 想要了解uxtheme.dll的详细调试文件(PDB)信息

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

t指令

1.tc 继续运行直到call指令停止

2.tt 继续运行直到ret指令停止

3.tct 继续运行直到call或者ret指令停止

4.th 继续运行直到跳转指令停止,跳转指令包括call ret 有条件无条件跳转等

5.ta+地址 继续运行程序直到指定地址到达为止

6.t 单步步入

pt 执行到当前函数的ret指令停止,相当于单步按t,直到ret指令停止

gu 继续执行直到当前函数完成

无符号驱动模块360FsFlt的入口点中断:

1.sxe ld:360FsFlt

在加载360FsFlt模块的时候会在DebugService函数里中断下来

2.lm m 360FsFlt

查看360FsFlt的起始地址

3.!dh -a 360FsFlt的起始地址

解析360FsFlt的PE文件,在address of entry point处会显示入口点地址偏移(该入口点并不是DriverEntry,是导出的start)

如果分析失败,则通过ida调整基地址后获取需要下断点的地址并直接用bp下断即可

4.bp 360FsFlt的起始地址+入口点地址偏移

在360FsFlt的入口点处下断点

给进程SoftManagerProxy.exe或者进程模块leakrepair.dll在载入内存时下断点

1.先设置一个异常

!gflag +ksl

sxe ld:SoftManagerProxy.exe

sxe ld:leakrepair.dll

2.接着输入g继续执行,直到进程启动时断下,再输入lm查看想要调试的模块的起始地址

3.断下之后由于peb还没建立,所以这段内存无法访问,但是通过ida找到代码入口点地址然后用bp下断

4.继续执行就会在代码入口点处断下

x64切换到x86模式下:

.load wow64exts

!sw

sx指令:

1.sx

显示所有支持的异常中断

2.加载内核模块时下断

sxe ld:MyDriver 驱动MyDriver加载前下断

sxn ld:MyDriver 驱动MyDriver加载时不会中断,但会显示一条相关信息

sxi ld:MyDriver 取消对MyDriver加载时的设置

3.卸载驱动时下断

sxe ud:MyDriver 驱动MyDriver卸载前下断

sxn ud:MyDriver 驱动MyDriver卸载时不会中断,但会显示一条相关信息

sxi ud:MyDriver 取消对MyDriver卸载时的设置

4.

sxr 复原异常中断设置

!dml_proc

查找字符串:

s -[type] range pattern

(1)type可以是b w d a u,默认为b

(2)range表示范围,有两种方式表示,一是起始地址+空格+终止地址,二是起始地址+空格+L+长度,如果搜索长度超过256MB,则用起始地址+空格+L?+长度

(3)pattern用于指定要搜索的内容,可以用空格分隔要搜索的数值

1.s-sa

s-sa 00000000`01360000 L00000000`0007b000 显示00000000`01360000开始的长度为00000000`0007b000的内存范围内所有的ASCII字符串

s-sa 00000000`01360000 00000000`013db000 显示00000000`01360000为起点00000000`0007b000为终点的内存范围内所有的ASCII字符串

2.s-su

s-su 00000000`01360000 L00000000`0007b000 显示00000000`01360000开始的长度为00000000`0007b000的内存范围内所有的UNICODE字符串

s-su 00000000`01360000 00000000`013db000 显示00000000`01360000为起点00000000`0007b000为终点的内存范围内所有的UNICODE字符串

3.s -a

s -a 00000000`01360000 L00000000`0007b000 "Windows" 在00000000`01360000开始的长度为00000000`0007b000的内存范围内搜索ASCII字符串"Windows"的地址

s -a 00000000`01360000 00000000`013db000 "Windows" 显示00000000`01360000为起点00000000`0007b000为终点的内存范围内搜索ASCII字符串"Windows"的地址

4.s -u

s -u 00000000`01360000 L00000000`0007b000 "Windows" 在00000000`01360000开始的长度为00000000`0007b000的内存范围内搜索UNICODE字符串"Windows"的地址

s -u 00000000`01360000 00000000`013db000 "Windows" 显示00000000`01360000为起点00000000`0007b000为终点的内存范围内搜索UNICODE字符串"Windows"的地址

5.以下三个是同一个意思

s 0012ff40 L20 'H' 'e' 'l' 'l' 'o'

s 0012ff40 L20 48 65 6c 6c 6f

s -a 0012ff40 L20 "Hello"

6.

s -a 0x0 L?0x7fffffff mytest 在目标空间为2G的user mode内存空间中搜索ASCII字符串"mytest"

!address [Address] 显示指定地址的内存属性

执行/跟踪到指定地址:

1.

ta [r] [= StartAddress] StopAddress

从StartAddress开始执行,到StopAddress为止执行过的指令就像单步按t一样显示出来,如果是tar则不显示寄存器值

例如:

ta 0x401890

从当前地址开始执行,执行到0x401890之前的所有指令都打印出来,并显示寄存器值

tr =0x00401124 0x401890

立刻从地址0x00401124开始执行,到0x401890地址期间执行过的所有指令都会打印出来,并且不显示寄存器值

2.

pa [r] [= StartAddress] StopAddress ["Command"]

从StartAddress开始执行,到StopAddress为止执行过的指令就像单步按p一样显示出来,如果是par则不显示寄存器值

例如:

pa 0x401890

从当前地址开始执行,执行到0x401890之前的所有指令都打印出来

par =0x00401124 0x401890

立刻从地址0x00401124开始执行,到0x401890地址期间执行过的所有指令都会打印出来,并且不显示寄存器值

最好的使用方法就是:

在StartAddress和StopAddress处都下断点,StartAddress处断下时,执行par StopAddress,执行完后,StopAddress处断下

如何将文件内容读取到调试器内存/从调试器内存写入文件?

注意这里的读写没有pe映射之类的操作,而是二进制读写

命令:.readmem  文件路径  加载基址 l长度                         将文件内容拷贝到调试目标内存

命令:.writemem  文件路径  加载基址 l长度                        从调试目标内存拷贝到文件

例:

0:000> .writemem 1234.bin 00000000`76eb0000 l0x20000

Writing 20000 bytes................................................................

显示指定进程块fffffa8003cdeb00的安全描述符信息

(1)dt _OBJECT_HEADER SecurityDescriptor fffffa8003cdeb00

显示安全描述符地址0xfffff8a00000463b

(2)!sd 0xfffff8a000004630

显示安全描述符详细信息

显示进程访问令牌

(1)!process 0 1 进程名

显示出Token的地址

(2)!token Token地址

显示Token详细信息

!exchain

显示当前的异常处理程序链

从指定地址开始输入汇编代码

a 地址

之后会出现Input>的符号,就可以输入汇编代码了,输入回车则退出

查看内存页的属性:

(1)用户模式

!address Address

!address -summary

(2)内核模式

!address Address

!address

显示所有KMDF驱动:

!wdfkd.wdfldr

!gle 查看LastError值

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

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

!locks 显示死锁

!cs 列出CriticalSection的详细信息

!idt 查看中断向量表内容

ld kernel32 加载kernel32.dll的符号

.call

符号加载与查看

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

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

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

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

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

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

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

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

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

ld kernel32 /f c:\kernel32.pdb // 加载kernel32.dll的符号kernel32.pdb

.reload /n // 加载内核层符号

.reload /u // 加载用户层符号

.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加载符号信息

.chain  // 显示已经加载进来的模块

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

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

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

查看调试进程

|   // 列出调试进程

|*  // 列出调试进程

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

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

查看线程

~ // 列出线程

~* // 所有线程

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

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

~. // 查看当前线程

~0s // 查看主线程

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

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

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

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

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

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

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

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

!runaway// 显示所有线程的CPU消耗

查看句柄

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

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

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

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

dump输出

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

显示栈帧

.frame // 显示当前栈帧

.frame n // 设置编号n的栈帧为当前栈帧

.frame /r n // 设置编号n的栈帧为当前栈帧 并显示寄存器变量

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

查看堆分配状况

!heap -p -a 00530B98 // 查看地址00530B98在哪个堆分配空间中

!heap // 查看所有堆分配空间信息

!heap -a 00530000 // 查看堆分配空间00530000的堆块信息

页堆(Page Heap)

1.开启页堆

开启该机制后,堆溢出时就立即触发异常

!gflag +hpa

!gflag -i app.exe +hpa

2.关闭页堆

!gflag -hpa

!gflag -i app.exe -hpa

3.查看是否gflag开启了哪些调试选项f

!gflag

开启子进程调试

.childdbg 1

关闭子进程调试

.childdbg 0

查看是否调试子进程

.childdbg

2020安全开发者峰会(2020 SDC)议题征集 中国.北京 7月!


文章来源: https://bbs.pediy.com/thread-258092.htm
如有侵权请联系:admin#unsafe.sh