diff --git a/WuchangFF/dllmain.cpp b/WuchangFF/dllmain.cpp index ea55898..2ff21b2 100644 --- a/WuchangFF/dllmain.cpp +++ b/WuchangFF/dllmain.cpp @@ -1,133 +1,116 @@ -// At this point code injection into the game results in crash. -// Do not use this plugin dll injection. - #include "Memory.hpp"; #include "Maths.hpp"; #include "ObfuscateString.h" #include #include #include -//#include #include -#include -#include -#include -#include // Constants const std::string PLUGIN_NAME = "WuchangFF"; const std::string PLUGIN_LOG = PLUGIN_NAME + ".log"; const std::string gameExecutable = "Project_Plague-Win64-Shipping.exe"; -const float baseAspect = 1.777777791; // Logger std::shared_ptr logger; -// Screen informations -static int screenWidth = GetSystemMetrics(SM_CXSCREEN); -static int screenHeight = GetSystemMetrics(SM_CYSCREEN); -static float aspectRatio = (float)screenWidth / screenHeight; - // Plugin states static bool AOBScanDone = false; static bool g_fix_enabled = false; -static bool g_fov_fix_enabled = false; -static bool g_aspect_ratio_fix_enabled = false; +static bool g_aspect_ratio_axis_constrain_fix_enabled = false; static bool g_DOF_fix_enabled = false; -static int g_AdditionalValue = 0; - -// Shared values -static float g_FOV_In = 0; -static float g_Compensated_FOV = 0; -static float g_FOV_Out = 0; +static bool g_Vignetting_fix_enabled = false; +static bool g_Fog_fix_enabled = false; // AOB Scan pointers -static uint8_t* FOVaddress = nullptr; -static uint8_t* Aspectaddress = nullptr; +static uint8_t* HORPLUSaddress = nullptr; static uint8_t* DOFaddress = nullptr; - -// Hooking -//static SafetyHookMid FOVHook{}; -//static SafetyHookMid AspectRatioHook{}; +static uint8_t* Vignettingaddress = nullptr; +static uint8_t* Fogaddress = nullptr; // Prototypes -static void FOVFixEnabled(bool fix_enabled); -static void AspectRatioFixEnabled(bool fix_enabled); +static void HORPlusFixEnabled(bool fix_enabled); static void DOFFixEnabled(bool fix_enabled); - -bool IsReadableExecutable(void* addr) -{ - MEMORY_BASIC_INFORMATION mbi; - if (VirtualQuery(addr, &mbi, sizeof(mbi))) - { - DWORD protect = mbi.Protect; - return (protect & PAGE_EXECUTE_READ) || (protect & PAGE_EXECUTE_READWRITE) || (protect & PAGE_EXECUTE_WRITECOPY); - } - return false; -} +static void VignettingFixEnabled(bool fix_enabled); +static void FogFixEnabled(bool fix_enabled); extern "C" __declspec(dllexport) void SetFixEnabled(bool enabled) { g_fix_enabled = enabled; if (g_fix_enabled && !AOBScanDone) { logger->info("--------------- AOB scan started ---------------"); - if (FOVaddress == nullptr) { - constexpr auto FOVStringObfuscated = make_obfuscated<0x4A>("EB ?? F3 0F ?? ?? ?? ?? ?? ?? F3 0F ?? ?? ?? 0F ?? ?? 8B 83"); - FOVaddress = Memory::aob_scan(gameExecutable, FOVStringObfuscated.decrypt(), PAGE_EXECUTE_READ); + if (HORPLUSaddress == nullptr) { + constexpr auto HORPLUSStringObfuscated = make_obfuscated<0x4A>("41 0F ?? ?? ?? ?? ?? ?? 48 8D ?? ?? ?? ?? ?? 4C ?? ?? 4D ?? ?? E8"); + HORPLUSaddress = Memory::aob_scan(gameExecutable, HORPLUSStringObfuscated.decrypt(), PAGE_EXECUTE_READ); - if (!FOVaddress) - logger->warn("FOV signature not found. Maybe your game has been updated and is no more compatible with this plugin."); - else { - logger->info("FOV signature found at address: 0x{:X}.", reinterpret_cast(FOVaddress)); - FOVaddress += 0xa; // Offset for the target opcode - } - } - if (Aspectaddress == nullptr) { - if (FOVaddress) { - Aspectaddress = FOVaddress + 0x0b; - logger->info("Aspect ratio signature found at address: 0x{:X}.", reinterpret_cast(Aspectaddress)); - } + if (!HORPLUSaddress) + logger->warn("HOR+ signature not found. Maybe your game has been updated and is no more compatible with this plugin."); + else + logger->info("HOR+ signature found at address: 0x{:X}.", reinterpret_cast(HORPLUSaddress)); } + if (DOFaddress == nullptr) { - constexpr auto DOFStringObfuscated = make_obfuscated<0x4A>("8B ?? ?? 48 ?? ?? E8 ?? ?? ?? ?? 0F ?? ?? 48 6B ?? ?? 48 8D"); + constexpr auto DOFStringObfuscated = make_obfuscated<0x4A>("48 ?? ?? 8B ?? ?? E8 ?? ?? ?? ?? 48 ?? ?? 48 6B ?? ?? 48 8D"); DOFaddress = Memory::aob_scan(gameExecutable, DOFStringObfuscated.decrypt(), PAGE_EXECUTE_READ); if (!DOFaddress) logger->warn("DOF signature not found. Maybe your game has been updated and is no more compatible with this plugin."); else { - logger->info("DOF ratio signature found at address: 0x{:X}.", reinterpret_cast(DOFaddress)); + logger->info("DOF signature found at address: 0x{:X}.", reinterpret_cast(DOFaddress)); + DOFaddress += 0x3; } - if (FOVaddress != nullptr && Aspectaddress != nullptr && DOFaddress != nullptr) - logger->info("All AOB signatures found. Ready to patch..."); - if (FOVaddress && Aspectaddress && DOFaddress) AOBScanDone = true; - logger->info("--------------- AOB scan finished ---------------"); } + + if (Vignettingaddress == nullptr) { + constexpr auto VignettingStringObfuscated = make_obfuscated<0x4A>("8B ?? 83 ?? ?? 7D ?? 89 B3 ?? ?? ?? ?? EB"); + Vignettingaddress = Memory::aob_scan(gameExecutable, VignettingStringObfuscated.decrypt(), PAGE_EXECUTE_READ); + + if (!Vignettingaddress) + logger->warn("Vignetting signature not found. Maybe your game has been updated and is no more compatible with this plugin."); + else { + logger->info("Vignetting signature found at address: 0x{:X}.", reinterpret_cast(Vignettingaddress)); + } + } + + if (Fogaddress == nullptr) { + constexpr auto FogStringObfuscated = make_obfuscated<0x4A>("75 ?? B3 ?? EB ?? 32 ?? 48 8B ?? ?? ?? 48 ?? ?? 74 ?? E8 ?? ?? ?? ?? 0F ?? ?? 48 8B"); + Fogaddress = Memory::aob_scan(gameExecutable, FogStringObfuscated.decrypt(), PAGE_EXECUTE_READ); + + if (!Fogaddress) + logger->warn("Fog signature not found. Maybe your game has been updated and is no more compatible with this plugin."); + else { + logger->info("Fog signature found at address: 0x{:X}.", reinterpret_cast(Fogaddress)); + } + } + + if (HORPLUSaddress && DOFaddress && Vignettingaddress && Fogaddress) { + logger->info("All AOB signatures found. Ready to patch..."); + AOBScanDone = true; + } + + logger->info("--------------- AOB scan finished ---------------"); } if (g_fix_enabled) { - if (FOVaddress) FOVFixEnabled(g_fov_fix_enabled || g_aspect_ratio_fix_enabled); - if (Aspectaddress) AspectRatioFixEnabled(g_aspect_ratio_fix_enabled); + if (HORPLUSaddress) HORPlusFixEnabled(g_aspect_ratio_axis_constrain_fix_enabled); if (DOFaddress) DOFFixEnabled(g_DOF_fix_enabled); + if (Vignettingaddress) VignettingFixEnabled(g_Vignetting_fix_enabled); + if (Fogaddress) FogFixEnabled(g_Fog_fix_enabled); } else { - if (FOVaddress) FOVFixEnabled(false); - if (Aspectaddress) AspectRatioFixEnabled(false); + if (HORPLUSaddress) HORPlusFixEnabled(false); if (DOFaddress) DOFFixEnabled(false); + if (Vignettingaddress) VignettingFixEnabled(false); + if (Fogaddress) FogFixEnabled(false); logger->info("All fixes disabled."); } } // Setters for Reshade addon call -extern "C" __declspec(dllexport) void SetFOVFixEnabled(bool enabled, bool init) +extern "C" __declspec(dllexport) void SetARAxisConstrainFixEnabled(bool enabled, bool init) { - g_fov_fix_enabled = enabled; - if (!init) FOVFixEnabled(g_fov_fix_enabled || g_aspect_ratio_fix_enabled); // FOV fix must be enabled when aspect ratio is too to compensate FOV -} - -extern "C" __declspec(dllexport) void SetAspectRatioFixEnabled(bool enabled, bool init) -{ - g_aspect_ratio_fix_enabled = enabled; - if (!init) AspectRatioFixEnabled(g_aspect_ratio_fix_enabled); + g_aspect_ratio_axis_constrain_fix_enabled = enabled; + if (!init) HORPlusFixEnabled(g_aspect_ratio_axis_constrain_fix_enabled); } extern "C" __declspec(dllexport) void SetDOFFixEnabled(bool enabled, bool init) @@ -136,241 +119,62 @@ extern "C" __declspec(dllexport) void SetDOFFixEnabled(bool enabled, bool init) if (!init) DOFFixEnabled(g_DOF_fix_enabled); } -extern "C" __declspec(dllexport) void SetFOV(int fov) +extern "C" __declspec(dllexport) void SetVignettingFixEnabled(bool enabled, bool init) { - g_AdditionalValue = fov; + g_Vignetting_fix_enabled = enabled; + if (!init) VignettingFixEnabled(g_Vignetting_fix_enabled); } -// Getters for Reshade addon call -extern "C" __declspec(dllexport) float GetFOVIn() { - return g_FOV_In; +extern "C" __declspec(dllexport) void SetFogFixEnabled(bool enabled, bool init) +{ + g_Fog_fix_enabled = enabled; + if (!init) FogFixEnabled(g_Fog_fix_enabled); } -extern "C" __declspec(dllexport) float GetCompensatedFOV() { - return g_Compensated_FOV; -} - -extern "C" __declspec(dllexport) float GetFOVOut() { - return g_FOV_Out; -} - -DWORD GetCurrentThreadIdSafe() { - return GetCurrentThreadId(); -} -DWORD GetMainThreadId(DWORD processId) { - DWORD mainThreadId = 0; - FILETIME earliestCreateTime = { MAXDWORD, MAXDWORD }; - - HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); - if (snapshot == INVALID_HANDLE_VALUE) return 0; - - THREADENTRY32 te; - te.dwSize = sizeof(te); - - if (Thread32First(snapshot, &te)) { - do { - if (te.th32OwnerProcessID == processId) { - HANDLE hThread = OpenThread(THREAD_QUERY_INFORMATION, FALSE, te.th32ThreadID); - if (hThread) { - FILETIME createTime, exitTime, kernelTime, userTime; - if (GetThreadTimes(hThread, &createTime, &exitTime, &kernelTime, &userTime)) { - if (CompareFileTime(&createTime, &earliestCreateTime) < 0) { - earliestCreateTime = createTime; - mainThreadId = te.th32ThreadID; - } - } - CloseHandle(hThread); - } - } - } while (Thread32Next(snapshot, &te)); +// Memory patch fixes +static void HORPlusFixEnabled(bool fix_enabled) { + if (g_fix_enabled && fix_enabled && HORPLUSaddress) { + Memory::PatchBytes(HORPLUSaddress, "\x31\xD2\x90\x90\x90\x90\x90\x90", 8); // xor edx,edx AspectRatioAxisConstraint=AspectRatio_MaintainYFOV + logger->info("HOR+ fix enabled"); } - - CloseHandle(snapshot); - return mainThreadId; -} - -void FreezeOtherThreads() { - DWORD currentThreadId = GetCurrentThreadId(); - DWORD currentProcessId = GetCurrentProcessId(); - DWORD mainThreadId = GetMainThreadId(currentProcessId); - - HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); - if (snapshot == INVALID_HANDLE_VALUE) return; - - THREADENTRY32 te; - te.dwSize = sizeof(te); - - if (Thread32First(snapshot, &te)) { - do { - if (te.th32OwnerProcessID == currentProcessId && - te.th32ThreadID != currentThreadId && - te.th32ThreadID != mainThreadId) { - HANDLE hThread = OpenThread(THREAD_SUSPEND_RESUME, FALSE, te.th32ThreadID); - if (hThread) { - SuspendThread(hThread); - CloseHandle(hThread); - } - } - } while (Thread32Next(snapshot, &te)); + if (!fix_enabled && HORPLUSaddress) { + Memory::RestoreBytes(HORPLUSaddress); + logger->info("HOR+ fix disabled"); } - - CloseHandle(snapshot); -} - - -void ResumeThreads() { - DWORD currentThreadId = GetCurrentThreadId(); - DWORD currentProcessId = GetCurrentProcessId(); - - HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); - if (snapshot == INVALID_HANDLE_VALUE) return; - - THREADENTRY32 te; - te.dwSize = sizeof(te); - - if (Thread32First(snapshot, &te)) { - do { - if (te.th32OwnerProcessID == currentProcessId && te.th32ThreadID != currentThreadId) { - HANDLE hThread = OpenThread(THREAD_SUSPEND_RESUME, FALSE, te.th32ThreadID); - if (hThread) { - ResumeThread(hThread); - CloseHandle(hThread); - } - } - } while (Thread32Next(snapshot, &te)); - } - - CloseHandle(snapshot); -} - -void* g_Trampoline = nullptr; - -void* AllocateNear(void* nearAddr, size_t size) { - SYSTEM_INFO sysInfo; - GetSystemInfo(&sysInfo); - - uintptr_t startAddr = reinterpret_cast(nearAddr); - uintptr_t minAddr = (startAddr > 0x7FFFFFFF) ? startAddr - 0x7FFFFFFF : 0; // -2Go - uintptr_t maxAddr = startAddr + 0x7FFFFFFF; // +2Go - - uintptr_t addr = minAddr; - while (addr < maxAddr) { - void* alloc = VirtualAlloc(reinterpret_cast(addr), size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); - if (alloc != nullptr) { - logger->info("Allocated memory at 0x{:X} near 0x{:X}", reinterpret_cast(alloc), reinterpret_cast(nearAddr)); - return alloc; - } - addr += sysInfo.dwPageSize; - } - - logger->info("Failed to allocate memory near 0x{:X}", reinterpret_cast(nearAddr)); - return nullptr; -} - -void* CreateTrampoline(void* target_addr, size_t length = 5) { - if (length < 5) length = 5; // minimum 5 octets pour jump - - // Allouer mémoire proche - //void* trampoline = AllocateNear(target_addr, length + 5); // +5 octets pour jump retour - void* trampoline = AllocateNear(target_addr, length + 5); // +5 octets pour jump retour - if (!trampoline) { - logger->info("Failed to allocate trampoline memory"); - return nullptr; - } - - // Copier les octets originaux - memcpy(trampoline, target_addr, length); - - // Calculer l'adresse de retour (target_addr + length) - uintptr_t retAddr = reinterpret_cast(target_addr) + length; - uintptr_t jmpFrom = reinterpret_cast(trampoline) + length; - - // Ecrire un jump relatif 5 octets à la fin du trampoline pour revenir au code original - int32_t relAddr = static_cast(retAddr - (jmpFrom + 5)); // rel = dest - (src+5) - uint8_t* p = reinterpret_cast(jmpFrom); - p[0] = 0xE9; // opcode JMP rel32 - memcpy(p + 1, &relAddr, sizeof(relAddr)); - - logger->info("Trampoline created at 0x{:X}, jump back to 0x{:X}", reinterpret_cast(trampoline), retAddr); - - return trampoline; -} - -//void HookFunction(void* target, void* destination, size_t length = 5) { -// DWORD oldProtect; -// VirtualProtect(target, length, PAGE_EXECUTE_READWRITE, &oldProtect); -// -// uintptr_t rel_addr = (uintptr_t)destination - (uintptr_t)target - 5; -// uint8_t patch[5] = { 0xE9 }; // jmp rel32 -// *reinterpret_cast(patch + 1) = static_cast(rel_addr); -// -// logger->info("Patching FOVaddress (0x{:X}) to jump to trampoline (0x{:X})", reinterpret_cast(target), reinterpret_cast(destination)); -// memcpy(target, patch, 5); -// VirtualProtect(target, length, oldProtect, &oldProtect); -//} -using FOVFuncType = void(__fastcall*)(); -FOVFuncType originalFOV = nullptr; - -static void FOVFixEnabled(bool fix_enabled) { - if (g_fix_enabled && fix_enabled && FOVaddress != nullptr) { - - //if (g_Trampoline) - // HookFunction(FOVaddress, g_Trampoline, 5); - - //if (!FOVHook) { // Hook only once - //if (IsReadableExecutable(FOVaddress)) { - //FOVHook = safetyhook::create_mid(FOVaddress, - // [](SafetyHookContext& ctx) { - // //g_FOV_In = ctx.xmm0.f32[0]; - // //if (g_aspect_ratio_fix_enabled) - // // g_Compensated_FOV = ctx.xmm0.f32[0] = Maths::CompensateHorizontalFOV(g_FOV_In, baseAspect, aspectRatio); - // //else - // // g_Compensated_FOV = ctx.xmm0.f32[0]; - // //g_FOV_Out = ctx.xmm0.f32[0] += (g_fov_fix_enabled ? g_AdditionalValue : 0); - // }); - //} - //} - //else FOVHook.enable(); - logger->info("FOV fix enabled"); - } - //if (!fix_enabled /* && FOVHook * / ) { - if (!fix_enabled) { - //FOVHook.disable(); - logger->info("FOV fix disabled"); - } -} - -static void AspectRatioFixEnabled(bool fix_enabled) { - //if (g_fix_enabled && fix_enabled && Aspectaddress != nullptr) { - // if (!AspectRatioHook) { - // AspectRatioHook = safetyhook::create_mid(Aspectaddress, - // [](SafetyHookContext& ctx) { - // ctx.rax = *reinterpret_cast(&aspectRatio); - // }); - // } - // else { - // AspectRatioHook.enable(); - // FOVFixEnabled(fix_enabled); // Usefull to compensate - // } - // logger->info("Aspect ratio fix enabled"); - //} - //if (!fix_enabled && AspectRatioHook && Aspectaddress) { - // AspectRatioHook.disable(); - // logger->info("Aspect ratio fix disabled"); - //} } static void DOFFixEnabled(bool fix_enabled) { - //if (g_fix_enabled && fix_enabled && DOFaddress != nullptr) { - // Memory::PatchBytes(DOFaddress, "\x31\xFF\x90", 3); // xor edi,edi r.DepthOfFieldQuality = 0 - // logger->info("Depth of field fix enabled"); - //} - //if (!fix_enabled && DOFaddress) { - // Memory::RestoreBytes(DOFaddress); - // logger->info("Depth of field fix disabled"); - //} + if (g_fix_enabled && fix_enabled && DOFaddress) { + Memory::PatchBytes(DOFaddress, "\x31\xFF\x90", 3); // xor edi,edi r.DepthOfFieldQuality = 0 + logger->info("Depth of field fix enabled"); + } + if (!fix_enabled && DOFaddress) { + Memory::RestoreBytes(DOFaddress); + logger->info("Depth of field fix disabled"); + } } +static void VignettingFixEnabled(bool fix_enabled) { + if (g_fix_enabled && fix_enabled && Vignettingaddress) { + Memory::PatchBytes(Vignettingaddress, "\x31\xC9", 2); // xor ecx,ecx r.Tonemapper.Quality=0 + logger->info("Vignetting fix enabled"); + } + if (!fix_enabled && Vignettingaddress) { + Memory::RestoreBytes(Vignettingaddress); + logger->info("Vignetting fix disabled"); + } +} + +static void FogFixEnabled(bool fix_enabled) { + if (g_fix_enabled && fix_enabled && Fogaddress) { + Memory::PatchBytes(Fogaddress, "\xEB", 1); // jmp "Project_Plague-Win64-Shipping.exe"+28E280E + logger->info("Fog fix enabled"); + } + if (!fix_enabled && Fogaddress) { + Memory::RestoreBytes(Fogaddress); + logger->info("Fog fix disabled"); + } +} static void InitializeLogger() { @@ -396,10 +200,6 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID) { InitializeLogger(); logger->info("Plugin {} loaded.", PLUGIN_NAME); - if (MH_Initialize() != MH_OK) { - logger->info("MinHook initialization failed!"); - return FALSE; - } } else if (reason == DLL_PROCESS_DETACH) {