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

    干貨|Windows下進程操作的一些C++代碼

    VSole2021-08-10 10:41:44

    0x01 進程遍歷

    因為進程是在隨時進行變動的所以我們需要獲取一張快照


    1.1 CreateToolhelp32Snapshot

    HANDLE CreateToolhelp32Snapshot(
      DWORD dwFlags,
      DWORD th32ProcessID
    );
    

    因為要獲取進程第一個參數選擇TH32CS_SNAPPROCESS來獲取系統中所有的進程,具體可以參考[CreateToolhelp32Snapshot]:https://docs.microsoft.com/zh-cn/windows/win32/api/tlhelp32/nf-tlhelp32-createtoolhelp32snapshot?f1url=%3FappId%3DDev16IDEF1%26l%3DZH-CN%26k%3Dk(TLHELP32%252FCreateToolhelp32Snapshot);k(CreateToolhelp32Snapshot);k(DevLang-C%252B%252B);k(TargetOS-Windows)%26rd%3Dtrue

    1.2 Process32First

    BOOL Process32First(
      HANDLE           hSnapshot,
      LPPROCESSENTRY32 lppe
    );
    

    第一個參數使用上面CreateToolhelp32Snapshot函數返回的句柄。第二個參數執行了PROCESSENTRY32結構的指針,它包含了進程信息。檢索進程里的第一個進程信息。

    1.2.1 PROCESSENTRY32

    typedef struct tagPROCESSENTRY32 {
      DWORD     dwSize;
      DWORD     cntUsage;
      DWORD     th32ProcessID;
      ULONG_PTR th32DefaultHeapID;
      DWORD     th32ModuleID;
      DWORD     cntThreads;
      DWORD     th32ParentProcessID;
      LONG      pcPriClassBase;
      DWORD     dwFlags;
      CHAR      szExeFile[MAX_PATH];
    } PROCESSENTRY32;
    

    使用時候要把結構體清零。szExeFile為進程名稱,其他都根據名稱一樣。

    1.3 Process32Next

    BOOL Process32Next(
      HANDLE           hSnapshot,
      LPPROCESSENTRY32 lppe
    );
    

    檢索快照中的下一個進程信息。

    void ListProcess() {
        HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
        PROCESSENTRY32 pe32 = { 0 };
        pe32.dwSize = sizeof(PROCESSENTRY32);
        BOOL bRet = Process32First(hSnap, &pe32);
        while (bRet)
        {
            bRet = Process32Next(hSnap, &pe32);
            printf(pe32.szExeFile);
            pid = pe32.th32ProcessID;
            wprintf(L"\r");
            printf("pid:%d", pe32.th32ProcessID);
            printf("\r-----------------------------------------");
            wprintf(L"\r");
        }
        ::CloseHandle(hSnap);
    }
    

    0x02 模塊遍歷

    同理只需要將CreateToolhelp32Snapshot的dwFlags修改為TH32CS_SNAPMODULE,th32ProcessID參數為進程的pid,這里要先獲取進程pid。

    2.1 獲取進程pid

    typedef struct tagPROCESSENTRY32 {
      DWORD     dwSize;
      DWORD     cntUsage;
      DWORD     th32ProcessID;
      ULONG_PTR th32DefaultHeapID;
      DWORD     th32ModuleID;
      DWORD     cntThreads;
      DWORD     th32ParentProcessID;
      LONG      pcPriClassBase;
      DWORD     dwFlags;
      CHAR      szExeFile[MAX_PATH];
    } PROCESSENTRY32;
    

    通過PROCESSENTRY32結構體的th32ProcessID來獲取進程pid。遍歷進程通過strcmp匹配到我們的進程名就返回the32ProcessID。

    int GetProcessPid(char* ProcessName) {
        Flag = CheckPorcess(ProcessName);
        if (Flag) {
            HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
            PROCESSENTRY32 pe32 = { 0 };
            pe32.dwSize = sizeof(PROCESSENTRY32);
            BOOL bRet = Process32First(hSnap, &pe32);
            while (bRet)
            {
                bRet = Process32Next(hSnap, &pe32);
                if (strcmp(pe32.szExeFile, ProcessName) == 0) {
                    pid = pe32.th32ProcessID;
                }
            }
            CloseHandle(hSnap);
            return pid;
        }
        printf("[-]Process not found");
        return 0;
    }
    

    2.2 模塊遍歷

    獲取到了進程pid,放入CreateToolhelp32Snapshot第二個參數,但是因為考慮到進程可能根本不存在所以寫一個CheckPorcess方法來判斷是否存在該進程。

    BOOL CheckPorcess(char* ParanetProcessName) {
        DWORD i = 0;
        HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
        PROCESSENTRY32 pe32 = { 0 };
        pe32.dwSize = sizeof(PROCESSENTRY32);
        BOOL bRet = Process32First(hSnap, &pe32);
        while (bRet)
        {
            bRet = Process32Next(hSnap, &pe32);
            if (strcmp(pe32.szExeFile, ParanetProcessName) == 0) {
                CloseHandle(hSnap);
                return TRUE;
            }
        }
        return FALSE;
    }
    

    然后遍歷模塊

    BOOL ListModule(char* ProcessName) {
        Flag = CheckPorcess(ProcessName);
        if (Flag) {
            pid = GetProcessPid(ProcessName);
            HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid);
            MODULEENTRY32 me32 = { 0 };
            me32.dwSize = sizeof(MODULEENTRY32);
            BOOL bRet = Module32First(hSnap, &me32);
            while (bRet)
            {
                bRet = Module32Next(hSnap, &me32);
                printf(me32.szExePath);
                printf("\r");
            }
            CloseHandle(hSnap);
            return TRUE;
        }
        
        printf("[-]Process not found");
        return FALSE;
    }
    

    0x03 遍歷線程

    使用TH32CS_SNAPTHREAD參數來獲取,這里都大同小異了。

    BOOL ListThread(char* ProcessName) {
        Flag = CheckPorcess(ProcessName);
        if (Flag) {
            pid = GetProcessPid(ProcessName);
            THREADENTRY32 te32 = { 0 };
            te32.dwSize = sizeof(THREADENTRY32);
            HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, pid);
            BOOL bRet = Thread32First(hSnap, &te32);
            while (bRet)
            {
                Thread32Next(hSnap, &te32);
                if (te32.th32OwnerProcessID == pid) {
                    printf(TEXT("     THREAD ID      = 0x%08X"), te32.th32ThreadID);
                    printf(TEXT("     base priority  = %d"), te32.tpBasePri);
                    printf(TEXT("     delta priority = %d"), te32.tpDeltaPri);
                    break;
                }
            }
            CloseHandle(hSnap);
            return TRUE;
        }
        printf("[-]Process not found");
        return FALSE;
    }
    

    通過te32.th32OwnerProcessID與GetProcessPid方法獲取到的pid來對比進而確定當前進程。

    0x04 干進程

    4.1 TerminateProcess

    BOOL TerminateProcess(
      HANDLE hProcess,
      UINT   uExitCode
    );
    

    第一個參數為要結束進程的進程句柄,第二個參數為終止代碼。

    4.2 OpenProcess

    HANDLE OpenProcess(
      DWORD dwDesiredAccess,
      BOOL  bInheritHandle,
      DWORD dwProcessId
    );
    

    第一個參數為進程訪問權限這里設置為擁有全部權限PROCESS_ALL_ACCESS,具體查看[進程訪問權限]:https://docs.microsoft.com/en-us/windows/win32/procthread/process-security-and-access-rights 第二個參數為是否要繼承句柄。第三個參數為進程pid。

    BOOL KillProcess(char* ProcessName) {
        Flag = CheckPorcess(ProcessName);
        if (Flag) {
            HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
            PROCESSENTRY32 pe32 = { 0 };
            pe32.dwSize = sizeof(PROCESSENTRY32);
            BOOL bRet = Process32First(hSnap, &pe32);
            while (bRet)
            {
                bRet = Process32Next(hSnap, &pe32);
                if (strcmp(pe32.szExeFile, ProcessName) == 0) {
                    pid = pe32.th32ProcessID;
                }
            }
            HANDLE hProcessName = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
            bRet = TerminateProcess(hProcessName, 0);
            if (bRet) {
                printf("Kill %s success!", pe32.szExeFile);
            }
            else
            {
                printf("Kill %s fail!", pe32.szExeFile);
            }
            CloseHandle(hSnap);
            return TRUE;
        }
        printf("[-]Process not found");
        return FALSE;
    }
    

    0x05 dll注入

    dll加載:1.靜態調用:通過在我們的程序中添加頭文件,以及lib文件來完成調用,前提就是獲取dll然后還有頭文件 2.動態調用:僅僅只需要一個dll即可完成調用

    這里寫一個Test方法

    #include 
    __declspec(dllexport) void Test(){
        MessageBox(NULL, NULL, NULL, NULL);
    }
    

    可以看到有一些臟數據。這里可以協商約定來解決 1.__stdcall 標準 棧傳參,函數內部(被調用者)平棧 2. __cdecl c 棧傳參,函數外部(調用者)平棧 3. __fastcall 快速 寄存器傳參 4. __thiscall 類的thiscall調用約定,使用ecx寄存器來傳遞this指針

    extern "C"{
        __declspec(dllexport) void __stdcall Test(){
            MessageBox(NULL, NULL, NULL, NULL);
        }
    }
    

    __stdcall是函數內部平參可以舉個例子

    void __stdcall test(int n1, int n2){
        
        return;
    }
    int main()
    {
        test(1, 2);
        return 0;
    }
    

    兩個返回8一個返回4

    void __stdcall test(int n1, int n2){
    002013C0  push        ebp  
    002013C1  mov         ebp,esp  
    002013C3  sub         esp,0C0h  
    002013C9  push        ebx  
    002013CA  push        esi  
    002013CB  push        edi  
    002013CC  lea         edi,[ebp-0C0h]  
    002013D2  mov         ecx,30h  
    002013D7  mov         eax,0CCCCCCCCh  
    002013DC  rep stos    dword ptr es:[edi]  
        
        return;
    }
    002013DE  pop         edi  
    002013DF  pop         esi  
    002013E0  pop         ebx  
    002013E1  mov         esp,ebp  
    002013E3  pop         ebp  
    002013E4  ret         8
    

    5.1 動態調用

    這里使用動態調用

    流程大概就是 1.在目標進程中申請內存 2.向目標進程內存中寫入shellcode(沒有特征,編碼比較麻煩) 3.創建遠線程執行shellcode

    首先打開進程獲取到進程句柄

    hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, rProcessId);
    if (hProcess == INVALID_HANDLE_VALUE) {
        return FALSE;
    }
    

    然后再要注入的進程中申請內存

    VirtualAllocEx

    LPVOID VirtualAllocEx(
      HANDLE hProcess,
      LPVOID lpAddress,
      SIZE_T dwSize,
      DWORD  flAllocationType,
      DWORD  flProtect
    );
    

    詳情查看[VirtualAllocEx]:https://docs.microsoft.com/zh-cn/windows/win32/api/memoryapi/nf-memoryapi-virtualallocex?f1url=%3FappId%3DDev16IDEF1%26l%3DZH-CN%26k%3Dk(MEMORYAPI%252FVirtualAllocEx);k(VirtualAllocEx);k(DevLang-C%252B%252B);k(TargetOS-Windows)%26rd%3Dtrue 這里要用到可讀可寫權限PAGE_READWRITE。

    pDllAddr = VirtualAllocEx(hProcess, NULL, strlen(szDllPath) + 1, MEM_COMMIT, PAGE_READWRITE);
    

    然后再要注入的進程里面寫入數據

    WriteProcessMemory

    BOOL WriteProcessMemory(
      HANDLE  hProcess,
      LPVOID  lpBaseAddress,
      LPCVOID lpBuffer,
      SIZE_T  nSize,
      SIZE_T  *lpNumberOfBytesWritten
    );
    WriteProcessMemory(hProcess, pDllAddr, szDllPath, strlen(szDllPath) + 1, NULL);
    

    然后獲取loadlibrary的地址后就通過CreateRemoteThread加載dll地址和函數地址來調用

    pfnStartAddr = GetProcAddress(::GetModuleHandle("Kernel32"), "LoadLibraryA");
    

    最后再使用CreateRemoteThread創建遠線程,注入DLL

    if ((hRemoteThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pfnStartAddr, pDllAddr, 0, NULL)) == NULL)
        {
            std::cout << "Injecting thread failed!" << std::endl;
            return FALSE;
        }
    

    InjectDll函數

    BOOL InjectDll(int rProcessId, const char* szDllPath) {
        HANDLE hProcess = NULL;
        LPVOID pDllAddr = NULL;
        FARPROC pfnStartAddr = NULL;
        HANDLE hRemoteThread = NULL;
        //打開進程
        hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, rProcessId);
        if (hProcess == INVALID_HANDLE_VALUE) {
            return FALSE;
        }
        //在要注入的進程中申請內存
        pDllAddr = VirtualAllocEx(hProcess, NULL, strlen(szDllPath) + 1, MEM_COMMIT, PAGE_READWRITE);
        if (!pDllAddr)
        {
            return FALSE;
        }
        //給要注入的進程中寫入數據
        WriteProcessMemory(hProcess, pDllAddr, szDllPath, strlen(szDllPath) + 1, NULL);
        //獲取LoadLibraryA函數的地址
        pfnStartAddr = GetProcAddress(::GetModuleHandle("Kernel32"), "LoadLibraryA");
        //使用CreateRemoteThread創建遠線程,注入DLL
        if ((hRemoteThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pfnStartAddr, pDllAddr, 0, NULL)) == NULL)
        {
            std::cout << "Injecting thread failed!" << std::endl;
            return FALSE;
        }
        /*CloseHandle(hProcess);
        CloseHandle(hRemoteThread);*/
        return TRUE;
    }
    

    這里我們寫一個程序加一個dll來驗證

    DemoDll.dll

    // dllmain.cpp : 定義 DLL 應用程序的入口點。
    #include "pch.h"
    #include 
    #include 
    #include 
    #include 
    int pid = 0;
    CString str;
    int GetCurrentID() {
        pid = _getpid();
        str.Format("%d", pid);
        return pid;
    }
    BOOL APIENTRY DllMain( HMODULE hModule,
                           DWORD  ul_reason_for_call,
                           LPVOID lpReserved
                         )
    {
        switch (ul_reason_for_call)
        {
        case DLL_PROCESS_ATTACH:
            pid = GetCurrentID();
            MessageBox(NULL, str, "title", MB_OK);
        case DLL_THREAD_ATTACH:
        case DLL_THREAD_DETACH:
        case DLL_PROCESS_DETACH:
            break;
        }
        return TRUE;
    }
    

    Demo.exe

    #include 
    #include 
    void main() {
        printf("test\r");
        system("pause");
    }
    

    運行Demo.exe,然后先遍歷模塊

    dll注入

    0x06 PPID欺騙

    PPID欺騙允許使用任意進程啟動程序

    同理先判斷父進程是否存在

    DWORD GetParanetProcessID(char* ParanetProcessName) {
        BOOL Check = CheckPorcess(ParanetProcessName);
        if (Check) {
            HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
            PROCESSENTRY32 pe32 = { 0 };
            pe32.dwSize = sizeof(PROCESSENTRY32);
            BOOL bRet = Process32First(hSnap, &pe32);
            while (bRet)
            {
                Process32Next(hSnap, &pe32);
                if (strcmp(pe32.szExeFile, ParanetProcessName) == 0) {
                    ppid = pe32.th32ProcessID;
                    break;
                }
            }
            CloseHandle(hSnap);
        }
        return ppid;
    }
    void PpidSpoofing(char* ProcessAddr,DWORD ParaentPid) {
        STARTUPINFOEXA si = { 0 };
        si.StartupInfo.cb = sizeof(STARTUPINFOEXA);
        PROCESS_INFORMATION pi = { 0 };
        SIZE_T SizeBuff;
        HANDLE parentProcessHandle = OpenProcess(PROCESS_ALL_ACCESS, false, ParaentPid);
        ZeroMemory(&si, sizeof(STARTUPINFOEXA));
        InitializeProcThreadAttributeList(NULL, 1, 0, &SizeBuff);
        si.lpAttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(GetProcessHeap(), 0, SizeBuff);
        InitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &SizeBuff);
        UpdateProcThreadAttribute(si.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &parentProcessHandle, sizeof(HANDLE), NULL, NULL);
        BOOL bRet = CreateProcessA(ProcessAddr, NULL, NULL, NULL, TRUE, CREATE_NEW_CONSOLE | EXTENDED_STARTUPINFO_PRESENT, NULL, NULL, reinterpret_cast<LPSTARTUPINFOA>(&si), &pi);
        if (!bRet) {
            printf("ProcessAddr error!");
        }
        CloseHandle(parentProcessHandle);
    }
    

    首先我們要獲取父進程的進程句柄然后為進程和線程創建初始化指定的屬性列表使用InitializeProcThreadAttributeList。

    BOOL InitializeProcThreadAttributeList(
      LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList,
      DWORD                        dwAttributeCount,
      DWORD                        dwFlags,
      PSIZE_T                      lpSize
    );
    

    最后一個參數指定輸入時lpAttributeList緩沖區的大小。si.lpAttributeList在堆中分配一塊內存,分配的大小為前面的SizeBuff。然后再使用InitializeProcThreadAttributeList初始化進程和線程的屬性列表最后使用UpdateProcThreadAttribute函數來更新進程和線程的指定屬性,最后創建我們的進程。


    sizeofchar函數
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    在二進制里面,每一位只要大于等于?則都要向高位進一。為了方便表示,還衍生出了二進制的子類,比如八進制,十六進制等,主要是二進制向這些進制轉換較為容易,而計算機平時又都處理二進制數據,因此就出現了這些常見的進制計數。信息存儲大多數計算機使用的都是8位的塊,或者叫字節,字節是作為計算機可尋址的最小單位。一般來說我們并不習慣于將一個字節寫成八位二進制的數,而是會寫成兩位十六進制的數。
    HOOK技術實戰
    2021-10-19 05:55:56
    對于Windows系統,它是建立在事件驅動機制上的,說白了就是整個系統都是通過消息傳遞實現的。hook(鉤子)是一種特殊的消息處理機制,它可以監視系統或者進程中的各種事件消息,截獲發往目標窗口的消息并進行處理。所以說,我們可以在系統中自定義鉤子,用來監視系統中特定事件的發生,完成特定功能,如屏幕取詞,監視日志,截獲鍵盤、鼠標輸入等等。
    干貨 | HOOK技術實戰
    2021-10-16 10:09:27
    基礎知識對于Windows系統,它是建立在事件驅動機制上的,說白了就是整個系統都是通過消息傳遞實現的。鉤子可以分為線程鉤子和系統鉤子,線程鉤子可以監視指定線程的事件消息,系統鉤子監視系統中的所有線程的事件消息。當前鉤子處理結束后應把鉤子信息傳遞給下一個鉤子函數。PE頭是固定不變的,位于DOS頭部中e_ifanew字段指出位置。
    FartExt是我之前學習脫殼實踐時做的一個自動脫殼機,是基于FART的主動調用思想實現對特定的抽取殼進行優化處理的工具。由于原本的FART沒有配置相關的,所以我增加了配置對指定app脫殼。
    PVOID buffer, ULONG length, LPCWSTR contentName, HAMSISESSION amsiSession,這樣一個一個去把導出函數寫出。不要去直接include系統文件amsi,這樣他那個文件里本來就有相關函數,這樣會起沖突,直接把有些結構體粘過來就好了。
    在一些開啟了 Hyper-V 的電腦上,RouterOS 可能無法在 VMWare Workstation 中模擬運行或啟動非常緩慢,如果遇到無法運行的情況,請酌情考慮關閉 Hyper-V,如果能成功運行但是啟動緩慢,可以及時拍攝快照。
    ETW的攻與防
    2022-06-07 16:11:58
    前言ETW全稱為Event Tracing for Windows,即windows事件跟蹤,它是Windows提供的原生的事件跟蹤日志系統。ETW Provider會預先注冊到ETW框架上,提供者程序在某個時刻觸發事件,并將標準化定義的事件提供給ETW框架
    本文更多的是根據調試Windows Server 2003,分析漏洞成因。但是AD域并沒有對其進行強校驗。通過建立與域控同名卻不以\$結尾的機器賬戶,即DC,對域控進行欺騙。至此便得到了高權限ST。從上圖中可以很明確的看到域控的機器名為WINSRVSERVER$,之后會使用WINSRVSERVER作為機器賬戶名進行欺騙。攻擊準備工作相關準備工作不是本文重點,可以在noPac項目中學習。
    如何調包Win32API函數?其實就是HookPE文件自己的IAT表。
    依賴于特定硬件環境的固件無法完整模擬,需要hook掉其中依賴于硬件的函數。LD_PRELOAD的劫持對于特定函數的劫持技術分為動態注入劫持和靜態注入劫持兩種。網上針對LD_PRELOAD的劫持也有大量的描述
    VSole
    網絡安全專家
      亚洲 欧美 自拍 唯美 另类