WEB开发网
开发学院软件开发VC 通用 Thunk 阅读

通用 Thunk

 2008-05-25 21:39:20 来源:WEB开发网   
核心提示: PUSH 1212 ; 使得堆栈增加4CALL func; 使得堆栈也增加4(因为返回地址也被压入堆栈)0x50000:...;被调用者返回这里,我们假设这里的地址是0x50000调用者希望被调用者使用 RET 4 (使得堆栈减少8:参数1212使用4,通用 Thunk(3),返回地址0x

PUSH 1212 ; 使得堆栈增加4

CALL func; 使得堆栈也增加4(因为返回地址也被压入堆栈)

0x50000:...;被调用者返回这里,我们假设这里的地址是0x50000

调用者希望被调用者使用 RET 4 (使得堆栈减少8:参数1212使用4,返回地址0x50000也使用4)来平衡堆栈,所以在这之后没有多余的机器码。所以,在这之后,堆栈是这个样子:

...
1212
0x50000 <- ESP

然后,我们来看看使用__thiscall 的被调用者所希望的参数和返回地址。一个真正的成员函数被调用时。

C obj;
obj.func(1212);

编译器以这样的方式准备参数:

PUSH 1212;
MOV ECX,obj;
CALL C::func

所以,在这之后,堆栈是这个样子:


1212
0x50000 <- ESP

ECX 保存着 this 指针。

这也就是被调用者(void __thiscall C::func(int); ) 需要的形式。

第3,我们看看被调用者如何返回。

事实上,它使用 RET 4 来返回到0x50000

所以,我们唯一需要做的就是准备好this指针,然后跳转到成员函数。(不需要更多的工作,参数和返回值已在正确位置,堆栈也将被正确的平衡。)

设计 ThisToStd

在我们设计第1个,也是最简单的类 ThisToStd 之前,我们还需要3种信息。

1、我们需要一种得到函数地址的方法。

对于数据指针,我们可以转化(cast)它到一个 int 值

void *p = &someValue;
int address = reinterpret_cast<int>(p);
/* 如果检查对64位机的可移植性,将会得到一个警告。不过可以忽略它,因为这个thunk只用在32位机上^_^*/
不同于数据指针,函数指针有更多的限制。void __stdcall fun(int) { … }
void C::fun(int) {}
//int address = (int)fun; // 不允许
//int address = (int)&C::fun; // 同样错误
有2种方法来进行一个强力的转化template<typename dst_type,typename src_type>
dst_type pointer_cast(src_type src) {
  return *static_cast<dst_type*>( static_cast<void*>(&src) );
}
template<typename dst_type,typename src_type>
dst_type union_cast(src_type src) {
  union {
    src_type src;
    dst_type dst;
  } u = {src};
  return u.dst;
}
所以,我们可以实现一个方法template<typename Pointer>
int PointerToInt32(Pointer pointer)
{
 return pointer_cast<int>(pointer); // or union_cast<int>(pointer);
}
int address = PointerToInt32(&fun); // 可以
int address = (int)&C::fun; // 也可以
更多详细信息见 ThunkBase.h

上一页  1 2 3 4 5 6 7 8  下一页

Tags:通用 Thunk

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接