本章介绍了windbg对用户层和内核层的常用调试命令,以及介绍了给DriverEntry下断点的方法
5.1 Debugging Tools for Windows
Download Debugging Tools for Windows - WinDbg - Windows drivers | Microsoft Docs
该软件包有好多种调试器,就 windbg 是有界面的调试器
这些调试器都是基于调试器引擎: DbgEng.dll,该调试器引擎有文档,可以用来写新的调试器
5.2 Windbg 用户调试
Windbg 支持三种命令:
- 内部命令:内建在调试器之中,用于操作被调试的目标
- 元命令:以
.
开头,操作调试进程自身,不直接操作被调试的目标 - 扩展命令:以
!
开头,扩展 DLL 为调试器提供了很多功能
用户模式调试,调试进程有两种方法:使用调试器打开进程,使用调试器附加进程
线程进程内部所有线程信息:
0:004> ~
0 Id: 2688.6c88 Suspend: 1 Teb: 00000085`0ba9d000 Unfrozen
1 Id: 2688.5274 Suspend: 1 Teb: 00000085`0ba9f000 Unfrozen
2 Id: 2688.6a78 Suspend: 1 Teb: 00000085`0baa1000 Unfrozen
3 Id: 2688.1908 Suspend: 1 Teb: 00000085`0baa3000 Unfrozen
. 4 Id: 2688.68d4 Suspend: 1 Teb: 00000085`0baa5000 Unfrozen // 前面有点的是当前线程
快速设置符号:
.symfix Path
查看已有符号信息:
lm
符号信息常见的有这几种类型:
- deferred:在当前调试会话中未用到,在需要时会被装入
- pdb symbol:正确符号已经被装入,后面会显示本地地址
- export symbol:这个 DLL 只有导出符号可用
- no symbol:没有符号
强制重新加载符号:
.reload /f modulename.dll
显示当前线程的栈追踪信息:
0:004> k
# Child-SP RetAddr Call Site
00 00000085`0c0ff7e8 00007ff8`7ba1c98e ntdll!DbgBreakPoint
01 00000085`0c0ff7f0 00007ff8`7aad7034 ntdll!DbgUiRemoteBreakin+0x4e
02 00000085`0c0ff820 00007ff8`7b9a2651 KERNEL32!BaseThreadInitThunk+0x14
03 00000085`0c0ff850 00000000`00000000 ntdll!RtlUserThreadStart+0x21
切换到其他线程:~ns
这里的 n 是线程索引号
0:004> ~2s
ntdll!NtWaitForWorkViaWorkerFactory+0x14:
00007ff8`7b9f07c4 c3 ret
0:002> ~
0 Id: 2688.6c88 Suspend: 1 Teb: 00000085`0ba9d000 Unfrozen
1 Id: 2688.5274 Suspend: 1 Teb: 00000085`0ba9f000 Unfrozen
. 2 Id: 2688.6a78 Suspend: 1 Teb: 00000085`0baa1000 Unfrozen // 当前线程
3 Id: 2688.1908 Suspend: 1 Teb: 00000085`0baa3000 Unfrozen
# 4 Id: 2688.68d4 Suspend: 1 Teb: 00000085`0baa5000 Unfrozen // 引起最后一个断点的线程
线程信息内容含义:
0 Id: 2688.6c88 Suspend: 1 Teb: 00000085`0ba9d000 Unfrozen
0 调试器线程索引
Id: 2688.6c88 进程ID.线程ID
Suspend: 1 挂起计数
Teb: 00000085`0ba9d000 TEB
Unfrozen 是否冻结(未冻结)
查看十进制和反查十六进制:
0:002> ? 0x400
Evaluate expression: 1024 = 00000000`00000400
0:002> ? 0n1024 // 十进制以0n开头
Evaluate expression: 1024 = 00000000`00000400
查看 TEB:不带任何地址显示当前线程 TEB(!teb
显示 teb 部分内容,要显示完整内容使用命令:dt ntdll!_TEB
)
0:002> !teb
TEB at 000000850baa1000
ExceptionList: 0000000000000000
StackBase: 000000850bf00000 // 当前线程用户栈基址
StackLimit: 000000850befd000 // 当前线程用户栈限制
SubSystemTib: 0000000000000000
FiberData: 0000000000001e00
ArbitraryUserPointer: 0000000000000000
Self: 000000850baa1000
EnvironmentPointer: 0000000000000000
ClientId: 0000000000002688 . 0000000000006a78 // 进程和线程ID
RpcHandle: 0000000000000000
Tls Storage: 0000000000000000 // 此线程的TLS数组
PEB Address: 000000850ba9c000 // PEB
LastErrorValue: 0 // 上一个Win32错误代码(GetLastError)
LastStatusValue: 0
Count Owned Locks: 0
HardErrorMode: 0
设置断点:
bp kernel32!createfilew
查看断点:
bl
禁用断点:
bd 断点索引
bd *
运行:
g
查看 Unicode 字符串:
du 地址
du @rax
步过执行(F10):
p
步入执行(F11):
t
查看错误值细节:
!error @eax
退出调试器:
q
断开调试器与进程的连接:
.detach
5.3 Windbg 内核调试
此处内容需要配置内核调试才可用,关于配置 Windows 的调试环境见第二章笔记处
显示进程信息:
!process 0 0 csrss.exe // 显示所有运行csrss.exe的进程信息
// 参数里第一个0:进程EPROCESS地址
// 参数里第二个0:显示信息的详细程度,0表示最小信息
显示作业信息:
!job job地址
dt nt!_EJOB job地址
作业是用来容纳一个或多个进程的对象,可以对其应用各种限制并监视各种统计信息
显式加载用户符号:
.reload /user
显示系统和进程的内存统计信息
!vm
显示系统中正在处理器上运行的线程的信息
!running
5.5 给 DriverEntry 下断点
在虚拟机里运行驱动前,把符号文件 pdb 也复制进去,然后安装驱动,先别启动,这个时候断下来,给未解析的符号处设置断点,然后恢复运行再启动驱动,就会在这里断下来:
1: kd> bu ch4_PriorityBooster!driverentry
1: kd> g
Breakpoint 0 hit
ch4_PriorityBooster!DriverEntry:
fffff805`498b11c0 4889542410 mov qword ptr [rsp+10h],rdx
可以看到,DriverEntry 是这么被调用的:
2: kd> k
# Child-SP RetAddr Call Site
00 ffffa408`ff2672d8 fffff805`498b5020 ch4_PriorityBooster!DriverEntry [C:\Users\selph\source\Book\WindowsKernelProgramming\ch4_PriorityBooster\ch4_PriorityBooster\entry.cpp @ 82]
01 ffffa408`ff2672e0 fffff805`41b107c6 ch4_PriorityBooster!GsDriverEntry+0x20 [minkernel\tools\gs_support\kmodefastfail\gs_driverentry.c @ 47]
02 ffffa408`ff267310 fffff805`41b101fe nt!IopLoadDriver+0x4c2
03 ffffa408`ff2674f0 fffff805`414bd095 nt!IopLoadUnloadDriver+0x4e
04 ffffa408`ff267530 fffff805`4152a7a5 nt!ExpWorkerThread+0x105
05 ffffa408`ff2675d0 fffff805`415c8b2a nt!PspSystemThreadStartup+0x55
06 ffffa408`ff267620 00000000`00000000 nt!KiStartSystemThread+0x2a
指定断点在某个进程执行时触发:
bp /p 指定进程EPROCESS地址 断点地址