#include #include #include //#pragma warning( push ) //#pragma warning( disable : 4668) #define WIN32_LEAN_AND_MEAN #include #include //#pragma warning( pop ) static void* faddrs[6]; char fnames[] = "DirectInput8Create\0" "DllCanUnloadNow\0" "DllGetClassObject\0" \ "DllRegisterServer\0" "DllUnregisterServer\0" "GetdfDIJoystick\0" "\3"; /*[[nodiscard]]*/ size_t next_name(char *names[]) { size_t len = 0; while(names != NULL) { if(**names == '\0') { (*names)++; break; } else if(**names == '\3') break; (*names)++; len++; } return len; } HMODULE init_faddrs(void) { HMODULE h = LoadLibrary("C:\\Windows\\SysWOW64\\dinput8.dll"); // perhaps i should ship my own original dinput8.dll and proxy from a renamed copy but uhhhh no if (h == NULL) goto init_end; char* fname = fnames; size_t i = 0; do { faddrs[i] = (void*)GetProcAddress(h, fname); i++; } while(next_name(&fname)); init_end: return h; } HMODULE hodll = NULL; /*void* sigscan(const char* pattern, const char* mask) { HMODULE module = GetModuleHandle(NULL); if(module == NULL) return NULL; MODULEINFO minfo; if(GetModuleInformation(GetCurrentProcess(), module, &minfo, sizeof(minfo)) == 0) return NULL; size_t len = strlen(mask); unsigned char* addr = (unsigned char*)minfo.lpBaseOfDll; for(DWORD i = 0; i < minfo.SizeOfImage - (len-1); i++) { for(size_t j = 0; j < len; j++) { if(addr[i + j] == (unsigned char)(pattern[j]) && (unsigned char)(mask[j]) != '?') { if(j == (len-1)) return (void*)(addr + i); } else break; } } return NULL; }*/ /* void* GetStackBaseFromTEB(void) { #if defined(_WIN64) return (void*)__readgsqword(0x08); #elif defined(_WIN32) return (void*)__readfsdword(0x04); #endif } */ void* GetEntryPointOfHostProcess(void) { HMODULE module = GetModuleHandle(NULL); if(module == NULL) return NULL; MODULEINFO minfo; if(GetModuleInformation(GetCurrentProcess(), module, &minfo, sizeof(minfo)) == 0) return NULL; return minfo.EntryPoint; } void* PD2_EBP = NULL; uint8_t writeback[5] = { 0 }; void* retaddr = NULL; #pragma pack(push, 4) typedef struct _Patch { uint8_t* writeback; uint8_t NOPs; // to keep alignment, unsure if actually needed but would be nice if the debugger suddenly didn't re-disassemble everything incorrectly after the patch void* addr; void (*func)(void); } Patch; #pragma pack(pop) void PatchCALL(Patch* patch, BOOL UnVProtect) { if(UnVProtect) { DWORD _; if(VirtualProtect(patch->addr, 5 + patch->NOPs, PAGE_EXECUTE_READWRITE, &_) == 0) { char err[64] = { '\0' }; snprintf(err, 64, "%lu", GetLastError()); MessageBox(GetCurrentProcess(), err, NULL, MB_OK); return; } } } void PatchGame(void* addr, void (*func)(void)) { DWORD _; if(VirtualProtect(addr, 5, PAGE_EXECUTE_READWRITE, &_) == 0) { char err[64] = { '\0' }; snprintf(err, 64, "%lu", GetLastError()); MessageBox(GetCurrentProcess(), err, NULL, MB_OK); return; } uint8_t oinst[5] = { 0 }; memcpy_s(oinst, sizeof(*oinst) * 5, addr, 5); uint8_t patched[5] = { 0xE9, 0x00, 0x00, 0x00, 0x00 }; ((int32_t*)(patched + 1))[0] = (uintptr_t)func - ((uintptr_t)addr + 1 + sizeof(uintptr_t)); // math assumes patching over a jmp or call, not that it really matters memcpy_s(addr, 5, patched, 5); memcpy_s(writeback, 5, oinst, 5); // magic global that hopefully works } void __declspec(naked) GetEBPWithinGame(void) { __asm { pushad } __asm { mov PD2_EBP, ebp } memcpy_s(retaddr, 5, writeback, 5); __asm { popad push retaddr ret } } BOOL WINAPI DllMain(/*[[maybe_unused]]*/ HINSTANCE h_dll, DWORD fwdReason, LPVOID lpvReserved) { switch(fwdReason) { case DLL_PROCESS_ATTACH: hodll = init_faddrs(); if(hodll == NULL) return FALSE; retaddr = GetEntryPointOfHostProcess(); PatchGame(retaddr, &GetEBPWithinGame); break; case DLL_THREAD_ATTACH: // [[fallthrough]]; case DLL_THREAD_DETACH: break; case DLL_PROCESS_DETACH: if(lpvReserved != NULL) break; if(hodll != NULL) FreeLibrary(hodll); break; } return TRUE; }