From 8acef742f2f965efc4b5d1549638f6b7d49a8482 Mon Sep 17 00:00:00 2001 From: Mr-X-GTA <110748953+Mr-X-GTA@users.noreply.github.com> Date: Sun, 4 Jan 2026 11:23:35 +0100 Subject: [PATCH] fix(anticheat): fix anticheat bypass (#843) --- src/core/hooking/Hooking.cpp | 1 + src/core/renderer/Renderer.cpp | 2 +- src/game/backend/AnticheatBypass.cpp | 54 ------------------- src/game/backend/NativeHooks.cpp | 1 - .../submenus/Network/SavedPlayers.cpp | 2 +- src/game/frontend/submenus/Player/Info.cpp | 35 +++++++++++- .../submenus/Settings/GUISettings.hpp | 1 - .../hooks/Anticheat/GameSkeletonUpdate.cpp | 34 ++++++++++++ src/game/hooks/Hooks.hpp | 2 + src/game/pointers/Pointers.cpp | 10 ++-- src/game/pointers/Pointers.hpp | 2 +- src/types/game_files/CGameDataHash.hpp | 3 +- src/types/network/PlatformAccountId.hpp | 21 ++++++++ src/types/network/netPlayer.hpp | 4 +- 14 files changed, 104 insertions(+), 68 deletions(-) create mode 100644 src/game/hooks/Anticheat/GameSkeletonUpdate.cpp create mode 100644 src/types/network/PlatformAccountId.hpp diff --git a/src/core/hooking/Hooking.cpp b/src/core/hooking/Hooking.cpp index 64cb358..f1967fd 100644 --- a/src/core/hooking/Hooking.cpp +++ b/src/core/hooking/Hooking.cpp @@ -17,6 +17,7 @@ namespace YimMenu BaseHook::Add(new DetourHook("ResizeBuffers", swapchain_vft[Hooks::SwapChain::VMTResizeBuffersIdx], Hooks::SwapChain::ResizeBuffers)); // BaseHook::Add(new DetourHook("QueueDependency", Pointers.QueueDependency, Hooks::Anticheat::QueueDependency)); + BaseHook::Add(new DetourHook("GameSkeletonUpdate", Pointers.GameSkeletonUpdate, Hooks::Anticheat::GameSkeletonUpdate)); BaseHook::Add(new DetourHook("PrepareMetricForSending", Pointers.PrepareMetricForSending, Hooks::Anticheat::PrepareMetricForSending)); BaseHook::Add(new DetourHook("GetThreadContext", reinterpret_cast(GetProcAddress(LoadLibraryA("kernel32.dll"), "GetThreadContext")), Hooks::Anticheat::GetThreadContext)); BaseHook::Add(new DetourHook("HttpStartRequest", Pointers.HttpStartRequest, Hooks::Anticheat::HttpStartRequest)); diff --git a/src/core/renderer/Renderer.cpp b/src/core/renderer/Renderer.cpp index bd2b049..d7c365f 100644 --- a/src/core/renderer/Renderer.cpp +++ b/src/core/renderer/Renderer.cpp @@ -190,7 +190,7 @@ namespace YimMenu m_HeapAllocator.Create(m_Device.Get(), m_DescriptorHeap.Get()); // never returns false, useless to check return - ImGui::CreateContext(&GetInstance().m_FontAtlas); + ImGui::CreateContext(); ImGui_ImplWin32_Init(*Pointers.Hwnd); ImGui_ImplDX12_InitInfo init_info = {}; diff --git a/src/game/backend/AnticheatBypass.cpp b/src/game/backend/AnticheatBypass.cpp index 77b536f..c226790 100644 --- a/src/game/backend/AnticheatBypass.cpp +++ b/src/game/backend/AnticheatBypass.cpp @@ -5,7 +5,6 @@ #include "game/pointers/Pointers.hpp" #include "game/backend/NativeHooks.hpp" #include "game/gta/Natives.hpp" -#include "types/rage/gameSkeleton.hpp" #include "types/anticheat/CAnticheatContext.hpp" using FnGetVersion = int (*)(); @@ -33,57 +32,6 @@ namespace YimMenu return NativeInvoker::GetNativeHandler(NativeIndex::NET_GAMESERVER_BEGIN_SERVICE)(ctx); } - static void NopGameSkeletonElement(rage::gameSkeletonUpdateElement* element) - { - // TODO: small memory leak - // Hey rockstar if you keep up with this I'll make you integrity check everything until you can't anymore, please grow a brain and realize that this is futile - // and kills performance if you're the host - auto vtable = *reinterpret_cast(element); - if (vtable[1] == Pointers.Nullsub) - return; // already nopped - - auto new_vtable = new void*[3]; - memcpy(new_vtable, vtable, sizeof(void*) * 3); - new_vtable[1] = Pointers.Nullsub; - *reinterpret_cast(element) = new_vtable; - } - - static void DefuseSigscanner() - { - bool patched = false; - for (auto mode = Pointers.GameSkeleton->m_UpdateModes; mode; mode = mode->m_Next) - { - for (auto update_node = mode->m_Head; update_node; update_node = update_node->m_Next) - { - if (update_node->m_Hash != "Common Main"_J) - continue; - - auto group = reinterpret_cast(update_node); - - for (auto 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 != "TamperActions"_J) - continue; - patched = true; - - NopGameSkeletonElement(reinterpret_cast(group_child_node)); - } - break; - } - } - - - if (patched) - { - LOGF(VERBOSE, "DefuseSigscanner: Patched out the sigscanner"); - } - else - { - LOGF(WARNING, "DefuseSigscanner: Failed to patch the sigscanner"); - } - } - void AnticheatBypass::RunOnStartupImpl() { bool loaded_late = false; @@ -102,8 +50,6 @@ namespace YimMenu void AnticheatBypass::RunScriptImpl() { - DefuseSigscanner(); - NativeHooks::AddHook("shop_controller"_J, NativeIndex::NET_GAMESERVER_BEGIN_SERVICE, &TransactionHook); m_IsFSLLoaded = CheckForFSL(); diff --git a/src/game/backend/NativeHooks.cpp b/src/game/backend/NativeHooks.cpp index 720c482..b9944fe 100644 --- a/src/game/backend/NativeHooks.cpp +++ b/src/game/backend/NativeHooks.cpp @@ -3,7 +3,6 @@ #include "game/gta/invoker/Invoker.hpp" #include "types/script/scrProgram.hpp" -#include "types/script/scrThread.hpp" namespace YimMenu diff --git a/src/game/frontend/submenus/Network/SavedPlayers.cpp b/src/game/frontend/submenus/Network/SavedPlayers.cpp index b47a095..17b7e98 100644 --- a/src/game/frontend/submenus/Network/SavedPlayers.cpp +++ b/src/game/frontend/submenus/Network/SavedPlayers.cpp @@ -27,7 +27,7 @@ namespace YimMenu::Submenus static bool ShouldRenderPlayer(std::string_view name, std::string_view search) { - if (!search[0]) + if (search.empty()) return true; if (name.size() < search.size()) diff --git a/src/game/frontend/submenus/Player/Info.cpp b/src/game/frontend/submenus/Player/Info.cpp index 261df7e..1830091 100644 --- a/src/game/frontend/submenus/Player/Info.cpp +++ b/src/game/frontend/submenus/Player/Info.cpp @@ -65,6 +65,37 @@ namespace YimMenu::Submenus ImGui::SetClipboardText(std::to_string(rid1).c_str()); } + auto& platformAccountId = Players::GetSelected().GetHandle()->m_PlatformAccountId; + switch (platformAccountId.m_Platform) + { + case PlatformAccountId::PLATFORM_XBOX: + ImGui::Text("Xbox User ID:"); + ImGui::SameLine(); + if (ImGui::SmallButton(std::to_string(platformAccountId.m_XboxUserId).c_str())) + { + ImGui::SetClipboardText(std::to_string(platformAccountId.m_XboxUserId).c_str()); + } + break; + case PlatformAccountId::PLATFORM_STEAM: + ImGui::Text("Steam ID:"); + ImGui::SameLine(); + if (ImGui::SmallButton(std::to_string(platformAccountId.m_SteamId).c_str())) + { + ImGui::SetClipboardText(std::to_string(platformAccountId.m_SteamId).c_str()); + } + break; + case PlatformAccountId::PLATFORM_EPIC: + ImGui::Text("Epic Account ID:"); + ImGui::SameLine(); + if (ImGui::SmallButton(platformAccountId.m_EpicAccountId)) + { + ImGui::SetClipboardText(platformAccountId.m_EpicAccountId); + } + break; + default: + break; + } + auto ip = Players::GetSelected().GetExternalAddress(); @@ -83,14 +114,14 @@ namespace YimMenu::Submenus if (ImGui::Button("View SC Profile")) FiberPool::Push([] { uint64_t handle[13]; - NETWORK::NETWORK_HANDLE_FROM_PLAYER(Players::GetSelected().GetId(), handle, sizeof(handle)); + NETWORK::NETWORK_HANDLE_FROM_PLAYER(Players::GetSelected().GetId(), handle, std::size(handle)); NETWORK::NETWORK_SHOW_PROFILE_UI(handle); }); ImGui::SameLine(); if (ImGui::Button("Add Friend")) FiberPool::Push([] { uint64_t handle[13]; - NETWORK::NETWORK_HANDLE_FROM_PLAYER(Players::GetSelected().GetId(), handle, sizeof(handle)); + NETWORK::NETWORK_HANDLE_FROM_PLAYER(Players::GetSelected().GetId(), handle, std::size(handle)); NETWORK::NETWORK_ADD_FRIEND(handle, ""); }); diff --git a/src/game/frontend/submenus/Settings/GUISettings.hpp b/src/game/frontend/submenus/Settings/GUISettings.hpp index b9f408b..dc085c5 100644 --- a/src/game/frontend/submenus/Settings/GUISettings.hpp +++ b/src/game/frontend/submenus/Settings/GUISettings.hpp @@ -2,7 +2,6 @@ #include "core/frontend/manager/Category.hpp" #include "game/frontend/items/Items.hpp" -#include namespace YimMenu { diff --git a/src/game/hooks/Anticheat/GameSkeletonUpdate.cpp b/src/game/hooks/Anticheat/GameSkeletonUpdate.cpp new file mode 100644 index 0000000..c06e0e9 --- /dev/null +++ b/src/game/hooks/Anticheat/GameSkeletonUpdate.cpp @@ -0,0 +1,34 @@ +#include "game/hooks/Hooks.hpp" +#include "core/util/Joaat.hpp" +#include "types/rage/gameSkeleton.hpp" + +namespace YimMenu::Hooks +{ + void Anticheat::GameSkeletonUpdate(rage::gameSkeleton* skeleton, int type) + { + for (auto mode = skeleton->m_UpdateModes; mode; mode = mode->m_Next) + { + if (mode->m_Type != type) + continue; + + for (auto group = mode->m_Head; group; group = group->m_Next) + { + if (group->m_Hash != "Common Main"_J) + { + group->Run(); + continue; + } + + for (auto item = static_cast(group)->m_Head; item; item = item->m_Next) + { + if (item->m_Hash != 0xA0F39FB6 && item->m_Hash != "TamperActions"_J) + { + item->Run(); + } + } + } + + break; + } + } +} \ No newline at end of file diff --git a/src/game/hooks/Hooks.hpp b/src/game/hooks/Hooks.hpp index 2fe72e7..00a3130 100644 --- a/src/game/hooks/Hooks.hpp +++ b/src/game/hooks/Hooks.hpp @@ -21,6 +21,7 @@ namespace rage class rlSessionDetailMsg; class rlSessionInfo; struct rlTaskStatus; + struct gameSkeleton; } class MatchmakingAttributes; @@ -44,6 +45,7 @@ namespace YimMenu::Hooks namespace Anticheat { extern void QueueDependency(__int64 a1); + extern void GameSkeletonUpdate(rage::gameSkeleton* skeleton, int type); extern bool PrepareMetricForSending(rage::JsonSerializer* ser, void* a2, void* a3, rage::rlMetric* metric); extern BOOL GetThreadContext(HANDLE hThread, LPCONTEXT lpContext); extern void HttpStartRequest(void* request); diff --git a/src/game/pointers/Pointers.cpp b/src/game/pointers/Pointers.cpp index 0578c88..d97ab9f 100644 --- a/src/game/pointers/Pointers.cpp +++ b/src/game/pointers/Pointers.cpp @@ -411,11 +411,6 @@ namespace YimMenu AssistedAimFindNewTarget = ptr.Sub(0x33).As(); }); - constexpr auto gameSkeletonPtrn = Pattern<"0F B6 C0 8D 14 00 83 C2 02">("GameSkeleton"); - scanner.Add(gameSkeletonPtrn, [this](PointerCalculator ptr) { - GameSkeleton = ptr.Add(0x9).Add(3).Rip().As(); - }); - constexpr auto anticheatInitializedHashPtrn = Pattern<"89 9E C8 00 00 00 48 8B 0D ? ? ? ? 48 85 C9 74 46">("AnticheatInitializedHash&GetAnticheatInitializedHash"); scanner.Add(anticheatInitializedHashPtrn, [this](PointerCalculator ptr) { AnticheatInitializedHash = ptr.Add(9).Rip().As(); @@ -457,6 +452,11 @@ namespace YimMenu MatchmakingSessionDetailSendResponse = addr.Add(0x2F).Rip().As(); }); + static constexpr auto gameSkeletonUpdatePtrn = Pattern<"56 48 83 EC 20 48 8B 81 40 01 00 00 48 85 C0">("GameSkeletonUpdate"); + scanner.Add(gameSkeletonUpdatePtrn, [this](PointerCalculator addr) { + GameSkeletonUpdate = addr.As(); + }); + if (!scanner.Scan()) { LOG(FATAL) << "Some patterns could not be found, unloading."; diff --git a/src/game/pointers/Pointers.hpp b/src/game/pointers/Pointers.hpp index 08cd357..ac5553c 100644 --- a/src/game/pointers/Pointers.hpp +++ b/src/game/pointers/Pointers.hpp @@ -160,7 +160,6 @@ namespace YimMenu PVOID GetDLCHash; PVOID AssistedAimShouldReleaseEntity; Functions::AssistedAimFindNewTarget AssistedAimFindNewTarget; - rage::gameSkeleton* GameSkeleton; PVOID Nullsub; rage::Obf32** AnticheatInitializedHash; PVOID GetAnticheatInitializedHash; @@ -171,6 +170,7 @@ namespace YimMenu PVOID MatchmakingUpdate; PVOID MatchmakingUnadvertise; PVOID MatchmakingSessionDetailSendResponse; + PVOID GameSkeletonUpdate; }; struct Pointers : PointerData diff --git a/src/types/game_files/CGameDataHash.hpp b/src/types/game_files/CGameDataHash.hpp index 580acae..a911a2e 100644 --- a/src/types/game_files/CGameDataHash.hpp +++ b/src/types/game_files/CGameDataHash.hpp @@ -8,6 +8,7 @@ class CGameDataHash public: bool m_IsJapaneseVersion; std::array m_Data; + char m_GameSkeletonHash[0x18]; // Obf64 }; -static_assert(sizeof(CGameDataHash) == 0x104); +static_assert(sizeof(CGameDataHash) == 0x11C); #pragma pack(pop) diff --git a/src/types/network/PlatformAccountId.hpp b/src/types/network/PlatformAccountId.hpp new file mode 100644 index 0000000..2d373e6 --- /dev/null +++ b/src/types/network/PlatformAccountId.hpp @@ -0,0 +1,21 @@ +#pragma once + +struct PlatformAccountId +{ + enum Platform : uint8_t + { + PLATFORM_INVALID = 0, + PLATFORM_XBOX = 1, + PLATFORM_STEAM = 10, + PLATFORM_EPIC = 15 + }; + + union { + uint64_t m_XboxUserId; //0x0000 + uint64_t m_SteamId; + char m_EpicAccountId[32 + 1]; + char m_Pad[40]; + }; + Platform m_Platform; //0x0028 +}; +static_assert(sizeof(PlatformAccountId) == 0x30); \ No newline at end of file diff --git a/src/types/network/netPlayer.hpp b/src/types/network/netPlayer.hpp index 2d9c25b..164650c 100644 --- a/src/types/network/netPlayer.hpp +++ b/src/types/network/netPlayer.hpp @@ -1,5 +1,6 @@ #pragma once #include "types/rage/RTTI.hpp" +#include "PlatformAccountId.hpp" namespace rage { @@ -31,7 +32,8 @@ namespace rage int m_AccountId; //0x0008 int64_t m_RockstarId; //0x0010 - char pad_0018[0x38]; //0x0018 voice chat stuff + PlatformAccountId m_PlatformAccountId; //0x0018 + uint32_t unk_0048; //0x0048 CNonPhysicalPlayerData* m_NonPhysicalPlayer; //0x0050 uint32_t m_MessageId; //0x0058 char pad_005C[4]; //0x005C