From 36955ed008b35edb18bf5028948b42341eb9df1d Mon Sep 17 00:00:00 2001 From: kizer Date: Wed, 24 Aug 2022 15:54:31 +0900 Subject: [PATCH] Fix broken GetInputDeviceManager signature (#972) --- Dalamud.Boot/utils.cpp | 25 +++++++++++++++++++++++-- Dalamud.Boot/utils.h | 9 ++++++++- Dalamud.Boot/xivfixes.cpp | 33 +++++++++++---------------------- 3 files changed, 42 insertions(+), 25 deletions(-) diff --git a/Dalamud.Boot/utils.cpp b/Dalamud.Boot/utils.cpp index 62b436aa2..79205eb8d 100644 --- a/Dalamud.Boot/utils.cpp +++ b/Dalamud.Boot/utils.cpp @@ -348,6 +348,27 @@ utils::signature_finder& utils::signature_finder::look_for_hex(std::string_view return *this; } +const char* utils::signature_finder::result::resolve_jump_target(size_t instructionOffset) const { + nmd_x86_instruction instruction{}; + if (!nmd_x86_decode(&Match[instructionOffset], NMD_X86_MAXIMUM_INSTRUCTION_LENGTH, &instruction, NMD_X86_MODE_64, NMD_X86_DECODER_FLAGS_ALL)) + throw std::runtime_error("Matched address does not have a valid assembly instruction"); + + size_t numExplicitOperands = 0; + for (size_t i = 0; i < instruction.num_operands; i++) + numExplicitOperands += instruction.operands[i].is_implicit ? 0 : 1; + if (numExplicitOperands != 1) + throw std::runtime_error("Number of operands at the instruction at matched address is not 1"); + + if (!(instruction.group & NMD_GROUP_CALL) && !(instruction.group & NMD_GROUP_JUMP)) + throw std::runtime_error("The instruction at matched address is not a call or jump instruction"); + + const auto& arg1 = instruction.operands[0]; + if (arg1.type != NMD_X86_OPERAND_TYPE_IMMEDIATE) + throw std::runtime_error("The first operand for the instruction at matched address is not an immediate value"); + + return &Match[instructionOffset] + instruction.length + arg1.fields.imm; +} + std::vector utils::signature_finder::find(size_t minCount, size_t maxCount, bool bErrorOnMoreThanMaximum) const { std::vector res; @@ -383,8 +404,8 @@ std::vector utils::signature_finder::find(size_ return res; } -std::span utils::signature_finder::find_one() const { - return find(1, 1, false).front().Match; +utils::signature_finder::result utils::signature_finder::find_one() const { + return find(1, 1, false).front(); } utils::memory_tenderizer::memory_tenderizer(const void* pAddress, size_t length, DWORD dwNewProtect) : m_data(reinterpret_cast(const_cast(pAddress)), length) { diff --git a/Dalamud.Boot/utils.h b/Dalamud.Boot/utils.h index 1e29493b7..5d5c90dde 100644 --- a/Dalamud.Boot/utils.h +++ b/Dalamud.Boot/utils.h @@ -96,11 +96,18 @@ namespace utils { size_t PatternIndex; size_t MatchIndex; size_t CaptureIndex; + + const char* resolve_jump_target(size_t instructionOffset = 0) const; + + template + T resolve_jump_target(size_t instructionOffset = 0) const { + return reinterpret_cast(const_cast(resolve_jump_target(instructionOffset))); + } }; std::vector find(size_t minCount, size_t maxCount, bool bErrorOnMoreThanMaximum) const; - std::span find_one() const; + result find_one() const; }; class memory_tenderizer { diff --git a/Dalamud.Boot/xivfixes.cpp b/Dalamud.Boot/xivfixes.cpp index c5cde28d3..ca437f4fd 100644 --- a/Dalamud.Boot/xivfixes.cpp +++ b/Dalamud.Boot/xivfixes.cpp @@ -169,26 +169,11 @@ static TFnGetInputDeviceManager* GetGetInputDeviceManager(HWND hwnd) { if (pCached) return pCached; - char szClassName[256]; - GetClassNameA(hwnd, szClassName, static_cast(sizeof szClassName)); - - WNDCLASSEXA wcx{}; - GetClassInfoExA(g_hGameInstance, szClassName, &wcx); - const auto match = utils::signature_finder() + return pCached = utils::signature_finder() .look_in(utils::loaded_module(g_hGameInstance), ".text") - .look_for_hex("41 81 fe 19 02 00 00 0f 87 ?? ?? 00 00 0f 84 ?? ?? 00 00") - .find_one(); - - auto ptr = match.data() + match.size() + *reinterpret_cast(match.data() + match.size() - 4); - ptr += 4; // CMP RBX, 0x7 - ptr += 2; // JNZ - ptr += 7; // MOV RCX, - ptr += 3; // TEST RCX, RCX - ptr += 2; // JZ - ptr += 5; // CALL - ptr += *reinterpret_cast(ptr - 4); - - return pCached = reinterpret_cast(ptr); + .look_for_hex("e8 ?? ?? ?? ?? 48 8b 58 10 48 85 db") + .find_one() + .resolve_jump_target(); } void xivfixes::prevent_devicechange_crashes(bool bApply) { @@ -202,9 +187,13 @@ void xivfixes::prevent_devicechange_crashes(bool bApply) { static const auto s_pfnBinder = static_cast(VirtualAlloc(nullptr, 64, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE)); static const auto s_pfnAlternativeWndProc = static_cast([](HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -> LRESULT { 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; + try { + 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; + } + } catch (const std::exception& e) { + logging::W("{} WndProc(0x{:X}, WM_DEVICECHANGE, DBT_DEVNODES_CHANGED, {}) called, but failed to resolve address for GetInputDeviceManager: {}", LogTag, reinterpret_cast(hWnd), lParam, e.what()); } }