FARPROC GetRemoteProcAddress(unsigned long pId, char *module, char *func) { HMODULE remoteMod = GetRemoteModuleHandle(pId, module); HMODULE localMod = GetModuleHandle(module); // Account for potential differences in base address // of modules in different processes. unsigned long delta = MakeDelta(unsigned long, remoteMod, localMod); return MakePtr(FARPROC, GetProcAddress(localMod, func), delta); }
LPTHREAD_START_ROUTINE inject_change_start_func( HANDLE hProcess, LPTHREAD_START_ROUTINE lpStartAddress, FARPROC rep_func, const char *new_dll, const char *new_func ) { LPTHREAD_START_ROUTINE ret = NULL; if((FARPROC)lpStartAddress == rep_func) { HMODULE hMod = GetRemoteModuleHandle(hProcess, new_dll); ret = (LPTHREAD_START_ROUTINE)GetRemoteProcAddress(hProcess, hMod, new_func); } return ret ? ret : lpStartAddress; }
int WaitUntilEntryPoint(HANDLE hProcess, HANDLE hThread, const char *module) { // Try to get the entry point by various means, sorted by both efficiency // and probability of them working. void *entry_addr = NULL; /** * Method 1: Initial value of EAX * After creating a process in suspended state, EAX is guaranteed to contain * the correct address of the entry point, even when the executable has the * DYNAMICBASE flag activated in its header. * * (Works on Windows, but not on Wine) */ if(!(entry_addr = entry_from_context(hThread))) { HMODULE module_base; /** * Method 2: EnumProcessModules, then parse the PE header. * * (Works on Wine, but not on Windows immediately after the target process * was created in suspended state.) */ if(!(module_base = GetRemoteModuleHandle(hProcess, module))) { /** * Method 3: Guessing 0x400000 * This is the default value in many compilers and should thus work for * most non-ASLR Windows applications. */ module_base = (HMODULE)0x400000; } entry_addr = GetRemoteModuleEntryPoint(hProcess, module_base); } if(entry_addr) { return ThreadWaitUntil(hProcess, hThread, entry_addr); } else { log_mboxf(NULL, MB_OK | MB_ICONEXCLAMATION, "Couldn't determine the entry point of %s!\n" "\n" "Seems as if %s won't work with this game on your system.\n", PathFindFileNameA(module), PROJECT_NAME_SHORT() ); return 1; } }
// Given a process ID, file pointer, NT header, and start of .idata, fix the imports bool FixImports(unsigned long pId, void *base, IMAGE_NT_HEADERS *ntHd, IMAGE_IMPORT_DESCRIPTOR *impDesc) { char *module; // Loop through all the required modules while((module = (char *)GetPtrFromRVA((DWORD)(impDesc->Name), ntHd, (PBYTE)base))) { // If the library is already loaded(like kernel32.dll or ntdll.dll) LoadLibrary will // just return the handle to that module. // A neat alternative would be to load them all again. This will help ensure // we have a working copy for our own function calls which is hidden :O HMODULE localMod = LoadLibraryA(module); // If the module isn't loaded in the remote process, we recursively call the // module mapping code. This has the added benefit of ensuring that any of // the current modules dependencies will be just as invisible as this one. if(!GetRemoteModuleHandle(pId, module)) MapRemoteModule(pId, module); // fix the time/date stamp impDesc->TimeDateStamp = ntHd->FileHeader.TimeDateStamp; // Lookup the first import thunk for this module // NOTE: It is possible this module could forward functions...which is something // that I really should handle. Maybe I'll add support for forward functions // a little bit later. IMAGE_THUNK_DATA *itd = (IMAGE_THUNK_DATA *)GetPtrFromRVA((DWORD)(impDesc->FirstThunk), ntHd, (PBYTE)base); while(itd->u1.AddressOfData) { IMAGE_IMPORT_BY_NAME *iibn; iibn = (IMAGE_IMPORT_BY_NAME *)GetPtrFromRVA((DWORD)(itd->u1.AddressOfData), ntHd, (PBYTE)base); itd->u1.Function = MakePtr(DWORD, GetRemoteProcAddress(pId, module, (char *)iibn->Name), 0); ++itd; } ++impDesc; } return true; }
FARPROC GetRemoteProcAddress(const char *module, const char *func, short nPID) { HMODULE remoteMod = GetRemoteModuleHandle(module, nPID); HMODULE localMod = GetModuleHandle(module); // If the module isn't already loaded, we load it, but since many of the // modules we'll probably be loading will do nasty things like modify // memory and hook functions, we use the DONT_RESOLVE_DLL_REFERENCES flag, // so that LoadLibraryEx only loads the dll, but doesn't execute it. if(!localMod) localMod = LoadLibraryEx(module, NULL, DONT_RESOLVE_DLL_REFERENCES); // Account for potential differences in base address // of modules in different processes. int delta = MakeDelta(int, remoteMod, localMod); FARPROC LocalFunctionAddress = GetProcAddress(localMod, func); return MakePtr(FARPROC, LocalFunctionAddress, delta); }
FARPROC GetRemoteProcAddress( HANDLE hProcess, char *szModuleName, char *szProcName ) { HMODULE hLocalModule = GetModuleHandleA( szModuleName ); if( hLocalModule == false ) return (FARPROC)0; FARPROC fpLocal = GetProcAddress( hLocalModule, szProcName ); if( fpLocal == (FARPROC)0 ) return (FARPROC)0; DWORD dwOffset = (DWORD)fpLocal - (DWORD)hLocalModule; HMODULE hRemoteModuleHandle = GetRemoteModuleHandle( szModuleName, hProcess, false ); if( hRemoteModuleHandle == (HMODULE)0 ) return (FARPROC)0; return (FARPROC)((DWORD)hRemoteModuleHandle + dwOffset); }