Anti-Warden技術之外掛的自我卸載

外掛Anti-warden的方法之一是給warden mod做數字簽名,在檢測到不安全或者未知的warden mod時,停止工作。對於以注入到遊戲進程的方式運行的外掛來說,應該在warden開始執行檢測之前自動卸載。這一篇介紹外掛自動卸載技術,也就是說如何在檢測到不安全的.mod時把自己卸載掉。可能有人會想,這有什麼難的,不就是調用FreeLibrary(假設加載用LoadLibrary)嗎。調用FreeLibrary是對的,不過需要一點兒小技巧。如下面代碼所示,檢測、卸載流程大致如下:

void InitWardenInterfacePatch()
{
    
if (!CheckWardenMod())
    {
        
// unsafe warden .mod!
        FreeLibrary(g_hInstDLL);
    }
}

InitWardenInterfacePatch的旁路點(detour patch)安裝在.mod解壓加載完成後、執行檢測代碼之前,如果檢查失敗則調用FreeLibrary卸載自身。代碼邏輯看上去很合理,但仔細想想,你會發現有點兒問題,就是在FreeLibrary之後,DLL的代碼和數據所佔用的內存已經被釋放了,可是FreeLibrary調用的返回地址是在DLL中,顯然這會產生內存訪問違例異常致使遊戲崩潰!如何解決這個問題呢?一種想法可能是(用VirtualAlloc)動態分配一塊內存,把調用FreeLibray的代碼拷貝到這塊內存裏執行,但這又會導致內存泄漏。另外一種想法是在棧裏預留一塊空間,把這塊代碼拷貝到預留的棧空間,然後用jmp指令跳到棧中運行。你可以看到,這個問題是有那麼點兒麻煩的。

這裏介紹另外一種簡潔、優雅的做法。有彙編基礎的朋友都知道,在x86上調用一個函數用指令call,返回函數則用ret。你可能想不到的是,其實用ret也能調用函數。ret指令的動作,是從棧指針esp指向的內存地址取出一個32位數做爲返回地址,然後跳到該地址處繼續執行。如果我們把FreeLibrary入棧再執行ret指令,就可以跳到FreeLibrary函數去:

push FreeLibrary; // function to call
ret; // call FreeLibrary to unload myself 

比較起來,這種方法和用call指令調用函數的不同之處在於,call指令在跳轉到目標函數執行之前還有一個動作,就是把call指令的下一條指令地址入棧。在這個例子中就是把FreeLibrary調用的下一條地址-這是我們不希望的。用ret指令可以省去這一副作用。用ret指令調用函數的關鍵是構造棧上的數據,把合適的參數傳遞給目標函數,並讓目標函數返回時返回到合適的地址繼續執行:

void __declspec(naked) InitWardenModPatch_ASM()
{
    __asm {
        call CheckWardenMod;
        test eax, eax;
        jz unloadmyself;
        ret;
unloadmyself:
        pop eax;            
// return address of FreeLibrary
        push hInstDLL;        // parameter of FreeLibrary
        push eax;        // return address of FreeLibrary
        push FreeLibrary;        // function to call
        ret;            // call FreeLibrary to unload myself
    }
}

 上述代碼中,ret指令調用前棧的佈局如下:

|  hInstDLL                                      |  High address
|  
return address of FreeLibrary  |
|  address of FreeLibrary             |  <-- ESP

這只是一個簡單的示例,在實際的應用中,棧上數據如何構造還應該結合具體的需要(跟detour patch有關)進行調整。最早提出利用ret調用函數的可能是Gary Nebbett(《Windows NT Native API Reference》的作者),用於程序的自我刪除

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章