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; }
VOID NTAPI INIT_FUNCTION KiSystemStartupBootStack(VOID) { PKTHREAD Thread; /* Initialize the kernel for the current CPU */ KiInitializeKernel(&KiInitialProcess.Pcb, (PKTHREAD)KeLoaderBlock->Thread, (PVOID)(KeLoaderBlock->KernelStack & ~3), (PKPRCB)__readfsdword(KPCR_PRCB), KeNumberProcessors - 1, KeLoaderBlock); /* Set the priority of this thread to 0 */ Thread = KeGetCurrentThread(); Thread->Priority = 0; /* Force interrupts enabled and lower IRQL back to DISPATCH_LEVEL */ _enable(); KfLowerIrql(DISPATCH_LEVEL); /* Set the right wait IRQL */ Thread->WaitIrql = DISPATCH_LEVEL; /* Jump into the idle loop */ KiIdleLoop(); }
void mono_threads_platform_get_stack_bounds (guint8 **staddr, size_t *stsize) { MEMORY_BASIC_INFORMATION meminfo; #ifdef _WIN64 /* win7 apis */ NT_TIB* tib = (NT_TIB*)NtCurrentTeb(); guint8 *stackTop = (guint8*)tib->StackBase; guint8 *stackBottom = (guint8*)tib->StackLimit; #else /* http://en.wikipedia.org/wiki/Win32_Thread_Information_Block */ void* tib = (void*)__readfsdword(0x18); guint8 *stackTop = (guint8*)*(int*)((char*)tib + 4); guint8 *stackBottom = (guint8*)*(int*)((char*)tib + 8); #endif /* Windows stacks are expanded on demand, one page at time. The TIB reports only the currently allocated amount. VirtualQuery will return the actual limit for the bottom, which is what we want. */ if (VirtualQuery (&meminfo, &meminfo, sizeof (meminfo)) == sizeof (meminfo)) stackBottom = MIN (stackBottom, (guint8*)meminfo.AllocationBase); *staddr = stackBottom; *stsize = stackTop - stackBottom; }
LPVOID WINAPI VirtualAllocRopProtect(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect) { NT_TIB * ThreadInfo; HANDLE hCurrentThread; CONTEXT * cThreadContext = (CONTEXT *)LocalAlloc(LMEM_ZEROINIT, sizeof(CONTEXT)); hCurrentThread = GetCurrentThread(); cThreadContext->ContextFlags = CONTEXT_CONTROL; // get the thread stack range from TIB. ThreadInfo = (NT_TIB *) __readfsdword( 0x18 ); if ( GetThreadContext( hCurrentThread, cThreadContext ) ) { // check if thread is passing the acual stack boundaries. if ( cThreadContext->Esp < (DWORD)ThreadInfo->StackLimit || cThreadContext->Esp >= (DWORD)ThreadInfo->StackBase ) { // at this point everything is definitely messed up, so no matter what we do with stack. __asm { mov esp, fs:[0x8] add esp,400h } // rise the bar :D RaiseException( STATUS_STACK_BUFFER_OVERRUN, EXCEPTION_NONCONTINUABLE, 0, NULL); } }
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; }
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; }
PUINT32 GetHeapFlags_x86() { PUINT32 pProcessHeap, pHeapFlags = NULL; if (IsWindowsVistaOrGreater()){ pProcessHeap = (PUINT32)(__readfsdword(0x30) + 0x18); pHeapFlags = (PUINT32)(*pProcessHeap + 0x40); } else { pProcessHeap = (PUINT32)(__readfsdword(0x30) + 0x18); pHeapFlags = (PUINT32)(*pProcessHeap + 0x0C); } return pHeapFlags; }
ResultType Clipboard::Open() { if (mIsOpen) return OK; #ifdef _WIN64 DWORD aThreadID = __readgsdword(0x48); // Used to identify if code is called from different thread (AutoHotkey.dll) #else DWORD aThreadID = __readfsdword(0x24); #endif for (DWORD start_time = GetTickCount();;) { if (OpenClipboard(g_hWnd)) { mIsOpen = true; return OK; } if (g_ClipboardTimeout != -1) // We were not told to wait indefinitely... if (!g_ClipboardTimeout // ...and we were told to make only one attempt, or ... || (int)(g_ClipboardTimeout - (GetTickCount() - start_time)) <= SLEEP_INTERVAL_HALF) //...it timed out. // Above must cast to int or any negative result will be lost due to DWORD type. return FAIL; // Use SLEEP_WITHOUT_INTERRUPTION to prevent MainWindowProc() from accepting new hotkeys // during our operation, since a new hotkey subroutine might interfere with // what we're doing here (e.g. if it tries to use the clipboard, or perhaps overwrites // the deref buffer if this object's caller gave it any pointers into that memory area): SLEEP_WITHOUT_INTERRUPTION(INTERVAL_UNSPECIFIED) } }
gpointer gum_tls_key_get_value (GumTlsKey key) { if (key < 64) { return (gpointer)__readfsdword (3600 + key * sizeof (gpointer)); } else if (key < 1088) { gpointer * tls_expansion_slots = (gpointer *) __readfsdword (3988); if (tls_expansion_slots != NULL) return tls_expansion_slots[key - 64]; return _gum_tls_key_get_tmp_value (key); } return NULL; }
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; }
PPEB GetPeb(VOID) { PPEB Peb = 0; #ifdef _WIN64 Peb = (PPEB)__readgsqword(0x60); #else Peb = (PPEB)__readfsdword(0x30); #endif return Peb; }
int main(int argc, char *argv[]) { HANDLE hEvent = CreateEvent(nullptr, FALSE, FALSE, L"Useless event"); HANDLE hThread1 = CreateThread(nullptr, 0, &ThreadEntry, hEvent, 0, nullptr); HANDLE hThread2 = CreateThread(nullptr, 0, &ThreadEntry, hEvent, 0, nullptr); HANDLE hThread3 = CreateThread(nullptr, 0, &ThreadEntry, hEvent, 0, nullptr); CONTEXT ctxThread1 = { CONTEXT_ALL }; (void)GetThreadContext(hThread1, &ctxThread1); CONTEXT ctxThread2 = { CONTEXT_ALL }; (void)GetThreadContext(hThread2, &ctxThread2); CONTEXT ctxThread3 = { CONTEXT_ALL }; (void)GetThreadContext(hThread3, &ctxThread3); LDT_ENTRY ldtThread1 = { 0 }; LDT_ENTRY ldtThread2 = { 0 }; LDT_ENTRY ldtThread3 = { 0 }; (void)GetThreadSelectorEntry(hThread1, ctxThread1.SegFs, &ldtThread1); (void)GetThreadSelectorEntry(hThread2, ctxThread2.SegFs, &ldtThread2); (void)GetThreadSelectorEntry(hThread3, ctxThread3.SegFs, &ldtThread3); NT_TIB *pTibMain = (NT_TIB *)__readfsdword(0x18); DWORD_PTR dwFSBase1 = (ldtThread1.HighWord.Bits.BaseHi << 24) | (ldtThread1.HighWord.Bits.BaseMid << 16) | ldtThread1.BaseLow; DWORD_PTR dwFSBase2 = (ldtThread2.HighWord.Bits.BaseHi << 24) | (ldtThread2.HighWord.Bits.BaseMid << 16) | ldtThread2.BaseLow; DWORD_PTR dwFSBase3 = (ldtThread3.HighWord.Bits.BaseHi << 24) | (ldtThread3.HighWord.Bits.BaseMid << 16) | ldtThread3.BaseLow; fprintf(stderr, "Thread 1 FS Segment base address: %X\n" "Thread 2 FS Segment base address : %X\n" "Thread 3 FS Segment base address : %X\n", dwFSBase1, dwFSBase2, dwFSBase3); DWORD_PTR dwWOW64Address1 = *(DWORD_PTR *)((unsigned char *)dwFSBase1 + 0xC0); DWORD_PTR dwWOW64Address2 = *(DWORD_PTR *)((unsigned char *)dwFSBase2 + 0xC0); DWORD_PTR dwWOW64Address3 = *(DWORD_PTR *)((unsigned char *)dwFSBase3 + 0xC0); fprintf(stderr, "Thread 1 FS:[0xC0] : %X\n" "Thread 2 FS:[0xC0] : %X\n" "Thread 3 FS:[0xC0] : %X\n", dwWOW64Address1, dwWOW64Address2, dwWOW64Address3); return 0; }
__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 }
size_t slp_cstack_save(PyCStackObject *cstprev) { size_t stsizeb = (cstprev)->ob_size * sizeof(intptr_t); memcpy((cstprev)->stack, (cstprev)->startaddr - (cstprev)->ob_size, stsizeb); #ifdef _SEH32 //save the SEH handler cstprev->exception_list = (DWORD) __readfsdword(FIELD_OFFSET(NT_TIB, ExceptionList)); #endif return stsizeb; }
int main(int argc, char *argv[]) { // Initialize PIN library. Print help message if -h(elp) is specified // in the command line or the command line is invalid if(PIN_Init(argc,argv)) return Usage(); /// Instrumentations // Register function to be called to instrument traces TRACE_AddInstrumentFunction(trace_instrumentation, 0); // Register function to be called when the application exits PIN_AddFiniFunction(this_is_the_end, 0); // Register function to be called when a module is loaded IMG_AddInstrumentFunction(image_instrumentation, 0); /// Other stuffs // This routine will be called if the sleeping_thread calls PIN_Detach() (when the time is out) PIN_AddDetachFunction(pin_is_detached, 0); // Run a thread that will wait for the time out PIN_SpawnInternalThread( sleeping_thread, 0, 0, NULL ); // If we are in a wow64 process we must blacklist manually the JMP FAR: stub // from being instrumented (each time a syscall is called, it will be instrumented for *nothing*) // Its address is in FS:[0xC0] on Windows 7 ADDRINT wow64stub = __readfsdword(0xC0); modules_blacklisted.insert( std::make_pair( std::string("wow64stub"), std::make_pair( wow64stub, wow64stub ) ) ); /// FIRE IN THE HOLE // Start the program, never returns PIN_StartProgram(); return 0; }
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 MemUReadCachelines ( IN UINT8 Buffer[], IN UINT32 Address, IN UINT16 ClCount ) { UINTN Index; UINT32 *Dest; for (Index = 0; Index < ClCount * 16; Index++) { Dest = (void *) &Buffer [Index * 4]; *Dest = __readfsdword (Address + Index * 4); _mm_mfence (); } }
// The million dollar question here is: is NT_TIB.StackBase required // to be aligned? UINT WINAPI Dirtbox::ShimCallback(PVOID ShimContextPtr) { SHIM_CONTEXT ShimContext = *(PSHIM_CONTEXT)ShimContextPtr; free(ShimContextPtr); PNT_TIB OldNtTib = (PNT_TIB)__readfsdword(NT_TIB_SELF); PBYTE Tls; ETHREAD Ethread; KPCR Kpcr; Tls = (PBYTE)_alloca(ShimContext.TlsDataSize); memset(&Ethread, 0, sizeof(ETHREAD)); memset(&Kpcr, 0, sizeof(KPCR)); // Initialize Ethread structure Ethread.Tcb.TlsData = Tls; Ethread.UniqueThread = (PVOID)GetCurrentThreadId(); // Initialize subsystem independent part Kpcr.NtTib.ExceptionList = OldNtTib->ExceptionList; // Xbox XAPI assumes that the thread-local storage is located // at the stack base. (see beginning of function) Kpcr.NtTib.StackBase = &Tls[ShimContext.TlsDataSize]; Kpcr.NtTib.StackLimit = OldNtTib->StackLimit; Kpcr.NtTib.ArbitraryUserPointer = (PVOID)GetFS(); Kpcr.NtTib.Self = &Kpcr.NtTib; // Initialize Xbox subsystem part Kpcr.SelfPcr = &Kpcr; Kpcr.Prcb = &Kpcr.PrcbData; Kpcr.Irql = 0; Kpcr.Prcb->CurrentThread = (PKTHREAD)&Ethread; // Allocate LDT entry for new TIB and store selector in old TIB AllocateLdtEntry( (PWORD)&OldNtTib->ArbitraryUserPointer, (DWORD)&Kpcr, sizeof(KPCR) ); SwapTibs(); ShimContext.SystemRoutine(ShimContext.StartRoutine, ShimContext.StartContext); FatalPrint("ShimCallback: Should never get here."); return 0; }
VOID WINAPI GetStartupInfoAHook(LPSTARTUPINFOA startupInfo) { // put back the original and call it memcpy(GetStartupInfoA, g_gsiOrig, 5); GetStartupInfoA(startupInfo); // analyze the return address for a recommended course of action (GameShield is using a Borland-style compiler, so the only VC CRT here will be Payne) char* charData = (char*)_ReturnAddress(); if (!memcmp(charData, "\x6A\xFE\x5F\x89\x7D\xFC\xB8\x4D", 8)) { PEXCEPTION_REGISTRATION_RECORD sehPtr = (PEXCEPTION_REGISTRATION_RECORD)__readfsdword(0); // and we don't want crt init to use its own exception handler either __writefsdword(0, (DWORD)sehPtr->Next->Next); // we also need to unVP the read-only data segments DWORD oldProtect; VirtualProtect(GetModuleHandle(nullptr), 0x119e000, PAGE_EXECUTE_READWRITE, &oldProtect); // this is here *temporarily* hook::jump(hook::pattern("81 EC 44 02 00 00 55 56 33 F6 33 C0").count(1).get(0).get<void>(), ThisIsActuallyLaunchery); // mhm memcpy(GetModuleFileNameA, g_gmfOrig, 5); memcpy(GetModuleFileNameW, g_gmfOrigW, 5); if (!g_launcher->PostLoadGame(GetModuleHandle(nullptr), nullptr)) { ExitProcess(0); } // so it can pop itself //__writefsdword(0, (DWORD)sehPtr); } else { // hook us back in for the next pass hook::jump((uintptr_t)GetStartupInfoA, GetStartupInfoAHook); } }
void gum_tls_key_set_value (GumTlsKey key, gpointer value) { if (key < 64) { __writefsdword (3600 + key * sizeof (gpointer), (DWORD) value); } else if (key < 1088) { gpointer * tls_expansion_slots = (gpointer *) __readfsdword (3988); 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); } } }
void hide_module_from_peb(HMODULE module_handle) { LDR_MODULE *mod; PEB *peb = (PEB *) __readfsdword(0x30); for (mod = (LDR_MODULE *) peb->LoaderData->InLoadOrderModuleList.Flink; mod->BaseAddress != NULL; mod = (LDR_MODULE *) mod->InLoadOrderModuleList.Flink) { if(mod->BaseAddress == module_handle) { CUT_LIST(mod->InLoadOrderModuleList); CUT_LIST(mod->InInitializationOrderModuleList); CUT_LIST(mod->InMemoryOrderModuleList); // TODO test whether this list is really used as a linked list // like InLoadOrderModuleList etc CUT_LIST(mod->HashTableEntry); memset(mod, 0, sizeof(LDR_MODULE)); break; } } }
PyCStackObject * slp_cstack_new(PyCStackObject **cst, intptr_t *stackref, PyTaskletObject *task) { PyThreadState *ts = PyThreadState_GET(); intptr_t *stackbase = ts->st.cstack_base; ptrdiff_t size = stackbase - stackref; assert(size >= 0); if (*cst != NULL) { if ((*cst)->task == task) (*cst)->task = NULL; Py_DECREF(*cst); } if (size < CSTACK_SLOTS && ((*cst) = cstack_cache[size])) { /* take stack from cache */ cstack_cache[size] = (PyCStackObject *) (*cst)->startaddr; --cstack_cachecount; _Py_NewReference((PyObject *)(*cst)); } else *cst = PyObject_NewVar(PyCStackObject, &PyCStack_Type, size); if (*cst == NULL) return NULL; (*cst)->startaddr = stackbase; (*cst)->next = (*cst)->prev = NULL; SLP_CHAIN_INSERT(PyCStackObject, &slp_cstack_chain, *cst, next, prev); (*cst)->serial = ts->st.serial; (*cst)->task = task; (*cst)->tstate = ts; (*cst)->nesting_level = ts->st.nesting_level; #ifdef _SEH32 //save the SEH handler (*cst)->exception_list = (DWORD) __readfsdword(FIELD_OFFSET(NT_TIB, ExceptionList)); #endif return *cst; }
/**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); } }
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); }
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)))); }
HANDLE Clipboard::GetClipboardDataTimeout(UINT uFormat, BOOL *aNullIsOkay) // Update for v1.1.16: The comments below are obsolete; search for "v1.1.16" for related comments. // Same as GetClipboardData() except that it doesn't give up if the first call to GetClipboardData() fails. // Instead, it continues to retry the operation for the number of milliseconds in g_ClipboardTimeout. // This is necessary because GetClipboardData() has been observed to fail in repeatable situations (this // is strange because our thread already has the clipboard locked open -- presumably it happens because the // GetClipboardData() is unable to start a data stream from the application that actually serves up the data). // If cases where the first call to GetClipboardData() fails, a subsequent call will often succeed if you give // the owning application (such as Excel and Word) a little time to catch up. This is especially necessary in // the OnClipboardChange label, where sometimes a clipboard-change notification comes in before the owning // app has finished preparing its data for subsequent readers of the clipboard. { #ifdef DEBUG_BY_LOGGING_CLIPBOARD_FORMATS // Provides a convenient log of clipboard formats for analysis. static FILE *fp = fopen("c:\\debug_clipboard_formats.txt", "w"); #endif if (aNullIsOkay) *aNullIsOkay = FALSE; // Set default. TCHAR format_name[MAX_PATH + 1]; // MSDN's RegisterClipboardFormat() doesn't document any max length, but the ones we're interested in certainly don't exceed MAX_PATH. if (uFormat < 0xC000 || uFormat > 0xFFFF) // It's a registered format (you're supposed to verify in-range before calling GetClipboardFormatName()). Also helps performance. *format_name = '\0'; // Don't need the name if it's a standard/CF_* format. else { // v1.0.42.04: // Probably need to call GetClipboardFormatName() rather than comparing directly to uFormat because // MSDN implies that OwnerLink and other registered formats might not always have the same ID under // all OSes (past and future). GetClipboardFormatName(uFormat, format_name, MAX_PATH); // Since RegisterClipboardFormat() is case insensitive, the case might vary. So use stricmp() when // comparing format_name to anything. // "Link Source", "Link Source Descriptor" , and anything else starting with "Link Source" is likely // to be data that should not be attempted to be retrieved because: // 1) It causes unwanted bookmark effects in various versions of MS Word. // 2) Tests show that these formats are on the clipboard only if MS Word is open at the time // ClipboardAll is accessed. That implies they're transitory formats that aren't as essential // or well suited to ClipboardAll as the other formats (but if it weren't for #1 above, this // wouldn't be enough reason to omit it). // 3) Although there is hardly any documentation to be found at MSDN or elsewhere about these formats, // it seems they're related to OLE, with further implications that the data is transitory. // Here are the formats that Word 2002 removes from the clipboard when it the app closes: // 0xC002 ObjectLink >>> Causes WORD bookmarking problem. // 0xC003 OwnerLink // 0xC00D Link Source >>> Causes WORD bookmarking problem. // 0xC00F Link Source Descriptor >>> Doesn't directly cause bookmarking, but probably goes with above. // 0xC0DC Hyperlink if ( !_tcsnicmp(format_name, _T("Link Source"), 11) || !_tcsicmp(format_name, _T("ObjectLink")) || !_tcsicmp(format_name, _T("OwnerLink")) // v1.0.44.07: The following were added to solve interference with MS Outlook's MS Word editor. // If a hotkey like ^F1::ClipboardSave:=ClipboardAll is pressed after pressing Ctrl-C in that // editor (perhaps only when copying HTML), two of the following error dialogs would otherwise // be displayed (this occurs in Outlook 2002 and probably later versions): // "An outgoing call cannot be made since the application is dispatching an input-synchronous call." || !_tcsicmp(format_name, _T("Native")) || !_tcsicmp(format_name, _T("Embed Source")) ) return NULL; if (!_tcsicmp(format_name, _T("MSDEVColumnSelect")) || !_tcsicmp(format_name, _T("MSDEVLineSelect"))) { // v1.1.16: These formats are used by Visual Studio, Scintilla controls and perhaps others for // copying whole lines and rectangular blocks. Because their very presence/absence is used as // a boolean indicator, the data is irrelevant. Presumably for this reason, Scintilla controls // set NULL data, though doing so and then not handling WM_RENDERFORMAT is probably invalid. // Note newer versions of Visual Studio use "VisualStudioEditorOperationsLineCutCopyClipboardTag" // for line copy, but that doesn't need to be handled here because it has non-NULL data (and the // latest unreleased Scintilla [as at 2014-08-19] uses both, so we can discard the long one). // Since we just want to preserve this format's presence, indicate to caller that NULL is okay: if (aNullIsOkay) // i.e. caller passed a variable for us to set. *aNullIsOkay = TRUE; return NULL; } } #ifdef DEBUG_BY_LOGGING_CLIPBOARD_FORMATS _ftprintf(fp, _T("%04X\t%s\n"), uFormat, format_name); // Since fclose() is never called, the program has to exit to close/release the file. #endif #ifndef ENABLE_CLIPBOARDGETDATA_TIMEOUT // v1.1.16: The timeout and retry behaviour of this function is currently disabled, since it does more // harm than good. It previously did NO GOOD WHATSOEVER, because SLEEP_WITHOUT_INTERRUPTION indirectly // calls g_clip.Close() via CLOSE_CLIPBOARD_IF_OPEN, so any subsequent attempts to retrieve data by us // or our caller always fail. The main point of failure where retrying helps is OpenClipboard(), when // another program has the clipboard open -- and that's handled elsewhere. If the timeout is re-enabled // for this function, the following format will need to be excluded to prevent unnecessary delays: // - FileContents (CSTR_FILECONTENTS): MSDN says it is used "to transfer data as if it were a file, // regardless of how it is actually stored". For example, it could be a file inside a zip folder. // However, on Windows 8 it seems to also be present for normal files. It might be possible to // retrieve its data via OleGetClipboard(), though it could be very large. // Just return the data, even if NULL: return GetClipboardData(uFormat); #else HANDLE h; #ifdef _WIN64 DWORD aThreadID = __readgsdword(0x48); // Used to identify if code is called from different thread (AutoHotkey.dll) #else DWORD aThreadID = __readfsdword(0x24); #endif for (DWORD start_time = GetTickCount();;) { // Known failure conditions: // GetClipboardData() apparently fails when the text on the clipboard is greater than a certain size // (Even though GetLastError() reports "Operation completed successfully"). The data size at which // this occurs is somewhere between 20 to 96 MB (perhaps depending on system's memory and CPU speed). if (h = GetClipboardData(uFormat)) // Assign return h; // It failed, so act according to the type of format and the timeout that's in effect. // Certain standard (numerically constant) clipboard formats are known to validly yield NULL from a // call to GetClipboardData(). Never retry these because it would only cause unnecessary delays // (i.e. a failure until timeout). // v1.0.42.04: More importantly, retrying them appears to cause problems with saving a Word/Excel // clipboard via ClipboardAll. if (uFormat == CF_HDROP // This format can fail "normally" for the reasons described at "clipboard_contains_files". || !_tcsicmp(format_name, _T("OwnerLink"))) // Known to validly yield NULL from a call to GetClipboardData(), so don't retry it to avoid having to wait the full timeout period. return NULL; if (g_ClipboardTimeout != -1) // We were not told to wait indefinitely and... if (!g_ClipboardTimeout // ...we were told to make only one attempt, or ... || (int)(g_ClipboardTimeout - (GetTickCount() - start_time)) <= SLEEP_INTERVAL_HALF) //...it timed out. // Above must cast to int or any negative result will be lost due to DWORD type. return NULL; // Use SLEEP_WITHOUT_INTERRUPTION to prevent MainWindowProc() from accepting new hotkeys // during our operation, since a new hotkey subroutine might interfere with // what we're doing here (e.g. if it tries to use the clipboard, or perhaps overwrites // the deref buffer if this object's caller gave it any pointers into that memory area): SLEEP_WITHOUT_INTERRUPTION(INTERVAL_UNSPECIFIED) } #endif }
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; }
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject,PUNICODE_STRING pRegistryPath) { PDEVICE_OBJECT DeviceObject; PEPROCESS Process; PETHREAD Thread; PKAPC_STATE ApcState; PVOID KdVersionBlock,NtdllBase; PULONG ptr,Functions,Names; PUSHORT Ordinals; PLDR_DATA_TABLE_ENTRY MmLoadedUserImageList,ModuleEntry; ULONG i; PIMAGE_DOS_HEADER pIDH; PIMAGE_NT_HEADERS pINH; PIMAGE_EXPORT_DIRECTORY pIED; pDriverObject->DriverUnload=Unload; KdVersionBlock=(PVOID)__readfsdword(0x34); // Get the KdVersionBlock MmLoadedUserImageList=*(PLDR_DATA_TABLE_ENTRY*)((PUCHAR)KdVersionBlock+0x228); // Get the MmLoadUserImageList DbgPrint("KdVersionBlock address: %#x",KdVersionBlock); DbgPrint("MmLoadedUserImageList address: %#x",MmLoadedUserImageList); ModuleEntry=(PLDR_DATA_TABLE_ENTRY)MmLoadedUserImageList->InLoadOrderLinks.Flink; // Move to first entry NtdllBase=ModuleEntry->DllBase; // ntdll is always located in first entry DbgPrint("ntdll base address: %#x",NtdllBase); pIDH=(PIMAGE_DOS_HEADER)NtdllBase; pINH=(PIMAGE_NT_HEADERS)((PUCHAR)NtdllBase+pIDH->e_lfanew); pIED=(PIMAGE_EXPORT_DIRECTORY)((PUCHAR)NtdllBase+pINH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); Functions=(PULONG)((PUCHAR)NtdllBase+pIED->AddressOfFunctions); Names=(PULONG)((PUCHAR)NtdllBase+pIED->AddressOfNames); Ordinals=(PUSHORT)((PUCHAR)NtdllBase+pIED->AddressOfNameOrdinals); // Parse the export table to locate LdrLoadDll for(i=0;i<pIED->NumberOfNames;i++) { if(!strcmp((char*)NtdllBase+Names[i],"LdrLoadDll")) { LdrLoadDll=(PLDR_LOAD_DLL)((PUCHAR)NtdllBase+Functions[Ordinals[i]]); break; } } DbgPrint("LdrLoadDll address: %#x",LdrLoadDll); Process=PsGetCurrentProcess(); Thread=PsGetCurrentThread(); ptr=(PULONG)Thread; // Locate the ApcState structure for(i=0;i<512;i++) { if(ptr[i]==(ULONG)Process) { ApcState=CONTAINING_RECORD(&ptr[i],KAPC_STATE,Process); // Get the actual address of KAPC_STATE ApcStateOffset=(ULONG)ApcState-(ULONG)Thread; // Calculate the offset of the ApcState structure break; } } DbgPrint("ApcState offset: %#x",ApcStateOffset); IoCreateDevice(pDriverObject,0,&DeviceName,FILE_DEVICE_UNKNOWN,FILE_DEVICE_SECURE_OPEN,FALSE,&DeviceObject); IoCreateSymbolicLink(&SymbolicLink,&DeviceName); for(i=0;i<IRP_MJ_MAXIMUM_FUNCTION;i++) { pDriverObject->MajorFunction[i]=DriverDispatch; } DeviceObject->Flags&=~DO_DEVICE_INITIALIZING; DeviceObject->Flags|=DO_DIRECT_IO; DbgPrint("DLL injection driver loaded."); return STATUS_SUCCESS; }