|
一:背景
1. 讲故事
上个月我写过一篇 如何洞察 C# 程序的 GDI 句柄泄露 文章,当时用的是 GDIView + WinDbg 把问题搞定,前者用来定位泄露资源,后者用来定位泄露代码,后面有朋友反馈两个问题:
- GDIView 统计不准怎么办?
- 我只有 Dump 可以统计吗?
其实那篇文章也聊过,在 x64 或者 wow64 的程序里,在用户态内存段中有一个 GDI Shared Handle Table 句柄表,这个表中就统计了各自句柄类型的数量,如果能统计出来也就回答了上面的问题,对吧。
32bit 程序的 GDI Shared Handle Table 段是没有的,即 _PEB.GdiSharedHandleTable = NULL。- 0:002> dt ntdll!_PEB GdiSharedHandleTable 01051000
- +0x0f8 GdiSharedHandleTable : (null)
复制代码 有了这些前置基础,接下来就可以开挖了。
二:挖 GdiSharedHandleTable
1. 测试代码
为了方便测试,我来造一个 DC句柄 的泄露。- internal class Program
- {
- [DllImport("Example_20_1_5", CallingConvention = CallingConvention.Cdecl)]
- extern static void GDILeak();
- static void Main(string[] args)
- {
- try
- {
- GDILeak();
- }
- catch (Exception ex)
- {
- Console.WriteLine(ex.Message);
- }
- Console.ReadLine();
- }
- }
复制代码 然后就是 GDILeak 的 C++ 实现代码。- extern "C"
- {
- _declspec(dllexport) void GDILeak();
- }
- void GDILeak()
- {
- while (true)
- {
- CreateDCW(L"DISPLAY", nullptr, nullptr, nullptr);
- auto const gdiObjectsCount = GetGuiResources(GetCurrentProcess(), GR_GDIOBJECTS);
- std::cout << "GDI objects: " << gdiObjectsCount << std::endl;
- Sleep(10);
- }
- }
复制代码
从卦中可以看到,当前有1029个 GDICell 结构体,接下来怎么鉴别每一条记录上都是什么类型呢?其实这里是有枚举的。
- DC = 0x01
- Region = 0x04
- Bitmap = 0x05
- Palette =0x08
- Font =0x0a
- Brush = 0x10
- Pen = 0x30
即 GDIView 中的 红色一列 。
到这里我们可以通过肉眼观察 + F5 检索,可以清晰的看到1029 个句柄对象,其中 1028 个是 DC 对象,其实这就是我们泄露的,截图如下:
3. 脚本处理
如果大家通读会发现这些都是固定步骤,完全可以写成比如 C++ 和 Javascript 的格式脚本,在 StackOverflow 上还真有这样的脚本。- 0:000> dt ntdll!_PEB GdiSharedHandleTable @$peb
- +0x0f8 GdiSharedHandleTable : 0x00000000`03560000 Void
复制代码 三:总结
如果大家想从 DUMP 文件中提取 GDI 句柄泄露类型,这是一篇很好的参考资料,相信能从另一个角度给你提供一些灵感。
来源:https://www.cnblogs.com/huangxincheng/archive/2023/07/25/17579180.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作! |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
x
|