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

C++ 虛函數逆向工程實戰教程(一):從虛表佈局到動態類型識別

     編輯:關於C++

前言:為何需要虛函數逆向分析?

大型 C++ 專案動輒數千個類別,繼承關係錯綜複雜。靜態分析時,虛函數呼叫的目標函數在編譯期無法確定,必須在執行期透過虛表(vtable)與虛指標(vptr)動態綁定。本文分享在 IDA Pro 等反編譯環境下,如何系統性處理虛函數逆向,縮小候選函數範圍,還原真實呼叫關係。

實驗環境與前提條件

  • 編譯器:GCC(行為為主,不同編譯器實現細節不同)
  • 平台:x86(32 位元)
  • 編譯選項:g++ -m32 -fno-rtti -fno-exceptions -O1
  • 二進制已 strip(移除符號表)
  • 無 RTTI、無異常處理機制

基礎範例:多態呼叫 walk()

struct Mammal {
    virtual ~Mammal() {}
    virtual void run() = 0;
    virtual void walk() = 0;
    virtual void move() { walk(); }
};
struct Cat : Mammal { void run() {} void walk() {} };
struct Dog : Mammal { void run() {} void walk() {} };

int main() {
    Mammal* m = (rand() % 2) ? new Cat() : new Dog();
    m->walk();
    delete m;
}

虛表佈局揭秘

編譯器為每個含虛函數的類別在 .rodata 段建立虛表(函數指標陣列),物件實例化時在開頭插入 vptr 指向對應虛表。GCC 虛表佈局(以本例為例):

偏移內容說明
0Destructor1完整解構函數(僅清理成員)
4Destructor2刪除解構函數(含 operator delete)
8run純虛函數 → __cxa_pure_virtual
12walkCat::walk / Dog::walk / 純虛
16moveMammal::move(子類未覆寫)

注意:新版 GCC 針對含純虛函數的類別,將前兩個解構函數槽位設為空指標。

IDA Pro 實戰:建立結構體還原虛表

  1. 定義類別結構體:僅含 vptr 指標
  2. 定義虛表結構體:每個槽位對應函數指標型別(如 void (*)(Cat*))
  3. 關聯 vptr 型別:將 Cat 的 vptr 設為 CatVtable*
  4. 重命名虛表符號:如 Cat__walk、Dog__run
  5. 標記變數動態型別:將 m 設為 Cat* 或 Dog*,反編譯器即顯示具體呼叫目標

關鍵洞見:靜態型別 vs 動態型別

原始碼中 m 宣告為 Mammal*(靜態型別),但執行時只能是 Cat* 或 Dog*(動態型別)。動態型別永遠不會是抽象類別。若虛表含 __cxa_pure_virtual,該型別不可能為運行時型別,可直接排除。此為虛函數逆向的核心判斷依據。

下一步預告

本文建立基礎流程:定位虛表 → 建立結構體 → 標記動態型別 → 還原呼叫。下篇將處理:多重繼承、虛繼承、大型類別體系的自動化腳本技巧、RTTI 缺失時的型別推導進階策略。

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