BOOL NtGlobalFlag() { PDWORD pNtGlobalFlag = NULL, pNtGlobalFlagWoW64 = NULL; #if defined (ENV64BIT) BYTE* _teb64 = (BYTE*)__readgsqword(0x30); DWORD64 _peb64 = *(DWORD64*)(_teb64 + 0x60); pNtGlobalFlag = (PDWORD)(__readgsqword(0x60) + 0xBC); #elif defined(ENV32BIT) /* NtGlobalFlags for real 32-bits OS */ BYTE* _teb32 = (BYTE*)__readfsdword(0x18); DWORD _peb32 = *(DWORD*)(_teb32 + 0x30); pNtGlobalFlag = (PDWORD)(_peb32 + 0x68); if (IsWoW64()) { /* In Wow64, there is a separate PEB for the 32-bit portion and the 64-bit portion which we can double-check */ BYTE* _teb64 = (BYTE*)__readfsdword(0x18) - 0x2000; DWORD64 _peb64 = *(DWORD64*)(_teb64 + 0x60); pNtGlobalFlagWoW64 = (PDWORD)(_peb64 + 0xBC); } #endif bool normalDetected = pNtGlobalFlag && *pNtGlobalFlag & 0x00000070; bool wow64Detected = pNtGlobalFlagWoW64 && *pNtGlobalFlagWoW64 & 0x00000070; if(normalDetected || wow64Detected) return TRUE; else return FALSE; }
PUINT32 GetForceFlags_x64() { PINT64 pProcessHeap = NULL; PUINT32 pHeapForceFlags = NULL; if (IsWindowsVistaOrGreater()){ pProcessHeap = (PINT64)(__readgsqword(0x60) + 0x30); pHeapForceFlags = (PUINT32)(*pProcessHeap + 0x74); } else { pProcessHeap = (PINT64)(__readgsqword(0x60) + 0x30); pHeapForceFlags = (PUINT32)(*pProcessHeap + 0x18); } return pHeapForceFlags; }
static NTSTATUS EvhdDirectIoControl(ParserInstance *parser, ULONG ControlCode, PVOID pSystemBuffer, ULONG InputBufferSize, ULONG OutputBufferSize) { NTSTATUS status = STATUS_SUCCESS; PDEVICE_OBJECT pDeviceObject = NULL; KeEnterCriticalRegion(); FltAcquirePushLockExclusive(&parser->DirectIoPushLock); IoReuseIrp(parser->pDirectIoIrp, STATUS_PENDING); parser->pDirectIoIrp->Flags |= IRP_NOCACHE; parser->pDirectIoIrp->Tail.Overlay.Thread = (PETHREAD)__readgsqword(0x188); // Pointer to calling thread control block parser->pDirectIoIrp->AssociatedIrp.SystemBuffer = pSystemBuffer; // IO buffer for buffered control code // fill stack frame parameters for synchronous IRP call PIO_STACK_LOCATION pStackFrame = IoGetNextIrpStackLocation(parser->pDirectIoIrp); pDeviceObject = IoGetRelatedDeviceObject(parser->pVhdmpFileObject); pStackFrame->FileObject = parser->pVhdmpFileObject; pStackFrame->DeviceObject = pDeviceObject; pStackFrame->Parameters.DeviceIoControl.IoControlCode = ControlCode; pStackFrame->Parameters.DeviceIoControl.InputBufferLength = InputBufferSize; pStackFrame->Parameters.DeviceIoControl.OutputBufferLength = OutputBufferSize; pStackFrame->MajorFunction = IRP_MJ_DEVICE_CONTROL; pStackFrame->MinorFunction = 0; pStackFrame->Flags = 0; pStackFrame->Control = 0; IoSynchronousCallDriver(pDeviceObject, parser->pDirectIoIrp); status = parser->pDirectIoIrp->IoStatus.Status; FltReleasePushLock(&parser->DirectIoPushLock); KeLeaveCriticalRegion(); return status; }
NTSTATUS EVhdGetQosStatusDisk(ParserInstance *parser, PVOID pSystemBuffer, ULONG32 dwSize, QoSStatusCompletionRoutine pfnCompletionCb, PVOID pInterface) { PDEVICE_OBJECT pDeviceObject = NULL; parser->pQoSStatusInterface = pInterface; parser->pfnQoSStatusCallback = pfnCompletionCb; memmove(parser->pQoSStatusBuffer, pSystemBuffer, dwSize); IoReuseIrp(parser->pQoSStatusIrp, STATUS_PENDING); parser->pQoSStatusIrp->Tail.Overlay.Thread = (PETHREAD)__readgsqword(0x188); // Pointer to calling thread control block parser->pQoSStatusIrp->AssociatedIrp.SystemBuffer = parser->pQoSStatusBuffer; // IO buffer for buffered control code PIO_STACK_LOCATION pStackFrame = IoGetNextIrpStackLocation(parser->pQoSStatusIrp); pDeviceObject = IoGetRelatedDeviceObject(parser->pVhdmpFileObject); pStackFrame->FileObject = parser->pVhdmpFileObject; pStackFrame->DeviceObject = pDeviceObject; pStackFrame->Parameters.DeviceIoControl.IoControlCode = IOCTL_STORAGE_VHD_GET_QOS_STATUS; pStackFrame->Parameters.DeviceIoControl.InputBufferLength = dwSize; pStackFrame->Parameters.DeviceIoControl.OutputBufferLength = 0x58; pStackFrame->MajorFunction = IRP_MJ_DEVICE_CONTROL; pStackFrame->MinorFunction = 0; pStackFrame->Flags = 0; pStackFrame->Control = SL_INVOKE_ON_CANCEL | SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR; pStackFrame->Context = parser; pStackFrame->CompletionRoutine = EvhdGetQosStatusCompletionRoutine; IoCallDriver(pDeviceObject, parser->pQoSStatusIrp); return STATUS_PENDING; }
SCFUNC PVOID scGetModuleBase(const char *moduleName) { PPEB pPeb; PLIST_ENTRY head, entry; PLDR_DATA_TABLE_ENTRY module; #if defined(_M_IX86) pPeb = (PPEB) __readfsdword(0x30); #elif defined(_M_X64) pPeb = (PPEB) __readgsqword(0x60); #endif head = &pPeb->Ldr->InLoadOrderModuleList; entry = head->Flink; while (entry != head) { module = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InLoadOrderModuleList); if (scW2Anicmp(module->BaseDllName.Buffer, moduleName, scStrlen(moduleName)) == 0) return module->DllBase; entry = entry->Flink; } return NULL; }
gpointer gum_tls_key_get_value (GumTlsKey key) { if (key < 64) { return (gpointer) __readgsqword (0x1480 + key * sizeof (gpointer)); } else if (key < 1088) { gpointer * tls_expansion_slots = (gpointer) __readgsqword (0x1780); if (tls_expansion_slots != NULL) return tls_expansion_slots[key - 64]; return _gum_tls_key_get_tmp_value (key); } return NULL; }
NTSTATUS EVhdNotifyRecoveryStatus(ParserInstance *parser, RecoveryStatusCompletionRoutine pfnCompletionCb, void *pInterface) { PDEVICE_OBJECT pDeviceObject = NULL; if (parser->bResiliencyEnabled) { if (!ExAcquireRundownProtection(&parser->RecoveryRundownProtection)) return STATUS_UNSUCCESSFUL; parser->pfnRecoveryStatusCallback = pfnCompletionCb; parser->pRecoveryStatusInterface = pInterface; IoReuseIrp(parser->pRecoveryStatusIrp, STATUS_PENDING); parser->pRecoveryStatusIrp->Tail.Overlay.Thread = (PETHREAD)__readgsqword(0x188); // Pointer to calling thread control block PIO_STACK_LOCATION pStackFrame = IoGetNextIrpStackLocation(parser->pRecoveryStatusIrp); pDeviceObject = IoGetRelatedDeviceObject(parser->pVhdmpFileObject); pStackFrame->FileObject = parser->pVhdmpFileObject; pStackFrame->DeviceObject = pDeviceObject; pStackFrame->Parameters.DeviceIoControl.IoControlCode = IOCTL_STORAGE_VHD_NOTIFY_RECOVERY_STATUS; pStackFrame->Parameters.DeviceIoControl.InputBufferLength = 0; pStackFrame->Parameters.DeviceIoControl.OutputBufferLength = 0; pStackFrame->MajorFunction = IRP_MJ_DEVICE_CONTROL; pStackFrame->MinorFunction = 0; pStackFrame->Flags = 0; pStackFrame->Control = SL_INVOKE_ON_CANCEL | SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR; pStackFrame->Context = parser; pStackFrame->CompletionRoutine = EvhdRecoveryStatusCompletionRoutine; IoCallDriver(pDeviceObject, parser->pRecoveryStatusIrp); return STATUS_PENDING; } else return STATUS_UNSUCCESSFUL; }
HANDLE GetKernel32Module( void ) { HANDLE hKernel32 = INVALID_HANDLE_VALUE; wchar_t szKernel32[] = { 'k'^XOR_KEY, 'e'^XOR_KEY, 'r'^XOR_KEY, 'n'^XOR_KEY, 'e'^XOR_KEY, 'l'^XOR_KEY, '3'^XOR_KEY, '2'^XOR_KEY, '.'^XOR_KEY, 'd'^XOR_KEY, 'l'^XOR_KEY, 'l'^XOR_KEY, '\0'^XOR_KEY }; #ifdef _WIN64 PPEB lpPeb = (PPEB) __readgsqword(0x60); #else PPEB lpPeb = (PPEB) __readfsdword(0x30); #endif PLIST_ENTRY pListHead = &lpPeb->Ldr->InMemoryOrderModuleList; PLIST_ENTRY pListEntry = pListHead->Flink; while (pListEntry != pListHead) { PLDR_DATA_TABLE_ENTRY pModEntry = CONTAINING_RECORD(pListEntry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks); if (pModEntry->FullDllName.Length) { PWCHAR strName = &pModEntry->FullDllName.Buffer[pModEntry->FullDllName.Length/sizeof(WCHAR) - 12]; if (!__WMEMCMP__(strName, szKernel32, _countof(szKernel32), TRUE, XOR_KEY)) { hKernel32 = (HANDLE)pModEntry->DllBase; break; } } pListEntry = pListEntry->Flink; } return hKernel32; }
int GetKPCR(struct PmemMemoryInfo *info) { __int64 active_processors = KeQueryActiveProcessors(); int i; for (i=0; i < 32; i++) { info->KPCR[i].QuadPart = 0; }; for (i=0; i < 32; i++) { if (active_processors & ((__int64)1 << i)) { KeSetSystemAffinityThread((__int64)1 << i); #if _WIN64 || __amd64__ //64 bit uses gs and _KPCR.Self is at 0x18: info->KPCR[i].QuadPart = (uintptr_t)__readgsqword(0x18); #else //32 bit uses fs and _KPCR.SelfPcr is at 0x1c: info->KPCR[i].QuadPart = (uintptr_t)__readfsword(0x1c); #endif }; }; KeRevertToUserAffinityThread(); return 1; };
RTDECL(bool) RTThreadPreemptIsPending(RTTHREAD hThread) { Assert(hThread == NIL_RTTHREAD); RT_NOREF1(hThread); /* * Read the globals and check if they are useful. */ /** @todo Should we check KPRCB.InterruptRequest and KPRCB.DpcInterruptRequested (older kernels). */ uint32_t const offQuantumEnd = g_offrtNtPbQuantumEnd; uint32_t const cbQuantumEnd = g_cbrtNtPbQuantumEnd; uint32_t const offDpcQueueDepth = g_offrtNtPbDpcQueueDepth; if (!offQuantumEnd && !cbQuantumEnd && !offDpcQueueDepth) return false; Assert((offQuantumEnd && cbQuantumEnd) || (!offQuantumEnd && !cbQuantumEnd)); /* * Disable interrupts so we won't be messed around. */ bool fPending; RTCCUINTREG fSavedFlags = ASMIntDisableFlags(); #ifdef RT_ARCH_X86 PKPCR pPcr = (PKPCR)__readfsdword(RT_OFFSETOF(KPCR,SelfPcr)); uint8_t *pbPrcb = (uint8_t *)pPcr->Prcb; #elif defined(RT_ARCH_AMD64) /* HACK ALERT! The offset is from windbg/vista64. */ PKPCR pPcr = (PKPCR)__readgsqword(RT_OFFSETOF(KPCR,Self)); uint8_t *pbPrcb = (uint8_t *)pPcr->CurrentPrcb; #else # error "port me" #endif /* Check QuantumEnd. */ if (cbQuantumEnd == 1) { uint8_t volatile *pbQuantumEnd = (uint8_t volatile *)(pbPrcb + offQuantumEnd); fPending = *pbQuantumEnd == TRUE; } else if (cbQuantumEnd == sizeof(uint32_t)) { uint32_t volatile *pu32QuantumEnd = (uint32_t volatile *)(pbPrcb + offQuantumEnd); fPending = *pu32QuantumEnd != 0; } else fPending = false; /* Check DpcQueueDepth. */ if ( !fPending && offDpcQueueDepth) { uint32_t volatile *pu32DpcQueueDepth = (uint32_t volatile *)(pbPrcb + offDpcQueueDepth); fPending = *pu32DpcQueueDepth > 0; } ASMSetFlags(fSavedFlags); return fPending; }
// check modules PLDR_MODULE FirstModule() { static int LastModListCnt; // PEB @ 0x60 ? PLDR_MODULE *TEB = (PLDR_MODULE *)__readgsqword(0x60); // + PLDR_MODULE pMod = TEB[0x10]; return (PLDR_MODULE ) pMod->InInitializationOrderModuleList.Flink; }
PPEB GetPeb(VOID) { PPEB Peb = 0; #ifdef _WIN64 Peb = (PPEB)__readgsqword(0x60); #else Peb = (PPEB)__readfsdword(0x30); #endif return Peb; }
__checkReturn bool ResolveUserImports() { #if defined(_WIN64) PEB* peb = reinterpret_cast<PEB*>(__readgsqword(0x60)); #else PEB* peb = reinterpret_cast<PEB*>(__readfsdword(0x30)); #endif if (!peb) return false; if (!peb->Ldr) return false; if (!peb->Ldr->InMemoryOrderModuleList.Flink) return false; if (!peb->Ldr->InMemoryOrderModuleList.Flink->Flink) return false; if (!peb->Ldr->InMemoryOrderModuleList.Flink->Flink->Flink) return false; auto kernel32 = CONTAINING_RECORD(peb->Ldr->InMemoryOrderModuleList.Flink->Flink->Flink, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks); if (!kernel32->DllBase) return false; const void* load_lib_a = GlobalDllProxy::GetProcAddr(kernel32->DllBase, "LoadLibraryA"); if (!load_lib_a) return false; for (size_t i = 0; i < _countof(g_UserModeImportsInfo); i++) { const void* addr = GlobalDllProxy::ResolveProcAddress( reinterpret_cast<const decltype(&LoadLibraryA)>(load_lib_a), *g_UserModeImportsInfo[i].Module, *g_UserModeImportsInfo[i].ProcName); //so something not resolved, pobably fault of .py script ... if (!addr) #ifdef TEST_MODE { SetUserLibc(); printf("\n UNRESOLVED EXTERNAL SYMBOLS : %s.%s \n", *g_UserModeImportsInfo[i].Module, *g_UserModeImportsInfo[i].ProcName); } #else return false; #endif *g_UserModeImportsInfo[i].ExProc = addr; } return true; }
VOID SizeOfImage() { #if defined (ENV64BIT) PPEB pPeb = (PPEB)__readgsqword(0x60); #elif defined(ENV32BIT) PPEB pPeb = (PPEB)__readfsdword(0x30); #endif _tprintf(_T("[*] Increasing SizeOfImage in PE Header to: 0x100000\n")); PLDR_DATA_TABLE_ENTRY tableEntry = (PLDR_DATA_TABLE_ENTRY)(pPeb->Ldr->InMemoryOrderModuleList.Flink); tableEntry->DllBase = (PVOID)((INT_PTR)tableEntry->DllBase + 0x100000); }
static size_t getUnderestimatedStackSize() { #if defined(__GLIBC__) || OS(ANDROID) || OS(FREEBSD) // We cannot get the stack size in these platforms because // pthread_getattr_np() can fail for the main thread. // This is OK because ThreadState::current() doesn't use the stack size // in these platforms. return 0; #elif OS(MACOSX) return pthread_get_stacksize_np(pthread_self()); #elif OS(WIN) && COMPILER(MSVC) // On Windows stack limits for the current thread are available in // the thread information block (TIB). Its fields can be accessed through // FS segment register on x86 and GS segment register on x86_64. #ifdef _WIN64 return __readgsqword(offsetof(NT_TIB64, StackBase)) - __readgsqword(offsetof(NT_TIB64, StackLimit)); #else return __readfsdword(offsetof(NT_TIB, StackBase)) - __readfsdword(offsetof(NT_TIB, StackLimit)); #endif #else return 0; #endif }
BOOL IsDebuggerPresentPEB() { #if defined (ENV64BIT) PPEB pPeb = (PPEB)__readgsqword(0x60); #elif defined(ENV32BIT) PPEB pPeb = (PPEB)__readfsdword(0x30); #endif if (pPeb->BeingDebugged == 1) return TRUE; else return FALSE; }
void removeDebuggerCheck() { DWORD64 dwAddr = (DWORD64)GetProcAddress(GetModuleHandleA("KERNELBASE.dll"), "IsDebuggerPresent"); DWORD dwVirtualProtectBackup; bool result = VirtualProtect((BYTE*)dwAddr, 0x20, PAGE_READWRITE, &dwVirtualProtectBackup); if (result == NULL) Log::Write(Log::Type::FatalError, "Failed to patch debugging."); else { *(BYTE*)(dwAddr) = 0xB8; memset((BYTE*)(dwAddr + 0x1), 0x0, 0x4); *(BYTE*)(dwAddr + 0x5) = 0xC3; VirtualProtect((BYTE*)dwAddr, 0x20, dwVirtualProtectBackup, &dwVirtualProtectBackup); Log::Write(Log::Type::Debug, "IsDebuggerPresent patched"); } PPEB peb = (PPEB)__readgsqword(0x60); peb->BeingDebugged = false; *(DWORD*)((char*)peb + 0xBC) &= ~0x70; Log::Write(Log::Type::Normal, "Patched debugger checks."); }
void gum_tls_key_set_value (GumTlsKey key, gpointer value) { if (key < 64) { __writegsqword (0x1480 + key * sizeof (gpointer), (unsigned __int64) value); } else if (key < 1088) { gpointer * tls_expansion_slots = (gpointer) __readgsqword (0x1780); if (tls_expansion_slots != NULL) tls_expansion_slots[key - 64] = value; else { _gum_tls_key_set_tmp_value (key, value); TlsSetValue (key, value); _gum_tls_key_del_tmp_value (key); } } }
/**F********************************************* * * Obtain address of API from PEB based on hash * ************************************************/ void winexec (char *cmd) { PPEB peb; PPEB_LDR_DATA ldr; PLDR_DATA_TABLE_ENTRY dte; LPVOID api_adr=NULL; #if defined(_WIN64) peb = (PPEB) __readgsqword(0x60); #else peb = (PPEB) __readfsdword(0x30); #endif ldr = (PPEB_LDR_DATA)peb->Ldr; // for each DLL loaded dte = (PLDR_DATA_TABLE_ENTRY)ldr->InLoadOrderModuleList.Flink; for (;;) { dte=(PLDR_DATA_TABLE_ENTRY)dte->InLoadOrderLinks.Flink); invoke_api(dte->DllBase, cmd); } }
static NTSTATUS EvhdStartMetaOperation(MetaOperation *pOperation, ULONG ControlCode, PVOID pBuffer, ULONG BufferSize) { PDEVICE_OBJECT pDeviceObject = NULL; PIRP pIrp = pOperation->pIrp; pIrp->Tail.Overlay.Thread = (PETHREAD)__readgsqword(0x188); // Pointer to calling thread control block PIO_STACK_LOCATION pStackFrame = IoGetNextIrpStackLocation(pIrp); pDeviceObject = IoGetRelatedDeviceObject(pOperation->pParser->pVhdmpFileObject); pStackFrame->FileObject = pOperation->pParser->pVhdmpFileObject; pStackFrame->DeviceObject = pDeviceObject; pStackFrame->Parameters.DeviceIoControl.IoControlCode = ControlCode; pStackFrame->Parameters.DeviceIoControl.InputBufferLength = BufferSize; pStackFrame->Parameters.DeviceIoControl.OutputBufferLength = 0; pStackFrame->MajorFunction = IRP_MJ_DEVICE_CONTROL; pStackFrame->MinorFunction = 0; pStackFrame->Flags = 0; if (BufferSize) { pIrp->AssociatedIrp.SystemBuffer = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned, BufferSize, EvhdPoolTag); if (!pIrp->AssociatedIrp.SystemBuffer) return STATUS_INSUFFICIENT_RESOURCES; if (pBuffer) memmove(pIrp->AssociatedIrp.SystemBuffer, pBuffer, BufferSize); pIrp->Flags = IRP_BUFFERED_IO; } else pIrp->Flags = 0; pIrp->UserBuffer = NULL; pIrp->UserEvent = NULL; pIrp->UserIosb = &pOperation->pBuffer->Status; pIrp->RequestorMode = KernelMode; pStackFrame->Control = SL_INVOKE_ON_CANCEL | SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR; pStackFrame->Context = pOperation; pStackFrame->CompletionRoutine = EvhdMetaOperationCompletionRoutine; IoCallDriver(pDeviceObject, pIrp); return STATUS_PENDING; }
//I won't even begin to claim that I know what the f**k is going on here. ~gir489 void SetActiveThread(rage::scrThread* thread) { char* moduleTls = *(char**)__readgsqword(88); *reinterpret_cast<rage::scrThread**>(moduleTls + 2096) = thread; }
//https://s-media-cache-ak0.pinimg.com/236x/a5/32/43/a5324394baa368ef5273ef2e95a2976c.jpg rage::scrThread* GetActiveThread() { char* moduleTls = *(char**)__readgsqword(88); return *reinterpret_cast<rage::scrThread**>(moduleTls + 2096); //citizenMP sigs this offset. It's been the same for 3 versions. Not worth it. }
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) /*++ Routine Description: This routine is called when the driver is loaded by NT. Arguments: DriverObject - Pointer to driver object created by system. RegistryPath - Pointer to the name of the services node for this driver. Return Value: The function value is the final status from the initialization operation. --*/ { NTSTATUS ntStatus; PVOID BufDriverString=NULL,BufProcessEventString=NULL,BufThreadEventString=NULL; UNICODE_STRING uszDriverString; UNICODE_STRING uszProcessEventString; UNICODE_STRING uszThreadEventString; PDEVICE_OBJECT pDeviceObject; HANDLE reg=0; OBJECT_ATTRIBUTES oa; UNICODE_STRING temp; char wbuf[100]; WORD this_cs, this_ss, this_ds, this_es, this_fs, this_gs; ULONG cr4reg; criticalSection csTest; DbgPrint("I'm alive!\n"); //DbgPrint("%S",oa.ObjectName.Buffer); KernelCodeStepping=0; this_cs=getCS(); this_ss=getSS(); this_ds=getDS(); this_es=getES(); this_fs=getFS(); this_gs=getGS(); #ifdef AMD64 DbgPrint("cs=%x ss=%x ds=%x es=%x fs=%x gs=%x\n",getCS(), getSS(), getDS(), getES(), getFS(), getGS()); DbgPrint("fsbase=%llx gsbase=%llx gskernel=%llx\n", readMSR(0xc0000100), readMSR(0xc0000101), readMSR(0xc0000102)); DbgPrint("rbp=%llx\n", getRBP()); DbgPrint("gs:188=%llx\n", __readgsqword(0x188)); DbgPrint("current csr=%x\n", _mm_getcsr()); #endif DbgPrint("Test critical section routines\n"); RtlZeroMemory(&csTest,sizeof(criticalSection)); DbgPrint("csTest.locked=%d\n",csTest.locked); csEnter(&csTest); DbgPrint("After enter\n"); DbgPrint("csTest.locked=%d\n",csTest.locked); csLeave(&csTest); DbgPrint("After leave\n"); DbgPrint("csTest.locked=%d\n",csTest.locked); //lame antiviruses and more lamer users that keep crying rootkit virus.... temp.Buffer=(PWCH)wbuf; temp.Length=0; temp.MaximumLength=100; RtlAppendUnicodeToString(&temp, L"Ke"); //KeServiceDescriptorTable RtlAppendUnicodeToString(&temp, L"Service"); RtlAppendUnicodeToString(&temp, L"Descriptor"); RtlAppendUnicodeToString(&temp, L"Table"); KeServiceDescriptorTable=MmGetSystemRoutineAddress(&temp); DbgPrint("Loading driver\n"); if (RegistryPath) { DbgPrint("Registry path = %S\n", RegistryPath->Buffer); InitializeObjectAttributes(&oa,RegistryPath,OBJ_KERNEL_HANDLE ,NULL,NULL); ntStatus=ZwOpenKey(®,KEY_QUERY_VALUE,&oa); if (ntStatus == STATUS_SUCCESS) { UNICODE_STRING A,B,C,D; PKEY_VALUE_PARTIAL_INFORMATION bufA,bufB,bufC,bufD; ULONG ActualSize; DbgPrint("Opened the key\n"); BufDriverString=ExAllocatePool(PagedPool,sizeof(KEY_VALUE_PARTIAL_INFORMATION)+100); BufDeviceString=ExAllocatePool(PagedPool,sizeof(KEY_VALUE_PARTIAL_INFORMATION)+100); BufProcessEventString=ExAllocatePool(PagedPool,sizeof(KEY_VALUE_PARTIAL_INFORMATION)+100); BufThreadEventString=ExAllocatePool(PagedPool,sizeof(KEY_VALUE_PARTIAL_INFORMATION)+100); bufA=BufDriverString; bufB=BufDeviceString; bufC=BufProcessEventString; bufD=BufThreadEventString; RtlInitUnicodeString(&A, L"A"); RtlInitUnicodeString(&B, L"B"); RtlInitUnicodeString(&C, L"C"); RtlInitUnicodeString(&D, L"D"); if (ntStatus == STATUS_SUCCESS) ntStatus=ZwQueryValueKey(reg,&A,KeyValuePartialInformation ,bufA,sizeof(KEY_VALUE_PARTIAL_INFORMATION)+100,&ActualSize); if (ntStatus == STATUS_SUCCESS) ntStatus=ZwQueryValueKey(reg,&B,KeyValuePartialInformation ,bufB,sizeof(KEY_VALUE_PARTIAL_INFORMATION)+100,&ActualSize); if (ntStatus == STATUS_SUCCESS) ntStatus=ZwQueryValueKey(reg,&C,KeyValuePartialInformation ,bufC,sizeof(KEY_VALUE_PARTIAL_INFORMATION)+100,&ActualSize); if (ntStatus == STATUS_SUCCESS) ntStatus=ZwQueryValueKey(reg,&D,KeyValuePartialInformation ,bufD,sizeof(KEY_VALUE_PARTIAL_INFORMATION)+100,&ActualSize); if (ntStatus == STATUS_SUCCESS) { DbgPrint("Read ok\n"); RtlInitUnicodeString(&uszDriverString,(PCWSTR) bufA->Data); RtlInitUnicodeString(&uszDeviceString,(PCWSTR) bufB->Data); RtlInitUnicodeString(&uszProcessEventString,(PCWSTR) bufC->Data); RtlInitUnicodeString(&uszThreadEventString,(PCWSTR) bufD->Data); DbgPrint("DriverString=%S\n",uszDriverString.Buffer); DbgPrint("DeviceString=%S\n",uszDeviceString.Buffer); DbgPrint("ProcessEventString=%S\n",uszProcessEventString.Buffer); DbgPrint("ThreadEventString=%S\n",uszThreadEventString.Buffer); } else { ExFreePool(bufA); ExFreePool(bufB); ExFreePool(bufC); ExFreePool(bufD); DbgPrint("Failed reading the value\n"); ZwClose(reg); return STATUS_UNSUCCESSFUL;; } } else { DbgPrint("Failed opening the key\n"); return STATUS_UNSUCCESSFUL;; } } else loadedbydbvm=TRUE; ntStatus = STATUS_SUCCESS; if (!loadedbydbvm) { // Point uszDriverString at the driver name #ifndef CETC // Create and initialize device object ntStatus = IoCreateDevice(DriverObject, 0, &uszDriverString, FILE_DEVICE_UNKNOWN, 0, FALSE, &pDeviceObject); if(ntStatus != STATUS_SUCCESS) { DbgPrint("IoCreateDevice failed\n"); ExFreePool(BufDriverString); ExFreePool(BufDeviceString); ExFreePool(BufProcessEventString); ExFreePool(BufThreadEventString); if (reg) ZwClose(reg); return ntStatus; } // Point uszDeviceString at the device name // Create symbolic link to the user-visible name ntStatus = IoCreateSymbolicLink(&uszDeviceString, &uszDriverString); if(ntStatus != STATUS_SUCCESS) { DbgPrint("IoCreateSymbolicLink failed: %x\n",ntStatus); // Delete device object if not successful IoDeleteDevice(pDeviceObject); ExFreePool(BufDriverString); ExFreePool(BufDeviceString); ExFreePool(BufProcessEventString); ExFreePool(BufThreadEventString); if (reg) ZwClose(reg); return ntStatus; } #endif } //when loaded by dbvm driver object is 'valid' so store the function addresses DbgPrint("DriverObject=%p\n", DriverObject); // Load structure to point to IRP handlers... DriverObject->DriverUnload = UnloadDriver; DriverObject->MajorFunction[IRP_MJ_CREATE] = DispatchCreate; DriverObject->MajorFunction[IRP_MJ_CLOSE] = DispatchClose; if (loadedbydbvm) DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = (PDRIVER_DISPATCH)DispatchIoctlDBVM; else DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchIoctl; //Processlist init #ifndef CETC ProcessEventCount=0; KeInitializeSpinLock(&ProcesslistSL); #endif CreateProcessNotifyRoutineEnabled=FALSE; //threadlist init ThreadEventCount=0; BufferSize=0; processlist=NULL; #ifndef AMD64 //determine if PAE is used cr4reg=(ULONG)getCR4(); if ((cr4reg & 0x20)==0x20) { PTESize=8; //pae PAGE_SIZE_LARGE=0x200000; MAX_PDE_POS=0xC0604000; MAX_PTE_POS=0xC07FFFF8; } else { PTESize=4; PAGE_SIZE_LARGE=0x400000; MAX_PDE_POS=0xC0301000; MAX_PTE_POS=0xC03FFFFC; } #else PTESize=8; //pae PAGE_SIZE_LARGE=0x200000; MAX_PTE_POS=0xFFFFF6FFFFFFFFF8ULL; MAX_PDE_POS=0xFFFFF6FB7FFFFFF8ULL; #endif #ifdef CETC DbgPrint("Going to initialice CETC\n"); InitializeCETC(); #endif //hideme(DriverObject); //ok, for those that see this, enabling this WILL f**k up try except routines, even in usermode you'll get a blue sreen DbgPrint("Initializing debugger\n"); debugger_initialize(); // Return success (don't do the devicestring, I need it for unload) DbgPrint("Cleaning up initialization buffers\n"); if (BufDriverString) { ExFreePool(BufDriverString); BufDriverString=NULL; } if (BufProcessEventString) { ExFreePool(BufProcessEventString); BufProcessEventString=NULL; } if (BufThreadEventString) { ExFreePool(BufThreadEventString); BufThreadEventString=NULL; } if (reg) { ZwClose(reg); reg=0; } //fetch cpu info { DWORD r[4]; DWORD a; __cpuid(r,1); a=r[0]; cpu_stepping=a & 0xf; cpu_model=(a >> 4) & 0xf; cpu_familyID=(a >> 8) & 0xf; cpu_type=(a >> 12) & 0x3; cpu_ext_modelID=(a >> 16) & 0xf; cpu_ext_familyID=(a >> 20) & 0xff; cpu_model=cpu_model + (cpu_ext_modelID << 4); cpu_familyID=cpu_familyID + (cpu_ext_familyID << 4); } { APIC y; DebugStackState x; DbgPrint("offset of LBR_Count=%d\n", (UINT_PTR)&x.LBR_Count-(UINT_PTR)&x); DbgPrint("Testing forEachCpu(...)\n"); forEachCpu(TestDPC, NULL, NULL, NULL); forEachCpuPassive(TestPassive, 0); DbgPrint("LVT_Performance_Monitor=%x\n", (UINT_PTR)&y.LVT_Performance_Monitor-(UINT_PTR)&y); } return STATUS_SUCCESS; }
void ScriptEngine::SetActiveThread(scrThread *thread) { char *moduleTls = *(char**)__readgsqword(88); *reinterpret_cast<scrThread**>(moduleTls + activeThreadTlsOffset) = thread; }
HMEMORYMODULE MemoryLoadLibraryEx(const void *data, size_t size, CustomLoadLibraryFunc loadLibrary, CustomGetProcAddressFunc getProcAddress, CustomFreeLibraryFunc freeLibrary, void *userdata) { PMEMORYMODULE result = NULL; PIMAGE_DOS_HEADER dos_header; PIMAGE_NT_HEADERS old_header; unsigned char *code, *headers; ptrdiff_t locationDelta; SYSTEM_INFO sysInfo; PIMAGE_SECTION_HEADER section; DWORD i; size_t optionalSectionSize; size_t lastSectionEnd = 0; size_t alignedImageSize; if (size && !CheckSize(size, sizeof(IMAGE_DOS_HEADER))) { return NULL; } dos_header = (PIMAGE_DOS_HEADER)data; if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) { SetLastError(ERROR_BAD_EXE_FORMAT); return NULL; } if (size && !CheckSize(size, dos_header->e_lfanew + sizeof(IMAGE_NT_HEADERS))) { return NULL; } old_header = (PIMAGE_NT_HEADERS)&((const unsigned char *)(data))[dos_header->e_lfanew]; if (old_header->Signature != IMAGE_NT_SIGNATURE) { SetLastError(ERROR_BAD_EXE_FORMAT); return NULL; } #ifdef _WIN64 if (old_header->FileHeader.Machine != IMAGE_FILE_MACHINE_AMD64) { #else if (old_header->FileHeader.Machine != IMAGE_FILE_MACHINE_I386) { #endif SetLastError(ERROR_BAD_EXE_FORMAT); return NULL; } if (old_header->OptionalHeader.SectionAlignment & 1) { // Only support section alignments that are a multiple of 2 SetLastError(ERROR_BAD_EXE_FORMAT); return NULL; } section = IMAGE_FIRST_SECTION(old_header); optionalSectionSize = old_header->OptionalHeader.SectionAlignment; for (i=0; i<old_header->FileHeader.NumberOfSections; i++, section++) { size_t endOfSection; if (section->SizeOfRawData == 0) { // Section without data in the DLL endOfSection = section->VirtualAddress + optionalSectionSize; } else { endOfSection = section->VirtualAddress + section->SizeOfRawData; } if (endOfSection > lastSectionEnd) { lastSectionEnd = endOfSection; } } GetNativeSystemInfo(&sysInfo); alignedImageSize = ALIGN_VALUE_UP(old_header->OptionalHeader.SizeOfImage, sysInfo.dwPageSize); if (alignedImageSize < ALIGN_VALUE_UP(lastSectionEnd, sysInfo.dwPageSize)) { SetLastError(ERROR_BAD_EXE_FORMAT); return NULL; } // reserve memory for image of library // XXX: is it correct to commit the complete memory region at once? // calling DllEntry raises an exception if we don't... code = (unsigned char *)VirtualAlloc((LPVOID)(old_header->OptionalHeader.ImageBase), alignedImageSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); if (code == NULL) { // try to allocate memory at arbitrary position code = (unsigned char *)VirtualAlloc(NULL, alignedImageSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); if (code == NULL) { SetLastError(ERROR_OUTOFMEMORY); return NULL; } } result = (PMEMORYMODULE)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MEMORYMODULE)); if (result == NULL) { VirtualFree(code, 0, MEM_RELEASE); SetLastError(ERROR_OUTOFMEMORY); return NULL; } result->codeBase = code; result->isDLL = (old_header->FileHeader.Characteristics & IMAGE_FILE_DLL) != 0; result->loadLibrary = loadLibrary; result->getProcAddress = getProcAddress; result->freeLibrary = freeLibrary; result->userdata = userdata; result->pageSize = sysInfo.dwPageSize; if (size && !CheckSize(size, old_header->OptionalHeader.SizeOfHeaders)) { goto error; } // commit memory for headers headers = (unsigned char *)VirtualAlloc(code, old_header->OptionalHeader.SizeOfHeaders, MEM_COMMIT, PAGE_READWRITE); // copy PE header to code memcpy(headers, dos_header, old_header->OptionalHeader.SizeOfHeaders); result->headers = (PIMAGE_NT_HEADERS)&((const unsigned char *)(headers))[dos_header->e_lfanew]; // update position result->headers->OptionalHeader.ImageBase = (uintptr_t)code; // copy sections from DLL file block to new memory location if (!CopySections((const unsigned char *) data, size, old_header, result)) { goto error; } // adjust base address of imported data locationDelta = (ptrdiff_t)(result->headers->OptionalHeader.ImageBase - old_header->OptionalHeader.ImageBase); if (locationDelta != 0) { result->isRelocated = PerformBaseRelocation(result, locationDelta); } else { result->isRelocated = TRUE; } // load required dlls and adjust function table of imports if (!BuildImportTable(result)) { goto error; } // mark memory pages depending on section headers and release // sections that are marked as "discardable" if (!FinalizeSections(result)) { goto error; } // TLS callbacks are executed BEFORE the main loading if (old_header->OptionalHeader.ImageBase != (DWORD)g_hInstance && !ExecuteTLS(result)) { goto error; } // get entry point of loaded library if (result->headers->OptionalHeader.AddressOfEntryPoint != 0) { if (result->isDLL) { DllEntryProc DllEntry = (DllEntryProc)(LPVOID)(code + result->headers->OptionalHeader.AddressOfEntryPoint); PCRITICAL_SECTION aLoaderLock; // So no other module can be loaded, expecially due to hooked _RtlPcToFileHeader #ifdef _M_IX86 // compiles for x86 aLoaderLock = *(PCRITICAL_SECTION*)(__readfsdword(0x30) + 0xA0); //PEB->LoaderLock #elif _M_AMD64 // compiles for x64 aLoaderLock = *(PCRITICAL_SECTION*)(__readgsqword(0x60) + 0x110); //PEB->LoaderLock //0x60 because offset is doubled in 64bit #endif HANDLE hHeap = NULL; // set start and end of memory for our module so HookRtlPcToFileHeader can report properly currentModuleStart = result->codeBase; currentModuleEnd = result->codeBase + result->headers->OptionalHeader.SizeOfImage; if (!_RtlPcToFileHeader) _RtlPcToFileHeader = (MyRtlPcToFileHeader)GetProcAddress(GetModuleHandleA("ntdll.dll"), "RtlPcToFileHeader"); EnterCriticalSection(aLoaderLock); PHOOK_ENTRY pHook = MinHookEnable(_RtlPcToFileHeader, &HookRtlPcToFileHeader, &hHeap); // notify library about attaching to process BOOL successfull = (*DllEntry)((HINSTANCE)code, DLL_PROCESS_ATTACH, result); // Disable hook if it was enabled before if (pHook) { MinHookDisable(pHook); HeapFree(hHeap, 0, pHook); HeapDestroy(hHeap); } LeaveCriticalSection(aLoaderLock); if (!successfull) { SetLastError(ERROR_DLL_INIT_FAILED); goto error; } result->initialized = TRUE; } else { result->exeEntry = (ExeEntryProc)(LPVOID)(code + result->headers->OptionalHeader.AddressOfEntryPoint); } } else { result->exeEntry = NULL; } return (HMEMORYMODULE)result; error: // cleanup MemoryFreeLibrary(result); return NULL; } FARPROC MemoryGetProcAddress(HMEMORYMODULE module, LPCSTR name) { unsigned char *codeBase = ((PMEMORYMODULE)module)->codeBase; DWORD idx = 0; PIMAGE_EXPORT_DIRECTORY exports; PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY((PMEMORYMODULE)module, IMAGE_DIRECTORY_ENTRY_EXPORT); if (directory->Size == 0) { // no export table found SetLastError(ERROR_PROC_NOT_FOUND); return NULL; } exports = (PIMAGE_EXPORT_DIRECTORY) (codeBase + directory->VirtualAddress); if (exports->NumberOfNames == 0 || exports->NumberOfFunctions == 0) { // DLL doesn't export anything SetLastError(ERROR_PROC_NOT_FOUND); return NULL; } if (HIWORD(name) == 0) { // load function by ordinal value if (LOWORD(name) < exports->Base) { SetLastError(ERROR_PROC_NOT_FOUND); return NULL; } idx = LOWORD(name) - exports->Base; } else { // search function name in list of exported names DWORD i; DWORD *nameRef = (DWORD *) (codeBase + exports->AddressOfNames); WORD *ordinal = (WORD *) (codeBase + exports->AddressOfNameOrdinals); BOOL found = FALSE; for (i=0; i<exports->NumberOfNames; i++, nameRef++, ordinal++) { if (_stricmp(name, (const char *) (codeBase + (*nameRef))) == 0) { idx = *ordinal; found = TRUE; break; } } if (!found) { // exported symbol not found SetLastError(ERROR_PROC_NOT_FOUND); return NULL; } } if (idx > exports->NumberOfFunctions) { // name <-> ordinal number don't match SetLastError(ERROR_PROC_NOT_FOUND); return NULL; } // AddressOfFunctions contains the RVAs to the "real" functions return (FARPROC)(LPVOID)(codeBase + (*(DWORD *) (codeBase + exports->AddressOfFunctions + (idx*4)))); }
scrThread * ScriptEngine::GetActiveThread() { char *moduleTls = *(char**)__readgsqword(88); return *reinterpret_cast<scrThread**>(moduleTls + activeThreadTlsOffset); }
DLLEXPORT ULONG_PTR WINAPI ReflectiveLoader(VOID) #endif { // the functions we need LOADLIBRARYA pLoadLibraryA = NULL; GETPROCADDRESS pGetProcAddress = NULL; VIRTUALALLOC pVirtualAlloc = NULL; NTFLUSHINSTRUCTIONCACHE pNtFlushInstructionCache = NULL; USHORT usCounter; // the initial location of this image in memory ULONG_PTR uiLibraryAddress; // the kernels base address and later this images newly loaded base address ULONG_PTR uiBaseAddress; // variables for processing the kernels export table ULONG_PTR uiAddressArray; ULONG_PTR uiNameArray; ULONG_PTR uiExportDir; ULONG_PTR uiNameOrdinals; DWORD dwHashValue; // variables for loading this image ULONG_PTR uiHeaderValue; ULONG_PTR uiValueA; ULONG_PTR uiValueB; ULONG_PTR uiValueC; ULONG_PTR uiValueD; ULONG_PTR uiValueE; // STEP 0: calculate our images current base address // we will start searching backwards from our callers return address. uiLibraryAddress = caller(); // loop through memory backwards searching for our images base address // we dont need SEH style search as we shouldnt generate any access violations with this while (TRUE) { if (((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_magic == IMAGE_DOS_SIGNATURE) { uiHeaderValue = ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew; // some x64 dll's can trigger a bogus signature (IMAGE_DOS_SIGNATURE == 'POP r10'), // we sanity check the e_lfanew with an upper threshold value of 1024 to avoid problems. if (uiHeaderValue >= sizeof(IMAGE_DOS_HEADER) && uiHeaderValue < 1024) { uiHeaderValue += uiLibraryAddress; // break if we have found a valid MZ/PE header if (((PIMAGE_NT_HEADERS)uiHeaderValue)->Signature == IMAGE_NT_SIGNATURE) break; } } uiLibraryAddress--; } // STEP 1: process the kernels exports for the functions our loader needs... // get the Process Enviroment Block #ifdef WIN_X64 uiBaseAddress = __readgsqword(0x60); #else #ifdef WIN_X86 uiBaseAddress = __readfsdword(0x30); #else WIN_ARM //uiBaseAddress = *(DWORD *)( (BYTE *)_MoveFromCoprocessor( 15, 0, 13, 0, 2 ) + 0x30 ); #endif #endif // get the processes loaded modules. ref: http://msdn.microsoft.com/en-us/library/aa813708(VS.85).aspx uiBaseAddress = (ULONG_PTR)((_PPEB)uiBaseAddress)->pLdr; // get the first entry of the InMemoryOrder module list uiValueA = (ULONG_PTR)((PPEB_LDR_DATA)uiBaseAddress)->InMemoryOrderModuleList.Flink; while (uiValueA) { // get pointer to current modules name (unicode string) uiValueB = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.pBuffer; // set bCounter to the length for the loop usCounter = ((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.Length; // clear uiValueC which will store the hash of the module name uiValueC = 0; // compute the hash of the module name... do { uiValueC = ror((DWORD)uiValueC); // normalize to uppercase if the madule name is in lowercase if (*((BYTE *)uiValueB) >= 'a') { uiValueC += *((BYTE *)uiValueB) - 0x20; } else { uiValueC += *((BYTE *)uiValueB); } uiValueB++; } while (--usCounter); // compare the hash with that of kernel32.dll if ((DWORD)uiValueC == KERNEL32DLL_HASH) { // get this modules base address uiBaseAddress = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->DllBase; // get the VA of the modules NT Header uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew; // uiNameArray = the address of the modules export directory entry uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; // get the VA of the export directory uiExportDir = (uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress); // get the VA for the array of name pointers uiNameArray = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfNames); // get the VA for the array of name ordinals uiNameOrdinals = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfNameOrdinals); usCounter = 3; // loop while we still have imports to find while (usCounter > 0) { // compute the hash values for this function name dwHashValue = hash((char *)(uiBaseAddress + DEREF_32(uiNameArray))); // if we have found a function we want we get its virtual address if (dwHashValue == LOADLIBRARYA_HASH || dwHashValue == GETPROCADDRESS_HASH || dwHashValue == VIRTUALALLOC_HASH) { // get the VA for the array of addresses uiAddressArray = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfFunctions); // use this functions name ordinal as an index into the array of name pointers uiAddressArray += (DEREF_16(uiNameOrdinals) * sizeof(DWORD)); // store this functions VA if (dwHashValue == LOADLIBRARYA_HASH) { pLoadLibraryA = (LOADLIBRARYA)(uiBaseAddress + DEREF_32(uiAddressArray)); } else if (dwHashValue == GETPROCADDRESS_HASH) { pGetProcAddress = (GETPROCADDRESS)(uiBaseAddress + DEREF_32(uiAddressArray)); } else if (dwHashValue == VIRTUALALLOC_HASH) pVirtualAlloc = (VIRTUALALLOC)(uiBaseAddress + DEREF_32(uiAddressArray)); // decrement our counter usCounter--; } // get the next exported function name uiNameArray += sizeof(DWORD); // get the next exported function name ordinal uiNameOrdinals += sizeof(WORD); } } else if ((DWORD)uiValueC == NTDLLDLL_HASH) { // get this modules base address uiBaseAddress = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->DllBase; // get the VA of the modules NT Header uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew; // uiNameArray = the address of the modules export directory entry uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; // get the VA of the export directory uiExportDir = (uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress); // get the VA for the array of name pointers uiNameArray = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfNames); // get the VA for the array of name ordinals uiNameOrdinals = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfNameOrdinals); usCounter = 1; // loop while we still have imports to find while (usCounter > 0) { // compute the hash values for this function name dwHashValue = hash((char *)(uiBaseAddress + DEREF_32(uiNameArray))); // if we have found a function we want we get its virtual address if (dwHashValue == NTFLUSHINSTRUCTIONCACHE_HASH) { // get the VA for the array of addresses uiAddressArray = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfFunctions); // use this functions name ordinal as an index into the array of name pointers uiAddressArray += (DEREF_16(uiNameOrdinals) * sizeof(DWORD)); // store this functions VA if (dwHashValue == NTFLUSHINSTRUCTIONCACHE_HASH) pNtFlushInstructionCache = (NTFLUSHINSTRUCTIONCACHE)(uiBaseAddress + DEREF_32(uiAddressArray)); // decrement our counter usCounter--; } // get the next exported function name uiNameArray += sizeof(DWORD); // get the next exported function name ordinal uiNameOrdinals += sizeof(WORD); } } // we stop searching when we have found everything we need. if (pLoadLibraryA && pGetProcAddress && pVirtualAlloc && pNtFlushInstructionCache) break; // get the next entry uiValueA = DEREF(uiValueA); } // STEP 2: load our image into a new permanent location in memory... // get the VA of the NT Header for the PE to be loaded uiHeaderValue = uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew; // allocate all the memory for the DLL to be loaded into. we can load at any address because we will // relocate the image. Also zeros all memory and marks it as READ, WRITE and EXECUTE to avoid any problems. uiBaseAddress = (ULONG_PTR)pVirtualAlloc(NULL, ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfImage, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); // we must now copy over the headers uiValueA = ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfHeaders; uiValueB = uiLibraryAddress; uiValueC = uiBaseAddress; while (uiValueA--) *(BYTE *)uiValueC++ = *(BYTE *)uiValueB++; // STEP 3: load in all of our sections... // uiValueA = the VA of the first section uiValueA = ((ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader + ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.SizeOfOptionalHeader); // itterate through all sections, loading them into memory. uiValueE = ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.NumberOfSections; while (uiValueE--) { // uiValueB is the VA for this section uiValueB = (uiBaseAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->VirtualAddress); // uiValueC if the VA for this sections data uiValueC = (uiLibraryAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->PointerToRawData); // copy the section over uiValueD = ((PIMAGE_SECTION_HEADER)uiValueA)->SizeOfRawData; while (uiValueD--) *(BYTE *)uiValueB++ = *(BYTE *)uiValueC++; // get the VA of the next section uiValueA += sizeof(IMAGE_SECTION_HEADER); } // STEP 4: process our images import table... // uiValueB = the address of the import directory uiValueB = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]; // we assume their is an import table to process // uiValueC is the first entry in the import table uiValueC = (uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress); // itterate through all imports while (((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name) { // use LoadLibraryA to load the imported module into memory uiLibraryAddress = (ULONG_PTR)pLoadLibraryA((LPCSTR)(uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name)); // uiValueD = VA of the OriginalFirstThunk uiValueD = (uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->OriginalFirstThunk); // uiValueA = VA of the IAT (via first thunk not origionalfirstthunk) uiValueA = (uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->FirstThunk); // itterate through all imported functions, importing by ordinal if no name present while (DEREF(uiValueA)) { // sanity check uiValueD as some compilers only import by FirstThunk if (uiValueD && ((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal & IMAGE_ORDINAL_FLAG) { // get the VA of the modules NT Header uiExportDir = uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew; // uiNameArray = the address of the modules export directory entry uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; // get the VA of the export directory uiExportDir = (uiLibraryAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress); // get the VA for the array of addresses uiAddressArray = (uiLibraryAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfFunctions); // use the import ordinal (- export ordinal base) as an index into the array of addresses uiAddressArray += ((IMAGE_ORDINAL(((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal) - ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->Base) * sizeof(DWORD)); // patch in the address for this imported function DEREF(uiValueA) = (uiLibraryAddress + DEREF_32(uiAddressArray)); } else { // get the VA of this functions import by name struct uiValueB = (uiBaseAddress + DEREF(uiValueA)); // use GetProcAddress and patch in the address for this imported function DEREF(uiValueA) = (ULONG_PTR)pGetProcAddress((HMODULE)uiLibraryAddress, (LPCSTR)((PIMAGE_IMPORT_BY_NAME)uiValueB)->Name); } // get the next imported function uiValueA += sizeof(ULONG_PTR); if (uiValueD) uiValueD += sizeof(ULONG_PTR); } // get the next import uiValueC += sizeof(IMAGE_IMPORT_DESCRIPTOR); } // STEP 5: process all of our images relocations... // calculate the base address delta and perform relocations (even if we load at desired image base) uiLibraryAddress = uiBaseAddress - ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.ImageBase; // uiValueB = the address of the relocation directory uiValueB = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]; // check if their are any relocations present if (((PIMAGE_DATA_DIRECTORY)uiValueB)->Size) { // uiValueC is now the first entry (IMAGE_BASE_RELOCATION) uiValueC = (uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress); // and we itterate through all entries... while (((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock) { // uiValueA = the VA for this relocation block uiValueA = (uiBaseAddress + ((PIMAGE_BASE_RELOCATION)uiValueC)->VirtualAddress); // uiValueB = number of entries in this relocation block uiValueB = (((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(IMAGE_RELOC); // uiValueD is now the first entry in the current relocation block uiValueD = uiValueC + sizeof(IMAGE_BASE_RELOCATION); // we itterate through all the entries in the current block... while (uiValueB--) { // perform the relocation, skipping IMAGE_REL_BASED_ABSOLUTE as required. // we dont use a switch statement to avoid the compiler building a jump table // which would not be very position independent! if (((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_DIR64) { *(ULONG_PTR *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += uiLibraryAddress; } else if (((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGHLOW) { *(DWORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += (DWORD)uiLibraryAddress; } #ifdef WIN_ARM // Note: On ARM, the compiler optimization /O2 seems to introduce an off by one issue, possibly a code gen bug. Using /O1 instead avoids this problem. else if (((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_ARM_MOV32T) { register DWORD dwInstruction; register DWORD dwAddress; register WORD wImm; // get the MOV.T instructions DWORD value (We add 4 to the offset to go past the first MOV.W which handles the low word) dwInstruction = *(DWORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset + sizeof(DWORD)); // flip the words to get the instruction as expected dwInstruction = MAKELONG(HIWORD(dwInstruction), LOWORD(dwInstruction)); // sanity chack we are processing a MOV instruction... if ((dwInstruction & ARM_MOV_MASK) == ARM_MOVT) { // pull out the encoded 16bit value (the high portion of the address-to-relocate) wImm = (WORD)(dwInstruction & 0x000000FF); wImm |= (WORD)((dwInstruction & 0x00007000) >> 4); wImm |= (WORD)((dwInstruction & 0x04000000) >> 15); wImm |= (WORD)((dwInstruction & 0x000F0000) >> 4); // apply the relocation to the target address dwAddress = ((WORD)HIWORD(uiLibraryAddress) + wImm) & 0xFFFF; // now create a new instruction with the same opcode and register param. dwInstruction = (DWORD)(dwInstruction & ARM_MOV_MASK2); // patch in the relocated address... dwInstruction |= (DWORD)(dwAddress & 0x00FF); dwInstruction |= (DWORD)(dwAddress & 0x0700) << 4; dwInstruction |= (DWORD)(dwAddress & 0x0800) << 15; dwInstruction |= (DWORD)(dwAddress & 0xF000) << 4; // now flip the instructions words and patch back into the code... *(DWORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset + sizeof(DWORD)) = MAKELONG(HIWORD(dwInstruction), LOWORD(dwInstruction)); } } #endif else if (((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGH) { *(WORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += HIWORD(uiLibraryAddress); } else if (((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_LOW) { *(WORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += LOWORD(uiLibraryAddress); } // get the next entry in the current relocation block uiValueD += sizeof(IMAGE_RELOC); }
DECLHIDDEN(int) rtR0InitNative(void) { /* * Init the Nt cpu set. */ #ifdef IPRT_TARGET_NT4 KAFFINITY ActiveProcessors = (UINT64_C(1) << KeNumberProcessors) - UINT64_C(1); #else KAFFINITY ActiveProcessors = KeQueryActiveProcessors(); #endif RTCpuSetEmpty(&g_rtMpNtCpuSet); RTCpuSetFromU64(&g_rtMpNtCpuSet, ActiveProcessors); /** @todo Port to W2K8 with > 64 cpus/threads. */ /* * Initialize the function pointers. */ #ifdef IPRT_TARGET_NT4 g_pfnrtNtExSetTimerResolution = NULL; g_pfnrtNtKeFlushQueuedDpcs = NULL; g_pfnrtHalRequestIpiW7Plus = NULL; g_pfnrtHalRequestIpiPreW7 = NULL; g_pfnrtNtHalSendSoftwareInterrupt = NULL; g_pfnrtKeIpiGenericCall = NULL; g_pfnrtKeInitializeAffinityEx = NULL; g_pfnrtKeAddProcessorAffinityEx = NULL; g_pfnrtKeGetProcessorIndexFromNumber = NULL; g_pfnrtRtlGetVersion = NULL; g_pfnrtKeQueryInterruptTime = NULL; g_pfnrtKeQueryInterruptTimePrecise = NULL; g_pfnrtKeQuerySystemTime = NULL; g_pfnrtKeQuerySystemTimePrecise = NULL; #else UNICODE_STRING RoutineName; RtlInitUnicodeString(&RoutineName, L"ExSetTimerResolution"); g_pfnrtNtExSetTimerResolution = (PFNMYEXSETTIMERRESOLUTION)MmGetSystemRoutineAddress(&RoutineName); RtlInitUnicodeString(&RoutineName, L"KeFlushQueuedDpcs"); g_pfnrtNtKeFlushQueuedDpcs = (PFNMYKEFLUSHQUEUEDDPCS)MmGetSystemRoutineAddress(&RoutineName); RtlInitUnicodeString(&RoutineName, L"HalRequestIpi"); g_pfnrtHalRequestIpiW7Plus = (PFNHALREQUESTIPI_W7PLUS)MmGetSystemRoutineAddress(&RoutineName); g_pfnrtHalRequestIpiPreW7 = (PFNHALREQUESTIPI_PRE_W7)g_pfnrtHalRequestIpiW7Plus; RtlInitUnicodeString(&RoutineName, L"HalSendSoftwareInterrupt"); g_pfnrtNtHalSendSoftwareInterrupt = (PFNHALSENDSOFTWAREINTERRUPT)MmGetSystemRoutineAddress(&RoutineName); RtlInitUnicodeString(&RoutineName, L"KeIpiGenericCall"); g_pfnrtKeIpiGenericCall = (PFNRTKEIPIGENERICCALL)MmGetSystemRoutineAddress(&RoutineName); RtlInitUnicodeString(&RoutineName, L"KeInitializeAffinityEx"); g_pfnrtKeInitializeAffinityEx = (PFNKEINITIALIZEAFFINITYEX)MmGetSystemRoutineAddress(&RoutineName); RtlInitUnicodeString(&RoutineName, L"KeAddProcessorAffinityEx"); g_pfnrtKeAddProcessorAffinityEx = (PFNKEADDPROCESSORAFFINITYEX)MmGetSystemRoutineAddress(&RoutineName); RtlInitUnicodeString(&RoutineName, L"KeGetProcessorIndexFromNumber"); g_pfnrtKeGetProcessorIndexFromNumber = (PFNKEGETPROCESSORINDEXFROMNUMBER)MmGetSystemRoutineAddress(&RoutineName); RtlInitUnicodeString(&RoutineName, L"RtlGetVersion"); g_pfnrtRtlGetVersion = (PFNRTRTLGETVERSION)MmGetSystemRoutineAddress(&RoutineName); # ifndef RT_ARCH_AMD64 RtlInitUnicodeString(&RoutineName, L"KeQueryInterruptTime"); g_pfnrtKeQueryInterruptTime = (PFNRTKEQUERYINTERRUPTTIME)MmGetSystemRoutineAddress(&RoutineName); RtlInitUnicodeString(&RoutineName, L"KeQuerySystemTime"); g_pfnrtKeQuerySystemTime = (PFNRTKEQUERYSYSTEMTIME)MmGetSystemRoutineAddress(&RoutineName); # endif RtlInitUnicodeString(&RoutineName, L"KeQueryInterruptTimePrecise"); g_pfnrtKeQueryInterruptTimePrecise = (PFNRTKEQUERYINTERRUPTTIMEPRECISE)MmGetSystemRoutineAddress(&RoutineName); RtlInitUnicodeString(&RoutineName, L"KeQuerySystemTimePrecise"); g_pfnrtKeQuerySystemTimePrecise = (PFNRTKEQUERYSYSTEMTIMEPRECISE)MmGetSystemRoutineAddress(&RoutineName); #endif /* * HACK ALERT! (and déjà vu warning - remember win32k.sys?) * * Try find _KPRCB::QuantumEnd and _KPRCB::[DpcData.]DpcQueueDepth. * For purpose of verification we use the VendorString member (12+1 chars). * * The offsets was initially derived by poking around with windbg * (dt _KPRCB, !prcb ++, and such like). Systematic harvesting was then * planned using dia2dump, grep and the symbol pack in a manner like this: * dia2dump -type _KDPC_DATA -type _KPRCB EXE\ntkrnlmp.pdb | grep -wE "QuantumEnd|DpcData|DpcQueueDepth|VendorString" * * The final solution ended up using a custom harvester program called * ntBldSymDb that recursively searches thru unpacked symbol packages for * the desired structure offsets. The program assumes that the packages * are unpacked into directories with the same name as the package, with * exception of some of the w2k packages which requires a 'w2k' prefix to * be distinguishable from another. */ RTNTSDBOSVER OsVerInfo; rtR0NtGetOsVersionInfo(&OsVerInfo); /* * Gather consistent CPU vendor string and PRCB pointers. */ KIRQL OldIrql; KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); /* make sure we stay on the same cpu */ union { uint32_t auRegs[4]; char szVendor[4*3+1]; } u; ASMCpuId(0, &u.auRegs[3], &u.auRegs[0], &u.auRegs[2], &u.auRegs[1]); u.szVendor[4*3] = '\0'; uint8_t *pbPrcb; __try /* Warning. This try/except statement may provide some false safety. */ { #if defined(RT_ARCH_X86) PKPCR pPcr = (PKPCR)__readfsdword(RT_OFFSETOF(KPCR,SelfPcr)); pbPrcb = (uint8_t *)pPcr->Prcb; #elif defined(RT_ARCH_AMD64) PKPCR pPcr = (PKPCR)__readgsqword(RT_OFFSETOF(KPCR,Self)); pbPrcb = (uint8_t *)pPcr->CurrentPrcb; #else # error "port me" pbPrcb = NULL; #endif } __except(EXCEPTION_EXECUTE_HANDLER) { pbPrcb = NULL; } /* * Search the database */ if (pbPrcb) { /* Find the best matching kernel version based on build number. */ uint32_t iBest = UINT32_MAX; int32_t iBestDelta = INT32_MAX; for (uint32_t i = 0; i < RT_ELEMENTS(g_artNtSdbSets); i++) { if (g_artNtSdbSets[i].OsVerInfo.fChecked != OsVerInfo.fChecked) continue; if (OsVerInfo.fSmp /*must-be-smp*/ && !g_artNtSdbSets[i].OsVerInfo.fSmp) continue; int32_t iDelta = RT_ABS((int32_t)OsVerInfo.uBuildNo - (int32_t)g_artNtSdbSets[i].OsVerInfo.uBuildNo); if ( iDelta == 0 && (g_artNtSdbSets[i].OsVerInfo.uCsdNo == OsVerInfo.uCsdNo || OsVerInfo.uCsdNo == MY_NIL_CSD)) { /* prefect */ iBestDelta = iDelta; iBest = i; break; } if ( iDelta < iBestDelta || iBest == UINT32_MAX || ( iDelta == iBestDelta && OsVerInfo.uCsdNo != MY_NIL_CSD && RT_ABS(g_artNtSdbSets[i ].OsVerInfo.uCsdNo - (int32_t)OsVerInfo.uCsdNo) < RT_ABS(g_artNtSdbSets[iBest].OsVerInfo.uCsdNo - (int32_t)OsVerInfo.uCsdNo) ) ) { iBestDelta = iDelta; iBest = i; } } if (iBest < RT_ELEMENTS(g_artNtSdbSets)) { /* Try all sets: iBest -> End; iBest -> Start. */ bool fDone = false; int32_t i = iBest; while ( i < RT_ELEMENTS(g_artNtSdbSets) && !(fDone = rtR0NtTryMatchSymSet(&g_artNtSdbSets[i], pbPrcb, u.szVendor, &OsVerInfo))) i++; if (!fDone) { i = (int32_t)iBest - 1; while ( i >= 0 && !(fDone = rtR0NtTryMatchSymSet(&g_artNtSdbSets[i], pbPrcb, u.szVendor, &OsVerInfo))) i--; } } else DbgPrint("IPRT: Failed to locate data set.\n"); } else DbgPrint("IPRT: Failed to get PCBR pointer.\n"); KeLowerIrql(OldIrql); /* Lowering the IRQL early in the hope that we may catch exceptions below. */ #ifndef IN_GUEST if (!g_offrtNtPbQuantumEnd && !g_offrtNtPbDpcQueueDepth) DbgPrint("IPRT: Neither _KPRCB::QuantumEnd nor _KPRCB::DpcQueueDepth was not found! Kernel %u.%u %u %s\n", OsVerInfo.uMajorVer, OsVerInfo.uMinorVer, OsVerInfo.uBuildNo, OsVerInfo.fChecked ? "checked" : "free"); # ifdef DEBUG else DbgPrint("IPRT: _KPRCB:{.QuantumEnd=%x/%d, .DpcQueueDepth=%x/%d} Kernel %u.%u %u %s\n", g_offrtNtPbQuantumEnd, g_cbrtNtPbQuantumEnd, g_offrtNtPbDpcQueueDepth, OsVerInfo.uMajorVer, OsVerInfo.uMinorVer, OsVerInfo.uBuildNo, OsVerInfo.fChecked ? "checked" : "free"); # endif #endif /* * Special IPI fun for RTMpPokeCpu. * * On Vista and later the DPC method doesn't seem to reliably send IPIs, * so we have to use alternative methods. The NtHalSendSoftwareInterrupt * is preferrable, but it's AMD64 only. The NalRequestIpip method changed * in Windows 7 with the lots-of-processors-support, but it's the only * targeted IPI game in town if we cannot use KeInsertQueueDpc. Worst case * we use broadcast IPIs. */ if ( OsVerInfo.uMajorVer > 6 || (OsVerInfo.uMajorVer == 6 && OsVerInfo.uMinorVer > 0)) g_pfnrtHalRequestIpiPreW7 = NULL; else g_pfnrtHalRequestIpiW7Plus = NULL; g_pfnrtMpPokeCpuWorker = rtMpPokeCpuUsingDpc; #ifndef IPRT_TARGET_NT4 if (g_pfnrtNtHalSendSoftwareInterrupt) g_pfnrtMpPokeCpuWorker = rtMpPokeCpuUsingHalSendSoftwareInterrupt; else if ( g_pfnrtHalRequestIpiW7Plus && g_pfnrtKeInitializeAffinityEx && g_pfnrtKeAddProcessorAffinityEx && g_pfnrtKeGetProcessorIndexFromNumber) g_pfnrtMpPokeCpuWorker = rtMpPokeCpuUsingHalReqestIpiW7Plus; else if (OsVerInfo.uMajorVer >= 6 && g_pfnrtKeIpiGenericCall) g_pfnrtMpPokeCpuWorker = rtMpPokeCpuUsingBroadcastIpi; /* else: Windows XP should send always send an IPI -> VERIFY */ #endif return VINF_SUCCESS; }
DLLEXPORT UINT_PTR WINAPI ReflectiveLoader( VOID ) #endif { // the functions we need LOADLIBRARYA pLoadLibraryA; GETPROCADDRESS pGetProcAddress; VIRTUALALLOC pVirtualAlloc; VIRTUALLOCK pVirtualLock; OUTPUTDEBUG pOutputDebug; USHORT usCounter; // the initial location of this image in memory UINT_PTR uiLibraryAddress; // the kernels base address and later this images newly loaded base address UINT_PTR uiBaseAddress; // variables for processing the kernels export table UINT_PTR uiAddressArray; UINT_PTR uiNameArray; UINT_PTR uiExportDir; UINT_PTR uiNameOrdinals; DWORD dwHashValue; // variables for loading this image UINT_PTR uiHeaderValue; UINT_PTR uiValueA; UINT_PTR uiValueB; UINT_PTR uiValueC; UINT_PTR uiValueD; UINT_PTR uiValueE; register UINT_PTR inspect; // STEP 0: calculate our images current base address // we will start searching backwards from our current EIP #ifdef _WIN64 uiLibraryAddress = eip(); #else __asm { call geteip geteip: pop uiLibraryAddress } #endif // loop through memory backwards searching for our images base address // we dont need SEH style search as we shouldnt generate any access violations with this while( TRUE ) { if( ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_magic == IMAGE_DOS_SIGNATURE ) { uiHeaderValue = ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew; // some x64 dll's can trigger a bogus signature (IMAGE_DOS_SIGNATURE == 'POP r10'), // we sanity check the e_lfanew with an upper threshold value of 1024 to avoid problems. if( uiHeaderValue >= sizeof(IMAGE_DOS_HEADER) && uiHeaderValue < 1024 ) { uiHeaderValue += uiLibraryAddress; // break if we have found a valid MZ/PE header if( ((PIMAGE_NT_HEADERS)uiHeaderValue)->Signature == IMAGE_NT_SIGNATURE ) break; } } uiLibraryAddress--; } // STEP 1: process the kernels exports for the functions our loader needs... // get the Process Enviroment Block #ifdef _WIN64 uiBaseAddress = __readgsqword( 0x60 ); #else uiBaseAddress = __readfsdword( 0x30 ); #endif // get the processes loaded modules. ref: http://msdn.microsoft.com/en-us/library/aa813708(VS.85).aspx uiBaseAddress = (UINT_PTR)((_PPEB)uiBaseAddress)->pLdr; // get the first entry of the InMemoryOrder module list uiValueA = (UINT_PTR)((PPEB_LDR_DATA)uiBaseAddress)->InMemoryOrderModuleList.Flink; while( uiValueA ) { // get pointer to current modules name (unicode string) uiValueB = (UINT_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.pBuffer; // set bCounter to the length for the loop usCounter = ((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.Length; // clear uiValueC which will store the hash of the module name uiValueC = 0; // compute the hash of the module name... do { uiValueC = ror( (DWORD)uiValueC ); // normalize to uppercase if the module name is in lowercase if( *((BYTE *)uiValueB) >= 'a' ) uiValueC += *((BYTE *)uiValueB) - 0x20; else uiValueC += *((BYTE *)uiValueB); uiValueB++; } while( --usCounter ); // compare the hash with that of kernel32.dll if( (DWORD)uiValueC == KERNEL32DLL_HASH ) { // get this modules base address uiBaseAddress = (UINT_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->DllBase; break; } // get the next entry uiValueA = DEREF( uiValueA ); } // get the VA of the modules NT Header uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew; // uiNameArray = the address of the modules export directory entry uiNameArray = (UINT_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ]; // get the VA of the export directory uiExportDir = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress ); // get the VA for the array of name pointers uiNameArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNames ); // get the VA for the array of name ordinals uiNameOrdinals = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNameOrdinals ); usCounter = 5; // loop while we still have imports to find while( usCounter > 0 ) { // compute the hash values for this function name dwHashValue = hash( (char *)( uiBaseAddress + DEREF_32( uiNameArray ) ) ); // if we have found a function we want we get its virtual address if( dwHashValue == LOADLIBRARYA_HASH || dwHashValue == GETPROCADDRESS_HASH || dwHashValue == VIRTUALALLOC_HASH || dwHashValue == VIRTUALLOCK_HASH || dwHashValue == OUTPUTDEBUG_HASH ) { // get the VA for the array of addresses uiAddressArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions ); // use this functions name ordinal as an index into the array of name pointers uiAddressArray += ( DEREF_16( uiNameOrdinals ) * sizeof(DWORD) ); // store this functions VA if( dwHashValue == LOADLIBRARYA_HASH ) pLoadLibraryA = (LOADLIBRARYA)( uiBaseAddress + DEREF_32( uiAddressArray ) ); else if( dwHashValue == GETPROCADDRESS_HASH ) pGetProcAddress = (GETPROCADDRESS)( uiBaseAddress + DEREF_32( uiAddressArray ) ); else if( dwHashValue == VIRTUALALLOC_HASH ) pVirtualAlloc = (VIRTUALALLOC)( uiBaseAddress + DEREF_32( uiAddressArray ) ); else if( dwHashValue == VIRTUALLOCK_HASH ) pVirtualLock = (VIRTUALLOCK)( uiBaseAddress + DEREF_32( uiAddressArray ) ); else if( dwHashValue == OUTPUTDEBUG_HASH ) pOutputDebug = (OUTPUTDEBUG)( uiBaseAddress + DEREF_32( uiAddressArray ) ); // decrement our counter usCounter--; } // get the next exported function name uiNameArray += sizeof(DWORD); // get the next exported function name ordinal uiNameOrdinals += sizeof(WORD); } // STEP 2: load our image into a new permanent location in memory... // get the VA of the NT Header for the PE to be loaded uiHeaderValue = uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew; // allocate all the memory for the DLL to be loaded into. we can load at any address because we will // relocate the image. Also zeros all memory and marks it as READ, WRITE and EXECUTE to avoid any problems. uiBaseAddress = (UINT_PTR)pVirtualAlloc( NULL, ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfImage, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE ); // prevent our image from being swapped to the pagefile pVirtualLock((LPVOID)uiBaseAddress, ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfImage); // we must now copy over the headers uiValueA = ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfHeaders; uiValueB = uiLibraryAddress; uiValueC = uiBaseAddress; __movsb( (PBYTE)uiValueC, (PBYTE)uiValueB, uiValueA ); // STEP 3: load in all of our sections... // uiValueA = the VA of the first section uiValueA = ( (UINT_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader + ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.SizeOfOptionalHeader ); uiValueE = ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.NumberOfSections; // iterate through all sections, loading them into memory. while( uiValueE-- ) { // uiValueB is the VA for this section uiValueB = ( uiBaseAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->VirtualAddress ); // uiValueC if the VA for this sections data uiValueC = ( uiLibraryAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->PointerToRawData ); // copy the section over uiValueD = ((PIMAGE_SECTION_HEADER)uiValueA)->SizeOfRawData; __movsb( (PBYTE)uiValueB, (PBYTE)uiValueC, uiValueD ); // get the VA of the next section uiValueA += sizeof( IMAGE_SECTION_HEADER ); } // STEP 4: process our images import table... // uiValueB = the address of the import directory uiValueB = (UINT_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_IMPORT ]; uiValueC = ( uiBaseAddress + (UINT_PTR)((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress ); // iterate through all imports until a null RVA is found (Characteristics is mis-named) while( ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Characteristics ) { /* pOutputDebug("Loading library: "); pOutputDebug((LPCSTR)( uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name )); pOutputDebug("\n"); */ // use LoadLibraryA to load the imported module into memory uiLibraryAddress = (UINT_PTR)pLoadLibraryA( (LPCSTR)( uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name ) ); if (! uiLibraryAddress) { //pOutputDebug("Loading library FAILED\n"); // get the next import uiValueC += sizeof( IMAGE_IMPORT_DESCRIPTOR ); continue; } // uiValueD = VA of the OriginalFirstThunk uiValueD = ( uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->OriginalFirstThunk ); // uiValueA = VA of the IAT (via first thunk not origionalfirstthunk) uiValueA = ( uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->FirstThunk ); // itterate through all imported functions, importing by ordinal if no name present while( DEREF(uiValueA) ) { // sanity check uiValueD as some compilers only import by FirstThunk if( uiValueD && ((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal & IMAGE_ORDINAL_FLAG ) { // get the VA of the modules NT Header uiExportDir = uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew; // uiNameArray = the address of the modules export directory entry uiNameArray = (UINT_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ]; // get the VA of the export directory uiExportDir = ( uiLibraryAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress ); // get the VA for the array of addresses uiAddressArray = ( uiLibraryAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions ); // use the import ordinal (- export ordinal base) as an index into the array of addresses uiAddressArray += ( ( IMAGE_ORDINAL( ((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal ) - ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->Base ) * sizeof(DWORD) ); // patch in the address for this imported function DEREF(uiValueA) = ( uiLibraryAddress + DEREF_32(uiAddressArray) ); } else { // get the VA of this functions import by name struct uiValueB = ( uiBaseAddress + DEREF(uiValueA) ); /* pOutputDebug("Resolving function: "); pOutputDebug((LPCSTR)( (LPCSTR)((PIMAGE_IMPORT_BY_NAME)uiValueB)->Name )); pOutputDebug("\n"); */ // use GetProcAddress and patch in the address for this imported function DEREF(uiValueA) = (UINT_PTR)pGetProcAddress( (HMODULE)uiLibraryAddress, (LPCSTR)((PIMAGE_IMPORT_BY_NAME)uiValueB)->Name ); } // get the next imported function uiValueA += sizeof( UINT_PTR ); if( uiValueD ) uiValueD += sizeof( UINT_PTR ); } // get the next import uiValueC += sizeof( IMAGE_IMPORT_DESCRIPTOR ); } // STEP 5: process all of our images relocations... // calculate the base address delta and perform relocations (even if we load at desired image base) uiLibraryAddress = uiBaseAddress - ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.ImageBase; // uiValueB = the address of the relocation directory uiValueB = (UINT_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_BASERELOC ]; // check if there are any relocations present if( ((PIMAGE_DATA_DIRECTORY)uiValueB)->Size ) { // uiValueC is now the first entry (IMAGE_BASE_RELOCATION) uiValueC = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress ); // and we iterate through all entries... while( ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock ) { // uiValueA = the VA for this relocation block uiValueA = ( uiBaseAddress + ((PIMAGE_BASE_RELOCATION)uiValueC)->VirtualAddress ); // uiValueB = number of entries in this relocation block uiValueB = ( ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION) ) / sizeof( IMAGE_RELOC ); // uiValueD is now the first entry in the current relocation block uiValueD = uiValueC + sizeof(IMAGE_BASE_RELOCATION); // we itterate through all the entries in the current block... while( uiValueB-- ) { // perform the relocation, skipping IMAGE_REL_BASED_ABSOLUTE as required. // we dont use a switch statement to avoid the compiler building a jump table // which would not be very position independent! if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_DIR64 ) *(UINT_PTR *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += uiLibraryAddress; else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGHLOW ) *(DWORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += (DWORD)uiLibraryAddress; else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGH ) *(WORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += HIWORD(uiLibraryAddress); else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_LOW ) *(WORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += LOWORD(uiLibraryAddress); // get the next entry in the current relocation block uiValueD += sizeof( IMAGE_RELOC ); } // get the next entry in the relocation directory uiValueC = uiValueC + ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock; } } // STEP 6: process the images exception directory if it has one (PE32+ for x64) /* // uiValueB = the address of the relocation directory uiValueB = (UINT_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXCEPTION ]; // check if their are any exception etries present if( ((PIMAGE_DATA_DIRECTORY)uiValueB)->Size ) { // get the number of entries uiValueA = ((PIMAGE_DATA_DIRECTORY)uiValueB)->Size / sizeof( IMAGE_RUNTIME_FUNCTION_ENTRY ); // uiValueC is now the first entry (IMAGE_RUNTIME_FUNCTION_ENTRY) uiValueC = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress ); // itterate through all entries while( uiValueA-- ) { //((IMAGE_RUNTIME_FUNCTION_ENTRY)uiValueC).BeginAddress // get the next entry uiValueC += sizeof( IMAGE_RUNTIME_FUNCTION_ENTRY ); } } */ // STEP 7: call our images entry point // uiValueA = the VA of our newly loaded DLL/EXE's entry point uiValueA = ( uiBaseAddress + ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.AddressOfEntryPoint ); // call our respective entry point, fudging our hInstance value #ifdef REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR // if we are injecting a DLL via LoadRemoteLibraryR we call DllMain and pass in our parameter (via the DllMain lpReserved parameter) ((DLLMAIN)uiValueA)( (HINSTANCE)uiBaseAddress, DLL_PROCESS_ATTACH, lpParameter ); #else // if we are injecting an DLL via a stub we call DllMain with no parameter ((DLLMAIN)uiValueA)( (HINSTANCE)uiBaseAddress, DLL_PROCESS_ATTACH, NULL ); #endif // STEP 8: return our new entry point address so whatever called us can call DLL_METASPLOIT_ATTACH/DLL_METASPLOIT_DETACH return uiValueA; }
QWORD MyPtiCurrent(void) { void *teb = (void *)__readgsqword(0x30); QWORD Win32ThreadInfo = (QWORD)*((PQWORD)((PBYTE)teb + 0x78)); return Win32ThreadInfo; }