visual studio上虽然也能调试内核,但太麻烦了。很臃肿,本身就是内嵌了一个Windbg
Windbg F1
按下F1就会跳出一个帮助手册,是学习Windbg非常好的参考手册
这个里面就有 Windbg的命令 有使用方法,使用例子
三类命令
元命令,扩展命令和命令
Commands 命令
Mera Commands里的是以. 开头的 叫元命令
Extension Commands 是以!开头的 是扩展命令
因为Windbg既可以调试应用层程序 也可以调试内核层程序,所以有点命令只能用在应用层,有的命令只能用在内核层,有的两者都能用
R3命令,内核命令和同时兼容命令
Debugging Techniques里面列出了一些调试方法 和错误码
首先关掉数字签名,打开调试模式
(只能用在用户态)
显示所有线程: ~*
显示当前活动线程 ~.
显示引起异常线程 ~#
显示第二个线程 ~2
选择第二个线程 ~2 s
显示所有线程的栈 ~* kb (调试几个线程发生死锁的时候要用到)
查看系统中每个线程执行的时间 !runaway
按下F6
附加上去
这个Noninvasive勾上就不能下断点,只能观察
进程就断下了
前面的就是线程编号 后面的就是进程所在Pid 再后面就是Tid...
当前线程
引发异常线程
选中第二个线程 现在处于第二个线程上下文
打印出所有线程的栈
第一个是返回地址 后面的是这个函数的参数
各个线程执行时间
如果不想调试了 就 .detach释放掉
线程就活了
断下的时候,这里可以看寄存器
没有的话 点下 view 都可以调出来
监视变量 和在vs上那个监视一样
windbg复制就是直接按右键 黏贴也是直接按右键
大体和vs上差不多
断点管理指令:
(支持 1--n *)
bl 列出断点
bc 删除断点
bd 禁用断点
be 启用断点
下断点:
bp address后面跟地址
bp model!func 跟模块!函数名,函数名后面也可以加偏移 (要求驱动必须加载到内存中来)失败了就会转话为bu断点
bu mode!func 跟模块!函数名,函数名后面也可以加偏移(延迟断点,即使内存中没有这个模块,也可以下,先记下来模块名称和函数名)专门针对还没加载到内存中的模块
bm model!f*c 支持正则表达式可以一次下多个断点
ba w4/r4/e1/i4 address 内存断点
ba w4 address w代表写 4就是4个字节 表示写内存断点
进程支持调试特点就是 Eprocess 里有一个 DebugPort这个端口 ,进程的内核对象都是叫Eprocess结构 这个Eprocess结构中有一个Debugport的调试端口,我们能用调试器去调试这个程序完全是用debugport来通讯的,有一些软件为防止去调试他,会开启一个线程,去定时的对这个debugport清零(设置为NULL),这样调试器就没办法通过DebugPort来传递调试事件了。就会好奇究竟是哪个线程对这个debugport进行清零呢?清零操作就是对这个内存地址进行一次写入操作,那就可以在调试器里面先对这个地址下一个写内存断点,这样目标在对这个DebugPort进行清零的时候,就可以断下来,就可以知道是谁在清零了,就可以对这个线程做一些操作,就没办法对这个地址进行清零了
ba r4 address
读内存断点,要读这个内存地址,也会引发这个断点,会断下来,就知道是谁再读这个地址
ba e1 address
e 是执行 执行断点 有人来执行这个代码,就会被断下
ba i4 address
i 是 IO IO断点 比如往某个寄存器某个端口进行IO操作
bp /p eprocess address/func 进程断点 Eprocess代表的进程执行到这个地方 才会被断下
bp /t ethread address/func 线程断点
断点分类:
INT3: 临时在代码中插入CC指令
EXCEPTION_BREAKPOINT(0x80000003)异常
内存断点:将要下断点所在的内存页增加一个名为PAGE_NOACCESS(写入时设为PAGE_EXECUTE_READ)的属性,引发异常再判断地址是否为断点位置,一页为单位设置,性能慢,但可以下多个
STATUS_GUARD_PAGE_VIOLATION(0x80000001)异常
硬件断点:DRx调试寄存器总共有8个,从DRx0到DRx7:DE0~DR3:调试地址寄存器,保存需要监视的地址,如设置硬件断点;DR4~DR5:保留 ; DR6~DR7 用来控制断点的大到小和触发断点的时机(比如说大小一个byte没出发时机为写入时),最多只能设置4个断点。由于CPU的支持,硬件断点的效率非常高,设置了硬件断点,在不触发的情况下,不会有肉眼可见的效率影响,毕竟只是写了个寄存器而已。CPU执行命令的时候,发现与dr寄存器符合的时候会触发
STATUS_SINGLE_STEP(单步异常,0x80000004)
OD中菜单里有提供这几种断点供选择
D系列内存查看命令
Eprocess 进程内核对象
dt [nt!] _EPROCESS [-r] 可以看到有什么成员
因为结构体套结构体 加个 -r 就可以递归看到每个成员里的成员
如果后面还加上一个地址的话,还可以用结构体去解析这个结构
dt _PEB address
如果只想看某个成员得值 dt _PEB Ldr 7ffdf000 来查看值
数:
db 以一个字节显示ASCII字符
dw 显示2字节的值
dd 显示4字节得值
dq 显示8字节的值
dp 显示指针长度的值
dD 显示double实数得值
df 显示float实数得值
字符:
da 显示ascii的值
du 显示Unicode的值
ds 显示ANSI_STRING的值
dS 显示UNICODE_STRING的值
混合显示
dW 显示2字节和ascii得值
dc 显示4字节和ascii值
db address L20(十六进制):显示内存address处32个b的长度
上面这些是用来查看虚拟内存的,如果要查看物理内存,就加个!
ddu 打印出地址 和内存的值
E:修改内存
eb/ed/eD/ef/ep/eq/ew
ea/eu/(非null结尾的字符)
eza/ezu(null结尾的字符)
ea address "string"
ed nt!Kd_SXS_Mask 0 禁用SXS.dd无用的调试输出
ed nt!Kd_FUSION_Mask 0
eb address value 改内存中一个字节(常用在调试 反调试) 有签名校验就会被发现
查看栈的情况
kb
当前栈基地址 返回地址 参数
kp
左边是栈基地址和返回地址, 每个参数的值放在了函数里
主要是针对函数参数大于了3个变量可以用kp看每个函数的参数
kp命令必须要有符号
kv
和kp类似,提示了FPO信息
FPO是一种优化,它压缩或者省略了在栈上为该函数穿建框架指针的过程。这个选项加速了函数调用,因为不需要建立和移除框架指针(ESP,EBP)了,同时他还释放了一个寄存器,用来存储使用频率较高的变量,只在IntelCPU架构上才有这种优化。
进程线程命令
(只在内核层)
!process 0 0 //列出系统进程信息
!process EPROCESS 7//列出进程详细信息
!process 0 7 //列出系统进程的详细信息
.process /p EPROCESS //进入该进程上下文查看explore.exe的peb
.thread ETHREAD //进入该线程上下文
!thread ETHREAD //查看线程结构
.logopen d:\tmp\dump.txt //重定向到文件
.logclose
uf 就是对函数反汇编