通过 WinDbg 双机调试,获取针对一次 NtCreateFile 调用的序列日志?
第一阶段:在函数入口处获取上下文与参数
1. 下断点并放行
kd> bp nt!NtCreateFile kd> g当虚拟机中发生文件创建/打开操作时,系统会断下。
2. 获取进程和线程上下文 (PID/TID)使用!thread命令查看当前触发该调用的线程和进程信息:
kd> !thread3. 获取调用栈与返回地址
kd> k4. 获取核心参数(访问权限、处置方式等)根据 32 位__stdcall栈布局提取参数(十六进制):
kd> dd esp+8 L1 ; 获取第2个参数:DesiredAccess (访问权限) kd> dd esp+20 L1 ; 获取第8个参数:CreateDisposition (创建处置) kd> dd esp+24 L1 ; 获取第9个参数:CreateOptions (创建选项)记下这几个值,后续可以对照微软官方文档(或ntstatus.h)翻译成易读的宏名称。windbg不支持直接将其翻译成易读的宏名称。
5. 深度解析目标文件路径这是最重要的一步,需要利用指针解引用获取OBJECT_ATTRIBUTES中的字符串:
1. 查看栈上的第3个参数(即 POBJECT_ATTRIBUTES 的地址) kd> dd esp+c L1 假设上一步输出为 "95d86c10 0107f01c",用 dt 命令解析该地址 kd> dt nt!_OBJECT_ATTRIBUTES 0107f01c 在输出中找到 ObjectName 字段的值,假设为 0x0018f248 使用 dS 命令(大写S)直接打印这个 UNICODE_STRING 结构体指向的字符串 kd> dS 0x0107f058 解析结构体 如果你想看看结构体内部,可以执行 kd> dt nt!_UNICODE_STRING 0x0107f058"8123456c 0018f230"中的第一列地址是你要读取的内存地址本身,即esp+c的绝对地址。第二列地址,这是存放在那个地址里的具体数据。
第二阶段:获取函数执行结果
前面我们拿到了所有的输入参数,现在我们需要让函数执行完毕,看看结果是成功还是失败(比如文件到底存不存在、权限够不够)。
6. 执行到函数返回使用gu(Go Up) 命令,让内核执行完NtCreateFile并停在返回后的第一条指令:
kd> gu7. 查看返回值 (NTSTATUS)在 x86 架构中,函数的返回值存放在EAX寄存器中:
kd> r eax假设输出eax=00000000。
如果你不知道这个错误码是什么意思,可以使用 WinDbg 的!error命令翻译:
kd> !error @eax它会告诉你0000000是STATUS_SUCCESS(成功)。这就是日志中的Return_Status。
最后,清除断点
在
kd>后面输入清除断点的命令:bc *(注:
bc意思是 Breakpoint Clear,*代表清除所有断点。如果你只想清除 0 号断点,可以输入bc 0)。然后再次输入:
g并回车。
这时候,因为拦路虎(断点)被清除了,你的 Win7 虚拟机就会瞬间恢复流畅运行,WinDbg 底部也会重新变成*BUSY* Debuggee is running...啦!
