请教一个关于thunk技术的问题,请进!
关于thunk我的理解是,thunk技术就是在内存里开辟一片空间,存放我们在程序运行时写入的代码,然后让程序跳转到我们开辟的空间,去执行这些代码。而对于让类的成员函数作为回调函数这样的情况,其实就是把调用类的成员函数的语句“call 成员函数”这句代码放到刚才开辟的那片空间去,然后再以该空间的首地址,作为回调函数的首地址传入对应函数去,是这样吗?
在看了http://blog.csdn.net/superarhow/archive/2006/07/10/898261.aspx这篇文章后,我跟了好久。。都没搞清楚这篇文章里的STDACJMPProc里面的汇编代码是做是什么用的?CalcJmpOffset这个函数又是做什么用的??在我的机子上,执行完下面那四句话
p->_this = (long)m_pThis;
p->_func = *(long *)&m_pFunc;
p->tag = 0xE8;
p->offset = CalcJmpOffset((long)p, (long)STDACJMPProc);
后,内存里是这样
01190000 E8 2B 21 27 FF 48 4C .+!'.HL
01190007 36 00 B4 10 40 00 00 6...@..
即call 2B 21 27(这句我明白,不过2B 21 27这个地址我跟进去,好像是STDACJMPProc的地址,那为什么还需经过CalcJmpOffset计算才赋值给offset呢?)
FF 48 4C 36 00 B4 10 40 (那么这句对应的汇编代码是什么呢?)
有领悟了的大哥指教一吓啊`谢谢!
问题点数:40、回复次数:5Top
1 楼superarhow(苏泊尔耗)回复于 2006-11-03 08:43:19 得分 25
由此看来,这篇贴子的作者一定很帅~~~~
内存里生成的内容是这样:
CALL STDACJMPProc
DD offset func
DD offset this_pointer
就这样跳到STDACJMPProc里面时,栈首的指针就指向DD offset func的地址。那段汇编代码就是把地址pop出来,然后取到func和this_pointer,把this_pointer放到ECX中再调用func,效果就和有this指针的一样了。
因为我们用的CALL(0xE8)是CALL NEAR PTR,所以CALL后面的地址是相对地址,所以要用那个CalcJmpOffset计算一下。Top
2 楼akirya(坏[其实偶不是什么所谓的坏人])回复于 2006-11-03 08:55:15 得分 0
这个vckbase上有篇文章讲。推荐用ollydbg调试Top
3 楼jixingzhong(瞌睡虫·星辰)回复于 2006-11-03 09:03:49 得分 5
http://dev.csdn.net/develop/article/15/15747.shtm
“我对C++中THUNK一种实现技术的分析”Top
4 楼mLee79()回复于 2006-11-03 09:13:46 得分 10
我一般都是 mov eax , procAddr ; call eax , 这样做比较方便, 不用计算偏移 .....
这东西, VC 调试照样方便 ...
以前写的 :
#include <windows.h>
#include <stdio.h>
class mTimer
{
BYTE m_cdTrk[16];
static void CALLBACK tTimerProcStatic( mTimer* _pTHIS ){_pTHIS->tTimerProc(); }
protected:
UINT m_nIDEvent;
UINT m_uElapse;
virtual void tTimerProc() = 0;
public:
mTimer( UINT uElapse ) : m_uElapse( uElapse ) , m_nIDEvent( 0 ){
void* pTHIS = this; void* procTimer = (void*)mTimer::tTimerProcStatic;
memcpy( m_cdTrk , "\x68\0\0\0\0\xB8\0\0\0\0\xFF\xD0\xC2\x10\x00" , 16 );
memcpy( m_cdTrk + 1 , &pTHIS , 4 );memcpy( m_cdTrk + 6 , &procTimer , 4 );}
virtual ~mTimer() { StopTimer(); }
public:
void StartTimer() { StopTimer(); m_nIDEvent = SetTimer( NULL , 0 , m_uElapse , (TIMERPROC)(void*)(m_cdTrk) ); }
void StopTimer() { if( m_nIDEvent ) { KillTimer( NULL , m_nIDEvent ); m_nIDEvent = 0; } }
};
class testTimer1 : public mTimer
{
virtual void tTimerProc(){
printf( "testTimer1::tTimerProc ID: %d , COUNT: %d.\n" , m_nIDEvent , m_count++ );
if( m_count > 10 ) PostQuitMessage(0);}
public:
UINT m_count;
testTimer1( UINT u = 1000 ) : mTimer( u ) , m_count(0) {}
};
class testTimer2 : public mTimer
{
virtual void tTimerProc(){printf( "testTimer2::tTimerProc ID: %d \n" , m_nIDEvent );}
public:
testTimer2( UINT u = 1000 ) : mTimer( u ) {}
};
int main()
{
MSG msg;
testTimer1 tmR;
testTimer2 tmR2(500);
tmR.StartTimer();
tmR2.StartTimer();
while( GetMessage( &msg , NULL , 0 , 0 ) )
DispatchMessage( &msg );
return 0;
}
Top
5 楼CrazyAzreal(顶..真系稳食艰难!)回复于 2006-11-03 10:36:21 得分 0
哈哈`明白了``我跟的时候,死活就是没往寄存器窗口看一眼。汗死``谢谢各位大虾了!Top




