From 70d04aa1cea219c09857a9f508f48f6bc9077fab Mon Sep 17 00:00:00 2001 From: Reece Watson <45642596+SkiddyToast@users.noreply.github.com> Date: Fri, 20 May 2022 18:17:41 -0400 Subject: [PATCH] feat(Protections): Added desync protection and notification (Closes #156) (#220) * feat(Protections): Added desync protection and notification (#156) * fix(Protections): Fix warning and revert Premake VS version --- BigBaseV2/src/gta/net_game_event.hpp | 150 ++++++++++++++++++ BigBaseV2/src/hooking.cpp | 12 +- BigBaseV2/src/hooking.hpp | 4 + .../src/hooks/get_network_event_data.cpp | 19 +++ BigBaseV2/src/hooks/receive_net_message.cpp | 82 ++++++++++ BigBaseV2/src/pointers.cpp | 12 ++ BigBaseV2/src/pointers.hpp | 3 + BigBaseV2/src/services/player_service.cpp | 22 +++ BigBaseV2/src/services/player_service.hpp | 2 + 9 files changed, 305 insertions(+), 1 deletion(-) create mode 100644 BigBaseV2/src/hooks/get_network_event_data.cpp create mode 100644 BigBaseV2/src/hooks/receive_net_message.cpp diff --git a/BigBaseV2/src/gta/net_game_event.hpp b/BigBaseV2/src/gta/net_game_event.hpp index f6999c16..45ebc86e 100644 --- a/BigBaseV2/src/gta/net_game_event.hpp +++ b/BigBaseV2/src/gta/net_game_event.hpp @@ -140,6 +140,156 @@ namespace rage uint32_t m_f20; }; + namespace netConnection { + class InFrame + { + public: + virtual ~InFrame() = default; + + virtual void destroy() = 0; + virtual uint32_t get_type() = 0; + virtual uint32_t _0x18() = 0; + + char pad_0008[56]; //0x0008 + uint32_t m_msg_id; //0x0040 + char pad_0044[4]; //0x0044 + InFrame* m_this; //0x0048 + char pad_0050[40]; //0x0050 + uint32_t m_length; //0x0078 + char pad_007C[4]; //0x007C + void* m_data; //0x0080 + }; + + enum class MessageType : std::uint32_t + { + MsgInvalid = 0xFFFFF, + MsgSessionAcceptChat = 0x62, + MsgStartMatchCmd = 0x2D, + MsgSetInvitableCmd = 0x1F, + MsgSessionMemberIds = 0x23, + MsgRequestGamerInfo = 0x54, + MsgRemoveGamersFromSessionCmd = 0x53, + MsgNotMigrating = 0x35, + MsgMigrateHostResponse = 0x12, + MsgMigrateHostRequest = 0x66, + MsgJoinResponse = 0x2A, + MsgJoinRequest = 0x41, + MsgHostLeftWhilstJoiningCmd = 0x58, + MsgConfigResponse = 0x5F, + MsgConfigRequest = 0x48, + MsgChangeSessionAttributesCmd = 0x5A, + MsgAddGamerToSessionCmd = 0x64, // this is where send net info to lobby is called, among other things + MsgReassignResponse = 0x10, + MsgReassignNegotiate = 0x01, + MsgReassignConfirm = 0x26, + MsgPlayerData = 0x18, + MsgPackedReliables = 0x30, + MsgPackedCloneSyncACKs = 0x3B, + MsgNonPhysicalData = 0x16, + MsgNetArrayMgrUpdateAck = 0x5D, + MsgNetArrayMgrUpdate = 0x60, + MsgNetArrayMgrSplitUpdateAck = 0x25, + MsgScriptVerifyHostAck = 0x0B, + MsgScriptVerifyHost = 0x3E, + MsgScriptNewHost = 0x0E, + MsgScriptMigrateHostFailAck = 0x1A, + MsgScriptMigrateHost = 0x33, + MsgScriptLeaveAck = 0x40, + MsgScriptLeave = 0x17, + MsgScriptJoinHostAck = 0x4D, + MsgScriptJoinAck = 0x43, + MsgScriptJoin = 0x5C, + MsgScriptHostRequest = 0x67, + MsgScriptHandshakeAck = 0x5B, + MsgScriptHandshake = 0x57, + MsgScriptBotLeave = 0x2B, // unused? + MsgScriptBotJoinAck = 0x63, // unused? + MsgScriptBotJoin = 0x1C, // unused? + MsgScriptBotHandshakeAck = 0x31, // unused? + MsgScriptBotHandshake = 0x4B, // unused? + MsgPartyLeaveGame = 0x3D, + MsgPartyEnterGame = 0x1E, + MsgCloneSync = 0x4E, // aka clone_create, clone_sync etc. + MsgActivateNetworkBot = 0x65, // unused? + MsgRequestObjectIds = 0x29, + MsgInformObjectIds = 0x09, + MsgTextMessage = 0x24, // this one is for chat + MsgPlayerIsTyping = 0x61, + MsgPackedEvents = 0x4F, // aka received_event + MsgPackedEventReliablesMsgs = 0x20, + MsgRequestKickFromHost = 0x0D, + MsgTransitionToGameStart = 0x50, + MsgTransitionToGameNotify = 0x02, + MsgTransitionToActivityStart = 0x06, + MsgTransitionToActivityFinish = 0x36, + MsgTransitionParameters = 0x3C, + MsgTransitionParameterString = 0x37, + MsgTransitionLaunchNotify = 0x1B, + MsgTransitionLaunch = 0x19, + MsgTransitionGamerInstruction = 0x14, + MsgTextMessage2 = 0x0A, // this one is for phone message + MsgSessionEstablishedRequest = 0x52, + MsgSessionEstablished = 0x07, + MsgRequestTransitionParameters = 0x42, + MsgRadioStationSyncRequest = 0x47, + MsgRadioStationSync = 0x46, + MsgPlayerCardSync = 0x3A, + MsgPlayerCardRequest = 0x6A, + MsgLostConnectionToHost = 0x81, + MsgKickPlayer = 0x34, // host kick + MsgDebugStall = 0x7E, // unused? + MsgCheckQueuedJoinRequestReply = 0x59, + MsgCheckQueuedJoinRequest = 0x51, + MsgBlacklist = 0x0C, + MsgRoamingRequestBubbleRequiredResponse = 0x83, + MsgRoamingRequestBubbleRequiredCheck = 0x82, + MsgRoamingRequestBubble = 0x2E, + MsgRoamingJoinBubble = 0x4C, + MsgRoamingJoinBubbleAck = 0x3F, + MsgRoamingInitialBubble = 0x32, + MsgVoiceStatus = 0x03, + MsgTextChatStatus = 0x00, + MsgJoinResponse2 = 0x08, + MsgJoinRequest2 = 0x68, + + MsgNetTimeSync = 0x38, // ctor 40 53 48 83 EC 20 BA ? ? ? ? 4C 8D 0D ? ? ? ? 48 8B D9 44 8D 42 37 + MsgNetComplaint = 0x55, // ctor 40 53 48 83 EC 20 BA ? ? ? ? 4C 8D 0D ? ? ? ? 48 8B D9 44 8D 42 54 + MsgNetLagPing = 0x27, // unused? ctor 40 53 48 83 EC 20 BA ? ? ? ? 4C 8D 0D ? ? ? ? 48 8B D9 44 8D 42 26 + MsgSearchResponse = 0x6B, // unused? ctor 40 53 48 83 EC 20 BA ? ? ? ? 4C 8D 0D ? ? ? ? 48 8B D9 44 8D 42 6A + MsgSearchRequest = 0x05, // unused? + MsgQosProbeResponse = 0x2C, // ctor 40 53 48 83 EC 20 BA ? ? ? ? 4C 8D 0D ? ? ? ? 48 8B D9 44 8D 42 2B + MsgQosProbeRequest = 0x1D, // ctor 40 53 48 83 EC 20 BA ? ? ? ? 4C 8D 0D ? ? ? ? 48 8B D9 44 8D 42 1C + MsgCxnRelayAddressChanged = 0x49, // ctor 40 53 48 83 EC 20 BA ? ? ? ? 4C 8D 0D ? ? ? ? 48 8B D9 44 8D 42 48 + MsgCxnRequestRemoteTimeout = 0x2F, // ctor 40 53 48 83 EC 20 BA ? ? ? ? 4C 8D 0D ? ? ? ? 48 8B D9 44 8D 42 2E + MsgSessionDetailRequest = 0x22, // ctor 40 53 48 83 EC 20 BA ? ? ? ? 4C 8D 0D ? ? ? ? 48 8B D9 44 8D 42 21 + MsgSessionDetailResponse = 0x13, // ctor 40 53 48 83 EC 20 BA ? ? ? ? 4C 8D 0D ? ? ? ? 48 8B D9 44 8D 42 12 + MsgKeyExchangeOffer = 0x0F, // ctor 40 53 48 83 EC 20 BA ? ? ? ? 4C 8D 0D ? ? ? ? 48 8B D9 44 8D 42 0E (last result) + MsgKeyExchangeAnswer = 0x44, // ctor 40 53 48 83 EC 20 BA ? ? ? ? 4C 8D 0D ? ? ? ? 48 8B D9 44 8D 42 43 + + Msg_0x87 = 0x87, + Msg_0x88 = 0x88, + Msg_0x80 = 0x80, + Msg_0x28 = 0x28, + Msg_0x11 = 0x11, + Msg_0x45 = 0x45, + Msg_0x89 = 0x89, + Msg_0x86 = 0x86, + }; + } + + class CEventNetwork + { + public: + virtual ~CEventNetwork() = default; + virtual void unk_0x8() = 0; + virtual void unk_0x10() = 0; + virtual __int64 get_type() = 0; + virtual void unk_0x20() = 0; + virtual void unk_0x28() = 0; + virtual bool get_extra_information(__int64* info_array, int check) = 0; + virtual void unk_0x38() = 0; + }; + class netGameEvent { public: diff --git a/BigBaseV2/src/hooking.cpp b/BigBaseV2/src/hooking.cpp index c9f5a0a5..b0b31d22 100644 --- a/BigBaseV2/src/hooking.cpp +++ b/BigBaseV2/src/hooking.cpp @@ -55,7 +55,11 @@ namespace big // Player Has Joined m_player_has_joined_hook("PHJ", g_pointers->m_player_has_joined, &hooks::player_join), // Player Has Left - m_player_has_left_hook("PHL", g_pointers->m_player_has_left, &hooks::player_leave) + m_player_has_left_hook("PHL", g_pointers->m_player_has_left, &hooks::player_leave), + // Receive Net Message + m_receive_net_message_hook("RNM", g_pointers->m_receive_net_message, &hooks::receive_net_message), + //Get Network Event Data + m_get_network_event_data_hook("GNED", g_pointers->m_get_network_event_data, &hooks::get_network_event_data) { m_swapchain_hook.hook(hooks::swapchain_present_index, &hooks::swapchain_present); m_swapchain_hook.hook(hooks::swapchain_resizebuffers_index, &hooks::swapchain_resizebuffers); @@ -96,6 +100,9 @@ namespace big m_send_net_info_to_lobby.enable(); + m_receive_net_message_hook.enable(); + m_get_network_event_data_hook.enable(); + m_enabled = true; } @@ -103,6 +110,9 @@ namespace big { m_enabled = false; + 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(); diff --git a/BigBaseV2/src/hooking.hpp b/BigBaseV2/src/hooking.hpp index f1e04432..d41b2afb 100644 --- a/BigBaseV2/src/hooking.hpp +++ b/BigBaseV2/src/hooking.hpp @@ -51,6 +51,8 @@ namespace big static bool scripted_game_event(CScriptedGameEvent* scripted_game_event, CNetGamePlayer* player); static bool send_net_info_to_lobby(rage::netPlayerData* player, int64_t a2, int64_t a3, DWORD* a4); + static bool receive_net_message(void* netConnectionManager, void* a2, rage::netConnection::InFrame* frame); + static void get_network_event_data(__int64 a1, rage::CEventNetwork* net_event); }; struct minhook_keepalive @@ -99,6 +101,8 @@ namespace big detour_hook m_received_event_hook; detour_hook m_send_net_info_to_lobby; + detour_hook m_receive_net_message_hook; + detour_hook m_get_network_event_data_hook; }; inline hooking *g_hooking{}; diff --git a/BigBaseV2/src/hooks/get_network_event_data.cpp b/BigBaseV2/src/hooks/get_network_event_data.cpp new file mode 100644 index 00000000..d6eaf42a --- /dev/null +++ b/BigBaseV2/src/hooks/get_network_event_data.cpp @@ -0,0 +1,19 @@ +#include "hooking.hpp" + +namespace big +{ + void hooks::get_network_event_data(__int64 a1, rage::CEventNetwork* net_event) + { + __int64 event_type = net_event->get_type(); + + switch (event_type) { + case 161: //CEventNetworkRemovedFromSessionDueToComplaints + { + g_notification_service->push_warning("Kicked", "You have been desync kicked."); + break; + } + } + + return g_hooking->m_get_network_event_data_hook.get_original()(a1, net_event); + } +} \ No newline at end of file diff --git a/BigBaseV2/src/hooks/receive_net_message.cpp b/BigBaseV2/src/hooks/receive_net_message.cpp new file mode 100644 index 00000000..952d1328 --- /dev/null +++ b/BigBaseV2/src/hooks/receive_net_message.cpp @@ -0,0 +1,82 @@ +#include "hooking.hpp" +#include "services/player_service.hpp" + +namespace big +{ + + inline bool get_message_type(rage::netConnection::MessageType& msg_type, rage::datBitBuffer& buffer) + { + uint32_t pos; + uint32_t magic; + uint32_t length; + uint32_t extended{}; + if ((buffer.m_flagBits & 2) != 0 || (buffer.m_flagBits & 1) == 0 ? (pos = buffer.m_curBit) : (pos = buffer.m_maxBit), + buffer.m_bitsRead + 15 > pos || !buffer.ReadDword(&magic, 14) || magic != 0x3246 || !buffer.ReadDword(&extended, 1)) + { + msg_type = rage::netConnection::MessageType::MsgInvalid; + return false; + } + + length = extended ? 16 : 8; + + if ((buffer.m_flagBits & 1) == 0 ? (pos = buffer.m_curBit) : (pos = buffer.m_maxBit), length + buffer.m_bitsRead <= pos && buffer.ReadDword((uint32_t*)&msg_type, length)) + return true; + else + return false; + } + + bool hooks::receive_net_message(void* netConnectionManager, void* a2, rage::netConnection::InFrame* frame) + { + + if (frame->get_type() == 4) + { + rage::datBitBuffer buffer((uint8_t*)frame->m_data, frame->m_length); + buffer.m_flagBits = 1; + rage::netConnection::MessageType msg_type; + + player* player = g_player_service->get_by_msg_id(frame->m_msg_id); + + if (player && get_message_type(msg_type, buffer)) + { + switch (msg_type) + { + //Desync Kick + case rage::netConnection::MessageType::MsgNetComplaint: + { + uint64_t host_token{}; + buffer.ReadQWord(&host_token, 64); + + std::vector players; + + uint32_t num_of_host_token{}; + buffer.ReadDword(&num_of_host_token, 32); + + if (num_of_host_token <= 64) { + + std::vector host_token_list{}; + for (uint32_t i = 0; i < num_of_host_token; i++) { + + uint64_t array_element{}; + buffer.ReadQWord(&array_element, 64); + host_token_list.push_back(array_element); + + if (CNetGamePlayer* net_player = g_player_service->get_by_host_token(array_element)->get_net_game_player()) + players.push_back(net_player); + + } + + } + + buffer.Seek(0); + + players.at(0)->m_complaints = 10000; + return false; + } + + } + } + } + + return g_hooking->m_receive_net_message_hook.get_original()(netConnectionManager, a2, frame); + } +} \ No newline at end of file diff --git a/BigBaseV2/src/pointers.cpp b/BigBaseV2/src/pointers.cpp index 5ecf32d1..b397d333 100644 --- a/BigBaseV2/src/pointers.cpp +++ b/BigBaseV2/src/pointers.cpp @@ -236,6 +236,18 @@ namespace big m_network_group_override = ptr.as(); }); + //Receive Net Message + main_batch.add("RNM", "48 8B C4 48 89 58 08 48 89 68 10 48 89 70 18 48 89 78 20 41 54 41 56 41 57 48 83 EC 20 4C 8B 71 50 33 ED", [this](memory::handle ptr) + { + m_receive_net_message = ptr.as(); + }); + + //Get Network Event Data + main_batch.add("GNED", "E9 ? ? ? ? E9 ? ? ? ? E9 ? ? ? ? E9 ? ? ? ? E9 ? ? ? ? CC FF 50 28", [this](memory::handle ptr) + { + m_get_network_event_data = ptr.as(); + }); + auto mem_region = memory::module(nullptr); main_batch.run(mem_region); diff --git a/BigBaseV2/src/pointers.hpp b/BigBaseV2/src/pointers.hpp index e684dcf7..aa68ae9b 100644 --- a/BigBaseV2/src/pointers.hpp +++ b/BigBaseV2/src/pointers.hpp @@ -78,6 +78,9 @@ namespace big // Received Event Signatures END PVOID m_send_net_info_to_lobby{}; + + PVOID m_receive_net_message{}; + PVOID m_get_network_event_data{}; }; inline pointers *g_pointers{}; diff --git a/BigBaseV2/src/services/player_service.cpp b/BigBaseV2/src/services/player_service.cpp index 0187887e..37df865c 100644 --- a/BigBaseV2/src/services/player_service.cpp +++ b/BigBaseV2/src/services/player_service.cpp @@ -128,6 +128,28 @@ namespace big return nullptr; } + player* player_service::get_by_msg_id(uint32_t msg_id) + { + std::map>::iterator it; + for (it = m_players.begin(); it != m_players.end(); it++) + { + if (it->second.get()->get_net_game_player()->m_msg_id == msg_id) + return it->second.get(); + } + return nullptr; + } + + player* player_service::get_by_host_token(uint64_t token) + { + std::map>::iterator it; + for (it = m_players.begin(); it != m_players.end(); it++) + { + if (it->second.get()->get_net_data()->m_host_token == token) + return it->second.get(); + } + return nullptr; + } + player* player_service::get_selected() { return m_selected_player == nullptr ? m_dummy_player : m_selected_player; diff --git a/BigBaseV2/src/services/player_service.hpp b/BigBaseV2/src/services/player_service.hpp index c8380301..dc0ecf43 100644 --- a/BigBaseV2/src/services/player_service.hpp +++ b/BigBaseV2/src/services/player_service.hpp @@ -52,6 +52,8 @@ namespace big void do_cleanup(); player* get_by_name(std::string name); + player* get_by_msg_id(uint32_t msg_id); + player* get_by_host_token(uint64_t token); player* get_selected(); void player_join(CNetGamePlayer* net_game_player);