高階遠端執行緒注入NtCreateThreadEx
阿新 • • 發佈:2022-03-19
目錄
高階遠端執行緒注入NtCreateThreadEx
一丶簡介
在Windows下NtCreateThreadEx
是CreateRemoteThread
的底層函式。RtlCreateUserThread
也是對 NtCreateThreadEx的一層包裝
所以著重一下研究NtCreateThreadEx
函式
二丶原型
2.1 函式原型
NtCreateThreadEx
在32位下和64位下函式原型不一致。
結構如下:
#ifdef _AMD64_ typedef DWORD(WINAPI* PfnZwCreateThreadEx)( 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 MaximunStackSize, LPVOID pUnkown); #else typedef DWORD(WINAPI *PfnZwCreateThreadEx)( PHANDLE ThreadHandle, ACCESS_MASK DesiredAccess, LPVOID ObjectAttributes, HANDLE ProcessHandle, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, BOOL CreateThreadFlags, DWORD ZeroBits, DWORD StackSize, DWORD MaximumStackSize, LPVOID pUnkown); #endif // DEBUG
如果要想使用 NtCreateThreadEx
函式。那麼就需要從NtDll
中以動態的方式匯出使用。
2.2 遠端執行緒注入程式碼
遠端執行緒程式碼注入分為如下幾個步驟
- OpenProcess 開啟要注入的程序
- VirtualAllocEx 在被注入的程序中申請讀寫記憶體
- WriteProcessMemory 寫入DLL路徑到申請的記憶體中
- VirtualProtectEx 修改記憶體保護屬性,這一步可以不需要使用。
- CreateRemoteThread 建立遠端執行緒,高階遠端執行緒注入可以 將此函式 替換為
NtCreateThreadEx
- WaitForSingleObject 等待過程完成
完整虛擬碼如下:
BOOLEAN RemoteInject(DWORD pid, LPWSTR wszInjectDllPathName,ULONG uDllPathSize) { HANDLE hProc = NULL; LPVOID lpBuffer = NULL; SIZE_T dwWriteBytes = 0; DWORD dwRetErrorCode = 0; HANDLE hThreadHandle = NULL;; PVOID pfnLoadLibraryW = NULL; HMODULE ntdll = NULL; HMODULE k32 = NULL; bool bIsOk = FALSE; do { ntdll = LoadLibrary(TEXT("ntdll.dll")); if (ntdll == NULL) { break; } k32 = LoadLibrary(TEXT("kernel32.dll")); if (k32 == NULL) { break; } m_ZwCreateThreadEx = reinterpret_cast<PfnZwCreateThreadEx>(GetProcAddress(ntdll, "ZwCreateThreadEx")); if (NULL == m_ZwCreateThreadEx) { break; } pfnLoadLibraryW = reinterpret_cast<PVOID>(::GetProcAddress(k32, "LoadLibraryW")); if (pfnLoadLibraryW == NULL) { break; } hProc = OpenProcess(PROCESS_ALL_ACCESS, false, pid); if (hProc == NULL) { break; } lpBuffer = VirtualAllocEx(hProc, 0, 0x1000, MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (NULL == lpBuffer) { break; } dwRetErrorCode = WriteProcessMemory(hProc, lpBuffer, wszInjectDllPathName, uDllPathSize, &dwWriteBytes); if (0 == dwRetErrorCode) { break; } m_ZwCreateThreadEx(&hThreadHandle, PROCESS_ALL_ACCESS, NULL, hProc, (LPTHREAD_START_ROUTINE)pfnLoadLibraryW, lpBuffer, 0, 0, 0, 0, NULL); WaitForSingleObject(hProc, 2000); if (NULL == hThreadHandle) { break; } bIsOk = TRUE; } while (FALSE); if (NULL != lpBuffer) { VirtualFreeEx(hProc, lpBuffer, 0, MEM_RELEASE); lpBuffer = NULL; } if (NULL != hProc) { CloseHandle(hProc); hProc = NULL; } if (NULL != hThreadHandle) { CloseHandle(hThreadHandle); hThreadHandle = NULL; } if (k32 != NULL) { FreeLibrary(k32); k32 = NULL; } if (ntdll != NULL) { FreeLibrary(ntdll); ntdll = NULL; } return bIsOk; }
注意: uDllPathSize 是DLL全路徑的空間長度。 如果是寬字元一定要 wcslen(str) * 2
才可以。
程式碼經過驗證 32位程式可以注入DLL到32位的程序。 64位程序可以注入dll到64位程序。
32位程序不可注入DLL到64位程序。需要特殊方式。