Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace polyhook with safetyhook #239

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion UE4SS/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,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)

Expand Down
5 changes: 2 additions & 3 deletions UE4SS/include/CrashDumper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

#include <memory>

#include <polyhook2/PE/IatHook.hpp>
#include <safetyhook.hpp>

namespace RC
{
Expand All @@ -11,8 +11,7 @@ namespace RC
private:
bool enabled = false;
void* m_previous_exception_filter = nullptr;
std::unique_ptr<PLH::IatHook> 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();
Expand Down
17 changes: 6 additions & 11 deletions UE4SS/include/UE4SSProgram.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
#include <Unreal/TArray.hpp>
#include <Unreal/UnrealVersion.hpp>

#include <safetyhook.hpp>

// Used to set up ImGui context and allocator in DLL mods
#define UE4SS_ENABLE_IMGUI() \
{ \
Expand Down Expand Up @@ -109,17 +111,10 @@ namespace RC
std::mutex m_event_queue_mutex{};

private:
std::unique_ptr<PLH::IatHook> m_load_library_a_hook;
uint64_t m_hook_trampoline_load_library_a;

std::unique_ptr<PLH::IatHook> m_load_library_ex_a_hook;
uint64_t m_hook_trampoline_load_library_ex_a;

std::unique_ptr<PLH::IatHook> m_load_library_w_hook;
uint64_t m_hook_trampoline_load_library_w;

std::unique_ptr<PLH::IatHook> 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<std::unique_ptr<Mod>> m_mods;
Expand Down
10 changes: 2 additions & 8 deletions UE4SS/src/CrashDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,21 +75,15 @@ namespace RC

CrashDumper::~CrashDumper()
{
m_set_unhandled_exception_filter_hook->unHook();
m_set_unhandled_exception_filter_hook = {};
SetUnhandledExceptionFilter(reinterpret_cast<LPTOP_LEVEL_EXCEPTION_FILTER>(m_previous_exception_filter));
}

void CrashDumper::enable()
{
SetErrorMode(SEM_FAILCRITICALERRORS);
m_previous_exception_filter = SetUnhandledExceptionFilter(ExceptionHandler);

m_set_unhandled_exception_filter_hook = std::make_unique<PLH::IatHook>("kernel32.dll",
"SetUnhandledExceptionFilter",
std::bit_cast<uint64_t>(&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;
}

Expand Down
43 changes: 9 additions & 34 deletions UE4SS/src/UE4SSProgram.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,31 +128,31 @@ 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<HMODULE>(dll_name);
program.fire_dll_load_for_cpp_mods(to_wstring(dll_name));
return lib;
}

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<HMODULE>(dll_name, file, flags);
program.fire_dll_load_for_cpp_mods(to_wstring(dll_name));
return lib;
}

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<HMODULE>(dll_name);
program.fire_dll_load_for_cpp_mods(dll_name);
return lib;
}

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<HMODULE>(dll_name, file, flags);
program.fire_dll_load_for_cpp_mods(dll_name);
return lib;
}
Expand Down Expand Up @@ -227,36 +227,11 @@ namespace RC
#else
#define UE4SS_COMPILER L"MSVC"
#endif

Output::send(STR("UE4SS Build Configuration: {} ({})\n"), to_wstring(UE4SS_CONFIGURATION), UE4SS_COMPILER);

m_load_library_a_hook = std::make_unique<PLH::IatHook>("kernel32.dll",
"LoadLibraryA",
std::bit_cast<uint64_t>(&HookedLoadLibraryA),
&m_hook_trampoline_load_library_a,
L"");
m_load_library_a_hook->hook();

m_load_library_ex_a_hook = std::make_unique<PLH::IatHook>("kernel32.dll",
"LoadLibraryExA",
std::bit_cast<uint64_t>(&HookedLoadLibraryExA),
&m_hook_trampoline_load_library_ex_a,
L"");
m_load_library_ex_a_hook->hook();

m_load_library_w_hook = std::make_unique<PLH::IatHook>("kernel32.dll",
"LoadLibraryW",
std::bit_cast<uint64_t>(&HookedLoadLibraryW),
&m_hook_trampoline_load_library_w,
L"");
m_load_library_w_hook->hook();

m_load_library_ex_w_hook = std::make_unique<PLH::IatHook>("kernel32.dll",
"LoadLibraryExW",
std::bit_cast<uint64_t>(&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();

Expand Down
1 change: 1 addition & 0 deletions deps/first/ASMHelper/include/ASMHelper/ASMHelper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
11 changes: 6 additions & 5 deletions deps/first/ASMHelper/src/ASMHelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,15 @@ namespace RC::ASM
{
auto instruction_ptr = static_cast<uint8_t*>(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
Expand All @@ -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<ZyanU64>(in_instruction_ptr), &resolved_address)))
if (ZYAN_SUCCESS(ZydisCalcAbsoluteAddress(&instruction.raw, &instruction.operands[0], std::bit_cast<ZyanU64>(in_instruction_ptr), &resolved_address)))
{
return std::bit_cast<void*>(resolved_address);
}
Expand Down
2 changes: 2 additions & 0 deletions deps/first/Helpers/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
21 changes: 21 additions & 0 deletions deps/first/Helpers/include/Helpers/Hook.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#pragma once

#include <Function/Function.hpp>

#include <safetyhook.hpp>

namespace RC::Helper::Hook
{
template <typename>
class call_hook;

template <typename ReturnType, typename... Params>
class call_hook<Function<ReturnType(Params...)>>
{
public:
ReturnType operator()(SafetyHookInline& hook, Params... args)
{
return hook.call<ReturnType, Params...>(std::forward<Params>(args)...);
}
};
} // namespace RC::Helper::Hook
24 changes: 13 additions & 11 deletions deps/third/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,42 +23,44 @@ FetchContent_Declare(ImGui
GIT_SHALLOW TRUE
GIT_PROGRESS ON
CONFIGURE_COMMAND "")

FetchContent_Declare(ImGuiTextEdit
GIT_REPOSITORY [email protected]:UE4SS-RE/ImGuiColorTextEdit.git
GIT_TAG master
GIT_SHALLOW TRUE
GIT_PROGRESS ON
CONFIGURE_COMMAND "")

add_subdirectory("imgui")
# ImGui end

# Zydis start
FetchContent_Declare(zydis
GIT_REPOSITORY [email protected]:zyantific/zydis.git
GIT_TAG v3.1.0
GIT_TAG v4.0.0
GIT_SHALLOW TRUE
GIT_PROGRESS ON)

add_subdirectory("zydis")
# Zydis end

# PolyHook start
FetchContent_Declare(PolyHook2
GIT_REPOSITORY [email protected]:stevemk14ebr/PolyHook_2_0.git
GIT_TAG 16bc0faf77a15b91b72763353901cfe34daf3174
# safetyhook start
FetchContent_Declare(
safetyhook
GIT_REPOSITORY "https://github.com/UE4SS-RE/safetyhook.git"
GIT_TAG "4def59079b95e08dc086cecf5515abde377059e5"
GIT_PROGRESS ON)
FetchContent_MakeAvailable(safetyhook)

add_subdirectory("PolyHook_2_0")
# PolyHook end
add_subdirectory("safetyhook")
# safetyhook end

# raw_pdb start
FetchContent_Declare(raw_pdb
GIT_REPOSITORY [email protected]:MolecularMatters/raw_pdb.git
GIT_TAG 8c6a7146393c83d27fa101e8bc8017f2a7f151df
GIT_PROGRESS ON)

add_subdirectory("raw_pdb")
# raw_pdb end
# Third Party Depenedencies
53 changes: 0 additions & 53 deletions deps/third/PolyHook_2_0/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,53 +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$<$<CONFIG:Debug>: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_MakeAvailable(PolyHook2)

# re-enable 'set_target_properties' and 'install' since we're done adding PolyHook
set(_DISABLE_SET_PROPERTIES FALSE)
set(_DISABLE_INSTALL FALSE)
10 changes: 10 additions & 0 deletions deps/third/safetyhook/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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)