是否可以在不使用CLSID和注册表查找的情况下获取加载的COM-Object的DLL-filename?
我有IUnknown
或者我的情况是IBaseFilter
接口指针,现在我想获取创建此COM-Object的DLL-filename。我可以使用对象点地址反向查找已创建它的已加载模块吗?然后让HMODULE
在GetModuleFileName
中使用它。
答案 0 :(得分:3)
Yirkha的回答是良好的,我有两个补充说明:
DirectShow过滤器通常是旧式C ++ COM对象,虚拟方法表驻留在代码段中,只要我们在单个进程内,就没有代理/存根代码。也就是说,从接口指针解析模块的hack确实运行良好。
EnumProcessModules
/ GetModuleInformation
可以更轻松地替换模块列表。 VirtualQueryEx
可以直接找到DLL的基地址:
const VOID* pvVirtualTable = *((const VOID**) pBaseFilter);
MEMORY_BASIC_INFORMATION Information;
if(VirtualQueryEx(GetCurrentProcess(), pvVirtualTable, &Information,
sizeof Information))
{
TCHAR pszPath[MAX_PATH] = { 0 };
if(GetModuleFileName((HMODULE) Information.AllocationBase, pszPath,
_countof(pszPath)))
{
P.S。我们也在DirectShowSpy here以及GraphStudioNext中执行此操作。
答案 1 :(得分:2)
自然只使用一些黑客攻击。对象本身位于堆上,它是共享的,但是你可以看到它的虚拟表所在的位置 - 它应该几乎普遍存在于创建者二进制文件的只读数据部分。
所以加载对象中的第一个指针,就像虚拟表指针驻留在Windows COM ABI中一样:
IBaseFilter* pFilter = ...;
char* vtbl = *reinterpret_cast<char**>(pFilter);
然后我最初建议用EnumProcessModules()
做一些马戏团,例如here,在每个模块上调用GetModuleInformation()
并检查vtbl
指针是否落入其内存范围。愚蠢的我,我忘记了VirtualQueryEx()
,所以罗马在他的回答中所描述的更好。
当然,所有这些只能用于进程内COM对象,并且不涉及代理。我认为它在你的DirectShow案例中仍然有用。
另请参阅有关使用IPersist::GetClassId()
和注册表查找的注释,它应该适用于大多数DirectShow过滤器。