利用时空旅行调试技术挖掘Windows GDI漏洞 (上)
字数 1296 2025-08-19 12:40:52
利用时空旅行调试技术挖掘Windows GDI漏洞(上)教学文档
1. 时空旅行调试技术(TTD)简介
时空旅行调试(Time Travel Debugging, TTD)是Windows Debugger Preview提供的一项强大功能,它允许开发者记录程序的执行过程,然后可以向前或向后"时间旅行"般地查看程序在任何时刻的状态。
1.1 TTD核心优势
- 执行历史记录:完整记录程序执行过程,包括所有内存状态
- 逆向调试:可以回退到任意执行点重新分析
- 完整上下文:保留所有内存分配、偏移信息
- 精确重现:避免传统调试中难以复现的问题
1.2 基本TTD命令
g-:回滚到跟踪初始状态!tt 00:回滚到开始(百分比格式)p-:回退一步执行p-10:回退10步执行
2. 漏洞分析环境搭建
2.1 所需工具
- Windows Debugger Preview (支持TTD)
- Winafl模糊测试工具套件
- afl-tmin测试用例最小化工具
- 十六进制编辑器
2.2 测试环境配置
- 操作系统:Windows 10 x64
- 测试套件:32位程序
- 目标DLL:gdi32full.dll, GDI32.dll
3. 漏洞发现过程
3.1 初始崩溃分析
通过模糊测试发现WMF文件处理漏洞,崩溃点位于memcpy函数:
(388.1928): Access violation - code c0000005 (!!! second chance !!!)
eax=00000012 ebx=00000000 ecx=00000001 edx=d0d0d0d0 esi=08632000 edi=086241c0
eip=74270b37 esp=00eff124 ebp=00eff14c iopl=0 nv up ei pl nz na po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010202
ucrtbase!memcpy+0x507:
74270b37 8b16 mov edx,dword ptr [esi] ds:002b:08632000=????????
3.2 关键观察点
- 崩溃发生在尝试读取esi(08632000)指向的内存
- 该地址未映射有效内存
- 堆分配记录显示仅分配了0x84字节
4. 测试用例最小化
使用afl-tmin工具最小化崩溃文件:
afl-tmin.exe -D C:\DRIO\bin32 -i input.wmf -o output_MIN.wmf -- -covtype edge -coverage_module GDI32.dll -target_method fuzzit -nargs 2 -- harness.exe @@
最小化后效果:
- 仅保留导致崩溃的关键字节
- 不相关字节被替换为0x30
- 便于识别用户可控数据区域
5. TTD跟踪记录
5.1 启动TTD记录
- 以管理员权限运行Windbg Preview
- File → Start Debugging → Launch Executable Advance
- 启用"Record process with Time Travel Debugging"
5.2 关键调用栈分析
0:000> kv
# ChildEBP RetAddr Args to Child
00 00eff128 76d6e086 08624154 08631f94 00000072 ucrtbase!memcpy+0x507
01 00eff14c 76d6dfd9 00000051 08621d20 00000000 gdi32full!MRBDIB::vInit+0x7d
02 00eff200 76d6da5f ffffff00 00001400 00001400 gdi32full!MF_AnyDIBits+0x167
03 00eff334 74743ca3 75211255 00000000 ffffff00 gdi32full!StretchDIBitsImpl+0xef
04 00eff374 76da86ec 75211255 00000000 ffffff00 GDI32!StretchDIBits+0x43
05 00eff494 76d69164 75211255 0862dff0 0861be96 gdi32full!PlayMetaFileRecord+0x3f3ec
06 00eff544 76d9749d 00000000 00000000 00eff568 gdi32full!CommonEnumMetaFile+0x3a5
07 00eff554 74745072 75211255 d0261074 0049414e gdi32full!PlayMetaFile+0x1d
08 00eff568 71ac9eb1 75211255 d0261074 d0261074 GDI32!PlayMetaFileStub+0x22
09 00eff5fc 71ac9980 09c39e18 000001e4 00000000 gdiplus!GetEmfFromWmfData+0x4f5
0a 00eff624 71a9bd6a 09c33f3c 09c33fd0 00000000 gdiplus!GetEmfFromWmf+0x69
0b 00eff770 71a8030c 09c33f3c 09c33fd0 00eff794 gdiplus!GetHeaderAndMetafile+0x1b970
0c 00eff79c 71a690f4 09c37fc8 00000001 71b59ec4 gdiplus!GpMetafile::InitStream+0x4c
0d 00eff7c0 71a77280 085a3fd0 00000000 09c31ff0 gdiplus!GpMetafile::GpMetafile+0xc2
0e 00eff7e4 71a771e1 09c31ff0 00000000 0859cfeb gdiplus!GpImage::LoadImageW+0x36
0f 00eff800 00311107 085a3fd0 09c31ff4 085a3fd0 gdiplus!GdipLoadImageFromFile+0x51
6. 关键函数分析
6.1 PlayMetaFileRecord函数
dx @$cursession.TTD.Calls("gdi32full!PlayMetaFileRecord")[2].TimeStart.SeekTo()
函数功能:通过执行记录中包含的GDI函数来播放Windows格式的元文件记录。
6.2 StretchDIBits函数
参数分析:
0:000> dds esp LD
0078f4b4 9f211284 <== hdc
0078f4b8 00003030 <== xDest
0078f4bc 00003030 <== yDest
0078f4c0 00003030 <== DestWidth
0078f4c4 00003030 <== DestHeight
0078f4c8 00003030 <== xSrc
0078f4cc 00003030 <== ySrc
0078f4d0 00003030 <== SrcWidth
0078f4d4 00003030 <== SrcHeight
0078f4d8 19a3affa <== *lpBits
0078f4dc 19a3af94 <== *lpbmi
0078f4e0 00000001 <== iUsage
0078f4e4 30303030 <== rop
6.3 BITMAPINFO结构分析
关键结构:
typedef struct tagBITMAPINFO {
BITMAPINFOHEADER bmiHeader;
RGBQUAD bmiColors[1];
} BITMAPINFO;
typedef struct tagBITMAPINFOHEADER {
DWORD biSize;
LONG biWidth;
LONG biHeight;
WORD biPlanes;
WORD biBitCount;
DWORD biCompression;
DWORD biSizeImage;
LONG biXPelsPerMeter;
LONG biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
} BITMAPINFOHEADER;
内存转储:
0:000> dc 19a3af94
19a3af94 00000066 30303030 30303030 00200000 f...00000000.. .
19a3afa4 00000003 30303030 30303030 30303030 ....000000000000
19a3afb4 00000000 30303030 30303030 30303030 ....000000000000
19a3afc4 30303030 30303030 30303030 30303030 0000000000000000
19a3afd4 30303030 30303030 30303030 30303030 0000000000000000
19a3afe4 30303030 30303030 30303030 30303030 0000000000000000
19a3aff4 30303030 30303030 d0d0d0d0 ???????? 00000000....????
19a3b004 ???????? ???????? ???????? ???????? ????????????????
7. 漏洞初步结论
通过TTD分析发现:
- 漏洞触发路径:GDI32!StretchDIBits → gdi32full!PlayMetaFileRecord → gdi32full!MRBDIB::vInit → ucrtbase!memcpy
- 关键问题:BITMAPINFO结构中的字段被精心构造,导致内存越界读取
- 攻击面:WMF文件处理过程中对BITMAPINFO结构的验证不足
8. 后续分析方向
- 精确追踪用户可控数据的传播路径
- 分析BITMAPINFO结构字段如何影响内存分配
- 确定漏洞是否可利用以及利用条件
- 探索其他可能受影响的GDI函数
(下篇将深入分析漏洞利用细节和防护措施)