青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

隨感而發

雜七雜八

統計

留言簿(13)

閱讀排行榜

評論排行榜

API回調成員函數 THUNK

想來想去還是羅嗦一下,API只能回調全局函數,而我們有時候希望他能回調成員函數。最常用的就是Timmer和窗口回調。要實現這個需求,就會用到THUNK技術。THUNK 我查了一下是:thunk  名詞 n.  ;,鏘 。跟這個完全沒有關系嘛(看來英文太爛是壞處還是挺多的)。學習了一下之后,我理解的意思就是:貍貓換太子。替換原來意圖,轉調我們需要的地址。

Thunk的原理其實說起來很簡單:巧妙的將數據段的幾個字節的數據設為特殊的值,然后告訴系統,這幾個字節的數據是代碼(即將一個函數指針指向這幾個字節的第一個字節),讓系統來執行

API回調成員函數:

直接用成員函數的地址傳給作為API的回調函數顯然會編譯出錯的,原因是他們的調用規則不一致,C++編譯器不允許這樣做。具體可以參考:

http://hi.baidu.com/shongbee2/blog/item/7867de9744e3c26155fb9611.html

而剛好THUNK技術就是讓數據段當做代碼斷用,如果我把回調函數地址用一個數據段給他,然后在數據段中再跳轉到成員函數的地址。這樣就可以間接的調用成員函數了。不錯,我就是學習的這個方法。嘻嘻。。

大致方向知道了,還得了解一下細節,函數調用的規則:

建議看一下http://hi.baidu.com/shongbee2/blog/item/7867de9744e3c26155fb9611.html(也就是上一篇文章啦。)需要注意的:調用者怎么處理棧,被調用者怎么使用棧和處理棧。系統回調函數基本上都是_stdcall的調用方式,成員函數是__thiscall的調用方式。他們的區別為:

關鍵字

堆棧清除

參數傳遞

__stdcall

被調用者

將參數倒序壓入堆棧(自右向左)

__thiscall

被調用者

壓入堆棧,this指針保存在 ECX 寄存器中

發現他們唯一不同的就是__thiscallthis指針保存到了ECX的寄存器中。其他都是一樣的。這種情況我們就方便了,我們只需在他調用我們的時候,我們吧this指針保存到ECX,然后跳轉到期望的成員函數地址就可以了。

//我認為思路就是這樣了。接下來是實現,貼源代碼:

#include "stdafx.h"
#include "wtypes.h"

#include <iostream>
using namespace std;

typedef void (*FUNC)(DWORD dwThis);
typedef int (_stdcall *FUNC1)(int a, int b);
#pragma pack(push,1)
typedef struct tagTHUNK
{
    BYTE    bMovEcx;   //MOVE ECX 將this指針移動到ECX的指令
    DWORD    dwThis;   // this   this指針的地址
    BYTE    bJmp;    //jmp   跳轉指令
    DWORD    dwRealProc; //proc offset 跳轉偏移

    void Init(DWORD proc,void* pThis)
    {
   bMovEcx = 0xB9;        //注釋見下面說明^_^
        dwThis = (DWORD)pThis;
        bJmp = 0xE9;
        dwRealProc = DWORD((INT_PTR)proc - ((INT_PTR)this+sizeof(THUNK)));
        FlushInstructionCache(GetCurrentProcess(),this,sizeof(THUNK));
    }
}THUNK;
#pragma pack(pop)
/**************************************************************************************
void Init(DWORD proc,void* pThis)里面的說明:
0xB9 為MOVE ECX的指令, 0xE9 跳轉的指令,這段初始化表示:
0013FF54 mov         ecx, ptr [this]
0013FF59 jmp         dwRealProc
這個單步一下便知。
下面那個API :FlushInstructionCache,查MSDN,表示刷新緩存,
因為我們修改了數據,建議他重新載入一下。

我最不能理解的是jmp的偏移是為什么是那樣計算,所以這里也著重說明一下:
jmp跳轉的是當前指令地址的偏移,我們參數中proc是實際函數的地址,我們需要
把他轉為jmp的偏移: 實際函數地址-jmp指令地址。
實際函數地址就是proc,jmp地址就是((INT_PTR)this+sizeof(THUNK)),所以就得到
dwRealProc = DWORD((INT_PTR)proc - ((INT_PTR)this+sizeof(THUNK)));這行代碼
還有一點,我對匯編不了解,下面是YY:為什么不是:
dwRealProc = DWORD((INT_PTR)proc - ((INT_PTR)this+sizeof(THUNK)) - sizeof(dwRealProc))
直觀上看jmp地址不是:this + sizeof(bMoveEcx) + sizeof(dwThis) + sizeof(bJmp)嗎?
也就是((INT_PTR)this+sizeof(THUNK)) - sizeof(dwRealProc) 啊。可是我看了一下編譯的結果,
發現0013FF59 jmp         dwRealProc 是一行的,也就是jmp地址實際就是:
((INT_PTR)this+sizeof(THUNK)) 這個地址。經過測試也沒有問題,我就認為是這樣了,不對的還
忘多指出。嘻嘻。
還有一個容易混淆的,就是我們會傳入this指針,在dwRealProc里面和 FlushInstructionCache
里面都用到了this。這里要注意啦:如果你不知道傳入的參數this指針和使用的這個this的話,你就該
重新復習一下C++基礎了。解釋一下:傳入的this指針變為參數pThis,使用的this是THUNK的this。^_^
*****************************************************************************************/

template<typename dst_type,typename src_type>
dst_type pointer_cast(src_type src)
{
return *static_cast<dst_type*>( static_cast<void*>(&src) );
}

class Test
{
public:
int m_nFirst;
    THUNK m_thunk;
    int      m_nTest;

    //構造函數中初始化為3,僅為測試,以便查看外面的方法JmpedTest是否可以正確取得這個值
    Test() : m_nTest(3),m_nFirst(4)
    {}

    void TestThunk()
    {
   m_thunk.Init(pointer_cast<int>(&Test::Test2),this);
        FUNC1 f = (FUNC1)&m_thunk;
        f(1,2);
        cout << "Test::TestThunk()" << endl;
    }

int Test2(int a, int b)
{
   cout << a << " " << b << " " << m_nFirst << " " << m_nTest << endl;
   return 0;
}
};

int _tmain(int argc, _TCHAR* argv[])
{
    Test t;
    t.TestThunk();
    system("pause");
    return 0;
}

總結:

這個明顯是暴力的去強制跳轉,直接把指令寫入到數據段中,增加了出錯的風險,而且可移植性變的很差。所以盡量少用。

要弄清楚函數調用規則和堆棧的平衡。如果你用_cedcl規則的函數調用的話,就會出錯啦。

學習代碼中只是處理了簡單的情況,還有幾種方式,例如不是強制跳轉,而是用call的方式調用,也可以實現。對于其他的函數規則例如成員函數是_stdcall,他是參數壓棧的,這個THUNK的寫法也不一樣了。。

因為數據段中用到了this,函數回調中會用到它,所以一定要保證這個this有效。特別是窗口回調函數,如果釋放了變量,但是窗口沒有銷毀是很容易出問題的。窗口回調函數也有比較喜歡用一個靜態的分配器,通過窗口識別,把他分配到不同的成員處理函數中的方式。

這個只是初學,原因是發現ATL的窗口回調是這樣做的。覺得很神奇,所以學習了一下,有不對的地方還望多多指教。嘻嘻。。。

找到的資料:

http://www.vckbase.com/document/viewdoc/?id=1821

http://www.codeproject.com/KB/cpp/GenericThunks.aspx

http://blog.csdn.net/superarhow/archive/2006/07/10/898261.aspx

http://www.cnblogs.com/homeofish/archive/2009/02/20/1395208.html

posted on 2010-12-11 16:14 shongbee2 閱讀(1612) 評論(0)  編輯 收藏 引用 所屬分類: c/c++

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            一区二区三区四区五区视频| 国产精品av免费在线观看| 国产精品久久久久一区二区三区 | 亚洲视频综合在线| 欧美极品在线播放| 一本色道久久精品| 亚洲调教视频在线观看| 国产日产精品一区二区三区四区的观看方式| 亚洲欧美另类中文字幕| 午夜亚洲福利在线老司机| 含羞草久久爱69一区| 欧美成人精品h版在线观看| 欧美国产三区| 性欧美超级视频| 美国成人直播| 亚洲无线视频| 久久久久久久久久久久久9999| 亚洲国内自拍| 午夜精品成人在线| 亚洲精品午夜| 亚洲欧美日韩国产一区二区| 影音先锋日韩有码| 亚洲免费精彩视频| 国产综合网站| 亚洲精品影视在线观看| 国产日韩在线看片| 免费日韩av| 国产精品午夜电影| 亚洲欧洲一区二区三区| 另类尿喷潮videofree| 亚洲欧美大片| 蜜乳av另类精品一区二区| 日韩视频免费| 午夜综合激情| 日韩视频―中文字幕| 亚洲深夜激情| 亚洲精品小视频在线观看| 欧美与欧洲交xxxx免费观看| 99精品国产热久久91蜜凸| 久久精品色图| 午夜一区二区三区在线观看| 欧美波霸影院| 欧美二区在线| 国内精品模特av私拍在线观看| 一本色道久久综合亚洲精品按摩| 久久国产天堂福利天堂| 亚洲视频播放| 欧美激情精品久久久久久久变态| 久久久久亚洲综合| 国产欧美日韩视频一区二区| 在线亚洲欧美视频| 99国产精品视频免费观看| 麻豆91精品91久久久的内涵| 久久蜜桃资源一区二区老牛| 国产日韩精品视频一区| 亚洲午夜视频| 亚洲欧美日韩国产一区二区| 欧美精品在线播放| 欧美mv日韩mv亚洲| 韩国av一区二区三区| 欧美一区二区三区另类| 久久国产色av| 狠狠色伊人亚洲综合成人| 欧美专区第一页| 久久视频在线看| 国产一区二区中文| 欧美在线综合| 久久综合色8888| 亚洲国产99| 欧美国产激情| 亚洲伦伦在线| 亚洲欧美日韩国产中文在线| 国产精品久久看| 香蕉精品999视频一区二区| 先锋影音国产一区| 国产麻豆午夜三级精品| 久久成人18免费观看| 一区二区三区欧美视频| 国产精品美女久久久| 先锋影音一区二区三区| 久久亚洲视频| 日韩写真视频在线观看| 欧美日韩情趣电影| 亚洲一级高清| 久热re这里精品视频在线6| 亚洲国产欧美日韩| 欧美日韩亚洲一区二区三区在线观看 | 伊人久久综合97精品| 免费日韩av片| 一区二区三区四区国产精品| 久久超碰97人人做人人爱| 悠悠资源网久久精品| 欧美日产国产成人免费图片| av成人毛片| 欧美一区二区三区日韩| 在线视频国内自拍亚洲视频| 欧美日韩另类视频| 欧美一区三区三区高中清蜜桃| 欧美暴力喷水在线| 亚洲制服欧美中文字幕中文字幕| 欧美日韩国产综合视频在线观看 | 在线综合亚洲| 精品福利电影| 欧美三级午夜理伦三级中文幕| 一区二区三区 在线观看视| 久久精品视频播放| 亚洲免费高清| 国产一区二区三区在线观看网站 | 一区二区三区精品视频| 国产综合精品| 欧美视频在线观看免费网址| 欧美一区亚洲二区| 9人人澡人人爽人人精品| 欧美成人午夜免费视在线看片| 亚洲一区二区在线看| 欧美中文字幕视频在线观看| 欧美日本一道本| 久久久国产精彩视频美女艺术照福利| 亚洲日韩欧美视频一区| 久久九九精品99国产精品| 99国产精品国产精品久久| 国产一区二区三区直播精品电影| 欧美黑人一区二区三区| 久久香蕉国产线看观看网| 午夜精品久久久久久久99樱桃| 欧美激情麻豆| 麻豆精品一区二区综合av| 欧美在线播放| 亚洲欧美日韩人成在线播放| 99视频+国产日韩欧美| 在线播放精品| 国内精品久久久久久影视8 | 亚洲淫片在线视频| av72成人在线| 亚洲激情影院| 欧美高清在线视频观看不卡| 另类av一区二区| 久久av二区| 久久久国产精品一区二区三区| 小黄鸭视频精品导航| 亚洲一区3d动漫同人无遮挡| 一本色道久久综合| 国产精品99久久99久久久二8 | 欧美福利视频| 欧美高清在线观看| 欧美好吊妞视频| 亚洲成人在线网站| 亚洲国产欧美不卡在线观看| 欧美二区在线| 亚洲国产精品精华液2区45| 你懂的国产精品永久在线| 欧美黄免费看| 亚洲国产高清在线| 亚洲美女黄色| 一本色道久久88亚洲综合88| 亚洲天堂视频在线观看| 午夜精品电影| 久久精品国产清高在天天线 | 欧美福利一区| 免费看av成人| 亚洲国产精品一区二区三区| 亚洲人午夜精品| 亚洲午夜小视频| 久久av一区二区三区亚洲| 久久久久久久综合色一本| 欧美激情欧美狂野欧美精品| 国产精品swag| 国产日本欧美视频| 亚洲国产欧洲综合997久久| 9色porny自拍视频一区二区| 欧美一区二区三区视频在线观看| 欧美一区二区高清在线观看| 免费试看一区| 一区二区三区免费网站| 久久精品夜色噜噜亚洲aⅴ| 欧美国产视频在线| 国产亚洲欧美在线| 亚洲青色在线| 羞羞漫画18久久大片| 欧美.com| 亚洲欧美日韩在线高清直播| 欧美91福利在线观看| 国产精品自在欧美一区| 久久一日本道色综合久久| 欧美揉bbbbb揉bbbbb| 狠狠色综合一区二区| 一区二区免费在线播放| 久久免费视频网| 99视频精品在线| 免费成人av在线| 国产精品视频大全| 亚洲激情成人网| 久久精品99无色码中文字幕| 亚洲日本va在线观看| 久久综合久久综合九色| 国产日韩亚洲欧美精品| 亚洲香蕉在线观看| 亚洲高清视频在线| 久久久777| 国产视频亚洲精品|