解密未记录的COM接口

3
我有一个指向实现了未公开接口的COM对象的指针。我真的非常想使用这个接口,但是我只有IID。软件大师Geoff Chappell在他的网站上记录了许多这些未公开的COM接口;例如,可以查看IListView。不知何故,他甚至设法获得了函数名称和签名。这样的事情怎么可能呢?他们是猜测的吗?
有人能指点我如何处理这样的事情吗?我知道使用任何未公开接口都存在风险。
更详细地说,我感兴趣的对象是ExplorerFrame.dll中臭名昭著的未公开ItemsView。通过在CoCreateInstance上设置API hook,我可以看到该对象是使用某个未公开的IID作为其主要接口创建的。我假设这就是通过该控件进行操作的接口,因此我对了解其成员很感兴趣。

如果没有文档,你怎么知道你喜欢它呢?找到类型库,使用OleView.exe。 - Hans Passant
修改了问题;看起来ExplorerFrame.dll没有类型库。在OleView中检查Itemsview并没有找到任何有用的东西。 - Paul Accisano
3个回答

5
您知道吗?您可以写信问我!曾经有一段时间,我会明确地写下名称和原型是从微软的公共符号文件中获取的,但我早已放弃了这种冗长的写法。如果我总是解释我的信息来源,那么我将侮辱那些做反向工程的读者,并冒着让那些只想要信息(通常并不令人激动人心)的读者感到无聊的风险。
如果您没有公共符号文件,那么类型库是下一个最好的选择。但是,当然,并不是所有的接口都出现在类型库中 - 甚至包括实现IDispatch的所有接口。
假设您有一个可执行文件及其公共符号文件,获取IID并列出方法几乎是最简单的反向工程。它可能有点复杂,以至于不能可靠自动化 - 尽管我很愿意被证明是错误的。
您可能已经知道了该接口,因为您具有其实现的虚函数表。大多数情况下,您会发现这一点是因为您正在进行反向工程,而在这种情况下,您通过从构造函数或析构函数开始工作来查找其所有接口的虚函数表。虚函数表是指向函数的指针数组。公共符号文件提供了这些函数的修饰名称。熟练的反向工程师可以通过视觉大部分地去修饰这些符号,并且Visual C++提供了一个UNDNAME工具(您的调试器或反汇编器也可能为您完成此工作)。查找IID通常需要检查QueryInterface方法,与接口的虚函数表从类的开头开始的已知偏移值进行匹配。
对于一个简单的接口,例如有半打方法,仅列出基本的IID、偏移和原型的整个练习在好的日子里可能需要10分钟,如果您懒一点最多只需要30分钟。当然,对于许多这些未记录的接口,您可能还想检查在多个版本中实现和IID是否相同 - 这可能很快使好日子变成坏日子。
顺便说一句,如果我猜测或者推测什么,我会尽力确保说清楚。例如,在您引用的关于未经记录的IListView接口的文档的末尾附近,我谈到了一个窗口消息:您可以知道我给出的名称是由我自己杜撰的,因为我说“可能类似于”。

1
嗨,Geoff。非常感谢您的回复。根据您的建议,我从Microsoft的符号服务器下载了ExplorerFrame的PDB。我真的不知道微软会提供这种信息!但是,我在理解它方面遇到了一些麻烦。我似乎找不到许多用于处理PDB的工具...您能详细说明一下如何从这些文件中提取所需的信息吗? - Paul Accisano

2
MSPDBxx.DLL是PDB文件的权威解释器。最常用的解释PDB文件的工具是调试器,以及作为DUMPBIN反汇编器时的Microsoft Visual C++链接器。它们并不能显示PDB文件中的所有内容,但它们可以做到基本的事情,比如列出所有符号、标记代码和数据,并从文件中包含的任何类型信息中总结(公共符号文件通常没有此信息)。
通常情况下,熟练的逆向工程师可以通过目测这些文件获得标准工具未显示的信息。其中最显著的例子是“section contribution information”(节贡献信息),这是公共符号文件在匹配代码与源文件时所能达到的最接近状态。
如何将调试器指向符号文件已有详细文档。我的方法是将二进制文件和相应的PDB文件复制到当前目录中,然后使用DUMPBIN生成列表。只要PDB文件的文件名与二进制文件的调试目录中的文件名匹配,DUMPBIN就会自动使用PDB文件。这真的非常简单。
我想非微软的反汇编器和反编译器至少能够像使用目标二进制文件一样使用任意可用的PDB文件。

0
如果您的指针实现了IDispatch(这很可能),您可以查询该接口,然后使用GetIDsOfNames方法。您可能需要猜测它可能使用哪些接口,并调用QI方法来查看哪个有效 :)

很遗憾,它没有实现IDispatch。唉,那听起来像是一个非常有用的函数... - Paul Accisano
你可能需要尝试错误排除;如果你有猜测,就去尝试并查看是否正确。 - seand
QueryInterface(IID_IDispatch) 返回 E_NOINTERFACE。但是,我已经知道接口是什么了;我不知道的是它定义的方法或它们的参数是什么。我猜我可以随机调用它们并查看哪些会崩溃,哪些不会,但我希望有一种更文明的方式... - Paul Accisano
祝你好运。是的,你可以尝试调用各种vtable位置并查看发生了什么。使用调试器,您应该能够看到函数清除堆栈,这将帮助您推断参数计数。我曾经编写过一个COM vtable拦截器,所以我之前也参与过一些疯狂的事情。 - seand

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接