From d3c230f9e05364938e56c97cb65804dee65ec69b Mon Sep 17 00:00:00 2001 From: kizer Date: Sat, 18 Jun 2022 02:01:38 +0900 Subject: [PATCH] Attempt to fix for alex compat (#884) --- Dalamud.Boot/Dalamud.Boot.vcxproj | 2 +- Dalamud.Boot/xivfixes.cpp | 107 ++++++++++++++++++++++++++---- 2 files changed, 94 insertions(+), 15 deletions(-) diff --git a/Dalamud.Boot/Dalamud.Boot.vcxproj b/Dalamud.Boot/Dalamud.Boot.vcxproj index 891eb0275..fe33e5406 100644 --- a/Dalamud.Boot/Dalamud.Boot.vcxproj +++ b/Dalamud.Boot/Dalamud.Boot.vcxproj @@ -53,7 +53,7 @@ Windows true false - dbghelp.lib;%(AdditionalDependencies) + dbghelp.lib;Version.lib;%(AdditionalDependencies) ..\lib\CoreCLR;%(AdditionalLibraryDirectories) diff --git a/Dalamud.Boot/xivfixes.cpp b/Dalamud.Boot/xivfixes.cpp index 7a72c4147..e807f76ca 100644 --- a/Dalamud.Boot/xivfixes.cpp +++ b/Dalamud.Boot/xivfixes.cpp @@ -13,7 +13,6 @@ static std::span assume_nonempty_span(std::span t, const char* descr) { throw std::runtime_error(std::format("Unexpected empty span found: {}", descr)); return t; } - void xivfixes::unhook_dll(bool bApply) { static const auto LogTag = "[xivfixes:unhook_dll]"; static const auto LogTagW = L"[xivfixes:unhook_dll]"; @@ -24,15 +23,15 @@ void xivfixes::unhook_dll(bool bApply) { return; const auto mods = utils::loaded_module::all_modules(); - for (size_t i = 0; i < mods.size(); i++) { - const auto& mod = mods[i]; + + const auto test_module = [&](size_t i, const utils::loaded_module & mod) { std::filesystem::path path; try { path = mod.path(); logging::I("{} [{}/{}] Module 0x{:X} ~ 0x{:X} (0x{:X}): \"{}\"", LogTagW, i + 1, mods.size(), mod.address_int(), mod.address_int() + mod.image_size(), mod.image_size(), path.wstring()); } catch (const std::exception& e) { - logging::W("{} [{}/{}] Module 0x{:X}: Failed to resolve path: {}", LogTag, i + 1, mods.size(), mod.address_int(), e.what()); - continue; + logging::W("{} [{}/{}] Module 0x{:X}: Failed to resolve path: {}", LogTag, i + 1, mods.size(), mod.address_int(), e.what()); + return; } const auto moduleName = unicode::convert(path.filename().wstring()); @@ -45,7 +44,7 @@ void xivfixes::unhook_dll(bool bApply) { auto hFsDllRaw = CreateFileW(path.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr); if (hFsDllRaw == INVALID_HANDLE_VALUE) { logging::W("{} Module loaded in current process but could not open file: Win32 error {}", LogTag, GetLastError()); - continue; + return; } auto hFsDll = std::unique_ptr(hFsDllRaw, &CloseHandle); @@ -54,11 +53,11 @@ void xivfixes::unhook_dll(bool bApply) { if (DWORD read{}; ReadFile(hFsDll.get(), &buf[0], static_cast(buf.size()), &read, nullptr)) { if (read < section.size_bytes()) { logging::W("{} ReadFile: read {} bytes < requested {} bytes", LogTagW, read, section.size_bytes()); - continue; + return; } } else { logging::I("{} ReadFile: Win32 error {}", LogTagW, GetLastError()); - continue; + return; } auto doRestore = false; @@ -96,7 +95,7 @@ void xivfixes::unhook_dll(bool bApply) { const auto names = mod.span_as(exportDirectory.AddressOfNames, exportDirectory.NumberOfNames); const auto ordinals = mod.span_as(exportDirectory.AddressOfNameOrdinals, exportDirectory.NumberOfNames); const auto functions = mod.span_as(exportDirectory.AddressOfFunctions, exportDirectory.NumberOfFunctions); - + std::string resolvedExportName; for (size_t j = 0; j < names.size(); ++j) { std::string_view name; @@ -109,7 +108,7 @@ void xivfixes::unhook_dll(bool bApply) { name = std::string_view(pcszName, strnlen(pcszName, 256)); logging::W("{} Name #{} points to a seemingly valid address outside the executable: {}", LogTag, j, name); } - + if (ordinals[j] >= functions.size()) { logging::W("{} Ordinal #{} points to function index #{} >= #{}. Skipping.", LogTag, j, ordinals[j], functions.size()); continue; @@ -142,7 +141,20 @@ void xivfixes::unhook_dll(bool bApply) { } catch (const std::exception& e) { logging::W("{} Error: {}", LogTag, e.what()); } - } + }; + + const auto aaaa = [&]() { + for (size_t i = 0; i < mods.size(); i++) { + const auto& mod = mods[i]; + __try { + test_module(i, mod); + } __except (EXCEPTION_EXECUTE_HANDLER) { + logging::W("{} Error: Access Violation", LogTag); + } + } + }; + + aaaa(); } using TFnGetInputDeviceManager = void* (); @@ -196,11 +208,12 @@ void xivfixes::prevent_devicechange_crashes(bool bApply) { logging::I(R"({} CreateWindow(0x{:08X}, "{}", "{}", 0x{:08X}, {}, {}, {}, {}, 0x{:X}, 0x{:X}, 0x{:X}, 0x{:X}) called; unhooking CreateWindowExA and hooking WndProc.)", LogTag, dwExStyle, lpClassName, lpWindowName, dwStyle, X, Y, nWidth, nHeight, reinterpret_cast(hWndParent), reinterpret_cast(hMenu), reinterpret_cast(hInstance), reinterpret_cast(lpParam)); - s_hookCreateWindowExA.reset(); - s_hookWndProc.emplace("FFXIVGAME:WndProc (prevent_devicechange_crashes)", hWnd); s_hookWndProc->set_detour([](HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -> LRESULT { - if (uMsg == WM_DEVICECHANGE && wParam == DBT_DEVNODES_CHANGED) { + + if (uMsg == WM_CREATE) { + s_hookCreateWindowExA.reset(); + } else if (uMsg == WM_DEVICECHANGE && wParam == DBT_DEVNODES_CHANGED) { if (!GetGetInputDeviceManager(hWnd)()) { logging::I("{} WndProc(0x{:X}, WM_DEVICECHANGE, DBT_DEVNODES_CHANGED, {}) called but the game does not have InputDeviceManager initialized; doing nothing.", LogTag, reinterpret_cast(hWnd), lParam); return 0; @@ -229,6 +242,64 @@ void xivfixes::prevent_devicechange_crashes(bool bApply) { } } +static bool is_xivalex(const std::filesystem::path& dllPath) { + DWORD verHandle = 0; + std::vector block; + block.resize(GetFileVersionInfoSizeW(dllPath.c_str(), &verHandle)); + if (block.empty()) + return false; + if (!GetFileVersionInfoW(dllPath.c_str(), 0, static_cast(block.size()), &block[0])) + return false; + struct LANGANDCODEPAGE { + WORD wLanguage; + WORD wCodePage; + } * lpTranslate; + UINT cbTranslate; + if (!VerQueryValueW(&block[0], + TEXT("\\VarFileInfo\\Translation"), + reinterpret_cast(&lpTranslate), + &cbTranslate)) { + return false; + } + + for (size_t i = 0; i < (cbTranslate / sizeof(struct LANGANDCODEPAGE)); i++) { + wchar_t* buf = nullptr; + UINT size = 0; + if (!VerQueryValueW(&block[0], + std::format(L"\\StringFileInfo\\{:04x}{:04x}\\FileDescription", + lpTranslate[i].wLanguage, + lpTranslate[i].wCodePage).c_str(), + reinterpret_cast(&buf), + &size)) { + continue; + } + auto currName = std::wstring_view(buf, size); + while (!currName.empty() && currName.back() == L'\0') + currName = currName.substr(0, currName.size() - 1); + if (currName.empty()) + continue; + if (currName == L"XivAlexander Main DLL") + return true; + } + return false; +} + +static bool is_openprocess_already_dealt_with() { + static const auto s_value = [] { + for (const auto& mod : utils::loaded_module::all_modules()) { + try { + if (is_xivalex(mod.path())) + return true; + + } catch (...) { + // pass + } + } + return false; + }(); + return s_value; +} + void xivfixes::disable_game_openprocess_access_check(bool bApply) { static const char* LogTag = "[xivfixes:disable_game_openprocess_access_check]"; static std::optional> s_hook; @@ -238,6 +309,10 @@ void xivfixes::disable_game_openprocess_access_check(bool bApply) { logging::I("{} Turned off via environment variable.", LogTag); return; } + if (is_openprocess_already_dealt_with()) { + logging::I("{} Someone else already did it.", LogTag); + return; + } s_hook.emplace("kernel32.dll!OpenProcess (import, disable_game_openprocess_access_check)", "kernel32.dll", "OpenProcess", 0); s_hook->set_detour([](DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId)->HANDLE { @@ -275,6 +350,10 @@ void xivfixes::redirect_openprocess(bool bApply) { logging::I("{} Turned off via environment variable.", LogTag); return; } + if (is_openprocess_already_dealt_with()) { + logging::I("{} Someone else already did it.", LogTag); + return; + } if (bootconfig::dotnet_openprocess_hook_mode() == bootconfig::ImportHooks) { auto hook = std::make_shared>("kernel32.dll!OpenProcess (global import, redirect_openprocess)", L"kernel32.dll", "OpenProcess");