首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> 關於VC++

Thunk 技術進階:告別手工機器碼,以編譯器生成動態代碼模板

     編輯:關於VC++

什麼是 Thunk 技術?

Thunk 技術指在程式運行時動態構造可執行機器碼——這原本是編譯器的工作。據《深度探索 C++ 物件模型》考證,「Thunk」一詞源自 Donald Knuth 姓氏倒寫,這位《計算機程式設計藝術》作者被譽為「編程聖經」撰寫者。

傳統做法的痛點

傳統 Thunk 寫法需手工查閱指令集,將機器碼填入字節陣列,再以函式指標跳轉執行。例如:

unsigned char code[9];
*((DWORD*)&code[0]) = 0x042444FF; // inc dword ptr [esp+4]
code[4] = 0xe9; // JMP
*((DWORD*)&code[5]) = (DWORD)&foo - (DWORD)&code[0] - 9;
void (*pf)(int) = (void(*)(int))&code[0];
pf(6); // 輸出 "In foo, a = 7"

此法極其繁瑣、易錯,且難以維護。

核心創意:讓編譯器幫忙生成機器碼模板

既然編譯器擅長將組語轉為機器碼,為何不直接寫內嵌組語,再由程式在運行時提取代碼段地址、替換動態數值?

關鍵難點在於跳轉偏移量等動態值在編譯期未知。解決方案:在組語中用特殊佔位符(如 0xFFFFFFFF)預留位置,運行時掃描替換為真實地址。

兩階段實作架構

1. 生成代碼模板

void ThunkTemplate(DWORD& addr1, DWORD& addr2) {
    int flag = 0;
    DWORD x1, x2;
    if(flag) { // 永不執行,僅供編譯器生成代碼
        __asm {
            thunk_begin:
            mov ecx, -1    // 佔位:this 指針
            mov eax, -2    // 佔位:目標函式地址
            jmp eax
            thunk_end:
        }
    }
    __asm {
        mov x1, offset thunk_begin
        mov x2, offset thunk_end
    }
    addr1 = x1; addr2 = x2;
}

2. 動態替換佔位符

void ReplaceCodeBuf(BYTE* code, int len, DWORD oldVal, DWORD newVal) {
    for(int i=0; i<len-4; ++i)
        if(*((DWORD*)&code[i]) == oldVal) {
            *((DWORD*)&code[i]) = newVal;
            return;
        }
}

3. 組裝使用


DWORD addr1, addr2;
ThunkTemplate(addr1, addr2);
memcpy(m_thunk, (void*)addr1, addr2-addr1);
ReplaceCodeBuf(m_thunk, addr2-addr1, -1, (DWORD)this);      // 填入 this
ReplaceCodeBuf(m_thunk, addr2-addr1, -2, (DWORD)&CTimer::CallBack); // 填入函式地址

實戰案例:解決回調函式無法傳遞 this 指針的難題

Windows 定時器回調 TimerProc 無額外參數傳遞 this,導致類成員函式無法直接作為回調。Thunk 技術完美破解:

  1. 系統調用 Thunk 代碼段入口
  2. Thunk 代碼準備 this 指針(置入 ECX 或堆疊)
  3. 跳轉至真實成員函式

文中完整展示了支援 __thiscall 與 __stdcall 兩種呼叫慣例的 Thunk 模板代碼,並封裝為 CTimer 類,實現「純成員函式作為回調」的優雅封裝。

總結

本文提出的「編譯器生成模板 + 運行時修補」方案,徹底消除手工機器碼的痛苦,且保留靈活性。即使偏好傳統字節陣列寫法,也可先用此法生成代碼再導出數值。源碼附後,歡迎研究改進。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved