通用 Thunk
2008-05-25 21:39:20 来源:WEB开发网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) { … }
有2种方法来进行一个强力的转化
void C::fun(int) {}
//int address = (int)fun; // 不允许
//int address = (int)&C::fun; // 同样错误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>
更多详细信息见 ThunkBase.h
int PointerToInt32(Pointer pointer)
{
return pointer_cast<int>(pointer); // or union_cast<int>(pointer);
}
int address = PointerToInt32(&fun); // 可以
int address = (int)&C::fun; // 也可以
更多精彩
赞助商链接