http://xjchilli.blog.163.com/blog/static/4534773920097732847203/

在对网页中的 ActiveX 控件进行操作的时候,需要获得该元素对应的 ActiveX 对象接口的指针。以 Flash 对象为例,代码类似于这个样子:

C++代码
IHTMLElement* elem = NULL;    IHTMLObjectElement* objelem = NULL;    elem->QueryInterface(IID_IHTMLObjectElement, (PVOID*)&objelem);    IShockwaveFlash* swf = NULL;    objelem->get_object((IDispatch**)&swf);    swf->get_Movie(&bsMovie);    OutputDebugStringW(bsMovie);    ::SysFreeString(bsMovie);   

有趣的是,我们还可以不经过 get_object,只使用 QueryInterface 就能获得 IShockwaveFlash 的接口指针进行调用,如下:

C++代码
IHTMLElement* elem = NULL;    IShockwaveFlash* swf = NULL;    elem->QueryInterface(IID_IShockwaveFlash, (PVOID*)&swf);    swf->get_Movie(&bsMovie);    OutputDebugStringW(bsMovie);    ::SysFreeString(bsMovie);   

我很怀疑这里面 get_Movie 的可靠性,便跟踪了进去,发现:

可以看到,目标函数的地址并不是位于 Flash OCX 领空之中的,而是在 mshtml 之中一个名为 TearoffThunk21 的函数——事实上,从字面上来看,它已经说明自己是个 thunk 了。那么,继续检查这个函数,它的实现如下:

反汇编代码
mov     dword ptr [eax+20h], 15h   

简单分析一下,这个 thunk 做了下面这几件事:

从堆栈中获取 this 指针; 获取当前函数(get_Movie)在虚表中的索引 15h; 从 this 指针中获取真正的 ActiveX 对象指针; 将堆栈中的 this 指针用真正的对象指针替换; 从 this 指针中获取某个指针,从下文来看,这个指针应该是 ActiveX 对象的虚表指针; 从虚表中获取当前函数(get_Movie)的地址(54h / 4 == 15h); 跳转到真正的函数中执行。

到这里,结论很自然地就出来了——通过直接 QueryInterface 而得到的 IShockwaveFlash 接口指针是个假的。那么,这个假的接口指针存在的意义又是什么呢?当然,存在即合理,因为有的 IHTMLElement 是查询不到 IHTMLObjectElement 接口的,比如由 <embed></embed> 标签盛放的 Flash 对象。

Trackbacks

引用 一名游客 说过的话:


如果真的是,那么 1、3、4 步完全可以省去。

Post by 李马 on 2009, July 31, 8:58 AM

楼主有没有比较过两个方法得到的指针? 
我怀疑通过QueryInterface()得到的也是真的IShockwaveFlash接口指针. 只不过这个flash对象是被Trident以aggregate的方式生成的.

Post by 一名游客 on 2009, July 30, 9:09 PM

 

发表评论