diff --git a/scripts/gtav-classes.cmake b/scripts/gtav-classes.cmake index 55b80e5a..26c4ec79 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 3c7763fcf996f53f891e40f12bbfa8115fd612a7 + GIT_TAG 9e76175d28b3de21c24a69e71bee779d704d8304 GIT_PROGRESS TRUE CONFIGURE_COMMAND "" BUILD_COMMAND "" diff --git a/src/function_types.hpp b/src/function_types.hpp index 581b4f61..ca87da5e 100644 --- a/src/function_types.hpp +++ b/src/function_types.hpp @@ -64,7 +64,7 @@ namespace big::functions using ptr_to_handle = Entity (*)(void*); using handle_to_ptr = rage::CDynamicEntity* (*)(Entity); - using set_gravity_level = void(*)(int level); + using set_gravity_level = void (*)(int level); using check_chat_profanity = int(__int64 chat_type, const char* input, const char** output); using write_player_game_state_data_node = bool (*)(rage::netObject* plr, CPlayerGameStateDataNode* node); @@ -120,9 +120,9 @@ namespace big::functions using start_get_presence_attributes = bool (*)(int profile_index, rage::rlScHandle* handle, int num_handles, rage::rlQueryPresenceAttributesContext** contexts, int count, rage::rlScTaskStatus* state); using join_session_by_info = bool (*)(Network* network, rage::rlSessionInfo* info, int unk, int flags, rage::rlGamerHandle* handles, int handlecount); - using invite_player_by_gamer_handle = bool(*)(uint64_t config, rage::rlGamerHandle* handle, int unk1, int unk2, int unk3, int unk4); - using add_friend_by_gamer_handle = void(*)(rage::rlGamerHandle* handle, const char* unk); - using show_profile_by_gamer_handle = void(*)(rage::rlGamerHandle* handle); + using invite_player_by_gamer_handle = bool (*)(uint64_t config, rage::rlGamerHandle* handle, int unk1, int unk2, int unk3, int unk4); + using add_friend_by_gamer_handle = void (*)(rage::rlGamerHandle* handle, const char* unk); + using show_profile_by_gamer_handle = void (*)(rage::rlGamerHandle* handle); using generate_uuid = bool (*)(uint64_t* uuid); @@ -194,9 +194,9 @@ namespace big::functions using delete_vehicle = bool (*)(CVehicle* veh); using delete_object = bool (*)(CObject* object, bool unk); - using decal_manager_remove = void(*)(PVOID manager, rage::fwEntity*, DWORD a3, DWORD64 a4, DWORD ignore_bitset); + using decal_manager_remove = void (*)(PVOID manager, rage::fwEntity*, DWORD a3, DWORD64 a4, DWORD ignore_bitset); - using remove_player_from_sender_list = bool(*)(void* list, uint64_t* rockstar_id); + using remove_player_from_sender_list = bool (*)(void* list, uint64_t* rockstar_id); - using get_ped_bone = bool(*)(CPed* ped_ptr, rage::fvector4& output, PedBones bone); + using get_ped_bone = bool (*)(CPed* ped_ptr, rage::fvector4& output, PedBones bone); } diff --git a/src/gta/json_serializer.hpp b/src/gta/json_serializer.hpp index b2fb56c1..d8349e4e 100644 --- a/src/gta/json_serializer.hpp +++ b/src/gta/json_serializer.hpp @@ -18,12 +18,11 @@ namespace rage buffer(_buffer), maxlen(_length) { - unk0 - = 0; - unk1 = 0; - curlen = 0; - unk4 = 1; - flags = 0; + unk0 = 0; + unk1 = 0; + curlen = 0; + unk4 = 1; + flags = 0; } inline char* get_string() const diff --git a/src/gta_pointers.hpp b/src/gta_pointers.hpp index 2e315567..ae7a0896 100644 --- a/src/gta_pointers.hpp +++ b/src/gta_pointers.hpp @@ -1,7 +1,8 @@ #pragma once -#include #include "function_types.hpp" +#include + class CCommunications; class FriendRegistry; class CNetworkPlayerMgr; @@ -27,6 +28,7 @@ namespace rage class RageSecurity; class netTime; class rlGamerInfo; + struct game_skeleton; } template @@ -71,6 +73,8 @@ namespace big CPedFactory** m_ped_factory; CNetworkPlayerMgr** m_network_player_mgr; CNetworkObjectMgr** m_network_object_mgr; + rage::game_skeleton* m_game_skeleton; + void (*m_nullsub)(); functions::ptr_to_handle m_ptr_to_handle; functions::handle_to_ptr m_handle_to_ptr; @@ -353,8 +357,6 @@ namespace big bool* m_is_social_club_overlay_active; - PVOID m_game_skeleton_update; - functions::get_ped_bone m_get_ped_bone; }; #pragma pack(pop) diff --git a/src/gta_util.hpp b/src/gta_util.hpp index c81e8891..b07ec1a7 100644 --- a/src/gta_util.hpp +++ b/src/gta_util.hpp @@ -1,7 +1,7 @@ #pragma once #include "gta/script_thread.hpp" -#include "script/tlsContext.hpp" #include "pointers.hpp" +#include "script/tlsContext.hpp" #include #include diff --git a/src/hooking.cpp b/src/hooking.cpp index d6a1613b..cbc1299c 100644 --- a/src/hooking.cpp +++ b/src/hooking.cpp @@ -147,8 +147,6 @@ namespace big detour_hook_helper::add("RBS", g_pointers->m_gta.m_read_bits_single); - detour_hook_helper::add("GSU", g_pointers->m_gta.m_game_skeleton_update); - g_hooking = this; } diff --git a/src/hooking.hpp b/src/hooking.hpp index 60eaea5c..e22e5641 100644 --- a/src/hooking.hpp +++ b/src/hooking.hpp @@ -1,14 +1,14 @@ #pragma once #include "MinHook.h" +#include "call_hook.hpp" #include "common.hpp" #include "detour_hook.hpp" #include "gta/enums.hpp" #include "gta/fwddec.hpp" -#include "gta/script_thread.hpp" #include "gta/json_serializer.hpp" +#include "gta/script_thread.hpp" #include "vmt_hook.hpp" #include "vtable_hook.hpp" -#include "call_hook.hpp" #include @@ -128,7 +128,7 @@ namespace big static void serialize_parachute_task(__int64 info, rage::CSyncDataBase* serializer); static int nt_query_virtual_memory(void* _this, HANDLE handle, PVOID base_addr, int info_class, MEMORY_BASIC_INFORMATION* info, int size, size_t* return_len); - static int queue_dependency(void* a1, int a2, void* dependency); + static int queue_dependency(void* a1, int a2, int64_t dependency); static bool prepare_metric_for_sending(rage::json_serializer* bit_buffer, int unk, int time, rage::rlMetric* metric); static bool http_start_request(void* request, const char* uri); @@ -185,7 +185,6 @@ namespace big static bool sync_reader_serialize_array(void* _this, void* array, int size); static bool remove_player_from_sender_list(void* list, uint64_t rockstar_id); - static void game_skeleton_update(__int64 skeleton, int type); }; class minhook_keepalive diff --git a/src/hooks/info/prepare_metric_for_sending.cpp b/src/hooks/info/prepare_metric_for_sending.cpp index ff9ad036..4f6cef9d 100644 --- a/src/hooks/info/prepare_metric_for_sending.cpp +++ b/src/hooks/info/prepare_metric_for_sending.cpp @@ -3,7 +3,7 @@ namespace big { - const auto bad_metrics = std::unordered_set({ + const auto bad_metrics = std::unordered_set({ "REPORTER", "REPORT_INVALIDMODEL", "MEM_NEW", @@ -36,6 +36,7 @@ namespace big "GSINT", "EARN", "GARAGE_TAMPER", + "DUPE_DETECT", "LAST_VEH", "FAIL_SERV", "CCF_UPDATE", @@ -43,25 +44,72 @@ namespace big "COLLECTIBLE", "FIRST_VEH", "MM", + "RDEV", + "RQA", + "RANK_UP", }); + std::string hex_encode(std::string_view input) { + const char* hex_chars = "0123456789ABCDEF"; + std::string output; + output.reserve(input.length() * 2); // Pre-allocate memory for efficiency + for (unsigned char c : input) { + output.push_back(hex_chars[c >> 4]); // Extract the high nibble (4 bits) + output.push_back(hex_chars[c & 0x0F]); // Extract the low nibble + } + return output; + } + + std::string remove_module_from_mmlist(std::string_view input, std::string_view element_to_remove) { + std::string result(input); + std::string delimiter = "|"; + size_t start_pos = 0; + + while (true) { + size_t delimiter_pos = result.find(delimiter, start_pos); + if (delimiter_pos == std::string::npos) { + break; + } + std::string current_element = result.substr(start_pos, delimiter_pos - start_pos); + if (current_element == element_to_remove) { + result.erase(start_pos, delimiter_pos - start_pos + delimiter.length()); + break; + } + start_pos = delimiter_pos + delimiter.length(); + } + + return result; + } + bool hooks::prepare_metric_for_sending(rage::json_serializer* serializer, int unk, int time, rage::rlMetric* metric) { - const auto ret = g_hooking->get_original()(serializer, unk, time, metric); - - const auto is_bad_metric = bad_metrics.contains(metric->get_name()); + char metric_json_buffer [256] {}; + rage::json_serializer yim_serializer(metric_json_buffer, sizeof(metric_json_buffer)); + metric->serialize(&yim_serializer); + const bool is_bad_metric = bad_metrics.contains(metric->get_name()); if (is_bad_metric) { - LOG(WARNING) << "BAD METRIC: " << metric->get_name() << "; DATA: " << serializer->get_string(); - + LOG(WARNING) << "BAD METRIC: " << metric->get_name() << "; DATA: " << yim_serializer.get_string(); + if(strcmp(metric->get_name(), "MM") == 0) + { + std::string data = std::string(reinterpret_cast(metric) + 0x18); + char module_name[MAX_PATH]; + GetModuleFileNameA(g_hmodule, module_name, sizeof(module_name)); + std::string encoded_module_name = hex_encode(std::filesystem::path(module_name).filename().string()); + std::string result = remove_module_from_mmlist(data, encoded_module_name + "00"); + if(result.size() != data.size()) + LOG(INFO) << "Removed YimMenu DLL from MM metric"; + strncpy(reinterpret_cast(metric) + 0x18, result.c_str(), 0x900); + return g_hooking->get_original()(serializer, unk, time, metric); + } return false; } if (!is_bad_metric && g.debug.logs.metric_logs) { - LOG(INFO) << "METRIC: " << metric->get_name() << "; DATA: " << serializer->get_string(); + LOG(INFO) << "METRIC: " << metric->get_name() << "; DATA: " << yim_serializer.get_string(); } - return ret; + return g_hooking->get_original()(serializer, unk, time, metric); } } diff --git a/src/hooks/misc/game_skeleton_update.cpp b/src/hooks/misc/game_skeleton_update.cpp deleted file mode 100644 index 5e68cb5a..00000000 --- a/src/hooks/misc/game_skeleton_update.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include "hooking.hpp" - -// rage::gameSkeleton -> modes (does not derive from updateBase?) -> groups -> items - -namespace big -{ - class game_skeleton_update_group; - class game_skeleton_item; - -#pragma pack(push, 8) - struct game_skeleton_update_mode - { - int m_type; // 0x00 - game_skeleton_update_group* m_groups; // 0x08 - game_skeleton_update_mode* m_next; // 0x10 - }; - static_assert(sizeof(game_skeleton_update_mode) == 0x18); - - struct game_skeleton_update_group - { - virtual ~game_skeleton_update_group() = default; - virtual void run() = 0; // 0x08 - - char pad[0x10]; // 0x08 - game_skeleton_update_group* m_next; // 0x18 - game_skeleton_item* m_items; // 0x20 - }; - static_assert(sizeof(game_skeleton_update_group) == 0x28); - - struct game_skeleton_item - { - virtual ~game_skeleton_item() = default; - virtual void run() = 0; // 0x08 - - char m_pad[0x8]; // 0x08 - uint32_t m_hash; // 0x10 - game_skeleton_item* m_next; // 0x18 - }; - static_assert(sizeof(game_skeleton_item) == 0x20); -#pragma pack(pop) - - void hooks::game_skeleton_update(__int64 skeleton, int type) - { - for (auto mode = *(game_skeleton_update_mode**)(skeleton + 0x140); mode; mode = mode->m_next) - { - if (mode && mode->m_type == type) - { - for (auto group = mode->m_groups; group; group = group->m_next) - { - for (auto item = group->m_items; item; item = item->m_next) - { - if (item->m_hash != 0xA0F39FB6) - { - item->run(); - } - } - } - - break; - } - } - } -} diff --git a/src/hooks/misc/queue_dependency.cpp b/src/hooks/misc/queue_dependency.cpp index a0b959e6..997d3805 100644 --- a/src/hooks/misc/queue_dependency.cpp +++ b/src/hooks/misc/queue_dependency.cpp @@ -1,15 +1,17 @@ #include "hooking.hpp" #include "pointers.hpp" - +#include "security/ObfVar.hpp" #include namespace big { - bool inline is_address_in_game_region(uint64_t address) + bool inline is_address_in_game_region(int64_t address) { - static uint64_t moduleBase = NULL; - static uint64_t moduleSize = NULL; - if ((!moduleBase) || (!moduleSize)) + if(!address) + return false; + static int64_t moduleBase = NULL; + static int64_t moduleSize = NULL; + if (!moduleBase || !moduleSize) { MODULEINFO info; if (!GetModuleInformation(GetCurrentProcess(), GetModuleHandle(0), &info, sizeof(info))) @@ -19,31 +21,34 @@ namespace big } else { - moduleBase = (uint64_t)GetModuleHandle(0); - moduleSize = (uint64_t)info.SizeOfImage; + moduleBase = (int64_t)GetModuleHandle(0); + moduleSize = (int64_t)info.SizeOfImage; } } return address > moduleBase && address < (moduleBase + moduleSize); } - bool is_jump(__int64 fptr) + struct ac_verifier { - if (!is_address_in_game_region(fptr)) + virtual ~ac_verifier() = 0; + virtual bool run() = 0; + rage::Obf32 m_last_time; // 0x8 + rage::Obf32 m_delay; // 0x18 + }; + + bool is_unwanted_dependency(int64_t cb) + { + int64_t f1 = *reinterpret_cast(cb + 0x60); + int64_t f2 = *reinterpret_cast(cb + 0x100); + int64_t f3 = *reinterpret_cast(cb + 0x1A0); + + if (!is_address_in_game_region(f1) || !is_address_in_game_region(f2) || !is_address_in_game_region(f3)) return false; - auto value = *(uint8_t*)(fptr); - return value == 0xE9; - } - - bool is_unwanted_dependency(__int64 cb) - { - auto f1 = *(__int64*)(cb + 0x60); - auto f2 = *(__int64*)(cb + 0x100); - - if (!is_address_in_game_region(f1) || (f2 && !is_address_in_game_region(f2))) + if(*reinterpret_cast(f1) != 0xE9) return false; - return is_jump(f1) || is_jump(f2); + return true; } static bool nullsub() @@ -51,12 +56,16 @@ namespace big return true; // returning false would cause the dependency to requeue } - int hooks::queue_dependency(void* a1, int a2, void* dependency) + int hooks::queue_dependency(void* a1, int a2, int64_t dependency) { - if (is_unwanted_dependency((__int64)dependency)) + if (is_unwanted_dependency(dependency)) { - *(void**)((__int64)dependency + 0x60) = nullsub; - *(void**)((__int64)dependency + 0x100) = nullsub; + LOG(INFO) << "Blocking AC Verifier " << std::hex << *reinterpret_cast(dependency + 0x60) - reinterpret_cast(GetModuleHandleA(0)); + ac_verifier* verifier = reinterpret_cast(dependency - 0x30); + verifier->m_delay = INT_MAX; // makes it so these won't queue in the future + *reinterpret_cast(dependency + 0x60) = nullsub; + *reinterpret_cast(dependency + 0x100) = nullsub; + *reinterpret_cast(dependency + 0x1A0) = nullsub; } return g_hooking->get_original()(a1, a2, dependency); diff --git a/src/main.cpp b/src/main.cpp index 69991324..7787f039 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -9,6 +9,7 @@ #include "lua/lua_manager.hpp" #include "native_hooks/native_hooks.hpp" #include "pointers.hpp" +#include "rage/gameSkeleton.hpp" #include "renderer.hpp" #include "script_mgr.hpp" #include "services/api/api_service.hpp" @@ -36,6 +37,41 @@ #include "thread_pool.hpp" #include "version.hpp" +namespace big +{ + void disable_anticheat_skeleton() + { + for (rage::game_skeleton_update_mode* mode = g_pointers->m_gta.m_game_skeleton->m_update_modes; mode; mode = mode->m_next) + { + for (rage::game_skeleton_update_base* update_node = mode->m_head; update_node; update_node = update_node->m_next) + { + if (update_node->m_hash != RAGE_JOAAT("Common Main")) + continue; + rage::game_skeleton_update_group* group = reinterpret_cast(update_node); + for (rage::game_skeleton_update_base* group_child_node = group->m_head; group_child_node; + group_child_node = group_child_node->m_next) + { + // TamperActions is a leftover from the old AC, but still useful to block anyway + if (group_child_node->m_hash != 0xA0F39FB6 && group_child_node->m_hash != RAGE_JOAAT("TamperActions")) + continue; + //LOG(INFO) << "Patching problematic skeleton update"; + reinterpret_cast(group_child_node)->m_function = + g_pointers->m_gta.m_nullsub; + } + break; + } + } + + for (rage::skeleton_data& i : g_pointers->m_gta.m_game_skeleton->m_sys_data) + { + if (i.m_hash != 0xA0F39FB6 && i.m_hash != RAGE_JOAAT("TamperActions")) + continue; + //LOG(INFO) << "Patching problematic skeleton init/shutdown"; + i.m_init_func = reinterpret_cast(g_pointers->m_gta.m_nullsub); + i.m_shutdown_func = reinterpret_cast(g_pointers->m_gta.m_nullsub); + } + } +} BOOL APIENTRY DllMain(HMODULE hmod, DWORD reason, PVOID) { @@ -75,6 +111,9 @@ BOOL APIENTRY DllMain(HMODULE hmod, DWORD reason, PVOID) auto pointers_instance = std::make_unique(); LOG(INFO) << "Pointers initialized."; + disable_anticheat_skeleton(); + LOG(INFO) << "Disabled anticheat gameskeleton."; + auto byte_patch_manager_instance = std::make_unique(); LOG(INFO) << "Byte Patch Manager initialized."; @@ -85,8 +124,8 @@ BOOL APIENTRY DllMain(HMODULE hmod, DWORD reason, PVOID) auto fiber_pool_instance = std::make_unique(11); LOG(INFO) << "Fiber pool initialized."; - g_http_client.init(g_file_manager.get_project_file("./proxy_settings.json")); - LOG(INFO) << "HTTP Client initialized."; + g_http_client.init(g_file_manager.get_project_file("./proxy_settings.json")); + LOG(INFO) << "HTTP Client initialized."; g_translation_service.init(); LOG(INFO) << "Translation Service initialized."; diff --git a/src/pointers.cpp b/src/pointers.cpp index be5132b6..e1dc6a80 100644 --- a/src/pointers.cpp +++ b/src/pointers.cpp @@ -4,6 +4,7 @@ #include "hooking.hpp" #include "memory/all.hpp" #include "rage/atSingleton.hpp" +#include "rage/gameSkeleton.hpp" #include "sc_pointers_layout_info.hpp" #include "security/RageSecurity.hpp" @@ -1722,13 +1723,22 @@ namespace big g_pointers->m_gta.m_is_social_club_overlay_active = ptr.add(2).rip().as(); } }, - // Game Skeleton Update + // Game Skeleton { - "GSU", - "40 53 48 83 EC 20 48 8B 81 40 01", + "GS", + "48 8D 0D ? ? ? ? BA ? ? ? ? 74 05 BA ? ? ? ? E8 ? ? ? ? E8 ? ? ? ? C6 05 ? ? ? ? ? 48 8D 0D ? ? ? ? BA ? ? ? ? 84 DB 75 05 BA ? ? ? ? E8 ? ? ? ? 48 8B CD C6 05 ? ? ? ? ? E8 ? ? ? ? 84", [](memory::handle ptr) { - g_pointers->m_gta.m_game_skeleton_update = ptr.as(); + g_pointers->m_gta.m_game_skeleton = ptr.add(3).rip().as(); + } + }, + // Nullsub + { + "NS", + "C3", + [](memory::handle ptr) + { + g_pointers->m_gta.m_nullsub = ptr.as(); } }, // Get Ped Bone diff --git a/src/script_global.hpp b/src/script_global.hpp index 8f2c627b..856630e6 100644 --- a/src/script_global.hpp +++ b/src/script_global.hpp @@ -7,7 +7,7 @@ namespace big { public: constexpr script_global(std::size_t index) : - m_index(index) + m_index(index) { } @@ -35,6 +35,5 @@ namespace big private: void* get() const; std::size_t m_index; - }; } diff --git a/src/script_local.cpp b/src/script_local.cpp index c5c3137d..2694b169 100644 --- a/src/script_local.cpp +++ b/src/script_local.cpp @@ -18,8 +18,8 @@ namespace big } script_local::script_local(std::size_t index) : - m_index(index), - m_stack(nullptr) + m_index(index), + m_stack(nullptr) { } diff --git a/src/script_mgr.cpp b/src/script_mgr.cpp index 4b6e36c9..3369ef09 100644 --- a/src/script_mgr.cpp +++ b/src/script_mgr.cpp @@ -2,10 +2,10 @@ #include "common.hpp" #include "gta/script_thread.hpp" -#include "script/tlsContext.hpp" #include "gta_util.hpp" #include "invoker.hpp" #include "pointers.hpp" +#include "script/tlsContext.hpp" namespace big { diff --git a/src/script_mgr.hpp b/src/script_mgr.hpp index d687f3f4..b9ea7d38 100644 --- a/src/script_mgr.hpp +++ b/src/script_mgr.hpp @@ -1,7 +1,7 @@ #pragma once #include "common.hpp" -#include "script.hpp" #include "lua/lua_manager.hpp" +#include "script.hpp" namespace big { diff --git a/src/thread_pool.cpp b/src/thread_pool.cpp index 39d67b3c..1d23d847 100644 --- a/src/thread_pool.cpp +++ b/src/thread_pool.cpp @@ -4,8 +4,8 @@ namespace big { thread_pool::thread_pool(const std::size_t preallocated_thread_count) : m_accept_jobs(true), - m_allocated_thread_count(preallocated_thread_count), - m_busy_threads(0) + m_allocated_thread_count(preallocated_thread_count), + m_busy_threads(0) { rescale_thread_pool();