小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

基于Thunk技術(shù)的Windows Timer的封裝

 SamBookshelf 2013-12-24

        由于最近項(xiàng)目是要開(kāi)發(fā)一個(gè)BHO瀏覽器插件,我們需要使用定時(shí)器來(lái)輪詢頁(yè)面的變化。實(shí)際上,就是讓定時(shí)器能夠訪問(wèn)成員變量,或者說(shuō)使定時(shí)器成為成員函數(shù)。但是,定時(shí)器調(diào)用的是一個(gè)回調(diào)函數(shù)(CALLBACK),回調(diào)函數(shù)是一個(gè)系統(tǒng)調(diào)用的函數(shù),它被封裝在類里面只能以static的方式定義。這種定義方式和我們的項(xiàng)目要求不符合,因?yàn)閟tatic函數(shù)只能訪問(wèn)static變量。

    我們首先分析CALLBACK函數(shù)不能被封裝成成員變量的原因。一個(gè)對(duì)象的成員函數(shù)能夠訪問(wèn)類成員的關(guān)鍵是它先傳了對(duì)象的this指針給函數(shù),函數(shù)就能夠用this.xx的方法訪問(wèn)成員變量了。通過(guò)反匯編分析,我們發(fā)現(xiàn)其實(shí)就是給ECX寄存器傳了this指針過(guò)去,之后訪問(wèn)類成員時(shí),其地址就是ECX加偏移量,這就是對(duì)象的本質(zhì)。

        為了達(dá)到這個(gè)目的,我嘗試了一些方法,均可行。但沒(méi)有Thunk來(lái)的直接。下面簡(jiǎn)單介紹一下:

1、全局變量法:通過(guò)全局map變量的方式記錄對(duì)象的指針,在設(shè)置定時(shí)器時(shí),將定時(shí)器的EventID和this指針作為鍵值對(duì)存到全局變量中。然后,定時(shí)器調(diào)用時(shí),EventID查詢當(dāng)前頁(yè)面的對(duì)象指針(完美解決)。

2、EventID:直接將對(duì)象的指針強(qiáng)轉(zhuǎn)成UINT類型當(dāng)成EventID傳入定時(shí)器設(shè)置的函數(shù),在定時(shí)器調(diào)用時(shí)再將EventID轉(zhuǎn)回this指針,這個(gè)方法應(yīng)該在64位操作系統(tǒng)中會(huì)失效(未驗(yàn)證)。

最終,我們選擇Thunk技術(shù)(微軟的ATL同樣適用Thunk技術(shù)封裝窗口)。Thunk技術(shù)的原理是使程序在運(yùn)行時(shí)直接執(zhí)行機(jī)器碼。在下面的代碼中將看到程序直接跳轉(zhuǎn)到分配的虛擬內(nèi)存上執(zhí)行代碼。

我們首先看代碼的核心部分:

  1. #pragma pack(push,1)    //取消字節(jié)對(duì)齊開(kāi)始(編譯優(yōu)化指令)  
  2. class Thunk  
  3. {  
  4. public:  
  5.     unsigned char    m_mov; // "mov eax,"的字節(jié)碼  
  6.     unsigned int    m_this; //this指針地址,結(jié)合上一句就是將this指針地址放入eax寄存器  
  7.     unsigned int    m_xchg_push; //交換棧頂元素和EAX并入棧EAX  
  8.     unsigned char   m_jmp;  //跳轉(zhuǎn)指令字節(jié)碼 0XE9  
  9.     unsigned int    m_relproc;  //跳轉(zhuǎn)偏移量  
  10. };  
  11. #pragma pack(pop) //取消字節(jié)對(duì)齊結(jié)束  
要讓程序執(zhí)行指定的機(jī)器碼之前,先要保證要執(zhí)行的機(jī)器碼正確,由于C++有內(nèi)存對(duì)齊的編譯優(yōu)化方法,先要告訴編譯器關(guān)閉此功能。
  1. #pragma pack(push,1)  
上圖的字節(jié)碼實(shí)際構(gòu)成了一下內(nèi)容:

  1. mov eax, this  
  2. xchg eax, [esp] : push eax  
  3. jmp func  
前兩句匯編指令執(zhí)行后,PC跳轉(zhuǎn)到func處時(shí),已經(jīng)有了this指針了,這時(shí)就能夠直接訪問(wèn)對(duì)象的成員變涼了。

下面直接上封裝后的全部代碼(VS2012編譯通過(guò))。

  1. /* 
  2. ThunkTimer模板類封裝 
  3. 作者:jedihy 
  4. 時(shí)間:2013.11.23 2:09 
  5. */  
  6.   
  7. #include <Windows.h>  
  8. #include <iostream>  
  9. #include <conio.h>  
  10. #include <stdio.h>  
  11.   
  12. using namespace std;  
  13.   
  14. #pragma pack(push,1)    //取消字節(jié)對(duì)齊開(kāi)始(編譯優(yōu)化指令)  
  15. class Thunk  
  16. {  
  17. public:  
  18.     unsigned char    m_mov; // "mov eax,"的字節(jié)碼  
  19.     unsigned int    m_this; //this指針地址,結(jié)合上一句就是將this指針地址放入eax寄存器  
  20.     unsigned int    m_xchg_push; //交換棧頂元素和EAX并入棧EAX  
  21.     unsigned char   m_jmp;  //跳轉(zhuǎn)指令字節(jié)碼 0XE9  
  22.     unsigned int    m_relproc;  //跳轉(zhuǎn)偏移量  
  23. };  
  24. #pragma pack(pop) //取消字節(jié)對(duì)齊結(jié)束  
  25.   
  26. class ThunkTimer{  
  27. public:  
  28.     ThunkTimer(){  
  29.         objid = (int)this;  
  30.         cout<<objid<<endl;  
  31.     }  
  32.     int objid;  
  33.     Thunk* thunk;  
  34.     void Init();  
  35.     void setTimer(unsigned int);  
  36.     void CALLBACK nativetimer(HWND, UINT, UINT, DWORD);  
  37. };  
  38. void ThunkTimer::setTimer(unsigned int timeout_ms){  
  39.     ::SetTimer(0,0,timeout_ms,(TIMERPROC )thunk);  
  40. }  
  41. void CALLBACK ThunkTimer::nativetimer(HWND hWnd, UINT uMsg, UINT uEvent, DWORD dwTime){  
  42.     cout<<objid<<endl;//對(duì)成員變量的訪問(wèn)  
  43.   
  44. }  
  45.   
  46. void ThunkTimer::Init(){  
  47.   
  48.     typedef void (_stdcall ThunkTimer::*TMFP)();  
  49.     //用union的特點(diǎn)巧取成員地址  
  50.     union {  
  51.         unsigned int func;  
  52.         TMFP method;  
  53.     } addr;  
  54.     addr.method =(TMFP)&ThunkTimer::nativetimer;  
  55.     thunk = (Thunk*)VirtualAlloc(NULL, sizeof(Thunk), MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);  
  56.     thunk->m_jmp       = 0xE9;   //JMP的字節(jié)碼就是0xe9  
  57.     thunk->m_mov       = 0xB8;   //mov eax, 的字節(jié)碼  
  58.     thunk->m_this       = (unsigned int)(void*)this; //this指針  
  59.     thunk->m_xchg_push    = 0x50240487;  //交換  
  60.     thunk->m_relproc    = addr.func - (unsigned int)(void *)(thunk +1);  //計(jì)算偏移量  
  61. }  
  62.   
  63. int main()  
  64. {  
  65.     ThunkTimer timer;  
  66.     timer.Init();  
  67.     timer.setTimer(100);  
  68.   
  69.     MSG msg;  
  70.     while (GetMessage(&msg, NULL, 0, 0)) {  
  71.         if (_kbhit()) {  
  72.             break;  
  73.         }  
  74.         DispatchMessage(&msg);  
  75.     }  
  76.     return 0;  
  77. }  


    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多