feat(Hooking): Easier declaring of detour hooks and quick prototyping (#544)

This commit is contained in:
Quentin E. / iDeath 2022-10-30 19:32:51 +01:00 committed by GitHub
parent b65e0c7ae5
commit 7c64e4d31f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 198 additions and 149 deletions

View File

@ -6,10 +6,28 @@
namespace big
{
detour_hook::detour_hook(std::string name, void* detour) :
m_name(std::move(name)),
m_detour(detour)
{
}
detour_hook::detour_hook(std::string name, void* target, void* detour) :
m_name(std::move(name)),
m_target(target),
m_detour(detour)
{
create_hook();
}
void detour_hook::set_target_and_create_hook(void* target)
{
m_target = target;
create_hook();
}
void detour_hook::create_hook()
{
fix_hook_address();
if (auto status = MH_CreateHook(m_target, m_detour, &m_original); status != MH_OK)

View File

@ -5,7 +5,8 @@ namespace big
class detour_hook
{
public:
explicit detour_hook(std::string name, void *target, void *detour);
explicit detour_hook(std::string name, void* detour);
explicit detour_hook(std::string name, void *target, void* detour);
~detour_hook() noexcept;
detour_hook(detour_hook&& that) = delete;
@ -13,23 +14,25 @@ namespace big
detour_hook(detour_hook const&) = delete;
detour_hook& operator=(detour_hook const&) = delete;
void set_target_and_create_hook(void* target);
void enable();
void disable();
template <typename T>
T get_original();
T get_original()
{
return static_cast<T>(m_original);
}
void fix_hook_address();
private:
std::string m_name;
void *m_target;
void *m_detour;
void *m_original{};
};
template <typename T>
inline T detour_hook::get_original()
{
return static_cast<T>(m_original);
}
private:
void create_hook();
std::string m_name;
void *m_original{};
void* m_target{};
void* m_detour{};
};
}

View File

@ -18,62 +18,57 @@ namespace big
{
hooking::hooking() :
// Swapchain
m_swapchain_hook(*g_pointers->m_swapchain, hooks::swapchain_num_funcs),
// Script Hook
m_run_script_threads_hook("SH", g_pointers->m_run_script_threads, &hooks::run_script_threads),
// Get Label Text
m_get_label_text("GLT", g_pointers->m_get_label_text, &hooks::get_label_text),
// Multiplayer chat filter
m_multiplayer_chat_filter("MCF", g_pointers->m_multiplayer_chat_filter, &hooks::multiplayer_chat_filter),
// Write Player Game State Data Node
m_write_player_game_state_data_node_hook("WPGSDN", g_pointers->m_write_player_game_state_data_node, &hooks::write_player_game_state_data_node),
// GTA Thead Start
m_gta_thread_start_hook("GTS", g_pointers->m_gta_thread_start, &hooks::gta_thread_start),
// GTA Thread Kill
m_gta_thread_kill_hook("GTK", g_pointers->m_gta_thread_kill, &hooks::gta_thread_kill),
// Network Player Mgr Init
m_network_player_mgr_init_hook("NPMI", g_pointers->m_network_player_mgr_init, &hooks::network_player_mgr_init),
// Network Player Mgr Shutdown
m_network_player_mgr_shutdown_hook("NPMS", g_pointers->m_network_player_mgr_shutdown, &hooks::network_player_mgr_shutdown),
// Network Group Override
m_network_group_override("NGO", g_pointers->m_network_group_override, &hooks::network_group_override),
// Received Event
m_received_event_hook("RE", g_pointers->m_received_event, &hooks::received_event),
// Send NET Info to Lobby
m_send_net_info_to_lobby("SNITL", g_pointers->m_send_net_info_to_lobby, &hooks::send_net_info_to_lobby),
// Assign Physical Index
m_assign_physical_index_hook("API", g_pointers->m_assign_physical_index, &hooks::assign_physical_index),
// Receive Net Message
m_receive_net_message_hook("RNM", g_pointers->m_receive_net_message, &hooks::receive_net_message),
// Received clone sync
m_received_clone_sync_hook("RCS", g_pointers->m_received_clone_sync, &hooks::received_clone_sync),
//Get Network Event Data
m_get_network_event_data_hook("GNED", g_pointers->m_get_network_event_data, &hooks::get_network_event_data),
m_write_player_gamer_data_node_hook("WPGDN", g_pointers->m_write_player_gamer_data_node, &hooks::write_player_gamer_data_node),
// Format Metric For Sending
m_format_metric_for_sending("FMFS", g_pointers->m_format_metric_for_sending, &hooks::format_metric_for_sending)
m_swapchain_hook(*g_pointers->m_swapchain, hooks::swapchain_num_funcs)
{
m_swapchain_hook.hook(hooks::swapchain_present_index, &hooks::swapchain_present);
m_swapchain_hook.hook(hooks::swapchain_resizebuffers_index, &hooks::swapchain_resizebuffers);
// The only instances in that vector at this point should only be the "lazy" hooks
// aka the ones that still don't have their m_target assigned
for (auto& detour_hook_helper : m_detour_hook_helpers)
{
detour_hook_helper->m_detour_hook->set_target_and_create_hook(detour_hook_helper->m_on_hooking_available());
}
detour_hook_helper::add<hooks::run_script_threads>("SH", g_pointers->m_run_script_threads);
detour_hook_helper::add<hooks::get_label_text>("GLT", g_pointers->m_get_label_text);
detour_hook_helper::add<hooks::multiplayer_chat_filter>("MCF", g_pointers->m_multiplayer_chat_filter);
detour_hook_helper::add<hooks::write_player_game_state_data_node>("WPGSDN", g_pointers->m_write_player_game_state_data_node);
detour_hook_helper::add<hooks::gta_thread_start>("GTS", g_pointers->m_gta_thread_start);
detour_hook_helper::add<hooks::gta_thread_kill>("GTK", g_pointers->m_gta_thread_kill);
detour_hook_helper::add<hooks::network_player_mgr_init>("NPMI", g_pointers->m_network_player_mgr_init);
detour_hook_helper::add<hooks::network_player_mgr_shutdown>("NPMS", g_pointers->m_network_player_mgr_shutdown);
detour_hook_helper::add<hooks::network_group_override>("NGO", g_pointers->m_network_group_override);
detour_hook_helper::add<hooks::received_event>("RE", g_pointers->m_received_event);
detour_hook_helper::add<hooks::send_net_info_to_lobby>("SNITL", g_pointers->m_send_net_info_to_lobby);
detour_hook_helper::add<hooks::assign_physical_index>("API", g_pointers->m_assign_physical_index);
detour_hook_helper::add<hooks::receive_net_message>("RNM", g_pointers->m_receive_net_message);
detour_hook_helper::add<hooks::received_clone_sync>("RCS", g_pointers->m_received_clone_sync);
detour_hook_helper::add<hooks::get_network_event_data>("GNED", g_pointers->m_get_network_event_data);
detour_hook_helper::add<hooks::write_player_gamer_data_node>("WPGDN", g_pointers->m_write_player_gamer_data_node);
detour_hook_helper::add<hooks::format_metric_for_sending>("FMFS", g_pointers->m_format_metric_for_sending);
g_hooking = this;
}
hooking::~hooking()
{
if (m_enabled)
{
disable();
}
g_hooking = nullptr;
}
@ -83,23 +78,10 @@ namespace big
m_swapchain_hook.enable();
m_og_wndproc = WNDPROC(SetWindowLongPtrW(g_pointers->m_hwnd, GWLP_WNDPROC, LONG_PTR(&hooks::wndproc)));
m_run_script_threads_hook.enable();
m_get_label_text.enable();
m_multiplayer_chat_filter.enable();
m_gta_thread_start_hook.enable();
m_gta_thread_kill_hook.enable();
m_network_group_override.enable();
m_network_player_mgr_init_hook.enable();
m_network_player_mgr_shutdown_hook.enable();
m_assign_physical_index_hook.enable();
m_received_event_hook.enable();
m_send_net_info_to_lobby.enable();
m_receive_net_message_hook.enable();
m_get_network_event_data_hook.enable();
m_received_clone_sync_hook.enable();
m_write_player_gamer_data_node_hook.enable();
m_write_player_game_state_data_node_hook.enable();
m_format_metric_for_sending.enable();
for (const auto& detour_hook_helper : m_detour_hook_helpers)
{
detour_hook_helper->m_detour_hook->enable();
}
MH_ApplyQueued();
@ -110,28 +92,40 @@ namespace big
{
m_enabled = false;
m_format_metric_for_sending.disable();
m_write_player_game_state_data_node_hook.disable();
m_write_player_gamer_data_node_hook.disable();
m_received_clone_sync_hook.disable();
m_get_network_event_data_hook.disable();
m_receive_net_message_hook.disable();
m_send_net_info_to_lobby.disable();
m_received_event_hook.disable();
m_assign_physical_index_hook.disable();
m_network_player_mgr_init_hook.disable();
m_network_player_mgr_shutdown_hook.disable();
m_network_group_override.disable();
m_gta_thread_kill_hook.disable();
m_gta_thread_start_hook.disable();
m_multiplayer_chat_filter.disable();
m_get_label_text.disable();
m_run_script_threads_hook.disable();
MH_ApplyQueued();
for (const auto& detour_hook_helper : m_detour_hook_helpers)
{
detour_hook_helper->m_detour_hook->disable();
}
SetWindowLongPtrW(g_pointers->m_hwnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(m_og_wndproc));
m_swapchain_hook.disable();
MH_ApplyQueued();
for (const auto& detour_hook_helper : m_detour_hook_helpers)
{
delete detour_hook_helper;
}
m_detour_hook_helpers.clear();
}
hooking::detour_hook_helper::~detour_hook_helper()
{
delete m_detour_hook;
}
void hooking::detour_hook_helper::enable_hook_if_hooking_is_already_running()
{
if (g_hooking && g_hooking->m_enabled)
{
if (m_on_hooking_available)
{
m_detour_hook->set_target_and_create_hook(m_on_hooking_available());
}
m_detour_hook->enable();
MH_ApplyQueued();
}
}
bool hooks::run_script_threads(std::uint32_t ops_to_execute)
@ -143,6 +137,6 @@ namespace big
g_script_mgr.tick();
}
return g_hooking->m_run_script_threads_hook.get_original<functions::run_script_threads>()(ops_to_execute);
return g_hooking->get_original<run_script_threads>()(ops_to_execute);
}
}

View File

@ -90,6 +90,65 @@ namespace big
void enable();
void disable();
class detour_hook_helper
{
friend hooking;
using ret_ptr_fn = std::function<void* ()>;
ret_ptr_fn m_on_hooking_available = nullptr;
detour_hook* m_detour_hook = nullptr;
~detour_hook_helper();
void enable_hook_if_hooking_is_already_running();
template <auto detour_function>
struct hook_to_detour_hook_helper
{
static inline detour_hook* m_detour_hook;
};
template <auto detour_function>
static detour_hook_helper* add_internal(detour_hook* dh)
{
auto d = new detour_hook_helper();
d->m_detour_hook = dh;
m_detour_hook_helpers.push_back(d);
hook_to_detour_hook_helper<detour_function>::m_detour_hook = dh;
return d;
}
public:
template <auto detour_function>
static void add(const std::string& name, void* target)
{
auto d = add_internal<detour_function>(new detour_hook(name, target, detour_function));
d->enable_hook_if_hooking_is_already_running();
}
template <auto detour_function>
static void* add_lazy(const std::string& name, detour_hook_helper::ret_ptr_fn on_hooking_available)
{
auto d = add_internal<detour_function>(new detour_hook(name, detour_function));
d->m_on_hooking_available = on_hooking_available;
d->enable_hook_if_hooking_is_already_running();
return nullptr;
}
};
template <auto detour_function>
static auto get_original()
{
return detour_hook_helper::hook_to_detour_hook_helper<detour_function>::m_detour_hook->get_original<decltype(detour_function)>();
}
private:
bool m_enabled{};
minhook_keepalive m_minhook_keepalive;
@ -98,33 +157,8 @@ namespace big
WNDPROC m_og_wndproc = nullptr;
detour_hook m_run_script_threads_hook;
detour_hook m_get_label_text;
detour_hook m_multiplayer_chat_filter;
detour_hook m_gta_thread_start_hook;
detour_hook m_gta_thread_kill_hook;
detour_hook m_network_player_mgr_init_hook;
detour_hook m_network_player_mgr_shutdown_hook;
detour_hook m_network_group_override;
detour_hook m_assign_physical_index_hook;
detour_hook m_received_event_hook;
detour_hook m_received_clone_sync_hook;
detour_hook m_send_net_info_to_lobby;
detour_hook m_receive_net_message_hook;
detour_hook m_get_network_event_data_hook;
detour_hook m_format_metric_for_sending;
detour_hook m_write_player_gamer_data_node_hook;
detour_hook m_write_player_game_state_data_node_hook;
static inline std::vector<detour_hook_helper*> m_detour_hook_helpers;
};
inline hooking *g_hooking{};
inline hooking* g_hooking{};
}

View File

@ -12,6 +12,6 @@ namespace big
}
}
return g_hooking->m_get_network_event_data_hook.get_original<decltype(&get_network_event_data)>()(unk, net_event);
return g_hooking->get_original<get_network_event_data>()(unk, net_event);
}
}
}

View File

@ -8,6 +8,6 @@ namespace big
if (const auto text = g_custom_text_service->get_text(label); text)
return text;
return g_hooking->m_get_label_text.get_original<decltype(&get_label_text)>()(unk, label);
return g_hooking->get_original<get_label_text>()(unk, label);
}
}

View File

@ -8,6 +8,6 @@ namespace big
{
return -1;
}
return g_hooking->m_multiplayer_chat_filter.get_original<decltype(&hooks::multiplayer_chat_filter)>()(chat_type, input, output);
return g_hooking->get_original<hooks::multiplayer_chat_filter>()(chat_type, input, output);
}
}

View File

@ -5,15 +5,15 @@ namespace big
{
rage::eThreadState hooks::gta_thread_kill(GtaThread* thread)
{
const auto result = g_hooking->m_gta_thread_kill_hook.get_original<decltype(&gta_thread_kill)>()(thread);
const auto result = g_hooking->get_original<gta_thread_kill>()(thread);
if (g->notifications.gta_thread_kill.log)
LOG(INFO) << "Script Thread '" << thread->m_name << "' terminated.";
if (g->notifications.gta_thread_kill.notify)
g_notification_service->push("Script Thread Termination", std::format("Script Thread '{}' terminated.", thread->m_name));
g_native_hooks->do_cleanup_for_thread(thread);
return result;
}
}
}

View File

@ -5,7 +5,7 @@ namespace big
{
GtaThread* hooks::gta_thread_start(unsigned int** a1, unsigned int a2)
{
GtaThread* new_thread = g_hooking->m_gta_thread_start_hook.get_original<decltype(&hooks::gta_thread_start)>()(a1, a2);
GtaThread* new_thread = g_hooking->get_original<hooks::gta_thread_start>()(a1, a2);
if (const char* name = new_thread->m_name; strlen(name) > 0)
{
@ -20,4 +20,4 @@ namespace big
return new_thread;
}
}
}

View File

@ -6,9 +6,9 @@ namespace big
{
void* hooks::assign_physical_index(CNetworkPlayerMgr* netPlayerMgr, CNetGamePlayer* player, uint8_t new_index)
{
const auto result = g_hooking->m_assign_physical_index_hook.get_original<decltype(&hooks::assign_physical_index)>()(netPlayerMgr, player, new_index);
const auto result = g_hooking->get_original<hooks::assign_physical_index>()(netPlayerMgr, player, new_index);
const auto* net_player_data = player->get_net_data();
if (new_index == static_cast<uint8_t>(-1))
{
g_player_service->player_leave(player);
@ -43,4 +43,4 @@ namespace big
}
return result;
}
}
}

View File

@ -10,7 +10,7 @@ namespace big
if (g->notifications.network_player_mgr_init.notify)
g_notification_service->push("Network Player Manager", "Entering session and initializing player data.");
g_hooking->m_network_player_mgr_init_hook.get_original<decltype(&hooks::network_player_mgr_init)>()(_this, a2, a3, a4);
g_hooking->get_original<hooks::network_player_mgr_init>()(_this, a2, a3, a4);
g_player_service->player_join(_this->m_local_net_player);
}
@ -24,6 +24,6 @@ namespace big
if (g->notifications.network_player_mgr_shutdown.notify)
g_notification_service->push("Network Player Manager", "Leaving session and cleaning up player data.");
g_hooking->m_network_player_mgr_shutdown_hook.get_original<decltype(&hooks::network_player_mgr_shutdown)>()(_this);
g_hooking->get_original<hooks::network_player_mgr_shutdown>()(_this);
}
}
}

View File

@ -13,6 +13,6 @@ namespace big
}
// original
return g_hooking->m_network_group_override.get_original<decltype(&network_group_override)>()(a1, a2, a3);
return g_hooking->get_original<network_group_override>()(a1, a2, a3);
}
}
}

View File

@ -91,6 +91,6 @@ namespace big
}
}
return g_hooking->m_receive_net_message_hook.get_original<decltype(&hooks::receive_net_message)>()(netConnectionManager, a2, frame);
return g_hooking->get_original<hooks::receive_net_message>()(netConnectionManager, a2, frame);
}
}

View File

@ -20,7 +20,7 @@ namespace big
CantApplyData_NetworkClosed = 7, // Can't apply data - network closed
SuccessfullSync = 8
};
int64_t hooks::received_clone_sync(CNetworkObjectMgr* mgr, CNetGamePlayer* src, CNetGamePlayer* dst, eObjType sync_type, uint16_t obj_id, rage::datBitBuffer* buffer, uint16_t unk, uint32_t timestamp) {
if (auto sync_tree = g_pointers->m_get_sync_tree_for_type(mgr, sync_type); sync_tree && *g_pointers->m_is_session_started)
{
@ -68,8 +68,8 @@ namespace big
return SyncResponse::WrongOwner;
}
}
return g_hooking->m_received_clone_sync_hook.get_original<decltype(&received_clone_sync)>()(mgr, src, dst, sync_type, obj_id, buffer, unk, timestamp);
return g_hooking->get_original<received_clone_sync>()(mgr, src, dst, sync_type, obj_id, buffer, unk, timestamp);
}
}
}

View File

@ -178,6 +178,6 @@ namespace big
break;
}
return g_hooking->m_received_event_hook.get_original<decltype(&received_event)>()(event_manager, source_player, target_player, event_id, event_index, event_handled_bitset, unk, buffer);
return g_hooking->get_original<received_event>()(event_manager, source_player, target_player, event_id, event_index, event_handled_bitset, unk, buffer);
}
}
}

View File

@ -32,7 +32,7 @@ namespace big
g_notification_service->push("Player Info Spoofing", "Sent spoofed values to lobby host.");
}
const auto result = g_hooking->m_send_net_info_to_lobby.get_original<decltype(&hooks::send_net_info_to_lobby)>()(player, a2, a3, a4);
const auto result = g_hooking->get_original<hooks::send_net_info_to_lobby>()(player, a2, a3, a4);
// restore player name to prevent detection of spoofed name
if (is_local_player && g->spoofing.spoof_username)
@ -40,4 +40,4 @@ namespace big
return result;
}
}
}

View File

@ -4,7 +4,7 @@ namespace big
{
bool hooks::write_player_game_state_data_node(rage::netObject* player, CPlayerGameStateDataNode* node)
{
auto ret = g_hooking->m_write_player_game_state_data_node_hook.get_original<decltype(&write_player_game_state_data_node)>()(player, node);
auto ret = g_hooking->get_original<write_player_game_state_data_node>()(player, node);
if (g->spoofing.spoof_hide_god)
node->m_is_invincible = false;

View File

@ -4,7 +4,7 @@ namespace big
{
void hooks::write_player_gamer_data_node(rage::netObject* player, CPlayerGamerDataNode* node)
{
g_hooking->m_write_player_gamer_data_node_hook.get_original<decltype(&write_player_gamer_data_node)>()(player, node);
g_hooking->get_original<write_player_gamer_data_node>()(player, node);
if (g->spoofing.spoof_crew_data)
{