在今后会有相当的实验环节,对于windows内核实验,调试环境是必不可少的,本章讲解双机调试的环境搭建与常见的WINDBG指令。
准备材料:
VMware workstation : [https://www.vmware.com/go/downloadworkstation-cn]
windows 7 x64 ISO (请使用种子下载工具进行下载):
[ed2k://|file|cn_windows_7_ultimate_with_sp1_x64_dvd_u_677408.iso|3420557312|B58548681854236C7939003B583A8078|/]
windbg: [https://docs.microsoft.com/zh-cn/windows-hardware/drivers/debugger/debugger-download-tools]
安装过程:
首先安装Vmware workstation pro,运行后无脑下一步就OK。
安装完成后界面如
接下来创建win7虚拟机,下一步到此画面,选择win7 ISO镜像
虚拟机较大,注意存储位置是否足够放下大概会占用20~40GB的空间
如需修改则作调整
在自定义硬件中需要注意内存大小适中,核心暂时定为1个,因为在练习时多核CPU有时会影响练习结果,并且多核上有些数据结构是一个核心一个,所以操作起来相对麻烦。
接下来重要的一点:添加一个串口
配置为此,注意另一端是应用程序,而非虚拟机
安装中
安装完成后开始配置windows 调试启动模式
接下来配置调式模式设置,一定要注意右下角串口端口,当前端口是2那么设置的调式端口就是2。
为方便今后调试,将调试启动项设置为默认启动项
至此windows启动项设置结束~
设置windbg调试器的快捷方式参数
“<windbg的路径>\windbg.exe" -b -k com:pipe,port=//./pipe/com_WIN7_64,baud=115200,resets=0 -y SRV*<符号存储的路径>*http://msdl.microsoft.com/download/symbols
测试调试环境
重启win7虚拟机,在vmware 加载完毕后 启动windbg快捷方式,windbg将会与windows 建立调试连接
windows将等待windbg的下一条指示,此时windows 将会被调试器挂起。
输入 g 指令后,windows将继续运行。
至此win7 与 windbg 的双机调试环境搭建完毕。
接下来了解下windbg的基本操作,以及注意事项
WINDBG 内核调试常用指令
扩展指令
!process 0 0 枚举进程 (全局句柄表 CID 下标)
!thread 枚举当前进程线程 (EPROCESS ActiveThread 链表)
!handle 枚举当前进程句柄对象信息(EPROCESS 本地句柄表)
!frame 调用帧
!devobj 设备对象(句柄表)
!fileobj 文件对象(句柄表)
!drvobj 驱动对象(句柄表)
!findhandle 对象所有引用信息(来自EPROCESS 句柄表)
!idt 检索idt表(来自KPCR)
!sw 切换当前处理器模式 32 <=> 64
!sym 显示当前符号设置
!drivers 显示所有驱动模块 (NtQuerySystemInformation SystemModuleInformation)
!pte 查找虚拟地址对应得PTE (EPROCESS->CR3)
!dml_proc 遍历所有进程及指定进程的线程,多数DML格式
!vad 进程内存段信息 (EPROCESS->VADRoot)
!vtop [PageDir,0] VA 显示虚拟地址的PML4E, PDPE, PDE, PE, PhyAddr (解析地址为页表下标)
!pcr 查看所有CPU结构信息(KPCR),通过FS(x86) GS(x64)获取
!poolused 查看当前系统分配pool与pool tag信息(用来查找未释放堆非常合适)
内部指令
.process 切换进程 (AttachProcess)
.thread 切换线程
k* 调用栈
u 反编译 ,L行数
f 反编译整个函数,/i当前反编译指令数,/c搜索函数内的call
b 向前反编译
r BIOS Real mode 代码
up 对物理地址反编译
r 寄存器操作
p 步过
t 步入
gu 步出
gc 运行
bp 断点
bp address "j()'';''" 条件断点
s 查找
s -sa 查找ascii 字符串
s -su 查找unicode 字符串
s -v 查找c++的类
s BaseAddr LSize '字' 0xff "字符串"
s -[w] 只查询可写数据区域
s -b,w,d,q byte,word,dword,qword 四种数据范围
bp address ".if(){}.elif(){}.else{}"
# 查询反编译窗口中的任何字符,正则符号注意转义
~
s 切换当前处理器
. 当前线程
# 当前出现异常,调试时间的线程
* 所有线程
number 指定线程
|s 设置当前进程(仅在用户模式下使用)
||s 设置当前系统(仅在多调试模式下使用)
?? 计算传入的C风格表达式
.expr 全局表达式的语言格式
/q 查看支持的语言
/s 设置当前解析语言
? 计算表达式
bl 断点列表
bc 删除断点
bd 禁用
be 启用
d 查看
b/w/d/q byte word dword qword
a ascii
u unicode
g 读取段选择子信息
l
s
t 套入指定结构体,
-r 递归查看深度(默认为1)
.cxr 切换到异常发生地(参数为异常产生的 _CONTEXT 结构地址)
xs* 为指定调试事件或异常指定操作方法,或中断
sxe 为指定异常做处理
xsd,xsn,xsi 不为指定异常处理
iml 初始化模块加载 (仅内核使用)
ibp 初始化断点
out 指定应用程序输出
ld 模块加载
ud 模块卸载
cpr 创建进程
epr 进程退出
ct 创建线程
et 线程退出
ser 系统错误
rdmsr 读取MSR寄存器
wrmsr 写入MSR寄存器
wt 追踪所有调用 usermode:(all), kernelmode:(only x86)
.load wow64exts 加载wow64拓展功能
.reload 重新加载模块
/d 重新加载调试器模块列表中的所有模块
/f * 强制调试器立即加载指定文件的符号
/s 重新加载系统的模块映射列表中所有模块,如果应用层使用模块名称,则必须使用/s
/user 仅仅重新加载应用层符号
/u 卸载所有模块
/w 不展开通配符
.browse 单指令窗口,不干扰主窗口,可支持退回
.cache forcedecodeuse 清空缓存,强制写入内存
.dump 创建Dump文件
.chain 查询windbg当前加载的库与插件
.extmatch cmd 查询windbg所有模块的拓展指令
/e mod 枚举或查询指定模块的指令
.attach 挂接进程
.detach 取消挂接
.beep 响一下
.time 显示会话开始时间与目标主机时间
.asm 设置反调试属性
.url 网页跳转指令
.dml_flow 寻找附近的代码,跳转来源与将跳转地址
/// 脚本语句 ///
@"string\\" => string\\ 字符串不做转义
. 某些语境下代表r/eip
.printf [option] format [,arg1,...]
/od debug
/oD debug prompt
/oe error
/on normal
/op prompt
/oP prompt resigter
/os symbols
/ov verbose
/ow warnning
format:
%p pointer
%N 32bit or 64bit pointer
%I (any 64 bit)ULONG64
%ma ascii string
%mu unicode string
%msa ANSI_STRING string
%msu UNICODE_STRING string
%y symbols information
%ly symbols and source line information
as 别名
/ma str 转换成ansi字符串表示
/mu str 转换成unicode字符串表示
/msa str 转换成ANSI_STRING结构
/msu str 转换成UNICODE_STRING结构
/x 1+2 数值,在.echo 中如果要.echo输出,需要放在.block下
/f E:\... 读出文件内容
/c code 代码,需要整段代码,引用时将标识符转换为代码
al 列出所有别名
ad * 删除(所有)别名
${as} 展开as宏
${/d:as} 是否定义as宏
${/n:as} as宏名称本身
${/f:as} 展开as宏,不存在则为空
j 类似.if,语法:j bool 表达式1;表达式2
z 类似于.do{}(),语法:表达式1;z(bool)
.sleep 暂停n毫秒
.block 块展开as宏
.if 如果 ,语法 .if( bool ){}
.elsif 否则如果,语法 .if(bool){}.elsif(bool){}
.else 否则 ,语法 if(bool){}.else{}
.break 跳出循环
.continue 结束本次循环
.do do-while,语法 do{}(bool)
.for 语法:for(init;bool;add){}
.foreach 对指令执行结果的每一个单词传入标识符,语法:foreach(标识符 {指令}){.echo "标识符"}
/s 对字符串的每一个单词传入标识符,语法:foreach(标识符 "字符串"){.echo "标识符"}
/f 对文件内容每一个单词传入标识符,语法:foreach(标识符 文件路径){.echo "标识符"}
.catch 异常捕获 .catch{代码}
.leave 退出到.catch外
.openlog file 打开日志
.logclose 关闭日志
.logfile 查看当前日志文件
poi 取地址值,语法 poi(address)
预定义函数宏
masm 内置宏
$iment 通过模块获得入口点,语法:$iment(Address))
$scmp 字符串对比,C++: strcmp
$sicmp 字符串对比,C++: stricmp
$spat 正则,语法 $spat("str", "pattern")
$vvalid 探测内存有效性,语法:$vvalid(Address,lenght)
C 内置宏
#CONTAINING_RECORD(Addr, Type, Field) LIST_ENTRY结构寻址
#FIELD_OFFSET(Struct, Field) 取得字段偏移
#RTL_CONTAINING_FIELD(Struct, Size, Field) 字段是否在大小范围内
#RTL_FIELD_SIZE(Struct, Field) 字段大小
windbg预定义宏
$ntnsym nt
$ntwsym ntdll
$ntsym 当前环境来决定是ntdll还是nt
$exentry 进程入口点
$proc EPROCESS
$thread ETHREAD
$peb PEB
$teb TEB
$tpid 进程ID
$tid 线程ID
$bp id 断点对应地址DML Debuggee markup language
/// DML (Debuggee Markup Language) ///
相关指令
.dml_start filename 解析文件内容为DML,并且打印
.dml_flow address1 address2 从address1开始,有多少个地址访问到从address2,和将要跳转到哪。
相关标签
<link cmd="command"> Descriptor </link> //链接
<b></b> //粗体
<i></i> //斜体
<u></u> //下划线
<col fg bg></col> //设置子图颜色
<exec cmd=""></exec> //指令执行
<altlink name cmd/> //右键菜单下