Skip to content

Commit

Permalink
XInputHook: Fix Steam's hooks causing failures sometimes
Browse files Browse the repository at this point in the history
  • Loading branch information
praydog committed Dec 25, 2023
1 parent 36f7ab9 commit 4f2994b
Showing 1 changed file with 89 additions and 4 deletions.
93 changes: 89 additions & 4 deletions src/hooks/XInputHook.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <chrono>
#include <spdlog/spdlog.h>
#include <utility/String.hpp>
#include <utility/Scan.hpp>

#include <SafetyHook.hpp>

Expand Down Expand Up @@ -49,6 +50,38 @@ XInputHook::XInputHook() {
return found_dll;
};

auto recursive_resolve_jmp = [](this const auto& self, uint8_t* instr) -> uintptr_t {
try {
const auto decoded = utility::decode_one(instr);

if (decoded) {
const auto mnem = std::string_view{decoded->Mnemonic};

if (mnem.starts_with("JMP")) {
const auto target = utility::resolve_displacement((uintptr_t)instr);

if (target.has_value()) {
if (instr[0] == 0xFF && instr[1] == 0x25) {
const auto real_target = *(uintptr_t*)*target;

if (real_target == 0) {
return (uintptr_t)instr;
}

return self((uint8_t*)real_target);
}

return self((uint8_t*)target.value());
}
}
}
} catch(...) {
SPDLOG_ERROR("[XInputHook] recursive_resolve_jmp exception");
}

return (uintptr_t)instr;
};

auto perform_hooks_1_4 = [&]() {
const auto xinput_1_4_dll = find_dll("xinput1_4.dll");

Expand All @@ -62,7 +95,20 @@ XInputHook::XInputHook() {
m_xinput_1_4_get_state_hook = safetyhook::create_inline(get_state_fn, get_state_hook_1_4);

if (!m_xinput_1_4_get_state_hook) {
spdlog::error("Failed to hook XInputGetState (1_4)");
spdlog::error("Failed to hook XInputGetState (1_4), trying jmp");

// Check if there is a jmp instruction at the start of the function and try to hook that instead
const auto jmp_addr = recursive_resolve_jmp((uint8_t*)get_state_fn);

if (jmp_addr != (uintptr_t)get_state_fn) {
m_xinput_1_4_get_state_hook = safetyhook::create_inline((void*)jmp_addr, get_state_hook_1_4);

if (!m_xinput_1_4_get_state_hook) {
spdlog::error("Failed to hook XInputGetState (1_4) (jmp)");
}
} else {
spdlog::error("Cannot try jmp hook for XInputGetState (1_4) (jmp) (recursive_resolve_jmp failed)");
}
}
} else {
spdlog::error("[XInputHook] Failed to find XInputGetState");
Expand All @@ -72,7 +118,20 @@ XInputHook::XInputHook() {
m_xinput_1_4_set_state_hook = safetyhook::create_inline(set_state_fn, set_state_hook_1_4);

if (!m_xinput_1_4_set_state_hook) {
spdlog::error("Failed to hook XInputSetState (1_4)");
spdlog::error("Failed to hook XInputSetState (1_4), trying jmp");

// Check if there is a jmp instruction at the start of the function and try to hook that instead
const auto jmp_addr = recursive_resolve_jmp((uint8_t*)set_state_fn);

if (jmp_addr != (uintptr_t)set_state_fn) {
m_xinput_1_4_set_state_hook = safetyhook::create_inline((void*)jmp_addr, set_state_hook_1_4);

if (!m_xinput_1_4_set_state_hook) {
spdlog::error("Failed to hook XInputSetState (1_4) (jmp)");
}
} else {
spdlog::error("Cannot try jmp hook for XInputSetState (1_4) (jmp) (recursive_resolve_jmp failed)");
}
}
} else {
spdlog::error("[XInputHook] Failed to find XInputSetState");
Expand All @@ -95,7 +154,20 @@ XInputHook::XInputHook() {
m_xinput_1_3_get_state_hook = safetyhook::create_inline(get_state_fn, get_state_hook_1_3);

if (!m_xinput_1_3_get_state_hook) {
spdlog::error("Failed to hook XInputGetState (1_3)");
spdlog::error("Failed to hook XInputGetState (1_3), trying jmp");

// Check if there is a jmp instruction at the start of the function and try to hook that instead
const auto jmp_addr = recursive_resolve_jmp((uint8_t*)get_state_fn);

if (jmp_addr != (uintptr_t)get_state_fn) {
m_xinput_1_3_get_state_hook = safetyhook::create_inline((void*)jmp_addr, get_state_hook_1_3);

if (!m_xinput_1_3_get_state_hook) {
spdlog::error("Failed to hook XInputGetState (1_3) (jmp)");
}
} else {
spdlog::error("Cannot try jmp hook for XInputGetState (1_3) (jmp) (recursive_resolve_jmp failed)");
}
}
} else {
spdlog::error("[XInputHook] Failed to find XInputGetState");
Expand All @@ -105,7 +177,20 @@ XInputHook::XInputHook() {
m_xinput_1_3_set_state_hook = safetyhook::create_inline(set_state_fn, set_state_hook_1_3);

if (!m_xinput_1_3_set_state_hook) {
spdlog::error("Failed to hook XInputSetState (1_3)");
spdlog::error("Failed to hook XInputSetState (1_3), trying jmp");

// Check if there is a jmp instruction at the start of the function and try to hook that instead
const auto jmp_addr = recursive_resolve_jmp((uint8_t*)set_state_fn);

if (jmp_addr != (uintptr_t)set_state_fn) {
m_xinput_1_3_set_state_hook = safetyhook::create_inline((void*)jmp_addr, set_state_hook_1_3);

if (!m_xinput_1_3_set_state_hook) {
spdlog::error("Failed to hook XInputSetState (1_3) (jmp)");
}
} else {
spdlog::error("Cannot try jmp hook for XInputSetState (1_3) (jmp) (recursive_resolve_jmp failed)");
}
}
} else {
spdlog::error("[XInputHook] Failed to find XInputSetState");
Expand Down

0 comments on commit 4f2994b

Please sign in to comment.