前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >ATL Thunk机制学习

ATL Thunk机制学习

作者头像
雪影
发布2018-08-02 12:07:59
7680
发布2018-08-02 12:07:59
举报
文章被收录于专栏:流媒体人生流媒体人生

  ATL模板类库使用Thunk技术来实现与窗口消息相关联的HWND和负责处理消息的对象的this指针之间的映射。      ATL中窗口类注册时,窗口过程函数缺省值都是StartWindowProc,当创建窗口产生第一条消息时将调用此函数。 StartWindowProc是CWindowImplBase的一个静态成员函数,它的工作是建立CWindowImpl派生对象的HWND与对象的 this指针之间的映射。在新的HWND被缓存到WindowImpl派生对象的成员数据中之后,对象真正的窗口过程将替代 StartWindowProc窗口过程,并且窗口过程参数HWND被替换成对象指针值。

[cpp] view plain copy

代码语言:javascript
复制
//for X86) 
PVOID __stdcall __AllocStdCallThunk(VOID);  
VOID  __stdcall __FreeStdCallThunk(PVOID);  
#pragma pack(push,1) 
struct _stdcallthunk  
{  
 DWORD   m_mov;          // mov dword ptr [esp+0x4], pThis (esp+0x4 is hWnd) 
 DWORD   m_this;         // 
 BYTE    m_jmp;          // jmp WndProc 
 DWORD   m_relproc;      // relative jmp 
 BOOL Init(DWORD_PTR proc, void* pThis)  
    {  
        m_mov = 0x042444C7;  //C7 44 24 0C 
        m_this = PtrToUlong(pThis);  
        m_jmp = 0xe9;  
        m_relproc = DWORD((INT_PTR)proc - ((INT_PTR)this+sizeof(_stdcallthunk)));  
 // write block from data cache and 
 //  flush from instruction cache 
        FlushInstructionCache(GetCurrentProcess(), this, sizeof(_stdcallthunk));  
 return TRUE;  
    }  
 //some thunks will dynamically allocate the memory for the code 
 void* GetCodeAddress()  
    {  
 return this;  
    }  
 void* operator new(size_t)  
    {  
 return __AllocStdCallThunk();  
    }  
 void operator delete(void* pThunk)  
    {  
        __FreeStdCallThunk(pThunk);  
    }  
};  
#pragma pack(pop)  

Init() 函数中这组汇编指令被初始化为下面的指令:

mov dword ptr [esp+0x4], pThis

jmp (int)proc - ((int)this+sizeof(_WndProcThunk))

它完成的功能是,用窗口类的指针 pThis 代替窗口句柄 hWndesp+0x4 中放的就是 hWnd ),然后跳转到传入的 proc 函数处( (int)proc - ((int)this+sizeof(_WndProcThunk))procthunk 之间的距离)。

[cpp] view plain copy

代码语言:javascript
复制
static LRESULT CALLBACK StartWindowProc(HWND hWnd, UINT uMsg,  
 WPARAM wParam, LPARAM lParam)  
    {  
        CContainedWindowT< TBase >* pThis = (CContainedWindowT< TBase >*)_AtlWinModule.ExtractCreateWndData();  
        ATLASSERT(pThis != NULL);  
 if(!pThis)  
        {  
 return 0;  
        }  
        pThis->m_hWnd = hWnd;  
 // Initialize the thunk.  This was allocated in CContainedWindowT::Create, 
 // so failure is unexpected here. 
        pThis->m_thunk.Init(WindowProc, pThis);  
        WNDPROC pProc = pThis->m_thunk.GetWNDPROC();  
        WNDPROC pOldProc = (WNDPROC)::SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)pProc);  
#ifdef _DEBUG 
 // check if somebody has subclassed us already since we discard it 
 if(pOldProc != StartWindowProc)  
            ATLTRACE(atlTraceWindowing, 0, _T("Subclassing through a hook discarded./n"));  
#else 
        pOldProc;    // avoid unused warning 
#endif 
 return pProc(hWnd, uMsg, wParam, lParam);  
    }  

以下是关于Thunk技术测试的例子

[cpp] view plain copy

代码语言:javascript
复制
//涂远东 2009 09 17 深圳 
//声明函数类型。 
typedef void (*TESTFUN)(void*);  
//定义修改代码的结构。 
#pragma pack(push,1) 
struct Thunk  
{  
 DWORD   m_mov;          // 修改参数指令 
 DWORD   m_this;         //修改后的参数 
 BYTE    m_jmp;      // jmp TESTFUN,跳转指令。 
 DWORD   m_relproc;  // relative jmp,相对跳转的位置。 
 //初始化跳转代码。 
 void Init(TESTFUN pFun, void* pThis)  
    {  
 //设置参数指令 
        m_mov = 0x042444C7;  //C7 44 24 0C 
 //设置修改后的参数 
        m_this = PtrToUlong(pThis);  
 //设置跳转指针。 
        m_jmp = 0xe9;  
 //设置跳转的相对地址。 
        m_relproc = (int)pFun - ((int)this+sizeof(Thunk));  
 //把CPU里的缓冲数据写到主内存。 
        FlushInstructionCache(GetCurrentProcess(),  
 this, sizeof(Thunk));  
    }  
};  
#pragma pack(pop) 
//测试动态修改内存里的指令数据。 
class CTest  
{  
public:  
 //保存动态修改代码的内存。 
    Thunk m_Thunk;  
 //真实运行的函数。 
 static void TestFun(void* p)  
    {  
        CTest* pTest = (CTest*)p;  
        pTest->Print();  
    }  
 void Print()  
    {  
        printf("这里仅仅是一个测试/n TestFun函数的参数被修改了/n");  
    }  
};  
int main(int argc, char* argv[])  
{  
 //如下调用这个类: 
 //测试运行。 
    CTest Test;  
    Test.m_Thunk.Init(Test.TestFun,&Test);  
    TESTFUN pTestFun = (TESTFUN)&(Test.m_Thunk);  
 char* psz = "test";  
    pTestFun((void*)psz);   
 return 0;  
}  
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2009年09月17日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档