From ab491031715d69401a2a39a5babea16d2bf31648 Mon Sep 17 00:00:00 2001 From: maybegreat48 <96936658+maybegreat48@users.noreply.github.com> Date: Sat, 19 Nov 2022 01:49:36 +0000 Subject: [PATCH] Improve protections again and player database (#606) --- scripts/gtav-classes.cmake | 2 +- src/backend/script_patches.hpp | 2 +- src/core/data/block_join_reasons.hpp | 30 ++ src/core/data/infractions.hpp | 28 ++ src/core/globals.hpp | 10 + src/function_types.hpp | 21 +- src/gta/array.hpp | 203 +-------- src/gta/enums.hpp | 32 -- src/gta/net_game_event.hpp | 52 ++- src/gta/sysMemAllocator.hpp | 71 +-- src/gui.cpp | 2 +- src/hooking.cpp | 11 + src/hooking.hpp | 29 +- src/hooks/metrics/send_metric.cpp | 1 + src/hooks/misc/sort_session_details.cpp | 19 + .../assign_physical_index.cpp | 34 ++ src/hooks/protections/can_apply_data.cpp | 287 +++++++++++++ src/hooks/protections/handle_join_request.cpp | 24 ++ src/hooks/protections/receive_net_message.cpp | 46 ++ .../protections/received_clone_create.cpp | 17 + src/hooks/protections/received_clone_sync.cpp | 403 +----------------- src/hooks/protections/received_event.cpp | 52 ++- .../protections/script_event_handler.cpp | 4 +- ...ze_dynamic_entity_game_state_data_node.cpp | 58 +++ .../serialize_ped_inventory_data_node.cpp | 49 +++ .../serialize_vehicle_gadget_data_node.cpp | 49 +++ .../spoofing/write_player_gamer_data_node.cpp | 1 + src/json_util.hpp | 17 + src/main.cpp | 4 + src/packet.cpp | 18 + src/packet.hpp | 51 +++ src/pointers.cpp | 62 ++- src/pointers.hpp | 18 +- src/services/gui/gui_service.hpp | 2 + .../notifications/notification_service.cpp | 6 +- .../player_database/persistent_player.hpp | 39 ++ .../player_database_service.cpp | 98 +++++ .../player_database_service.hpp | 31 ++ src/services/players/player.hpp | 4 + .../vehicle}/model_attachment.hpp | 15 +- src/services/vehicle/persist_car_service.hpp | 3 +- src/util/notify.hpp | 25 +- src/util/session.hpp | 11 + src/views/debug/view_debug_misc.cpp | 5 + src/views/network/view_player_database.cpp | 152 +++++++ src/views/network/view_session.cpp | 7 + src/views/players/view_player.cpp | 107 +++-- src/views/players/view_players.cpp | 6 + src/views/view.hpp | 1 + 49 files changed, 1416 insertions(+), 803 deletions(-) create mode 100644 src/core/data/block_join_reasons.hpp create mode 100644 src/core/data/infractions.hpp create mode 100644 src/hooks/misc/sort_session_details.cpp create mode 100644 src/hooks/protections/can_apply_data.cpp create mode 100644 src/hooks/protections/handle_join_request.cpp create mode 100644 src/hooks/protections/received_clone_create.cpp create mode 100644 src/hooks/protections/serialize_dynamic_entity_game_state_data_node.cpp create mode 100644 src/hooks/protections/serialize_ped_inventory_data_node.cpp create mode 100644 src/hooks/protections/serialize_vehicle_gadget_data_node.cpp create mode 100644 src/json_util.hpp create mode 100644 src/packet.cpp create mode 100644 src/packet.hpp create mode 100644 src/services/player_database/persistent_player.hpp create mode 100644 src/services/player_database/player_database_service.cpp create mode 100644 src/services/player_database/player_database_service.hpp rename src/{core/data => services/vehicle}/model_attachment.hpp (85%) create mode 100644 src/views/network/view_player_database.cpp diff --git a/scripts/gtav-classes.cmake b/scripts/gtav-classes.cmake index 5f80733a..2e8d618d 100644 --- a/scripts/gtav-classes.cmake +++ b/scripts/gtav-classes.cmake @@ -3,7 +3,7 @@ include(FetchContent) FetchContent_Declare( gtav_classes GIT_REPOSITORY https://github.com/Yimura/GTAV-Classes.git - GIT_TAG 0a23b823e2dd2e52004b206b7cce735d326c209f + GIT_TAG 1dc66fb37fec895c96c2b1e4944e382a83c5e993 GIT_PROGRESS TRUE CONFIGURE_COMMAND "" BUILD_COMMAND "" diff --git a/src/backend/script_patches.hpp b/src/backend/script_patches.hpp index e46c6c00..3b200f0f 100644 --- a/src/backend/script_patches.hpp +++ b/src/backend/script_patches.hpp @@ -7,7 +7,7 @@ namespace big { g_script_patcher_service->add_patch({ RAGE_JOAAT("freemode"), "2D 01 08 00 ? 38 00 5D ? ? ? 2A 06", 5, {0x6E, 0x2E, 0x01, 0x01}, &g->session.decloak_players }); g_script_patcher_service->add_patch({ RAGE_JOAAT("freemode"), "2D 01 04 00 ? 2C ? ? ? 5D ? ? ? 6E 57 ? ? 2C", 5, { 0x2E, 0x01, 0x00 }, &g->protections.script_host_kick }); - g_script_patcher_service->add_patch({ RAGE_JOAAT("freemode"), "2D 00 07 00 00 5D ? ? ? 56 ? ? 6E ", 5, { 0x2E, 0x00, 0x00 }, &g->tunables.no_idle_kick }); + g_script_patcher_service->add_patch({ RAGE_JOAAT("freemode"), "2D 01 08 00 00 5D ? ? ? 56 ? ? 6E ", 5, { 0x2E, 0x01, 0x00 }, &g->tunables.no_idle_kick }); g_script_patcher_service->add_patch({ RAGE_JOAAT("freemode"), "2D 01 09 00 00 5D ? ? ? 56 ? ? 2E", 5, { 0x2E, 0x01, 0x00 }, nullptr }); // disable death when undermap/spectating g_script_patcher_service->add_patch({ RAGE_JOAAT("shop_controller"), "2D 01 04 00 00 2C ? ? ? 56 ? ? 6E ", 5, { 0x6E, 0x2E, 0x01, 0x01 }, nullptr }); // despawn bypass diff --git a/src/core/data/block_join_reasons.hpp b/src/core/data/block_join_reasons.hpp new file mode 100644 index 00000000..f233d088 --- /dev/null +++ b/src/core/data/block_join_reasons.hpp @@ -0,0 +1,30 @@ +#pragma once + +namespace big +{ + inline std::unordered_map block_join_reasons = + { + { 1, "None" }, + { 5, "Been Voted Out" }, // You have already been voted out of this game session. + { 7, "Incompatible Assets" }, // Failed to join session due to incompatible assets. + { 8, "Session Full" }, // The session you're trying to join is currently full. + { 9, "Slot Full" }, // The session you're trying to join is currently full of players. + { 10, "No Title Update" }, // Please make sure all players have the latest Title Update. + { 12, "Invites Disabled" }, // Invites are currently disabled in the session. + { 13, "Different Targeting Mode" }, // The session you are trying to join is using a different targeting preference. You can change your preference in the Settings tab of the Pause Menu in Grand Theft Auto V. Joining a new GTA Online Session. + { 14, "Cheater" }, // You are classed as a cheat and can only play with other cheats until you are forgiven. + { 16, "Incompatible DLC" }, // Incompatible downloadable content. All players must have the latest compatibility pack. + { 17, "Crew Only" }, // You are trying to enter a Crew Members only session. + { 21, "Session No Longer Exists" }, // The session you are trying to join no longer exists. + { 22, "Invite Only" }, // The session you are trying to join is private. You will need to be invited to join this session. + { 26, "Friends Only" }, // The session you are trying to join is friends only. + { 23, "Different Build Type" }, // The session you are trying to join is a different build type. + { 25, "Different Content" }, // The session you are trying to join is not using the same content. + { 18, "Bad Sport" }, // The session you are trying to join is for people who are not Bad Sports or cheaters - you are a Bad Sport. + { 19, "Bad Sports Only" }, // The session you are trying to join is for Bad Sports only. + { 20, "Cheaters Only" }, // The session you are trying to join is for cheaters only. + { 27, "Bad Reputation" }, // Unable to join this session, your account has a bad reputation. + { 28, "May Not Exist" }, // Unable to connect to session. The session may no longer exist. + { 29, "Premium Race" }, // Unable to Join. The session you are trying to join is a Premium Race. Joining and accepting invites is disabled for this mode. + }; +} \ No newline at end of file diff --git a/src/core/data/infractions.hpp b/src/core/data/infractions.hpp new file mode 100644 index 00000000..effb1a24 --- /dev/null +++ b/src/core/data/infractions.hpp @@ -0,0 +1,28 @@ +#pragma once +#include "gta/joaat.hpp" + +namespace big +{ + // Add new values to the bottom + enum class Infraction + { + DESYNC_PROTECTION, + BREAKUP_KICK_DETECTED, + LOST_CONNECTION_KICK_DETECTED, + SPOOFED_ROCKSTAR_ID, + TRIGGERED_ANTICHEAT, + TRIED_CRASH_PLAYER, + TRIED_KICK_PLAYER + }; + + inline std::unordered_map infraction_desc = + { + {Infraction::DESYNC_PROTECTION, "Used desync protections"}, + {Infraction::BREAKUP_KICK_DETECTED, "Kicked someone using breakup kick"}, + {Infraction::LOST_CONNECTION_KICK_DETECTED, "Tried to kick someone using lost connection kick"}, + {Infraction::SPOOFED_ROCKSTAR_ID, "Had spoofed RID"}, + {Infraction::TRIGGERED_ANTICHEAT, "Triggered Rockstar's anticheat"}, + {Infraction::TRIED_CRASH_PLAYER, "Tried to crash you"}, + {Infraction::TRIED_KICK_PLAYER, "Tried to kick you"} + }; +} \ No newline at end of file diff --git a/src/core/globals.hpp b/src/core/globals.hpp index c1a67586..8c3700c7 100644 --- a/src/core/globals.hpp +++ b/src/core/globals.hpp @@ -7,6 +7,8 @@ #include "imgui.h" #include +class CNetGamePlayer; + namespace big { class menu_settings; @@ -195,6 +197,8 @@ namespace big bool log_text_messages = false; bool decloak_players = false; bool force_session_host = false; + bool player_magnet_enabled = false; + int player_magnet_count = 32; bool is_team = false; }; @@ -401,6 +405,8 @@ namespace big int friend_count = 0; int player_count = 0; + CNetGamePlayer* m_syncing_player = nullptr; + debug debug{}; tunables tunables{}; notifications notifications{}; @@ -603,6 +609,8 @@ namespace big this->session.disable_chat_filter = j["session"]["disable_chat_filter"]; this->session.decloak_players = j["session"]["decloak_players"]; this->session.force_session_host = j["session"]["force_session_host"]; + this->session.player_magnet_enabled = j["session"]["player_magnet_enabled"]; + this->session.player_magnet_count = j["session"]["player_magnet_count"]; this->session.is_team = j["session"]["is_team"]; this->settings.dev_dlc = j["settings"]["dev_dlc"]; @@ -921,6 +929,8 @@ namespace big { "disable_chat_filter", this->session.disable_chat_filter }, { "decloak_players", this->session.decloak_players }, { "force_session_host", this->session.force_session_host }, + { "player_magnet_enabled", this->session.player_magnet_enabled }, + { "player_magnet_count", this->session.player_magnet_count }, { "is_team", this->session.is_team } } }, diff --git a/src/function_types.hpp b/src/function_types.hpp index 94f146c4..23abfea5 100644 --- a/src/function_types.hpp +++ b/src/function_types.hpp @@ -1,6 +1,13 @@ #pragma once -#include "datanodes/player/CPlayerGameStateDataNode.hpp" -#include "rage/rlGamerInfo.hpp" +#include +#include + +class CMsgJoinResponse; + +namespace rage +{ + class netConnectionManager; +} namespace big::functions { @@ -37,7 +44,7 @@ namespace big::functions using write_bitbuf_int64 = bool(*)(rage::datBitBuffer* buffer, int64_t val, int bits); using write_bitbuf_int32 = bool(*)(rage::datBitBuffer* buffer, int32_t val, int bits); using write_bitbuf_bool = bool(*)(rage::datBitBuffer* buffer, bool val, int bits); - using write_bitbuf_array = bool(*)(rage::datBitBuffer* buffer, uint8_t* val, int bits, int unk); + using write_bitbuf_array = bool(*)(rage::datBitBuffer* buffer, void* val, int bits, int unk); // Bitbuffer read/write END // Received Event Signatures START @@ -69,5 +76,13 @@ namespace big::functions using generate_uuid = bool(*)(std::uint64_t* uuid); + using get_vehicle_gadget_array_size = int(*)(eVehicleGadgetType type); + + using write_join_response_data = bool(*)(CMsgJoinResponse* response, void* data, int size, uint32_t* size_used); + + using queue_packet = bool(*)(rage::netConnectionManager* mgr, int msg_id, void* data, int size, int flags, void* unk); + + using generate_uuid = bool(*)(std::uint64_t* uuid); + using send_chat_message = bool(*)(int64_t* send_chat_ptr, rage::rlGamerInfo* game_info, char* message, bool is_team); } diff --git a/src/gta/array.hpp b/src/gta/array.hpp index 6f3cc9ba..a2693cbc 100644 --- a/src/gta/array.hpp +++ b/src/gta/array.hpp @@ -2,205 +2,4 @@ #include #include "fwddec.hpp" #include "sysMemAllocator.hpp" - -namespace rage -{ -#pragma pack(push, 8) - template - class atArray - { - public: - atArray() - { - m_data = nullptr; - m_count = 0; - m_size = 0; - } - - atArray(const atArray& right) - { - m_count = right.m_count; - m_size = right.m_size; - - m_data = (T*)rage::GetAllocator()->allocate(m_size * sizeof(T), 16, 0); - std::uninitialized_copy(right.m_data, right.m_data + right.m_count, m_data); - } - - atArray(int capacity) - { - m_data = (T*)rage::GetAllocator()->allocate(capacity * sizeof(T), 16, 0); - m_count = 0; - m_size = capacity; - } - - void clear() - { - m_count = 0; - m_size = 0; - - if (m_data) - { - rage::GetAllocator()->free(m_data); - - m_data = nullptr; - } - } - - void append(atArray array_value) - { - auto value_array_size = array_value.size(); - auto old_capacity = m_count; - - if ((value_array_size + m_count) > std::numeric_limits::max()) - LOG(FATAL) << "RAGE atArray::append was given too large of an atArray to append"; - - auto size = (uint16_t)value_array_size; - expand(m_count + size); - m_size += size; - - auto i = old_capacity; - for (auto weapon_hash : array_value) - { - m_data[i] = weapon_hash; - i++; - } - } - - void append(std::vector value_array) - { - auto value_array_size = value_array.size(); - auto old_capacity = m_count; - - if ((value_array_size + m_count) > std::numeric_limits::max()) - LOG(FATAL) << "RAGE atArray::append was given too large of a vector to append"; - - auto size = (uint16_t)value_array_size; - expand(m_count + size); - m_size += size; - - auto i = old_capacity; - for (auto weapon_hash : value_array) - { - m_data[i] = weapon_hash; - i++; - } - } - - void append(const std::initializer_list value_array) - { - auto value_array_size = value_array.size(); - auto old_capacity = m_count; - - if ((value_array_size + m_count) > std::numeric_limits::max()) - LOG(FATAL) << "RAGE atArray::append was given too large of a list to append"; - - auto size = (uint16_t)value_array_size; - expand(m_count + size); - m_size += size; - - auto i = old_capacity; - for (const T* it = value_array.begin(); it != value_array.end(); ++it) - { - m_data[i] = *it; - i++; - } - } - - void append(T value) - { - set(m_count, value); - } - - void set(uint16_t offset, const T& value) - { - if (offset >= m_count) - { - expand(offset + 1); - } - - if (offset >= m_size) - { - m_size = offset + 1; - } - - m_data[offset] = value; - } - - void expand(uint16_t newSize) - { - if (m_count >= newSize) - { - return; - } - - T* newOffset = (T*)rage::GetAllocator()->allocate(newSize * sizeof(T), 16, 0); - - // initialize the new entries - std::uninitialized_fill(newOffset, newOffset + newSize, T()); - - // copy the existing entries - if (m_data) - { - std::copy(m_data, m_data + m_size, newOffset); - - rage::GetAllocator()->free(m_data); - } - - m_data = newOffset; - m_count = newSize; - } - - T* begin() const - { - return &m_data[0]; - } - - T* end() const - { - return &m_data[m_size]; - } - - T* data() const - { - return m_data; - } - - std::uint16_t size() const - { - return m_size; - } - - std::uint16_t count() const - { - return m_count; - } - - T& operator[](std::uint16_t index) const - { - return m_data[index]; - } - - friend std::ostream& operator<<(std::ostream& o, const atArray& j) - { - o << "Array Size: " << j.size() << std::endl; - for(int i = 0; i < j.size(); i++) - { - T item = j[i]; - if (std::is_pointer()) - o << "\tArray Pointer: " << HEX_TO_UPPER(item) << " Item: [" << HEX_TO_UPPER(*(T*)item) << "]"; - else - o << "\tArray Item: " << item; - if (i != j.size() - 1) - o << std::endl; - } - return o; - } - - private: - T* m_data; - std::uint16_t m_size; - std::uint16_t m_count; - }; - static_assert(sizeof(rage::atArray) == 0x10, "rage::atArray is not properly sized"); -#pragma pack(pop) -} \ No newline at end of file +#include \ No newline at end of file diff --git a/src/gta/enums.hpp b/src/gta/enums.hpp index 3021747f..f52da8ea 100644 --- a/src/gta/enums.hpp +++ b/src/gta/enums.hpp @@ -3,38 +3,6 @@ constexpr auto MAX_PLAYERS = 32; -enum eObjType : uint16_t { - carObjType = 0, - bikeObjType = 1, - boatObjType = 2, - doorObjType = 3, - heliObjType = 4, - objType = 5, - pedObjType = 6, - pickupObjType = 7, - pickupPlacementObjType = 8, - planeObjType = 9, - submarineObjType = 10, - playerObjType = 11, - trailerObjType = 12, - trainObjType = 13, - unkObjType14 = 14, - unkObjType = 69 -}; - -enum eSyncReply : int64_t -{ - NoSyncTreeFound = 1, // No sync tree found - PlayerIsNotInOurRoamingBubble = 1, // Player is not in our roaming bubble - WrongOwner = 2, // Wrong owner - ObjectIsBeingReassinged = 2, // Object is being reassigned - CantApplyData_NoNetworkObject = 4, // Can't apply data - no network object - CantApplyData = 6, // Can't apply data - CantApplyData_NoGameObject = 6, // Can't apply data - no game object - CantApplyData_NetworkClosed = 7, // Can't apply data - network closed - SuccessfullSync = 8 -}; - enum class ControllerInputs : std::uint32_t { INPUT_NEXT_CAMERA, diff --git a/src/gta/net_game_event.hpp b/src/gta/net_game_event.hpp index e103d460..b08ac71b 100644 --- a/src/gta/net_game_event.hpp +++ b/src/gta/net_game_event.hpp @@ -6,12 +6,48 @@ #pragma pack(push, 1) namespace rage { + class CSyncDataBase + { + public: + virtual ~CSyncDataBase() = default; + virtual bool SerializeDword(uint32_t* dword, int size) = 0; + virtual bool SerializeWord(uint16_t* word, int size) = 0; + virtual bool SerializeByte(uint8_t* byte, int size) = 0; + virtual bool SerializeInt32(int32_t* i, int size) = 0; + virtual bool SerializeInt16(int16_t* i, int size) = 0; + virtual bool SerializeSignedByte(int8_t* byte, int size) = 0; + virtual bool SerializeBool(bool* flag) = 0; + virtual bool SerializeInt64(int64_t* i, int size) = 0; + virtual bool SerializeInt32Alt(int32_t* i, int size) = 0; + virtual bool SerializeInt16Alt(int16_t* i, int size) = 0; + virtual bool SerializeSignedByteAlt(int8_t* byte, int size) = 0; + virtual bool SerializeQword(uint64_t* qword, int size) = 0; + virtual bool SerializeDwordAlt(uint32_t* dword, int size) = 0; + virtual bool SerializeWordAlt(uint16_t* word, int size) = 0; + virtual bool SerializeByteAlt(uint8_t* byte, int size) = 0; + virtual bool SerializeSignedFloat(float* flt, float divisor, int size) = 0; + virtual bool SerializeFloat(float* flt, float divisor, int size) = 0; + virtual bool SerializeNetworkId(uint16_t* net_id) = 0; + virtual bool SerializeVector3(rage::fvector3* vec3, float divisor, int size) = 0; + virtual bool SerializeQuaternion(void* unk) = 0; // i have no clue what that is + virtual bool SerializeVector3SignedZComponent(rage::fvector3* vec3, float divisor, int size) = 0; + virtual bool SerializeOrientation(rage::fvector4* vec4, float size) = 0; // yes, the size is a float + virtual bool SerializeArray(void* array, int size) = 0; + virtual bool SerializeString(char* str, int max_length) = 0; + virtual bool IsSizeCalculator() = 0; + virtual bool IsSizeCalculator2() = 0; + + void* unk_0x8; + void* syncLog; + datBitBuffer* buffer; + }; + class netPlayer; class datBitBuffer { public: - datBitBuffer(uint8_t* data, uint32_t size) { + datBitBuffer(void* data, uint32_t size) { m_data = data; m_bitOffset = 0; m_maxBit = size * 8; @@ -46,7 +82,7 @@ namespace rage return 0; auto const bufPos = m_bitsRead + m_bitOffset; auto const initialBitOffset = bufPos & 0b111; - auto const start = &m_data[bufPos / 8]; + auto const start = &((uint8_t*)m_data)[bufPos / 8]; auto const next = &start[1]; auto result = (start[0] << initialBitOffset) & 0xff; for (auto i = 0; i < ((numBits - 1) / 8); i++) { @@ -139,7 +175,7 @@ namespace rage } return false; } - bool WriteArray(uint8_t* array, int size) { + bool WriteArray(void* array, int size) { return big::g_pointers->m_write_bitbuf_array(this, array, size, 0); } bool ReadArray(PVOID array, int size) { @@ -167,8 +203,16 @@ namespace rage return T(val); } + + template + inline void Write(T data, int length) + { + static_assert(sizeof(T) <= 8, "maximum of 64 bit write"); + + WriteQWord((uint64_t)data, length); + } public: - uint8_t* m_data; //0x0000 + void* m_data; //0x0000 uint32_t m_bitOffset; //0x0008 uint32_t m_maxBit; //0x000C uint32_t m_bitsRead; //0x0010 diff --git a/src/gta/sysMemAllocator.hpp b/src/gta/sysMemAllocator.hpp index 914d2454..cb37a460 100644 --- a/src/gta/sysMemAllocator.hpp +++ b/src/gta/sysMemAllocator.hpp @@ -1,72 +1,3 @@ #pragma once #include "fwddec.hpp" - -namespace rage -{ - class sysMemAllocator - { - public: - virtual ~sysMemAllocator() = 0; - - virtual void SetQuitOnFail(bool) = 0; - virtual void* Allocate(size_t size, size_t align, int subAllocator) = 0; - - inline void* allocate(size_t size, size_t align, int subAllocator) - { - return Allocate(size, align, subAllocator); - } - - virtual void* TryAllocate(size_t size, size_t align, int subAllocator) = 0; - - virtual void Free(void* pointer) = 0; - - virtual void free(void* pointer) - { - return Free(pointer); - } - - virtual void TryFree(void* pointer) = 0; - - virtual void Resize(void* pointer, size_t size) = 0; - - virtual sysMemAllocator* GetAllocator(int allocator) const = 0; - - virtual sysMemAllocator* GetAllocator(int allocator) = 0; - - virtual sysMemAllocator* GetPointerOwner(void* pointer) = 0; - - virtual size_t GetSize(void* pointer) const = 0; - - virtual size_t GetMemoryUsed(int memoryBucket) = 0; - - virtual size_t GetMemoryAvailable() = 0; - - public: - - static sysMemAllocator* UpdateAllocatorValue() - { - //B9 ? ? ? ? 48 8B 0C 01 45 33 C9 49 8B D2 48 - auto g_gtaTlsEntry = *(sysMemAllocator**)(*(uintptr_t*)(__readgsqword(88)) + 0xC8); //This has been 0xC8 since 323, I'm not adding this signature to pointers... - - if (g_gtaTlsEntry == nullptr) - LOG(FATAL) << "Failed to find tlsEntry within GTA5.exe via __readgsqword"; - - *(sysMemAllocator**)(*(uintptr_t*)(__readgsqword(88)) + 0xC8) = g_gtaTlsEntry; - *(sysMemAllocator**)(*(uintptr_t*)(__readgsqword(88)) + 0xC8 - 8) = g_gtaTlsEntry; - - return g_gtaTlsEntry; - } - }; - - inline sysMemAllocator* GetAllocator() - { - sysMemAllocator* allocator = *(sysMemAllocator**)(*(uintptr_t*)(__readgsqword(88)) + 0xC8); - - if (!allocator) - { - return sysMemAllocator::UpdateAllocatorValue(); - } - - return allocator; - } -} \ No newline at end of file +#include \ No newline at end of file diff --git a/src/gui.cpp b/src/gui.cpp index 5a5135d1..d34565ea 100644 --- a/src/gui.cpp +++ b/src/gui.cpp @@ -37,7 +37,7 @@ namespace big colors[ImGuiCol_Text] = ImVec4(0.80f, 0.80f, 0.83f, 1.00f); colors[ImGuiCol_TextDisabled] = ImVec4(0.24f, 0.23f, 0.29f, 1.00f); colors[ImGuiCol_WindowBg] = ImGui::ColorConvertU32ToFloat4(g->window.color); - colors[ImGuiCol_ChildBg] = ImVec4(0.10f, 0.09f, 0.12f, 1.00f); + colors[ImGuiCol_ChildBg] = ImGui::ColorConvertU32ToFloat4(g->window.color); colors[ImGuiCol_PopupBg] = ImVec4(0.07f, 0.07f, 0.09f, 1.00f); colors[ImGuiCol_Border] = ImVec4(0.80f, 0.80f, 0.83f, 0.88f); colors[ImGuiCol_BorderShadow] = ImVec4(0.92f, 0.91f, 0.88f, 0.00f); diff --git a/src/hooking.cpp b/src/hooking.cpp index 41605d79..8933f8e7 100644 --- a/src/hooking.cpp +++ b/src/hooking.cpp @@ -53,7 +53,10 @@ namespace big detour_hook_helper::add("API", g_pointers->m_assign_physical_index); detour_hook_helper::add("RNM", g_pointers->m_receive_net_message); + + detour_hook_helper::add("RCC", g_pointers->m_received_clone_create); detour_hook_helper::add("RCS", g_pointers->m_received_clone_sync); + detour_hook_helper::add("CAD", g_pointers->m_can_apply_data); detour_hook_helper::add("GNED", g_pointers->m_get_network_event_data); detour_hook_helper::add("WPGDN", g_pointers->m_write_player_gamer_data_node); @@ -65,6 +68,14 @@ namespace big detour_hook_helper::add("UPAI", g_pointers->m_update_presence_attribute_int); detour_hook_helper::add("UPAS", g_pointers->m_update_presence_attribute_string); + detour_hook_helper::add("SDEGSDN", g_pointers->m_serialize_dynamic_entity_game_state_data_node); + detour_hook_helper::add("SPIDN", g_pointers->m_serialize_ped_inventory_data_node); + detour_hook_helper::add("SVGDN", g_pointers->m_serialize_vehicle_gadget_data_node); + + detour_hook_helper::add("HJR", g_pointers->m_handle_join_request); + + detour_hook_helper::add("SSD", g_pointers->m_sort_session_details); + g_hooking = this; } diff --git a/src/hooking.hpp b/src/hooking.hpp index 5dd9e5c8..b0bb3f61 100644 --- a/src/hooking.hpp +++ b/src/hooking.hpp @@ -8,9 +8,20 @@ #include "vmt_hook.hpp" #include "MinHook.h" #include "gta/enums.hpp" -#include "datanodes/player/CPlayerGamerDataNode.hpp" -#include "datanodes/player/CPlayerGameStateDataNode.hpp" -#include "rage/rlMetric.hpp" + +class CPlayerGamerDataNode; +class CPlayerGameStateDataNode; +class CPedInventoryDataNode; +class CDynamicEntityGameStateDataNode; +class CVehicleGadgetDataNode; +class CJoinRequestContext; +class SessionSortEntry; + +namespace rage +{ + class rlMetric; + class snSession; +} namespace big { @@ -61,7 +72,9 @@ namespace big static void format_metric_for_sending(int a1, int64_t a2, int64_t a3, rage::rlMetric* metric); //SYNC - static int64_t received_clone_sync(CNetworkObjectMgr* mgr, CNetGamePlayer* src, CNetGamePlayer* dst, eObjType sync_type, uint16_t obj_id, rage::datBitBuffer* bufer, uint16_t unk, uint32_t timestamp); + static bool received_clone_create(CNetworkObjectMgr* mgr, CNetGamePlayer* src, CNetGamePlayer* dst, eNetObjType object_type, int32_t object_id, int32_t object_flag, rage::datBitBuffer* buffer, int32_t timestamp); + static eAckCode received_clone_sync(CNetworkObjectMgr* mgr, CNetGamePlayer* src, CNetGamePlayer* dst, eNetObjType object_type, uint16_t object_id, rage::datBitBuffer* bufer, uint16_t unk, uint32_t timestamp); + static bool can_apply_data(rage::netSyncTree* tree, rage::netObject* object); static void write_player_gamer_data_node(rage::netObject* player, CPlayerGamerDataNode* node); static bool write_player_game_state_data_node(rage::netObject* player, CPlayerGameStateDataNode* node); @@ -70,6 +83,14 @@ namespace big static bool update_presence_attribute_int(void* presence_data, int profile_index, char* attr, std::uint64_t value); static bool update_presence_attribute_string(void* presence_data, int profile_index, char* attr, char* value); + + static void serialize_ped_inventory_data_node(CPedInventoryDataNode* node, rage::CSyncDataBase* data); + static void serialize_dynamic_entity_game_state_data_node(CDynamicEntityGameStateDataNode* node, rage::CSyncDataBase* data); + static void serialize_vehicle_gadget_data_node(CVehicleGadgetDataNode* node, rage::CSyncDataBase* data); + + static bool handle_join_request(Network* network, rage::snSession* session, rage::rlGamerInfo* player_info, CJoinRequestContext* ctx, BOOL is_transition_session); + + static bool sort_session_details(SessionSortEntry* e1, SessionSortEntry* e2); }; class minhook_keepalive diff --git a/src/hooks/metrics/send_metric.cpp b/src/hooks/metrics/send_metric.cpp index 437f8761..16fdd25f 100644 --- a/src/hooks/metrics/send_metric.cpp +++ b/src/hooks/metrics/send_metric.cpp @@ -1,4 +1,5 @@ #include "hooking.hpp" +#include namespace rage { diff --git a/src/hooks/misc/sort_session_details.cpp b/src/hooks/misc/sort_session_details.cpp new file mode 100644 index 00000000..675f8a3c --- /dev/null +++ b/src/hooks/misc/sort_session_details.cpp @@ -0,0 +1,19 @@ +#include "hooking.hpp" +#include + +namespace big +{ + // true => e1 > e2 + // false => e1 < e2 + bool hooks::sort_session_details(SessionSortEntry* e1, SessionSortEntry* e2) + { + if (g->session.player_magnet_enabled) + { + return std::abs((int)e1->m_session_detail->m_player_count - g->session.player_magnet_count) < std::abs((int)e2->m_session_detail->m_player_count - g->session.player_magnet_count); + } + else + { + return g_hooking->get_original()(e1, e2); + } + } +} \ No newline at end of file diff --git a/src/hooks/player_management/assign_physical_index.cpp b/src/hooks/player_management/assign_physical_index.cpp index 6b55ca3d..7af9b1d7 100644 --- a/src/hooks/player_management/assign_physical_index.cpp +++ b/src/hooks/player_management/assign_physical_index.cpp @@ -1,6 +1,11 @@ #include "hooking.hpp" +#include "fiber_pool.hpp" #include "services/players/player_service.hpp" +#include "services/player_database/player_database_service.hpp" #include "util/notify.hpp" +#include "packet.hpp" +#include "gta_util.hpp" +#include namespace big { @@ -40,6 +45,35 @@ namespace big if (g->notifications.player_join.notify) g_notification_service->push("Player Joined", std::format("{} taking slot #{} with Rockstar ID: {}", net_player_data->m_name, player->m_player_id, net_player_data->m_gamer_handle_2.m_rockstar_id)); + + auto id = player->m_player_id; + g_fiber_pool->queue_job([id] + { + if (auto plyr = g_player_service->get_by_id(id)) + { + if (auto entry = g_player_database_service->get_player_by_rockstar_id(plyr->get_net_data()->m_gamer_handle_2.m_rockstar_id)) + { + plyr->is_modder = entry->is_modder; + plyr->block_join = entry->block_join; + plyr->block_join_reason = plyr->block_join_reason; + + if (strcmp(plyr->get_name(), entry->name.data())) + { + g_notification_service->push("Players", std::format("{} changed their name to {}", entry->name, plyr->get_name())); + entry->name = plyr->get_name(); + g_player_database_service->save(); + } + } + + if (auto snplyr = plyr->get_session_player()) + { + packet msg{}; + msg.write_message(rage::eNetMessage::MsgSessionEstablishedRequest); + msg.write(gta_util::get_network()->m_game_session_ptr->m_rline_session.m_session_id, 64); + msg.send(snplyr->m_msg_id); + } + } + }); } return result; } diff --git a/src/hooks/protections/can_apply_data.cpp b/src/hooks/protections/can_apply_data.cpp new file mode 100644 index 00000000..47eb84e5 --- /dev/null +++ b/src/hooks/protections/can_apply_data.cpp @@ -0,0 +1,287 @@ +#include "hooking.hpp" +#include "core/globals.hpp" +#include "base/CObject.hpp" +#include "entities/fwEntity.hpp" +#include "rage/netSyncDataNodeBase.hpp" +#include "rage/netSyncTree.hpp" +#include "gta/net_object_mgr.hpp" +#include "datanodes/door/CDoorCreationDataNode.hpp" +#include "datanodes/dynamic_entity/CDynamicEntityGameStateDataNode.hpp" +#include "datanodes/object/CObjectCreationDataNode.hpp" +#include "datanodes/ped/CPedAttachDataNode.hpp" +#include "datanodes/ped/CPedCreationDataNode.hpp" +#include "datanodes/ped/CPedInventoryDataNode.hpp" +#include "datanodes/pickup/CPickupCreationDataNode.hpp" +#include "datanodes/physical/CPhysicalAttachDataNode.hpp" +#include "datanodes/player/CPlayerAppearanceDataNode.hpp" +#include "datanodes/proximity_migrateable/CSectorDataNode.hpp" +#include "datanodes/vehicle/CVehicleCreationDataNode.hpp" +#include "datanodes/vehicle/CVehicleGadgetDataNode.hpp" +#include "network/netObject.hpp" +#include "base/CBaseModelInfo.hpp" +#include "vehicle/CVehicleModelInfo.hpp" +#include "util/model_info.hpp" +#include "network/CNetGamePlayer.hpp" +#include "util/notify.hpp" +#define CLASS_TO_MANGLED_NAME(c) "?AV"#c"@@" + +namespace big +{ + constexpr uint64_t operator ""_fnv1a(char const* str, std::size_t len) + { + auto const fnv_offset_basis = 14695981039346656037ULL; + auto const fnv_prime = 1099511628211ULL; + + auto value = fnv_offset_basis; + for (auto i = 0; i < len; i++) + { + value ^= static_cast(str[i]); + value *= fnv_prime; + } + value ^= value >> 32; + + return value; + } + + constexpr uint32_t crash_peds[] = { RAGE_JOAAT("slod_human"), RAGE_JOAAT("slod_small_quadped"), RAGE_JOAAT("slod_large_quadped") }; + + constexpr uint32_t crash_vehicles[] = { RAGE_JOAAT("arbitergt"), RAGE_JOAAT("astron2"), RAGE_JOAAT("cyclone2"), RAGE_JOAAT("ignus2"), RAGE_JOAAT("s95") }; + + constexpr uint32_t crash_objects[] = { RAGE_JOAAT("prop_dummy_01"), RAGE_JOAAT("prop_dummy_car"), RAGE_JOAAT("prop_dummy_light"), RAGE_JOAAT("prop_dummy_plane"), + RAGE_JOAAT("prop_distantcar_night"), RAGE_JOAAT("prop_distantcar_day"), RAGE_JOAAT("hei_bh1_08_details4_em_night"), + RAGE_JOAAT("dt1_18_sq_night_slod"), RAGE_JOAAT("ss1_12_night_slod"), -1288391198, RAGE_JOAAT("h4_prop_bush_bgnvla_med_01"), RAGE_JOAAT("h4_prop_bush_bgnvla_lrg_01"), + RAGE_JOAAT("h4_prop_bush_buddleia_low_01"), RAGE_JOAAT("h4_prop_bush_ear_aa"), RAGE_JOAAT("h4_prop_bush_ear_ab"), RAGE_JOAAT("h4_prop_bush_fern_low_01"), + RAGE_JOAAT("h4_prop_bush_fern_tall_cc"), RAGE_JOAAT("h4_prop_bush_mang_ad"), RAGE_JOAAT("h4_prop_bush_mang_low_aa"), RAGE_JOAAT("h4_prop_bush_mang_low_ab"), + RAGE_JOAAT("h4_prop_bush_seagrape_low_01"), RAGE_JOAAT("prop_h4_ground_cover"), RAGE_JOAAT("h4_prop_weed_groundcover_01"), RAGE_JOAAT("h4_prop_grass_med_01"), + RAGE_JOAAT("h4_prop_grass_tropical_lush_01"), RAGE_JOAAT("h4_prop_grass_wiregrass_01"), RAGE_JOAAT("h4_prop_weed_01_plant"), RAGE_JOAAT("h4_prop_weed_01_row"), + RAGE_JOAAT("urbanweeds02_l1"), RAGE_JOAAT("proc_forest_grass01"), RAGE_JOAAT("prop_small_bushyba"), RAGE_JOAAT("v_res_d_dildo_a"), RAGE_JOAAT("v_res_d_dildo_b"), RAGE_JOAAT("v_res_d_dildo_c"), + RAGE_JOAAT("v_res_d_dildo_d"), RAGE_JOAAT("v_res_d_dildo_e"), RAGE_JOAAT("v_res_d_dildo_f"), RAGE_JOAAT("v_res_skateboard"), RAGE_JOAAT("prop_battery_01"), RAGE_JOAAT("prop_barbell_01"), + RAGE_JOAAT("prop_barbell_02"), RAGE_JOAAT("prop_bandsaw_01"), RAGE_JOAAT("prop_bbq_3"), RAGE_JOAAT("v_med_curtainsnewcloth2"), RAGE_JOAAT("bh1_07_flagpoles"), + 92962485 }; + + inline bool is_crash_ped(uint32_t model) + { + for (auto iterator : crash_peds) + if (iterator == model) + return true; + return false; + } + + inline bool is_crash_vehicle(uint32_t model) + { + for (auto iterator : crash_vehicles) + if (iterator == model) + return true; + return false; + } + + inline bool is_crash_object(uint32_t model) + { + for (auto iterator : crash_objects) + if (iterator == model) + return true; + return false; + } + + template + T* get_node_from_object(rage::netSyncNodeBase* node) + { + constexpr uint64_t hash = CLASS_TO_MANGLED_NAME(T)""_fnv1a; + if (node->IsParentNode()) + { + for (auto child = node->m_first_child; child; child = child->m_next_sibling) + { + T* attach_node = get_node_from_object(child); + if (attach_node != nullptr) + return attach_node; + } + } + else if (node->IsDataNode()) + { + if (typeid(*node).hash_code() == hash) + return dynamic_cast(node); + } + return nullptr; + } + + bool is_attachment_infinite(CPhysicalAttachDataNode* node, uint16_t object_id) + { + if (rage::netObject* attached_object = (*g_pointers->m_network_object_mgr)->find_object_by_id(node->m_attached_to, false); attached_object) + { + if (rage::netSyncTree* tree = attached_object->GetSyncTree(); tree) + { + if (rage::netSyncNodeBase* base_node = tree->m_sync_node; base_node) + { + const auto attached_attach_node = get_node_from_object(base_node); + if (attached_attach_node && attached_attach_node->m_attached) + { + if (attached_attach_node->m_attached_to == object_id) + { + return true; + } + else + { + return is_attachment_infinite(attached_attach_node, object_id); + } + } + } + } + } + + return false; + } + + bool is_ped_attachment_infinite(CPedAttachDataNode* node, uint16_t object_id) + { + if (rage::netObject* attached_object = (*g_pointers->m_network_object_mgr)->find_object_by_id(node->m_attached_to, false); attached_object) + { + if (rage::netSyncTree* tree = attached_object->GetSyncTree(); tree) + { + if (rage::netSyncNodeBase* base_node = tree->m_sync_node; base_node) + { + const auto attached_attach_node = get_node_from_object(base_node); + if (attached_attach_node && attached_attach_node->m_attached) + { + if (attached_attach_node->m_attached_to == object_id) + { + return true; + } + else + { + return is_ped_attachment_infinite(attached_attach_node, object_id); + } + } + } + } + } + + return false; + } + + bool check_node(rage::netSyncNodeBase* node, CNetGamePlayer* sender, rage::netObject* object) + { + if (node->IsParentNode()) + { + for (auto child = node->m_first_child; child; child = child->m_next_sibling) + { + if (check_node(child, sender, object)) + return true; + } + } + else if (node->IsDataNode()) + { + switch (typeid(*node).hash_code()) + { + case "?AVCDoorCreationDataNode@@"_fnv1a: + { + const auto creation_node = dynamic_cast(node); + if (is_crash_object(creation_node->m_model)) + { + notify::crash_blocked(sender, "invalid door model"); + return true; + } + break; + } + case "?AVCPickupCreationDataNode@@"_fnv1a: + { + const auto creation_node = dynamic_cast(node); + if (is_crash_object(creation_node->m_custom_model)) + { + notify::crash_blocked(sender, "invalid door model"); + return true; + } + break; + } + case "?AVCPhysicalAttachDataNode@@"_fnv1a: + { + const auto attach_node = dynamic_cast(node); + + // TODO: Find a better method to avoid false positives + auto model_hash = object->GetGameObject() ? object->GetGameObject()->m_model_info->m_hash : 0; + if (attach_node->m_attached && attach_node->m_attached_to == object->m_object_id && (model_hash != RAGE_JOAAT("hauler2") && model_hash != RAGE_JOAAT("phantom3"))) + { + notify::crash_blocked(sender, "infinite physical attachment"); + return true; + } + break; + } + case "?AVCPedCreationDataNode@@"_fnv1a: + { + const auto creation_node = dynamic_cast(node); + if (is_crash_ped(creation_node->m_model)) + { + notify::crash_blocked(sender, "invalid ped model"); + return true; + } + else if (creation_node->m_has_prop && is_crash_object(creation_node->m_prop_model)) + { + notify::crash_blocked(sender, "invalid ped prop model"); + return true; + } + break; + } + case "?AVCPedAttachDataNode@@"_fnv1a: + { + const auto attach_node = dynamic_cast(node); + if (attach_node->m_attached && attach_node->m_attached_to == object->m_object_id) + { + notify::crash_blocked(sender, "infinite ped attachment"); + return true; + } + break; + } + case "?AVCVehicleCreationDataNode@@"_fnv1a: + { + const auto vehicle_creation_node = dynamic_cast(node); + if (is_crash_vehicle(vehicle_creation_node->m_model)) + { + notify::crash_blocked(sender, "invalid vehicle model"); + return true; + } + break; + } + case "?AVCObjectCreationDataNode@@"_fnv1a: + { + const auto creation_node = dynamic_cast(node); + if (is_crash_object(creation_node->m_model)) + { + notify::crash_blocked(sender, "invalid object model"); + return true; + } + break; + } + case "?AVCPlayerAppearanceDataNode@@"_fnv1a: + { + const auto player_appearance_node = dynamic_cast(node); + if (is_crash_ped(player_appearance_node->m_model_hash)) + { + notify::crash_blocked(sender, "invalid player model"); + return true; + } + break; + } + case "?AVCSectorDataNode@@"_fnv1a: + { + const auto sector_node = dynamic_cast(node); + if (sector_node->m_pos_x == 712 || sector_node->m_pos_y == 712 || sector_node->m_pos_z == 712) + { + notify::crash_blocked(sender, "invalid sector position"); + return true; + } + break; + } + } + } + return false; + } + + bool hooks::can_apply_data(rage::netSyncTree* tree, rage::netObject* object) + { + if (tree->m_child_node_count && check_node(tree->m_sync_node, g->m_syncing_player, object)) + { + return false; + } + + return g_hooking->get_original()(tree, object); + } +} \ No newline at end of file diff --git a/src/hooks/protections/handle_join_request.cpp b/src/hooks/protections/handle_join_request.cpp new file mode 100644 index 00000000..3d52a7ce --- /dev/null +++ b/src/hooks/protections/handle_join_request.cpp @@ -0,0 +1,24 @@ +#include "hooking.hpp" +#include +#include +#include +#include "services/player_database/player_database_service.hpp" + +namespace big +{ + bool hooks::handle_join_request(Network* network, rage::snSession* session, rage::rlGamerInfo* player_info, CJoinRequestContext* ctx, BOOL is_transition_session) + { + if (auto player = g_player_database_service->get_player_by_rockstar_id(player_info->m_gamer_handle_2.m_rockstar_id); player && player->block_join) + { + CMsgJoinResponse response{}; + response.m_status_code = player->block_join_reason; + g_pointers->m_write_join_response_data(&response, ctx->m_join_response_data, 512, &ctx->m_join_response_size); + g_notification_service->push("Block Join", std::format("Blocked {} from joining", player->name)); + return false; + } + else + { + return g_hooking->get_original()(network, session, player_info, ctx, is_transition_session); + } + } +} \ No newline at end of file diff --git a/src/hooks/protections/receive_net_message.cpp b/src/hooks/protections/receive_net_message.cpp index 74d05bde..93a2f3ea 100644 --- a/src/hooks/protections/receive_net_message.cpp +++ b/src/hooks/protections/receive_net_message.cpp @@ -2,6 +2,7 @@ #include "services/players/player_service.hpp" #include "natives.hpp" #include "gta_util.hpp" +#include "util/session.hpp" #include namespace big @@ -86,6 +87,7 @@ namespace big { if (player->m_num_failed_transition_attempts++ == 20) { + session::add_infraction(player, Infraction::TRIED_KICK_PLAYER); g_notification_service->push_error("Protections", std::format("{} tried to OOM kick you!", player->get_name())); } return true; @@ -120,6 +122,7 @@ namespace big if (player && pl && player->id() != pl->id() && count == 1 && frame->m_msg_id == -1) { g_notification_service->push_error("Warning!", std::format("{} breakup kicked {}!", player->get_name(), pl->get_name())); + session::add_infraction(player, Infraction::BREAKUP_KICK_DETECTED); } break; } @@ -133,6 +136,7 @@ namespace big auto self = g_player_service->get_self(); if (self->get_net_data() && self->get_net_data()->m_gamer_handle_2.m_rockstar_id == handle.m_rockstar_id) { + session::add_infraction(player, Infraction::TRIED_KICK_PLAYER); g_notification_service->push_error("Protections", std::format("{} tried to lost connection kick you!", player->get_name())); return true; } @@ -141,6 +145,7 @@ namespace big { if (plyr->get_net_data() && plyr != player && player->get_net_data()->m_gamer_handle_2.m_rockstar_id == handle.m_rockstar_id) { + session::add_infraction(player, Infraction::LOST_CONNECTION_KICK_DETECTED); g_notification_service->push_error("Protections", std::format("{} tried to lost connection kick {}!", player->get_name(), plyr->get_name())); return true; } @@ -148,6 +153,47 @@ namespace big break; } + case rage::eNetMessage::MsgSessionEstablished: + { + rage::rlGamerHandle handle{ 0 }; + if (player && player->get_net_data()) + { + uint64_t session_id; + buffer.ReadQWord(&session_id, 64); + gamer_handle_deserialize(handle, buffer); + if (session_id == gta_util::get_network()->m_game_session_ptr->m_rline_session.m_session_id) + { + if (handle.m_rockstar_id != player->get_net_data()->m_gamer_handle_2.m_rockstar_id) + { + session::add_infraction(player, Infraction::SPOOFED_ROCKSTAR_ID); // TODO: store this RID + } + } + } + break; + } + case rage::eNetMessage::MsgNetComplaint: + { + uint64_t host_token{}; + buffer.ReadQWord(&host_token, 64); + + std::vector players; + + uint32_t num_of_tokens{}; + buffer.ReadDword(&num_of_tokens, 32); + + if (player && host_token != player->get_net_data()->m_host_token) + session::add_infraction(player, Infraction::DESYNC_PROTECTION); + + return true; // block desync kicks as host + } + case rage::eNetMessage::MsgRequestObjectIds: + { + if (player && player->block_join) + { + g_notification_service->push("Join Blocker", std::format("Trying to prevent {} from joining...", player->get_name())); + return true; + } + } } } } diff --git a/src/hooks/protections/received_clone_create.cpp b/src/hooks/protections/received_clone_create.cpp new file mode 100644 index 00000000..1c14dce3 --- /dev/null +++ b/src/hooks/protections/received_clone_create.cpp @@ -0,0 +1,17 @@ +#include "hooking.hpp" +#include "util/notify.hpp" + +namespace big +{ + bool hooks::received_clone_create(CNetworkObjectMgr* mgr, CNetGamePlayer* src, CNetGamePlayer* dst, eNetObjType object_type, int32_t object_id, int32_t object_flag, rage::datBitBuffer* buffer, int32_t timestamp) + { + if (object_type < eNetObjType::NET_OBJ_TYPE_AUTOMOBILE || object_type > eNetObjType::NET_OBJ_TYPE_TRAIN) + { + notify::crash_blocked(src, "out of bounds object type"); + return true; + } + + g->m_syncing_player = src; + return g_hooking->get_original()(mgr, src, dst, object_type, object_id, object_flag, buffer, timestamp); + } +} \ No newline at end of file diff --git a/src/hooks/protections/received_clone_sync.cpp b/src/hooks/protections/received_clone_sync.cpp index a2448729..8294b954 100644 --- a/src/hooks/protections/received_clone_sync.cpp +++ b/src/hooks/protections/received_clone_sync.cpp @@ -1,406 +1,23 @@ #include "hooking.hpp" -#include "core/globals.hpp" -#include "base/CObject.hpp" -#include "entities/fwEntity.hpp" -#include "rage/netSyncDataNodeBase.hpp" -#include "rage/netSyncTree.hpp" -#include "gta/net_object_mgr.hpp" -#include "datanodes/door/CDoorCreationDataNode.hpp" -#include "datanodes/dynamic_entity/CDynamicEntityGameStateDataNode.hpp" -#include "datanodes/object/CObjectCreationDataNode.hpp" -#include "datanodes/ped/CPedAttachDataNode.hpp" -#include "datanodes/ped/CPedCreationDataNode.hpp" -#include "datanodes/ped/CPedInventoryDataNode.hpp" -#include "datanodes/pickup/CPickupCreationDataNode.hpp" -#include "datanodes/physical/CPhysicalAttachDataNode.hpp" -#include "datanodes/player/CPlayerAppearanceDataNode.hpp" -#include "datanodes/proximity_migrateable/CSectorDataNode.hpp" -#include "datanodes/vehicle/CVehicleCreationDataNode.hpp" -#include "datanodes/vehicle/CVehicleGadgetDataNode.hpp" -#include "network/netObject.hpp" -#include "base/CBaseModelInfo.hpp" -#include "vehicle/CVehicleModelInfo.hpp" -#include "util/model_info.hpp" -#include "network/CNetGamePlayer.hpp" -#define CLASS_TO_MANGLED_NAME(c) "?AV"#c"@@" +#include "util/notify.hpp" namespace big { - constexpr uint64_t operator ""_fnv1a(char const* str, std::size_t len) + eAckCode hooks::received_clone_sync(CNetworkObjectMgr* mgr, CNetGamePlayer* src, CNetGamePlayer* dst, eNetObjType object_type, uint16_t object_id, rage::datBitBuffer* buffer, uint16_t unk, uint32_t timestamp) { - auto const fnv_offset_basis = 14695981039346656037ULL; - auto const fnv_prime = 1099511628211ULL; - - auto value = fnv_offset_basis; - for (auto i = 0; i < len; i++) { - value ^= static_cast(str[i]); - value *= fnv_prime; - } - value ^= value >> 32; - - return value; - } - - constexpr uint32_t crash_models[] = { RAGE_JOAAT("prop_dummy_01"), RAGE_JOAAT("prop_dummy_car"), RAGE_JOAAT("prop_dummy_light"), RAGE_JOAAT("prop_dummy_plane"), RAGE_JOAAT("slod_human"), - RAGE_JOAAT("slod_small_quadped"), RAGE_JOAAT("slod_large_quadped"), RAGE_JOAAT("prop_distantcar_night"), RAGE_JOAAT("prop_distantcar_day"), RAGE_JOAAT("hei_bh1_08_details4_em_night"), - RAGE_JOAAT("dt1_18_sq_night_slod"), RAGE_JOAAT("ss1_12_night_slod"), -1288391198, RAGE_JOAAT("h4_prop_bush_bgnvla_med_01"), RAGE_JOAAT("h4_prop_bush_bgnvla_lrg_01"), - RAGE_JOAAT("h4_prop_bush_buddleia_low_01"), RAGE_JOAAT("h4_prop_bush_ear_aa"), RAGE_JOAAT("h4_prop_bush_ear_ab"), RAGE_JOAAT("h4_prop_bush_fern_low_01"), - RAGE_JOAAT("h4_prop_bush_fern_tall_cc"), RAGE_JOAAT("h4_prop_bush_mang_ad"), RAGE_JOAAT("h4_prop_bush_mang_low_aa"), RAGE_JOAAT("h4_prop_bush_mang_low_ab"), - RAGE_JOAAT("h4_prop_bush_seagrape_low_01"), RAGE_JOAAT("prop_h4_ground_cover"), RAGE_JOAAT("h4_prop_weed_groundcover_01"), RAGE_JOAAT("h4_prop_grass_med_01"), - RAGE_JOAAT("h4_prop_grass_tropical_lush_01"), RAGE_JOAAT("h4_prop_grass_wiregrass_01"), RAGE_JOAAT("h4_prop_weed_01_plant"), RAGE_JOAAT("h4_prop_weed_01_row"), - RAGE_JOAAT("urbanweeds02_l1"), RAGE_JOAAT("proc_forest_grass01"), RAGE_JOAAT("prop_small_bushyba"), RAGE_JOAAT("arbitergt"), RAGE_JOAAT("astron2"), RAGE_JOAAT("cyclone2"), - RAGE_JOAAT("ignus2"), RAGE_JOAAT("s95"), RAGE_JOAAT("hc_gunman"), RAGE_JOAAT("v_res_d_dildo_a"), RAGE_JOAAT("v_res_d_dildo_b"), RAGE_JOAAT("v_res_d_dildo_c"), - RAGE_JOAAT("v_res_d_dildo_d"), RAGE_JOAAT("v_res_d_dildo_e"), RAGE_JOAAT("v_res_d_dildo_f"), RAGE_JOAAT("v_res_skateboard"), RAGE_JOAAT("prop_battery_01"), RAGE_JOAAT("prop_barbell_01"), - RAGE_JOAAT("prop_barbell_02"), RAGE_JOAAT("prop_bandsaw_01"), RAGE_JOAAT("prop_bbq_3"), RAGE_JOAAT("v_med_curtainsnewcloth2"), RAGE_JOAAT("bh1_07_flagpoles"), - 92962485, RAGE_JOAAT("ig_wade") }; - - constexpr uint32_t cage_models[] = { RAGE_JOAAT("prop_rub_cage01a"), RAGE_JOAAT("prop_fnclink_05crnr1"), RAGE_JOAAT("prop_gold_cont_01"), RAGE_JOAAT("prop_gold_cont_01b"), - RAGE_JOAAT("prop_feeder1"), RAGE_JOAAT("stt_prop_stunt_tube_s"), RAGE_JOAAT("prop_feeder1_cr"), RAGE_JOAAT("p_cablecar_s") }; - - inline bool is_model_a_crash_model(uint32_t model) { - for (auto iterator : crash_models) + if (object_type < eNetObjType::NET_OBJ_TYPE_AUTOMOBILE || object_type > eNetObjType::NET_OBJ_TYPE_TRAIN) { - if (iterator == model) return true; + notify::crash_blocked(src, "out of bounds object type"); + return eAckCode::ACKCODE_FAIL; } - return false; - } - inline bool is_model_a_cage_model(uint32_t model) { - for (auto iterator : cage_models) + if (auto net_obj = g_pointers->m_get_net_object(mgr, object_id, true); net_obj && net_obj->m_object_type != (int16_t)object_type) { - if (iterator == model) return true; - } - return false; - } - - template - T* get_node_from_object(rage::netSyncNodeBase* node) - { - constexpr uint64_t hash = CLASS_TO_MANGLED_NAME(T)""_fnv1a; - if (node->IsParentNode()) - { - for (auto child = node->m_first_child; child; child = child->m_next_sibling) { - T* attach_node = get_node_from_object(child); - if (attach_node != nullptr) - return attach_node; - } - } - else if (node->IsDataNode()) - { - if (typeid(*node).hash_code() == hash) - return dynamic_cast(node); - } - return nullptr; - } - - bool is_attachment_infinite(CPhysicalAttachDataNode* node, uint16_t object_id) { - if (rage::netObject* attached_object = (*g_pointers->m_network_object_mgr)->find_object_by_id(node->m_attached_to, false); attached_object) - { - if (rage::netSyncTree* tree = attached_object->GetSyncTree(); tree) - { - if (rage::netSyncNodeBase* base_node = tree->m_sync_node; base_node) { - const auto attached_attach_node = get_node_from_object(base_node); - if (attached_attach_node && attached_attach_node->m_attached) - { - if (attached_attach_node->m_attached_to == object_id) { - return true; - } - else { - return is_attachment_infinite(attached_attach_node, object_id); - } - } - } - } + notify::crash_blocked(src, "incorrect object type"); + return eAckCode::ACKCODE_FAIL; } - return false; - } - - bool is_ped_attachment_infinite(CPedAttachDataNode* node, uint16_t object_id) { - if (rage::netObject* attached_object = (*g_pointers->m_network_object_mgr)->find_object_by_id(node->m_attached_to, false); attached_object) - { - if (rage::netSyncTree* tree = attached_object->GetSyncTree(); tree) - { - if (rage::netSyncNodeBase* base_node = tree->m_sync_node; base_node) { - const auto attached_attach_node = get_node_from_object(base_node); - if (attached_attach_node && attached_attach_node->m_attached) - { - if (attached_attach_node->m_attached_to == object_id) { - return true; - } - else { - return is_ped_attachment_infinite(attached_attach_node, object_id); - } - } - } - } - } - - return false; - } - - bool check_node(rage::netSyncNodeBase* node, CNetGamePlayer* sender, uint16_t object_id) - { - if (node->IsParentNode()) - { - for (auto child = node->m_first_child; child; child = child->m_next_sibling) { - if (check_node(child, sender, object_id)) - return true; - } - } - else if (node->IsDataNode()) - { - //LOG(INFO) << typeid(*node).name() << ": " << HEX_TO_UPPER(typeid(*node).hash_code()); //Use this to get hashes for each node - switch (typeid(*node).hash_code()) { - case "?AVCDoorCreationDataNode@@"_fnv1a: //CDoorCreationDataNode - { - const auto creation_node = dynamic_cast(node); - if (is_model_a_crash_model(creation_node->m_model)) - { - if (g->notifications.invalid_sync.log) - LOG(WARNING) << "Invalid door model: Model: " << HEX_TO_UPPER(creation_node->m_model) << " From: " << sender->get_name(); - if (g->notifications.invalid_sync.notify) - g_notification_service->push_warning(std::format("Invalid door model from {}", sender->get_name()), std::format("Model: 0x{:x}", creation_node->m_model)); - return true; - } - break; - } - case "?AVCPickupCreationDataNode@@"_fnv1a: //CPickupCreationDataNode - { - const auto creation_node = dynamic_cast(node); - if (is_model_a_crash_model(creation_node->m_custom_model)) - { - if (g->notifications.invalid_sync.log) - LOG(WARNING) << "Invalid pickup model: Model: " << HEX_TO_UPPER(creation_node->m_custom_model) << " From : " << sender->get_name(); - if (g->notifications.invalid_sync.notify) - g_notification_service->push_warning(std::format("Invalid pickup model from {}", sender->get_name()), std::format("Model: 0x{:x}", creation_node->m_custom_model)); - return true; - } - break; - } - case "?AVCPhysicalAttachDataNode@@"_fnv1a: //CPhysicalAttachDataNode - { - const auto attach_node = dynamic_cast(node); - if (attach_node->m_attached && attach_node->m_attached_to == object_id) - { - if (g->notifications.invalid_sync.log) - LOG(WARNING) << "Infinite attachment: Node: " << typeid(*node).name() << " From : " << sender->get_name(); - if (g->notifications.invalid_sync.notify) - g_notification_service->push_warning(std::format("Infinite attachment from {}", sender->get_name()), std::format("Node: {}", typeid(*node).name())); - return true; - } - else if (attach_node->m_attached && is_attachment_infinite(attach_node, object_id)) - { - if (g->notifications.invalid_sync.log) - LOG(WARNING) << "Infinite attachment v2: Node: " << typeid(*node).name() << " From : " << sender->get_name(); - if (g->notifications.invalid_sync.notify) - g_notification_service->push_warning(std::format("Infinite attachment v2 from {}", sender->get_name()), std::format("Node: {}", typeid(*node).name())); - return true; - } - break; - } - case "?AVCPedCreationDataNode@@"_fnv1a: //CPedCreationDataNode - { - const auto creation_node = dynamic_cast(node); - if (is_model_a_crash_model(creation_node->m_model)) - { - if (g->notifications.invalid_sync.log) - LOG(WARNING) << "Invalid ped model: Model: " << HEX_TO_UPPER(creation_node->m_model) << " From : " << sender->get_name(); - if (g->notifications.invalid_sync.notify) - g_notification_service->push_warning(std::format("Invalid ped model from {}", sender->get_name()), std::format("Model: 0x{:x}", creation_node->m_model)); - return true; - } - else if (creation_node->m_has_prop && is_model_a_crash_model(creation_node->m_prop_model)) { - if (g->notifications.invalid_sync.log) - LOG(WARNING) << "Invalid ped prop model: Model: " << HEX_TO_UPPER(creation_node->m_prop_model) << " From : " << sender->get_name(); - if (g->notifications.invalid_sync.notify) - g_notification_service->push_warning(std::format("Invalid ped prop model from {}", sender->get_name()), std::format("Model: 0x{:x}", creation_node->m_prop_model)); - return true; - } - break; - } - case "?AVCPedAttachDataNode@@"_fnv1a: //CPedAttachDataNode - { - const auto attach_node = dynamic_cast(node); - if (attach_node->m_attached && attach_node->m_attached_to == object_id) - { - if (g->notifications.invalid_sync.log) - LOG(WARNING) << "Infinite ped attachment: Node: " << typeid(*node).name() << " From : " << sender->get_name(); - if (g->notifications.invalid_sync.notify) - g_notification_service->push_warning(std::format("Infinite ped attachment from {}", sender->get_name()), std::format("Node: {}", typeid(*node).name())); - return true; - } - else if (attach_node->m_attached && is_ped_attachment_infinite(attach_node, object_id)) - { - if (g->notifications.invalid_sync.log) - LOG(WARNING) << "Infinite ped attachment v2: Node: " << typeid(*node).name() << " From : " << sender->get_name(); - if (g->notifications.invalid_sync.notify) - g_notification_service->push_warning(std::format("Infinite ped attachment v2 from {}", sender->get_name()), std::format("Node: {}", typeid(*node).name())); - return true; - } - break; - } - case "?AVCPedInventoryDataNode@@"_fnv1a://CPedInventoryDataNode - { - const auto inventory_node = dynamic_cast(node); - if (inventory_node->m_num_items > 105 || inventory_node->m_num_ammos > 65) - { - if (g->notifications.invalid_sync.log) - LOG(WARNING) << "Invalid inventory data from: " << sender->get_name(); - if (g->notifications.invalid_sync.notify) - g_notification_service->push_warning(std::format("Invalid inventory data from {}", sender->get_name()), "Invalid inventory data."); - return true; - } - break; - } - case "?AVCVehicleCreationDataNode@@"_fnv1a: //CVehicleCreationDataNode - { - const auto vehicle_creation_node = dynamic_cast(node); - if (is_model_a_crash_model(vehicle_creation_node->m_model)) { - if (g->notifications.invalid_sync.log) - LOG(WARNING) << "Invalid vehicle model: Model: " << HEX_TO_UPPER(vehicle_creation_node->m_model) << " From : " << sender->get_name(); - if (g->notifications.invalid_sync.notify) - g_notification_service->push_warning(std::format("Invalid vehicle model from {}", sender->get_name()), std::format("Model: 0x{:x}", vehicle_creation_node->m_model)); - return true; - } - break; - } - case "?AVCVehicleGadgetDataNode@@"_fnv1a: //CVehicleGadgetDataNode - { - const auto vehicle_gadget_node = dynamic_cast(node); - if (vehicle_gadget_node->m_gadget_count > 2) - { - if (g->notifications.invalid_sync.log) - LOG(WARNING) << "Invalid vehicle gadget count from: " << sender->get_name(); - if (g->notifications.invalid_sync.notify) - g_notification_service->push_warning(std::format("Invalid vehicle gadget count from {}", sender->get_name()), "Invalid vehicle gadget count."); - return true; - } - break; - } - case "?AVCObjectCreationDataNode@@"_fnv1a: //CObjectCreationDataNode - { - const auto creation_node = dynamic_cast(node); - if (is_model_a_crash_model(creation_node->m_model)) { - if (g->notifications.invalid_sync.log) - LOG(WARNING) << "Invalid object model: Model: " << HEX_TO_UPPER(creation_node->m_model) << " From : " << sender->get_name(); - if (g->notifications.invalid_sync.notify) - g_notification_service->push_warning(std::format("Invalid object model from {}", sender->get_name()), std::format("Model: 0x{:x}", creation_node->m_model)); - return true; - } - else if (is_model_a_cage_model(creation_node->m_model)) { - if (g->notifications.invalid_sync.log) - LOG(WARNING) << "Cage model: Model: " << HEX_TO_UPPER(creation_node->m_model) << " From : " << sender->get_name(); - if (g->notifications.invalid_sync.notify) - g_notification_service->push_warning(std::format("Cage model from {}", sender->get_name()), std::format("Model: 0x{:x}", creation_node->m_model)); - return true; - } - break; - } - case "?AVCPlayerAppearanceDataNode@@"_fnv1a: //CPlayerAppearanceDataNode - { - const auto player_appearance_node = dynamic_cast(node); - if (is_model_a_crash_model(player_appearance_node->m_model_hash)) { - if (g->notifications.invalid_sync.log) - LOG(WARNING) << "Invalid player model: Model:" << HEX_TO_UPPER(player_appearance_node->m_model_hash) << " From : " << sender->get_name(); - if (g->notifications.invalid_sync.notify) - g_notification_service->push_warning(std::format("Invalid player model from {}", sender->get_name()), std::format("Model: 0x{:x}", player_appearance_node->m_model_hash)); - return true; - } - break; - } - case "?AVCSectorDataNode@@"_fnv1a: //CSectorDataNode - { - const auto sector_node = dynamic_cast(node); - if (sector_node->m_pos_x == 712 || sector_node->m_pos_y == 712 || sector_node->m_pos_z == 712) - { - if (g->notifications.invalid_sync.log) - LOG(WARNING) << "Invalid sector position from: " << sender->get_name(); - if (g->notifications.invalid_sync.notify) - g_notification_service->push_warning(std::format("Invalid sector position from {}", sender->get_name()), "Invalid sector position."); - return true; - } - break; - } - case "?AVCDynamicEntityGameStateDataNode@@"_fnv1a: //CDynamicEntityGameStateDataNode - { - const auto game_state_node = dynamic_cast(node); - if (game_state_node->m_decor_count > 11) - { - if (g->notifications.invalid_sync.log) - LOG(WARNING) << "Invalid decorator count from: " << sender->get_name(); - if (g->notifications.invalid_sync.notify) - g_notification_service->push_warning(std::format("Invalid decorator count from {}", sender->get_name()), "Invalid decorator count."); - return true; - } - break; - } - } - } - return false; - } - - 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) - { - if (auto net_obj = g_pointers->m_get_net_object(mgr, obj_id, true); net_obj) - { - auto tree_name = g_pointers->m_get_sync_type_info(sync_type, 0); - - if (sync_type < eObjType::carObjType || sync_type > eObjType::unkObjType14) - { - if (g->notifications.out_of_allowed_range_sync_type.log) - LOG(WARNING) << "Out of Bounds sync: Type: " << sync_type << " Tree name: " << tree_name << " From: " << src->get_name(); - if (g->notifications.out_of_allowed_range_sync_type.notify) - g_notification_service->push_warning(std::format("Out Of Allowed Sync Range from {}", src->get_name()), std::format("Type {} in sync tree {}", std::uint16_t(sync_type), tree_name)); - - return g_hooking->get_original()(mgr, src, dst, sync_type, obj_id, buffer, unk, timestamp); - } - - if (net_obj->m_object_type != sync_type) - { - if (g->notifications.mismatch_sync_type.log) - LOG(WARNING) << "Mismatch sync: Type: " << sync_type << " Tree name: " << tree_name << " From: " << src->get_name(); - if (g->notifications.mismatch_sync_type.notify) - g_notification_service->push_warning(std::format("Mismatch Sync from {}", src->get_name()), std::format("Type {} in sync tree {}", std::uint16_t(sync_type), tree_name)); - - return eSyncReply::WrongOwner; - } - - if (auto game_obj = net_obj->GetGameObject(); game_obj) - { - if (const auto model_info = game_obj->m_model_info; model_info) - { - // sync_type is telling us it's a vehicle - // let's check if it's actually a vehicle according to our game... - if (((sync_type >= eObjType::bikeObjType && sync_type <= eObjType::heliObjType) - || (sync_type >= eObjType::planeObjType && sync_type <= eObjType::submarineObjType) - || (sync_type >= eObjType::trailerObjType && sync_type <= eObjType::trainObjType)) - && model_info->m_model_type != eModelType::Vehicle) - { - return eSyncReply::CantApplyData; - } - } - else - { - // Fall through? Should not happen but let's try to be safe - return eSyncReply::CantApplyData; - } - } - - uint32_t pos = buffer->m_bitsRead; - g_pointers->m_read_bitbuffer_into_sync_tree(sync_tree, 2, 0, buffer, 0); - buffer->Seek(pos); - - //LOG(INFO) << typeid(*tree).name() << ": " << HEX_TO_UPPER(typeid(*tree).hash_code()); //Use this to get hashes for each tree - - if (sync_tree->m_child_node_count && check_node(sync_tree->m_sync_node, src, obj_id)) - { - return eSyncReply::CantApplyData; - } - } - } - return g_hooking->get_original()(mgr, src, dst, sync_type, obj_id, buffer, unk, timestamp); + g->m_syncing_player = src; + return g_hooking->get_original()(mgr, src, dst, object_type, object_id, buffer, unk, timestamp); } } diff --git a/src/hooks/protections/received_event.cpp b/src/hooks/protections/received_event.cpp index 7120f226..10d6128b 100644 --- a/src/hooks/protections/received_event.cpp +++ b/src/hooks/protections/received_event.cpp @@ -3,6 +3,7 @@ #include "hooking.hpp" #include #include "gta/script_id.hpp" +#include "util/notify.hpp" namespace big { @@ -32,7 +33,6 @@ namespace big if (event_id > 91u) { g_pointers->m_send_event_ack(event_manager, source_player, target_player, event_index, event_handled_bitset); - return; } @@ -81,15 +81,10 @@ namespace big uint16_t unk2 = buffer->Read(13); uint32_t action = buffer->Read(8); - if (action >= 15 && action <= 18 || action == 33) + if ((action >= 15 && action <= 18) || action == 33) { g_pointers->m_send_event_ack(event_manager, source_player, target_player, event_index, event_handled_bitset); - - if (g->notifications.received_event.vehicle_temp_action.log) - LOG(INFO) << "RECEIVED_EVENT_HANDLER : " << source_player->get_name() << " sent TASK_VEHICLE_TEMP_ACTION crash."; - if (g->notifications.received_event.vehicle_temp_action.notify) - g_notification_service->push_error("Protections", std::format("{} sent TASK_VEHICLE_TEMP_ACTION crash.", source_player->get_name())); - + notify::crash_blocked(source_player, "vehicle temp action"); return; } } @@ -172,7 +167,6 @@ namespace big break; } // player sending this event is a modder - case eNetworkEvents::NETWORK_CHECK_CODE_CRCS_EVENT: case eNetworkEvents::REPORT_MYSELF_EVENT: { if (g->notifications.received_event.modder_detect.log) @@ -180,6 +174,9 @@ namespace big if (g->notifications.received_event.modder_detect.notify) g_notification_service->push_warning("Protections", std::format("{} sent out a modder event.", source_player->get_name())); + if (auto plyr = g_player_service->get_by_id(source_player->m_player_id)) + session::add_infraction(plyr, Infraction::TRIGGERED_ANTICHEAT); + break; } case eNetworkEvents::REQUEST_CONTROL_EVENT: @@ -202,7 +199,7 @@ namespace big case eNetworkEvents::SCRIPT_WORLD_STATE_EVENT: { auto type = buffer->Read(4); - (void)buffer->Read(1); + buffer->Read(1); CGameScriptId id; script_id_deserialize(id, *buffer); @@ -221,7 +218,8 @@ namespace big if (type != 7) { // most definitely a crash - g_notification_service->push_error("Protections", std::format("{} sent rope crash.", source_player->get_name())); + LOG(INFO) << std::hex << std::uppercase << "0x" << id.m_hash; + notify::crash_blocked(source_player, "rope"); g_pointers->m_send_event_ack(event_manager, source_player, target_player, event_index, event_handled_bitset); return; } @@ -234,7 +232,7 @@ namespace big if (unk2 == 0 && (unk3 == 0 || unk3 == 103)) { - g_notification_service->push_error("Protections", std::format("{} sent SCRIPT_WORLD_STATE_EVENT crash.", source_player->get_name())); + notify::crash_blocked(source_player, "pop group override"); g_pointers->m_send_event_ack(event_manager, source_player, target_player, event_index, event_handled_bitset); return; } @@ -250,6 +248,7 @@ namespace big if (hash == RAGE_JOAAT("WEAPON_UNARMED")) { + notify::crash_blocked(source_player, "remove unarmed"); g_pointers->m_send_event_ack(event_manager, source_player, target_player, event_index, event_handled_bitset); return; } @@ -278,6 +277,35 @@ namespace big buffer->Seek(0); break; } + case eNetworkEvents::GIVE_CONTROL_EVENT: + { + uint32_t timestamp = buffer->Read(32); + int count = buffer->Read(2); + bool unk = buffer->Read(1); + + if (count > 3) + { + count = 3; + } + + for (int i = 0; i < count; i++) + { + int net_id = buffer->Read(13); + eNetObjType object_type = buffer->Read(4); + int unk = buffer->Read(3); + + if (object_type < eNetObjType::NET_OBJ_TYPE_AUTOMOBILE || object_type > eNetObjType::NET_OBJ_TYPE_TRAIN) + { + notify::crash_blocked(source_player, "out of bounds give control type"); + g_pointers->m_send_event_ack(event_manager, source_player, target_player, event_index, event_handled_bitset); + return; + } + } + + buffer->Seek(0); + g->m_syncing_player = source_player; + break; + } default: break; } diff --git a/src/hooks/protections/script_event_handler.cpp b/src/hooks/protections/script_event_handler.cpp index 51339e73..6c8ad1cd 100644 --- a/src/hooks/protections/script_event_handler.cpp +++ b/src/hooks/protections/script_event_handler.cpp @@ -1,5 +1,6 @@ #include "hooking.hpp" #include "gta_util.hpp" +#include "util/session.hpp" #include namespace big @@ -276,8 +277,9 @@ namespace big case eRemoteEvent::SHKick: if (g->protections.script_events.network_bail) { + if (auto plyr = g_player_service->get_by_id(player->m_player_id)) + session::add_infraction(plyr, Infraction::TRIED_KICK_PLAYER); format_string(player_name, "Network Bail", notify.network_bail.log, notify.network_bail.notify); - return true; } break; diff --git a/src/hooks/protections/serialize_dynamic_entity_game_state_data_node.cpp b/src/hooks/protections/serialize_dynamic_entity_game_state_data_node.cpp new file mode 100644 index 00000000..d08d87ab --- /dev/null +++ b/src/hooks/protections/serialize_dynamic_entity_game_state_data_node.cpp @@ -0,0 +1,58 @@ +#include "hooking.hpp" +#include "gta/net_game_event.hpp" +#include "util/notify.hpp" +#include + +namespace big +{ + constexpr uint32_t NULL_INTERIOR = 0x0FFFCFFFF; + + void hooks::serialize_dynamic_entity_game_state_data_node(CDynamicEntityGameStateDataNode* node, rage::CSyncDataBase* data) + { + data->SerializeBool(&node->unk_00C5); + if (node->unk_00C5 && !data->IsSizeCalculator()) + { + data->SerializeDwordAlt(&node->m_interior_index, 32); + } + else + { + bool is_null_interior = node->m_interior_index == NULL_INTERIOR; + data->SerializeBool(&is_null_interior); + + if (!is_null_interior || data->IsSizeCalculator()) + { + data->SerializeDwordAlt(&node->m_interior_index, 32); + } + else + { + node->m_interior_index = NULL_INTERIOR; + } + } + + data->SerializeBool(&node->unk_00C4); + + bool has_decors = node->m_decor_count != 0; + data->SerializeBool(&has_decors); + + if (has_decors || data->IsSizeCalculator()) + { + data->SerializeDwordAlt(&node->m_decor_count, 4); + + if (data->IsSizeCalculator()) + node->m_decor_count = 11; + + if (node->m_decor_count > 11) + { + notify::crash_blocked(g->m_syncing_player, "out of bounds decorator count"); + return; + } + + for (uint32_t i = 0; i < node->m_decor_count; i++) + { + data->SerializeDwordAlt(&node->m_decors[i].m_type, 3); + data->SerializeDwordAlt(&node->m_decors[i].m_value, 32); + data->SerializeDwordAlt(&node->m_decors[i].m_name_hash, 32); + } + } + } +} \ No newline at end of file diff --git a/src/hooks/protections/serialize_ped_inventory_data_node.cpp b/src/hooks/protections/serialize_ped_inventory_data_node.cpp new file mode 100644 index 00000000..7edd2a0f --- /dev/null +++ b/src/hooks/protections/serialize_ped_inventory_data_node.cpp @@ -0,0 +1,49 @@ +#include "hooking.hpp" +#include "gta/net_game_event.hpp" +#include "util/notify.hpp" +#include + +namespace big +{ + void hooks::serialize_ped_inventory_data_node(CPedInventoryDataNode* node, rage::CSyncDataBase* data) + { + if (data->IsSizeCalculator()) + { + node->m_num_items = 105; + node->m_num_ammos = 65; + } + + data->SerializeDwordAlt(&node->m_num_items, 7); + if (node->m_num_items > 105) + { + notify::crash_blocked(g->m_syncing_player, "out of bounds inventory item count"); + return; + } + + for (uint32_t i = 0; i < node->m_num_items; i++) + { + data->SerializeDwordAlt(&node->m_items[i], 9); + node->unk_1680[i] = 0; + node->unk_16E9[i] = 0; + } + + data->SerializeDwordAlt(&node->m_num_ammos, 7); + data->SerializeBool(&node->m_ammo_all_infinite); + if (node->m_num_ammos > 65) + { + notify::crash_blocked(g->m_syncing_player, "out of bounds inventory ammo count"); + return; + } + + for (uint32_t i = 0; i < node->m_num_ammos; i++) + { + data->SerializeDwordAlt(&node->m_ammos[i], 9); + if (node->m_ammo_all_infinite && !data->IsSizeCalculator()) + continue; + data->SerializeBool(&node->m_infinite_ammos[i]); + if (node->m_infinite_ammos[i] && !data->IsSizeCalculator()) + continue; + data->SerializeDwordAlt(&node->m_ammo_quantities[i], 14); + } + } +} \ No newline at end of file diff --git a/src/hooks/protections/serialize_vehicle_gadget_data_node.cpp b/src/hooks/protections/serialize_vehicle_gadget_data_node.cpp new file mode 100644 index 00000000..d688c5eb --- /dev/null +++ b/src/hooks/protections/serialize_vehicle_gadget_data_node.cpp @@ -0,0 +1,49 @@ +#include "hooking.hpp" +#include "gta/net_game_event.hpp" +#include "util/notify.hpp" +#include + +namespace big +{ + void hooks::serialize_vehicle_gadget_data_node(CVehicleGadgetDataNode* node, rage::CSyncDataBase* data) + { + data->SerializeBool(&node->m_has_parent_offset); + if (node->m_has_parent_offset || data->IsSizeCalculator()) + { + data->SerializeSignedFloat((float*)&node->m_parent_offset_x, 24.0f, 14); + data->SerializeSignedFloat((float*)&node->m_parent_offset_y, 24.0f, 14); + data->SerializeSignedFloat((float*)&node->m_parent_offset_z, 24.0f, 14); + } + else + { + node->m_parent_offset_x = 0; + node->m_parent_offset_y = 0; + node->m_parent_offset_z = 0; + node->m_parent_offset_w = 0; + } + + data->SerializeDwordAlt(&node->m_gadget_count, 2); + + if (data->IsSizeCalculator()) + node->m_gadget_count = 2; + + if (node->m_gadget_count > 2) + { + notify::crash_blocked(g->m_syncing_player, "out of bounds vehicle gadget count"); + return; + } + + for (uint32_t i = 0; i < node->m_gadget_count; i++) + { + data->SerializeDwordAlt((uint32_t*)&node->m_gadget_data[i].m_gadget_type, 3); + + int size; + if (data->IsSizeCalculator()) + size = 94; + else + size = g_pointers->m_get_vehicle_gadget_array_size(node->m_gadget_data[i].m_gadget_type); + + data->SerializeArray(&node->m_gadget_data[i].m_data, size); + } + } +} \ No newline at end of file diff --git a/src/hooks/spoofing/write_player_gamer_data_node.cpp b/src/hooks/spoofing/write_player_gamer_data_node.cpp index b33877e9..51e25c2f 100644 --- a/src/hooks/spoofing/write_player_gamer_data_node.cpp +++ b/src/hooks/spoofing/write_player_gamer_data_node.cpp @@ -1,4 +1,5 @@ #include "hooking.hpp" +#include namespace big { diff --git a/src/json_util.hpp b/src/json_util.hpp new file mode 100644 index 00000000..4ee15127 --- /dev/null +++ b/src/json_util.hpp @@ -0,0 +1,17 @@ +#pragma once + +namespace big +{ + template + static inline void set_from_key_or_default(const nlohmann::json& j, const char* key, ValueType& value, ValueType default_value = {}) + { + if (j.contains(key)) + { + j.at(key).get_to(value); + } + else + { + value = default_value; + } + } +} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index c297fad9..f4ce99f0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -23,6 +23,7 @@ #include "services/model_preview/model_preview_service.hpp" #include "services/vehicle/handling_service.hpp" #include "services/script_patcher/script_patcher_service.hpp" +#include "services/player_database/player_database_service.hpp" BOOL APIENTRY DllMain(HMODULE hmod, DWORD reason, PVOID) { @@ -86,6 +87,7 @@ BOOL APIENTRY DllMain(HMODULE hmod, DWORD reason, PVOID) auto handling_service_instance = std::make_unique(); auto gui_service_instance = std::make_unique(); auto script_patcher_service_instance = std::make_unique(); + auto player_database_service_instance = std::make_unique(); LOG(INFO) << "Registered service instances..."; g_script_mgr.add_script(std::make_unique