Skip to content
Suzu
2 min read

【Windows Internal】DllMain

DllMain 的相關說明、用途、實作。

View the complete series →
On this page

【Windows Internal】DllMain

DLLMain 是 DLL 的進入點 function,loader 在 load/unload DLL 或 threads 生滅的時候會自動呼叫他,

所以我們可以把惡意邏輯放在 DLL_PROCESS_ATTACH

DLL 一被 map 就會以宿主權限執行。

組成&應用

進入點簽章:

BOOL WINAPI DllMain(
    HINSTANCE hinstDLL,    // DLL 模組的 handle(= 映射後的 Base Address)
    DWORD     fdwReason,   // 為什麼被呼叫
    LPVOID    lpvReserved  // 保留,可用來區分 static/dynamic 載入、process/thread 終止
);

四種 fdwReason

reason時機典型用途
DLL_PROCESS_ATTACHDLL 被映射進 Process(啟動時解析 import,或 LoadLibrary初始化;惡意邏輯放這裡
DLL_THREAD_ATTACHProcess 內有新 Thread 誕生每 Thread 初始化(多數 DLL 會停用此通知)
DLL_THREAD_DETACHThread 結束每 Thread 清理
DLL_PROCESS_DETACHDLL 即將從 process detach收尾清理

DLL_PROCESS_ATTACH = 免費的自動執行

Attacker 不需要 Victim 呼叫任何匯出 Function,

只要 DLL 被 Load 進來,DLL_PROCESS_ATTACH 就一定會跑到,

這就是 DLL Hijacking 的原理,載入本身就等於執行。

DllMain 是可選的

沒有 DllMain 的 DLL 還是能照常載入、提供匯出 Function,

寫了 DllMain 只是多了在載入當下搶先執行一段程式碼的能力。

Loader Lock: 為什麼要把 DllMain 設計得極簡?

DllMain 是在 loader 持有 process 級 loader lock 的狀態下被呼叫的,

所以微軟官方也說 DllMain 裡面什麼都不能安全做(不能 LoadLibrary、建立 thread、跑複雜邏輯),

專業的 DllMain 只做最少的事,然後把真正的工作移交出去。

實作例子

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        PrintAttachMessage(true);                 // ① 用 OutputDebugString 留下足跡
        g_instance = hModule;
        if (IsUIAccessBool()) {                   // ② 確認自己真的在 UIAccess 行程裡(防誤觸發)
            OutputDebugStringA("Starting process\n");
            std::wstring path = GetRealExecutablePath();  // 再吃一次 mount point 轉向,取回主程式真身
            if (path.size() > 0) {
                StartProcess(path.c_str());       // ③ token 手術 + 以 "bypass 1" 重啟主程式
            }
        }
        break;
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
        break;
    case DLL_PROCESS_DETACH:
        PrintAttachMessage(false);
        break;
    }
    return TRUE;
}

然後我們可以用 DebugView 觀察,DLL 載入的瞬間應該會跑出類似:

osk.exe (Attach) - PID: 12345 Elevated: true UIAccess: true
Starting process

這個就代表 DLL 已經在 osk.exe 的權限上下文裡醒來了。

Share this page