From 2e8f65c619aefbee8739ff37ab7742678c9e560d Mon Sep 17 00:00:00 2001 From: localcc Date: Thu, 19 Oct 2023 16:48:00 +0200 Subject: [PATCH] Replace polyhook with safetyhook This greatly simplifies code and reduces boilerplate --- UE4SS/CMakeLists.txt | 2 +- UE4SS/include/CrashDumper.hpp | 5 +- UE4SS/include/UE4SSProgram.hpp | 17 ++---- UE4SS/src/CrashDumper.cpp | 10 +--- UE4SS/src/UE4SSProgram.cpp | 39 +++--------- .../ASMHelper/include/ASMHelper/ASMHelper.hpp | 1 + deps/first/ASMHelper/src/ASMHelper.cpp | 11 ++-- deps/first/Helpers/CMakeLists.txt | 2 + deps/first/Helpers/include/Helpers/Hook.hpp | 21 +++++++ deps/third/CMakeLists.txt | 2 +- deps/third/PolyHook_2_0/CMakeLists.txt | 59 ------------------- deps/third/safetyhook/CMakeLists.txt | 10 ++++ deps/third/zydis/CMakeLists.txt | 2 +- 13 files changed, 61 insertions(+), 120 deletions(-) create mode 100644 deps/first/Helpers/include/Helpers/Hook.hpp delete mode 100644 deps/third/PolyHook_2_0/CMakeLists.txt create mode 100644 deps/third/safetyhook/CMakeLists.txt diff --git a/UE4SS/CMakeLists.txt b/UE4SS/CMakeLists.txt index adb345e3a..aa8835dcf 100644 --- a/UE4SS/CMakeLists.txt +++ b/UE4SS/CMakeLists.txt @@ -160,7 +160,7 @@ target_link_libraries(${TARGET} PUBLIC MProgram ScopedTimer) target_link_libraries(${TARGET} PUBLIC - ImGui PolyHook_2 d3d11 GLFW opengl32 dbghelp) + ImGui safetyhook d3d11 GLFW opengl32 dbghelp) set_property(TARGET ${TARGET} PROPERTY INTERPROCEDURAL_OPTIMIZATION ON) diff --git a/UE4SS/include/CrashDumper.hpp b/UE4SS/include/CrashDumper.hpp index b2ab6f7c7..6aedfa925 100644 --- a/UE4SS/include/CrashDumper.hpp +++ b/UE4SS/include/CrashDumper.hpp @@ -2,7 +2,7 @@ #include -#include +#include namespace RC { @@ -11,8 +11,7 @@ namespace RC private: bool enabled = false; void* m_previous_exception_filter = nullptr; - std::unique_ptr m_set_unhandled_exception_filter_hook; - uint64_t m_hook_trampoline_set_unhandled_exception_filter_hook; + SafetyHookInline m_set_unhandled_exception_filter_hook; public: CrashDumper(); diff --git a/UE4SS/include/UE4SSProgram.hpp b/UE4SS/include/UE4SSProgram.hpp index 5052b91cd..cc700c7aa 100644 --- a/UE4SS/include/UE4SSProgram.hpp +++ b/UE4SS/include/UE4SSProgram.hpp @@ -21,6 +21,8 @@ #include #include +#include + // Used to set up ImGui context and allocator in DLL mods #define UE4SS_ENABLE_IMGUI() \ { \ @@ -109,17 +111,10 @@ namespace RC std::mutex m_event_queue_mutex{}; private: - std::unique_ptr m_load_library_a_hook; - uint64_t m_hook_trampoline_load_library_a; - - std::unique_ptr m_load_library_ex_a_hook; - uint64_t m_hook_trampoline_load_library_ex_a; - - std::unique_ptr m_load_library_w_hook; - uint64_t m_hook_trampoline_load_library_w; - - std::unique_ptr m_load_library_ex_w_hook; - uint64_t m_hook_trampoline_load_library_ex_w; + SafetyHookInline m_load_library_a_hook; + SafetyHookInline m_load_library_ex_a_hook; + SafetyHookInline m_load_library_w_hook; + SafetyHookInline m_load_library_ex_w_hook; public: static inline std::vector> m_mods; diff --git a/UE4SS/src/CrashDumper.cpp b/UE4SS/src/CrashDumper.cpp index 3a81f4240..2bc60ed6b 100644 --- a/UE4SS/src/CrashDumper.cpp +++ b/UE4SS/src/CrashDumper.cpp @@ -75,7 +75,7 @@ namespace RC CrashDumper::~CrashDumper() { - m_set_unhandled_exception_filter_hook->unHook(); + m_set_unhandled_exception_filter_hook = {}; SetUnhandledExceptionFilter(reinterpret_cast(m_previous_exception_filter)); } @@ -83,13 +83,7 @@ namespace RC { SetErrorMode(SEM_FAILCRITICALERRORS); m_previous_exception_filter = SetUnhandledExceptionFilter(ExceptionHandler); - - m_set_unhandled_exception_filter_hook = std::make_unique("kernel32.dll", - "SetUnhandledExceptionFilter", - std::bit_cast(&HookedSetUnhandledExceptionFilter), - &m_hook_trampoline_set_unhandled_exception_filter_hook, - L""); - m_set_unhandled_exception_filter_hook->hook(); + m_set_unhandled_exception_filter_hook = safetyhook::create_inline(SetUnhandledExceptionFilter, HookedSetUnhandledExceptionFilter); this->enabled = true; } diff --git a/UE4SS/src/UE4SSProgram.cpp b/UE4SS/src/UE4SSProgram.cpp index 12a9c5f7d..c3d3652e7 100644 --- a/UE4SS/src/UE4SSProgram.cpp +++ b/UE4SS/src/UE4SSProgram.cpp @@ -129,7 +129,7 @@ namespace RC void* HookedLoadLibraryA(const char* dll_name) { UE4SSProgram& program = UE4SSProgram::get_program(); - HMODULE lib = PLH::FnCast(program.m_hook_trampoline_load_library_a, &LoadLibraryA)(dll_name); + HMODULE lib = program.m_load_library_a_hook.call(dll_name); program.fire_dll_load_for_cpp_mods(to_wstring(dll_name)); return lib; } @@ -137,7 +137,7 @@ namespace RC void* HookedLoadLibraryExA(const char* dll_name, void* file, int32_t flags) { UE4SSProgram& program = UE4SSProgram::get_program(); - HMODULE lib = PLH::FnCast(program.m_hook_trampoline_load_library_ex_a, &LoadLibraryExA)(dll_name, file, flags); + HMODULE lib = program.m_load_library_ex_a_hook.call(dll_name, file, flags); program.fire_dll_load_for_cpp_mods(to_wstring(dll_name)); return lib; } @@ -145,7 +145,7 @@ namespace RC void* HookedLoadLibraryW(const wchar_t* dll_name) { UE4SSProgram& program = UE4SSProgram::get_program(); - HMODULE lib = PLH::FnCast(program.m_hook_trampoline_load_library_w, &LoadLibraryW)(dll_name); + HMODULE lib = program.m_load_library_w_hook.call(dll_name); program.fire_dll_load_for_cpp_mods(dll_name); return lib; } @@ -153,7 +153,7 @@ namespace RC void* HookedLoadLibraryExW(const wchar_t* dll_name, void* file, int32_t flags) { UE4SSProgram& program = UE4SSProgram::get_program(); - HMODULE lib = PLH::FnCast(program.m_hook_trampoline_load_library_ex_w, &LoadLibraryExW)(dll_name, file, flags); + HMODULE lib = program.m_load_library_ex_w_hook.call(dll_name, file, flags); program.fire_dll_load_for_cpp_mods(dll_name); return lib; } @@ -229,33 +229,10 @@ namespace RC Output::send(STR("WITH_CASE_PRESERVING_NAME: No\n\n")); #endif - m_load_library_a_hook = std::make_unique("kernel32.dll", - "LoadLibraryA", - std::bit_cast(&HookedLoadLibraryA), - &m_hook_trampoline_load_library_a, - L""); - m_load_library_a_hook->hook(); - - m_load_library_ex_a_hook = std::make_unique("kernel32.dll", - "LoadLibraryExA", - std::bit_cast(&HookedLoadLibraryExA), - &m_hook_trampoline_load_library_ex_a, - L""); - m_load_library_ex_a_hook->hook(); - - m_load_library_w_hook = std::make_unique("kernel32.dll", - "LoadLibraryW", - std::bit_cast(&HookedLoadLibraryW), - &m_hook_trampoline_load_library_w, - L""); - m_load_library_w_hook->hook(); - - m_load_library_ex_w_hook = std::make_unique("kernel32.dll", - "LoadLibraryExW", - std::bit_cast(&HookedLoadLibraryExW), - &m_hook_trampoline_load_library_ex_w, - L""); - m_load_library_ex_w_hook->hook(); + m_load_library_a_hook = safetyhook::create_inline(LoadLibraryA, HookedLoadLibraryA); + m_load_library_ex_a_hook = safetyhook::create_inline(LoadLibraryExA, HookedLoadLibraryExA); + m_load_library_w_hook = safetyhook::create_inline(LoadLibraryW, HookedLoadLibraryW); + m_load_library_ex_w_hook = safetyhook::create_inline(LoadLibraryExW, HookedLoadLibraryExW); Unreal::UnrealInitializer::SetupUnrealModules(); diff --git a/deps/first/ASMHelper/include/ASMHelper/ASMHelper.hpp b/deps/first/ASMHelper/include/ASMHelper/ASMHelper.hpp index 83961b8b9..8aa86ab84 100644 --- a/deps/first/ASMHelper/include/ASMHelper/ASMHelper.hpp +++ b/deps/first/ASMHelper/include/ASMHelper/ASMHelper.hpp @@ -9,6 +9,7 @@ namespace RC::ASM { void* address{}; ZydisDecodedInstruction raw{}; + ZydisDecodedOperand operands[ZYDIS_MAX_OPERAND_COUNT]{}; }; RC_ASM_API auto is_jmp_instruction(void* instruction_ptr) -> bool; diff --git a/deps/first/ASMHelper/src/ASMHelper.cpp b/deps/first/ASMHelper/src/ASMHelper.cpp index 574f04526..660dbc6bc 100644 --- a/deps/first/ASMHelper/src/ASMHelper.cpp +++ b/deps/first/ASMHelper/src/ASMHelper.cpp @@ -10,14 +10,15 @@ namespace RC::ASM { auto instruction_ptr = static_cast(in_instruction_ptr); ZydisDecoder decoder{}; - ZydisDecoderInit(&decoder, ZYDIS_MACHINE_MODE_LONG_64, ZYDIS_ADDRESS_WIDTH_64); + ZydisDecoderInit(&decoder, ZYDIS_MACHINE_MODE_LONG_64, ZYDIS_STACK_WIDTH_64); ZyanUSize offset = 0; - ZydisDecodedInstruction instruction{}; - while (ZYAN_SUCCESS(ZydisDecoderDecodeBuffer(&decoder, instruction_ptr + offset, 16 - offset, &instruction))) + + Instruction instruction{in_instruction_ptr, {}, {}}; + while (ZYAN_SUCCESS(ZydisDecoderDecodeFull(&decoder, instruction_ptr + offset, 16 - offset, &instruction.raw, instruction.operands))) { break; } - return {in_instruction_ptr, instruction}; + return instruction; } auto is_jmp_instruction(void* in_instruction_ptr) -> bool @@ -36,7 +37,7 @@ namespace RC::ASM { auto instruction = get_first_instruction_at_address(in_instruction_ptr); ZyanU64 resolved_address{}; - if (ZYAN_SUCCESS(ZydisCalcAbsoluteAddress(&instruction.raw, &instruction.raw.operands[0], std::bit_cast(in_instruction_ptr), &resolved_address))) + if (ZYAN_SUCCESS(ZydisCalcAbsoluteAddress(&instruction.raw, &instruction.operands[0], std::bit_cast(in_instruction_ptr), &resolved_address))) { return std::bit_cast(resolved_address); } diff --git a/deps/first/Helpers/CMakeLists.txt b/deps/first/Helpers/CMakeLists.txt index 1b73f2faa..ece88b35c 100644 --- a/deps/first/Helpers/CMakeLists.txt +++ b/deps/first/Helpers/CMakeLists.txt @@ -10,3 +10,5 @@ add_library(${TARGET} INTERFACE) target_compile_features(${TARGET} INTERFACE cxx_std_20) target_include_directories(${TARGET} INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include) + +target_link_libraries(${TARGET} INTERFACE File Function safetyhook) diff --git a/deps/first/Helpers/include/Helpers/Hook.hpp b/deps/first/Helpers/include/Helpers/Hook.hpp new file mode 100644 index 000000000..127dbb936 --- /dev/null +++ b/deps/first/Helpers/include/Helpers/Hook.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include + +#include + +namespace RC::Helper::Hook +{ + template + class call_hook; + + template + class call_hook> + { + public: + ReturnType operator()(SafetyHookInline& hook, Params... args) + { + return hook.call(std::forward(args)...); + } + }; +} // namespace RC::Helper::Hook diff --git a/deps/third/CMakeLists.txt b/deps/third/CMakeLists.txt index 47e97062f..577a89149 100644 --- a/deps/third/CMakeLists.txt +++ b/deps/third/CMakeLists.txt @@ -2,7 +2,7 @@ add_subdirectory("GLFW") add_subdirectory("imgui") add_subdirectory("zydis") -add_subdirectory("PolyHook_2_0") +add_subdirectory("safetyhook") add_subdirectory("raw_pdb") # Third Party Depenedencies \ No newline at end of file diff --git a/deps/third/PolyHook_2_0/CMakeLists.txt b/deps/third/PolyHook_2_0/CMakeLists.txt deleted file mode 100644 index feeb1487d..000000000 --- a/deps/third/PolyHook_2_0/CMakeLists.txt +++ /dev/null @@ -1,59 +0,0 @@ -include(FetchContent) - -set(FETCHCONTENT_QUIET OFF) - -set(ZYDIS_LIBRARY Zydis) -set(ZYCORE_LIBRARY Zycore) - -get_target_property(ZYDIS_INCLUDE_DIR ${ZYDIS_LIBRARY} INCLUDE_DIRECTORIES) -get_target_property(ZYCORE_INCLUDE_DIR ${ZYCORE_LIBRARY} INCLUDE_DIRECTORIES) -message(${ZYDIS_INCLUDE_DIR}) - -if (${UE4SS_PolyHook_BUILD_SHARED}) - set(MAKE_POLYHOOK_DEPENDENCIES_SHARED ON) - set(MAKE_POLYHOOK_DEPENDENCIES_STATIC OFF) -else () - set(MAKE_POLYHOOK_DEPENDENCIES_SHARED OFF) - set(MAKE_POLYHOOK_DEPENDENCIES_STATIC ON) -endif () - - -set(POLYHOOK_BUILD_DLL ON CACHE BOOL "Build dll & lib instead of tests" FORCE) -set(POLYHOOK_BUILD_SHARED_LIB ${MAKE_POLYHOOK_DEPENDENCIES_SHARED} CACHE BOOL "Build polyhook2 as shared libary" FORCE) -set(POLYHOOK_USE_EXTERNAL_ZYDIS ON CACHE BOOL "Use external zydis libary" FORCE) -set(ASMJIT_STATIC ${MAKE_POLYHOOK_DEPENDENCIES_STATIC} CACHE BOOL "Build 'asmjit' library as static" FORCE) -set(POLYHOOK_BUILD_STATIC_RUNTIME OFF CACHE BOOL "Use static runtime" FORCE) - -# add a conditional for disabling 'set_target_properties' on demand to prevent PolyHook from setting MSVC_RUNTIME_LIBRARY to "MultiThreaded$<$:Debug>DLL" -if(NOT DEFINED _DISABLE_SET_PROPERTIES) - set(_DISABLE_SET_PROPERTIES TRUE) - - macro(set_target_properties) - if (NOT _DISABLE_SET_PROPERTIES) - _set_target_properties(${ARGV}) - endif() - endmacro() -endif() - -# add a conditional for disabling 'install' on demand -if(NOT DEFINED _DISABLE_INSTALL) - set(_DISABLE_INSTALL TRUE) - - macro(install) - if (NOT _DISABLE_INSTALL) - _install(${ARGV}) - endif() - endmacro() -endif() - -FetchContent_Declare(PolyHook2 - PREFIX ${CMAKE_CURRENT_BINARY_DIR}/PolyHook2 - GIT_REPOSITORY git@github.com:stevemk14ebr/PolyHook_2_0.git - GIT_TAG 16bc0faf77a15b91b72763353901cfe34daf3174 - GIT_PROGRESS ON) - -FetchContent_MakeAvailable(PolyHook2) - -# re-enable 'set_target_properties' and 'install' since we're done adding PolyHook -set(_DISABLE_SET_PROPERTIES FALSE) -set(_DISABLE_INSTALL FALSE) diff --git a/deps/third/safetyhook/CMakeLists.txt b/deps/third/safetyhook/CMakeLists.txt new file mode 100644 index 000000000..6b612c9af --- /dev/null +++ b/deps/third/safetyhook/CMakeLists.txt @@ -0,0 +1,10 @@ +include(FetchContent) + +set(FETCHCONTENT_QUIET OFF) + +FetchContent_Declare( + safetyhook + GIT_REPOSITORY "https://github.com/UE4SS-RE/safetyhook.git" + GIT_TAG "4def59079b95e08dc086cecf5515abde377059e5" +) +FetchContent_MakeAvailable(safetyhook) \ No newline at end of file diff --git a/deps/third/zydis/CMakeLists.txt b/deps/third/zydis/CMakeLists.txt index d9e5f41c1..b31be8575 100644 --- a/deps/third/zydis/CMakeLists.txt +++ b/deps/third/zydis/CMakeLists.txt @@ -19,7 +19,7 @@ set(ASMJIT_NO_CUSTOM_FLAGS ON CACHE BOOL "" FORCE) FetchContent_Declare(zydis PREFIX ${CMAKE_CURRENT_BINARY_DIR}/zydis GIT_REPOSITORY git@github.com:zyantific/zydis.git - GIT_TAG v3.1.0 + GIT_TAG v4.0.0 GIT_PROGRESS ON) FetchContent_MakeAvailable(zydis)