From 7af6395a130685954cd9903bc02084640ae05e27 Mon Sep 17 00:00:00 2001 From: rebeccadoth Date: Tue, 10 Nov 2026 19:17:23 +0100 Subject: initial commit --- .gitignore | 4 ++ CMakeLists.txt | 11 ++++ build.ps1 | 11 ++++ dllproxy.c | 180 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ exports.def | 9 +++ proxy.S | 24 ++++++++ 6 files changed, 239 insertions(+) create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 build.ps1 create mode 100644 dllproxy.c create mode 100644 exports.def create mode 100644 proxy.S diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ed4a5dc --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +build/ +asdbuild/ +*.lnk +Makefile \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..7fe6bf7 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 3.10) +project(pd2-bw LANGUAGES C ASM_NASM) + +set(CMAKE_C_STANDARD "11") + +set(CMAKE_C_FLAGS "/Wall") + +set_source_files_properties(proxy.S PROPERTIES LANGUAGE ASM_NASM) + +add_library(DINPUT8 SHARED proxy.S dllproxy.c exports.def) +#add_executable(test dllproxy.c proxy.S) diff --git a/build.ps1 b/build.ps1 new file mode 100644 index 0000000..1b107ff --- /dev/null +++ b/build.ps1 @@ -0,0 +1,11 @@ +if (Test-Path -Path "build\") { + cd build + cmake --build . + cd .. +} else { + mkdir build + cd build + cmake -G "Visual Studio 17 2022" -A Win32 .. + cd .. + .\build.ps1 +} \ No newline at end of file diff --git a/dllproxy.c b/dllproxy.c new file mode 100644 index 0000000..808c168 --- /dev/null +++ b/dllproxy.c @@ -0,0 +1,180 @@ +#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; +} diff --git a/exports.def b/exports.def new file mode 100644 index 0000000..23e7f1b --- /dev/null +++ b/exports.def @@ -0,0 +1,9 @@ +LIBRARY "DINPUT8.dll" + +EXPORTS +DirectInput8Create PRIVATE +DllCanUnloadNow PRIVATE +DllGetClassObject PRIVATE +DllRegisterServer PRIVATE +DllUnregisterServer PRIVATE +GetdfDIJoystick PRIVATE \ No newline at end of file diff --git a/proxy.S b/proxy.S new file mode 100644 index 0000000..72010ae --- /dev/null +++ b/proxy.S @@ -0,0 +1,24 @@ +[bits 32] + +extern _faddrs + +global _DirectInput8Create +global _DllCanUnloadNow +global _DllGetClassObject +global _DllRegisterServer +global _DllUnregisterServer +global _GetdfDIJoystick + +section .text +_DirectInput8Create: + jmp _faddrs[0 * 4] +_DllCanUnloadNow: + jmp _faddrs[1 * 4] +_DllGetClassObject: + jmp _faddrs[2 * 4] +_DllRegisterServer: + jmp _faddrs[3 * 4] +_DllUnregisterServer: + jmp _faddrs[4 * 4] +_GetdfDIJoystick: + jmp _faddrs[5 * 4] \ No newline at end of file -- cgit v1.2.3