我正在通过 WinDbg DMP 文件调查内存泄漏。我发现有很多实例AmazeType在堆中,虽然它是一个很好的类型,有办法存在太多。我想知道谁在囤积它们。
!gcroot-ingAmazeType引导我进入“引用计数句柄”。这是有道理的,因为真棒类型列表通过 COM 可调用包装器存储在 COM 对象实例的属性中。
0:047> !gcroot 00000001c093e448
HandleTable:
00000000015041a0 (ref counted handle)
-> 00000001c0932fd8 System.Collections.Generic.List`1[[AmazeType, AmazeAssembly]]
-> 00000001c0927ef8 BaseAmazeType[]
-> 00000001c093e448 AmazeType
Run Code Online (Sandbox Code Playgroud)
可以用引用计数句柄做什么00000000015041a0来获取有关 RCW 和与之相关的 COM 对象的信息?如果没有,如何交替攻击问题?
小智 5
我没有在 64 位转储中完成此操作,只有 32 位转储,但希望这对您有所帮助。
(我意识到这对你来说可能为时已晚,但希望它会帮助其他人。)
根据我的经验,从COM 对象到 .NET 对象的运行方式是这样的。因此,从 .NET 对象到 COM 对象是逆向过程的一种情况。我正在使用来自真实转储的示例,但经过审查和重命名。
从 COM 到 .NET 对象。
您的 COM 对象中有一个字段,可能如下所示:
+0x30 m_iTestObject : ATL:CComPtr<ITestObject> { 0e645150 }
Run Code Online (Sandbox Code Playgroud)
这是间接指向 clr!Unknown_QueryInterface 吗?如果不是,那就不是 CCW:
0:000> dds poi(0e645150) L1
0631c090 07466260 clr!Unknown_QueryInterface
Run Code Online (Sandbox Code Playgroud)
好吧,这是一个 CCW。我们回到原始地址 0e645150,此时我们必须检查一些偏移量,因为它们似乎在 .NET 运行时之间有所不同。到目前为止,我发现的三个偏移量是 -0x0c、-0x10 和 -0x14。显然,在 64 位下偏移量可能不同,但是您可以看到尝试不同的偏移量然后针对结果运行 !mdt 应该很容易:
0:000> dds poi(0e645150-0x0c) L1
2506a4c0 00000000
0:000> dds poi(0e645150-0x10) L1
01785bd8 08acc744
0:000> dds poi(0e645150-0x14) L1
00000000 ????????
Run Code Online (Sandbox Code Playgroud)
我们现在可以对每个结果运行 !mdt (sosex) 或 !do。碰巧的是,其中只有一个实际上给了我们一个有效地址,即 08acc744:
0:000> !mdt 08acc744
08acc744 (TestAssembly.TestObject)
requests:08accba8 (System.Collections.Generic.List`1[[TestAssembly.TestRequest, TestAssembly]])
notifySink:08aee138 (TestAssembly.SinkWrapper)
Run Code Online (Sandbox Code Playgroud)
回溯到指向这个 .NET 对象的 COM 对象:
我们从 08acc744 处的同一个 .NET 对象开始并检查其引用。(您已经使用 !gcroot 查找 RefCounted 句柄):
0:000> !refs 08acc744
Objects referenced by 08ACC744
NONE
Objects that reference 08ACC744 (TestAssembly.TestObject):
RefCounted Handle at 01785BD8, AppDomain=0456F158
Run Code Online (Sandbox Code Playgroud)
好的,所以我们有了手柄。什么指向它?
0:000> s -d 0x00000000 L?0xffffffff 01785bd8
0e645140 01785bd8 2506a4c0 0630ec60 00000000 .[x....%`.0.....
Run Code Online (Sandbox Code Playgroud)
所以这个句柄是从 0e645140 指向的。我们知道,下一级不是直接指向这个地址,而是从这里指向一个偏移量。我们能找到任何指向这些偏移地址的东西吗?
0:000> s -d 0x00000000 L?0xffffffff 0e645140+0x0c
0:000> s -d 0x00000000 L?0xffffffff 0e645140+0x10
27f90d68 0e645150 25d100e8 27fab0f8 00000000 PQd....%...'....
0:000> s -d 0x00000000 L?0xffffffff 0e645140+0x14
Run Code Online (Sandbox Code Playgroud)
我们在 27f90d68 找到了一个指针,我们希望它是 COM 对象内的一个字段。让我们转储该地址周围的内存:
0:000> dds 27f90d68-0x40
27f90d28 0537f8b8
27f90d2c 00000000
27f90d30 559965bd
27f90d34 88000000
27f90d38 15ffe604 TestCore2!ATL::CComObject<CTestContainer>::`vftable'
27f90d3c 15ffe5e4 TestCore2!ATL::CComObject<CTestContainer>::`vftable'
27f90d40 00000002
27f90d44 0000000e
27f90d48 ffffffff
27f90d4c 0000000f
27f90d50 00000010
27f90d54 1dc721d8
27f90d58 00000000
27f90d5c 27d6ef80
27f90d60 262b1ec0
27f90d64 00000001
27f90d68 0e645150
27f90d6c 25d100e8
27f90d70 27fab0f8
27f90d74 00000000
27f90d78 559965b4
Run Code Online (Sandbox Code Playgroud)
我们可以看到一个带有 vftable 的对象,在我们的地址之前开始,所以希望我们的地址是该对象内的一个字段。(请注意,对象很可能在 vftable 条目之间存在间隙,例如 ATL 接收器指针之类的东西可以驻留,但碰巧这是对象的开始)。
0:000> dt 27f90d38 TestCore2!ATL::CComObject<CTestContainer>
+0x000 __VFN_table : 0x15ffe604
=16010f38 _tih : ATL::CComTypeInfoHolder
+0x004 __VFN_table : 0x15ffe5e4
=16010f58 _tih : ATL::CComTypeInfoHolder
+0x008 m_dwRef : 0n2
+0x008 m_pOuterUnknown : 0x00000002 IUnknown
+0x00c m_nStateOrdinal : 0n14
+0x010 m_nKeyOrdinal : 0n-1
+0x014 m_nErrorCodeOrdinal : 0n15
+0x018 m_nErrorTextOrdinal : 0n16
...
+0x30 m_iTestObject : ATL:CComPtr<ITestObject> { 0e645150 }
Run Code Online (Sandbox Code Playgroud)
这样我们就从 .NET 对象返回到指向它的 COM 对象。
我希望这很有用。
| 归档时间: |
|
| 查看次数: |
475 次 |
| 最近记录: |