browser icon
You are using an insecure version of your web browser. Please update your browser!
Using an outdated browser makes your computer unsafe. For a safer, faster, more enjoyable user experience, please update your browser today or try a newer browser.

Trident 中的 Object Thunk

Posted by on 2009 年 07 月 30 日

你可以任意转载本文,但请在转载后的文章中注明作者和原始链接。
媒体约稿请联系 titilima_AT_163.com(把“_AT_”换成“@”)。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
IHTMLElement* elem = NULL;
// get the element....
 
IHTMLObjectElement* objelem = NULL;
elem->QueryInterface(IID_IHTMLObjectElement, (PVOID*)&objelem);
 
IShockwaveFlash* swf = NULL;
objelem->get_object((IDispatch**)&swf);
 
BSTR bsMovie = NULL;
swf->get_Movie(&bsMovie);
OutputDebugStringW(bsMovie);
 
::SysFreeString(bsMovie);
swf->Release();
objelem->Release();
elem->Release();

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

1
2
3
4
5
6
7
8
9
10
11
12
13
IHTMLElement* elem = NULL;
// get the element....
 
IShockwaveFlash* swf = NULL;
elem->QueryInterface(IID_IShockwaveFlash, (PVOID*)&swf);
 
BSTR bsMovie = NULL;
swf->get_Movie(&bsMovie);
OutputDebugStringW(bsMovie);
 
::SysFreeString(bsMovie);
swf->Release();  
elem->Release();

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

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

1
2
3
4
5
6
7
mov     eax, [esp+arg_0]
mov     dword ptr [eax+20h], 15h
mov     ecx, [eax+0Ch]
mov     [esp+arg_0], ecx
mov     ecx, [eax+10h]
mov     ecx, [ecx+54h]
jmp     ecx

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

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

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

订阅本站

4 Comments

  • At 2009.07.30 21:09, 一名游客 said:

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

    • At 2009.07.31 08:58, 李马 said:

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

      • At 2012.03.24 09:50, dj said:

        你的这篇文章给我的启发很大,thanks.
        PS.能交换一下友链吗?

        • At 2012.03.24 10:37, 李马 said:

          已添加。

          (Required)
          (Required, will not be published)