From 2aee48bffabf24702730d0b59355f2dc74df8d81 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sun, 7 Aug 2016 16:50:04 +0200 Subject: [PATCH] More anticheat exceptions --- src/Components/Modules/AntiCheat.cpp | 92 +++++++++++++++++++--------- src/Components/Modules/AntiCheat.hpp | 77 +++++++++++++---------- src/Components/Modules/Auth.cpp | 4 +- src/Components/Modules/Command.hpp | 87 +++++++++++++------------- src/Components/Modules/Discovery.cpp | 2 + src/Components/Modules/Discovery.hpp | 48 +++++++-------- src/Game/Functions.cpp | 3 + src/Game/Functions.hpp | 6 ++ 8 files changed, 188 insertions(+), 131 deletions(-) diff --git a/src/Components/Modules/AntiCheat.cpp b/src/Components/Modules/AntiCheat.cpp index 33b9f10b..2eecb68c 100644 --- a/src/Components/Modules/AntiCheat.cpp +++ b/src/Components/Modules/AntiCheat.cpp @@ -5,7 +5,6 @@ namespace Components int AntiCheat::LastCheck; std::string AntiCheat::Hash; Utils::Hook AntiCheat::LoadLibHook[4]; - Utils::Hook AntiCheat::VirtualProtectHook; // This function does nothing, it only adds the two passed variables and returns the value // The only important thing it does is to clean the first parameter, and then return @@ -105,8 +104,13 @@ namespace Components FARPROC loadLibA = GetProcAddress(kernel32, Utils::String::XOR(std::string(reinterpret_cast(loadLibAStr), sizeof loadLibAStr), -1).data()); FARPROC loadLibW = GetProcAddress(kernel32, Utils::String::XOR(std::string(reinterpret_cast(loadLibWStr), sizeof loadLibWStr), -1).data()); +#ifdef DEBUG_LOAD_LIBRARY + AntiCheat::LoadLibHook[0].Initialize(loadLibA, LoadLibaryAStub, HOOK_JUMP); + AntiCheat::LoadLibHook[1].Initialize(loadLibW, LoadLibaryWStub, HOOK_JUMP); +#else AntiCheat::LoadLibHook[0].Initialize(loadLibA, loadLibStub, HOOK_JUMP); AntiCheat::LoadLibHook[1].Initialize(loadLibW, loadLibStub, HOOK_JUMP); +#endif //AntiCheat::LoadLibHook[2].Initialize(LoadLibraryExA, loadLibExStub, HOOK_JUMP); //AntiCheat::LoadLibHook[3].Initialize(LoadLibraryExW, loadLibExStub, HOOK_JUMP); } @@ -140,6 +144,32 @@ namespace Components AntiCheat::PerformCheck(); } +#ifdef DEBUG_LOAD_LIBRARY + HANDLE AntiCheat::LoadLibary(std::wstring library, void* callee) + { + HMODULE module; + char buffer[MAX_PATH] = { 0 }; + + GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, reinterpret_cast(callee), &module); + GetModuleFileNameA(module, buffer, sizeof buffer); + + MessageBoxA(0, fmt::sprintf("Loading library %s via %s %X", std::string(library.begin(), library.end()).data(), buffer, reinterpret_cast(callee)).data(), 0, 0); + + return LoadLibraryExW(library.data(), NULL, 0); + } + + HANDLE WINAPI AntiCheat::LoadLibaryAStub(const char* library) + { + std::string lib(library); + return AntiCheat::LoadLibary(std::wstring(lib.begin(), lib.end()), _ReturnAddress()); + } + + HANDLE WINAPI AntiCheat::LoadLibaryWStub(const wchar_t* library) + { + return AntiCheat::LoadLibary(library, _ReturnAddress()); + } +#endif + void AntiCheat::UninstallLibHook() { for (int i = 0; i < ARRAYSIZE(AntiCheat::LoadLibHook); ++i) @@ -175,33 +205,37 @@ namespace Components AntiCheat::InstallLibHook(); } -// BOOL WINAPI AntiCheat::VirtualProtectStub(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect) -// { -// AntiCheat::VirtualProtectHook.Uninstall(false); -// -// if (flNewProtect == PAGE_WRITECOPY || flNewProtect == PAGE_READWRITE || flNewProtect == PAGE_EXECUTE_READWRITE || flNewProtect == PAGE_WRITECOMBINE) -// { -// DWORD addr = (DWORD)lpAddress; -// DWORD start = 0x401000; -// DWORD end = start + 0x2D6000; -// -// if (addr > start && addr < end) -// { -// OutputDebugStringA(Utils::VA("Write access to address %X", lpAddress)); -// } -// } -// -// BOOL retVal = VirtualProtect(lpAddress, dwSize, flNewProtect, lpflOldProtect); -// AntiCheat::VirtualProtectHook.Install(false); -// return retVal; -// } + void __declspec(naked) AntiCheat::CinematicStub() + { + __asm + { + pushad + call AntiCheat::UninstallLibHook + popad + + call Game::R_Cinematic_StartPlayback_Now + + pushad + call AntiCheat::InstallLibHook + popad + + retn + } + } + + bool AntiCheat::EncodeInitStub(const char* param) + { + AntiCheat::UninstallLibHook(); + + bool result = Game::Encode_Init(param); + + AntiCheat::InstallLibHook(); + + return result; + } AntiCheat::AntiCheat() { - // This is required for debugging...in release mode :P - //AntiCheat::VirtualProtectHook.Initialize(VirtualProtect, VirtualProtectStub, HOOK_JUMP); - //AntiCheat::VirtualProtectHook.Install(true, true); - AntiCheat::EmptyHash(); #ifdef DEBUG @@ -210,9 +244,12 @@ namespace Components AntiCheat::CrashClient(); }); #else - Utils::Hook(0x60BE8E, AntiCheat::SoundInitStub, HOOK_CALL).Install()->Quick(); - Utils::Hook(0x418204, AntiCheat::SoundInitStub, HOOK_CALL).Install()->Quick(); + Utils::Hook(0x507BD5, AntiCheat::PatchWinAPI, HOOK_CALL).Install()->Quick(); + Utils::Hook(0x60BE8E, AntiCheat::SoundInitStub, HOOK_CALL).Install()->Quick(); + Utils::Hook(0x418204, AntiCheat::SoundInitStub, HOOK_CALL).Install()->Quick(); + Utils::Hook(0x51C76C, AntiCheat::CinematicStub, HOOK_CALL).Install()->Quick(); + Utils::Hook(0x4A22E5, AntiCheat::EncodeInitStub, HOOK_CALL).Install()->Quick(); QuickPatch::OnFrame(AntiCheat::Frame); // TODO: Probably move that :P @@ -224,7 +261,6 @@ namespace Components { AntiCheat::EmptyHash(); - AntiCheat::VirtualProtectHook.Uninstall(false); for (int i = 0; i < ARRAYSIZE(AntiCheat::LoadLibHook); ++i) { AntiCheat::LoadLibHook[i].Uninstall(); diff --git a/src/Components/Modules/AntiCheat.hpp b/src/Components/Modules/AntiCheat.hpp index 813a2b71..03d9f0ee 100644 --- a/src/Components/Modules/AntiCheat.hpp +++ b/src/Components/Modules/AntiCheat.hpp @@ -1,34 +1,43 @@ -namespace Components -{ - class AntiCheat : public Component - { - public: - AntiCheat(); - ~AntiCheat(); - const char* GetName() { return "Component"; }; // Wrong name :P - - static void CrashClient(); - static void EmptyHash(); - - static void InitLoadLibHook(); - - private: - static int LastCheck; - static std::string Hash; - - static void Frame(); - static void PerformCheck(); - static void PatchWinAPI(); - - static void NullSub(); - - static void UninstallLibHook(); - static void InstallLibHook(); - - static void SoundInitStub(); - static BOOL WINAPI VirtualProtectStub(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect); - - static Utils::Hook LoadLibHook[4]; - static Utils::Hook VirtualProtectHook; - }; -} +// Uncomment that to see if we are preventing necessary libraries from being loaded +//#define DEBUG_LOAD_LIBRARY + +namespace Components +{ + class AntiCheat : public Component + { + public: + AntiCheat(); + ~AntiCheat(); + const char* GetName() { return "Component"; }; // Wrong name :P + + static void CrashClient(); + static void EmptyHash(); + + static void InitLoadLibHook(); + + private: + static int LastCheck; + static std::string Hash; + + static void Frame(); + static void PerformCheck(); + static void PatchWinAPI(); + + static void NullSub(); + + static void UninstallLibHook(); + static void InstallLibHook(); + +#ifdef DEBUG_LOAD_LIBRARY + static HANDLE LoadLibary(std::wstring library, void* callee); + static HANDLE WINAPI LoadLibaryAStub(const char* library); + static HANDLE WINAPI LoadLibaryWStub(const wchar_t* library); +#endif + + static void CinematicStub(); + static void SoundInitStub(); + static bool EncodeInitStub(const char* param); + + static Utils::Hook LoadLibHook[4]; + }; +} diff --git a/src/Components/Modules/Auth.cpp b/src/Components/Modules/Auth.cpp index e453a12a..09d70aba 100644 --- a/src/Components/Modules/Auth.cpp +++ b/src/Components/Modules/Auth.cpp @@ -21,7 +21,7 @@ namespace Components std::string connectString(format, len); Game::SV_Cmd_TokenizeString(connectString.data()); - Command::Params params(true, *Game::cmd_id_sv); + Command::Params params(true); if (params.Length() < 3) { @@ -88,7 +88,7 @@ namespace Components Game::SV_Cmd_TokenizeString(connectData.infostring().data()); // Access the params - Command::Params params(true, *Game::cmd_id_sv); + Command::Params params(true); // Ensure there are enough params if (params.Length() < 3) diff --git a/src/Components/Modules/Command.hpp b/src/Components/Modules/Command.hpp index 990e51f6..89a8575e 100644 --- a/src/Components/Modules/Command.hpp +++ b/src/Components/Modules/Command.hpp @@ -1,43 +1,44 @@ -namespace Components -{ - class Command : public Component - { - public: - class Params - { - public: - Params(bool sv, DWORD id) : CommandId(id), IsSV(sv) {}; - Params(const Params &obj) : CommandId(obj.CommandId), IsSV(obj.IsSV) {}; - Params() : Params(false, *Game::cmd_id) {}; - - char* operator[](size_t index); - size_t Length(); - - std::string Join(size_t startIndex); - - private: - bool IsSV; - DWORD CommandId; - }; - - typedef void(Callback)(Command::Params params); - - Command(); - ~Command(); - const char* GetName() { return "Command"; }; - - static void Add(const char* name, Callback* callback); - static void AddSV(const char* name, Callback* callback); - static void AddRaw(const char* name, void(*callback)()); - static void AddRawSV(const char* name, void(*callback)()); - static void Execute(std::string command, bool sync = true); - - private: - static Game::cmd_function_t* Allocate(); - static std::vector Functions; - static std::map> FunctionMap; - static std::map> FunctionMapSV; - static void MainCallback(); - static void MainCallbackSV(); - }; -} +namespace Components +{ + class Command : public Component + { + public: + class Params + { + public: + Params(bool sv, DWORD id) : CommandId(id), IsSV(sv) {}; + Params(bool sv) : Params(sv, (sv ? *Game::cmd_id_sv : *Game::cmd_id)) {}; + Params(const Params &obj) : CommandId(obj.CommandId), IsSV(obj.IsSV) {}; + Params() : Params(false, *Game::cmd_id) {}; + + char* operator[](size_t index); + size_t Length(); + + std::string Join(size_t startIndex); + + private: + bool IsSV; + DWORD CommandId; + }; + + typedef void(Callback)(Command::Params params); + + Command(); + ~Command(); + const char* GetName() { return "Command"; }; + + static void Add(const char* name, Callback* callback); + static void AddSV(const char* name, Callback* callback); + static void AddRaw(const char* name, void(*callback)()); + static void AddRawSV(const char* name, void(*callback)()); + static void Execute(std::string command, bool sync = true); + + private: + static Game::cmd_function_t* Allocate(); + static std::vector Functions; + static std::map> FunctionMap; + static std::map> FunctionMapSV; + static void MainCallback(); + static void MainCallbackSV(); + }; +} diff --git a/src/Components/Modules/Discovery.cpp b/src/Components/Modules/Discovery.cpp index 1f889a59..2acdfa4c 100644 --- a/src/Components/Modules/Discovery.cpp +++ b/src/Components/Modules/Discovery.cpp @@ -14,6 +14,8 @@ namespace Components Dvar::Register("net_discoveryPortRangeMin", 25000, 0, 65535, Game::dvar_flag::DVAR_FLAG_SAVED, "Minimum scan range port for local server discovery"); Dvar::Register("net_discoveryPortRangeMax", 35000, 1, 65536, Game::dvar_flag::DVAR_FLAG_SAVED, "Maximum scan range port for local server discovery"); + // An additional thread prevents lags + // Not sure if that's the best way though Discovery::DiscoveryContainer.Perform = false; Discovery::DiscoveryContainer.Terminate = false; Discovery::DiscoveryContainer.Thread = std::thread([] () diff --git a/src/Components/Modules/Discovery.hpp b/src/Components/Modules/Discovery.hpp index c176bacd..a88b2b98 100644 --- a/src/Components/Modules/Discovery.hpp +++ b/src/Components/Modules/Discovery.hpp @@ -1,24 +1,24 @@ -namespace Components -{ - class Discovery : public Component - { - public: - Discovery(); - ~Discovery(); - const char* GetName() { return "Discovery"; }; - - static void Perform(); - - private: - class Container - { - public: - bool Perform; - bool Terminate; - std::thread Thread; - std::string Challenge; - }; - - static Container DiscoveryContainer; - }; -} +namespace Components +{ + class Discovery : public Component + { + public: + Discovery(); + ~Discovery(); + const char* GetName() { return "Discovery"; }; + + static void Perform(); + + private: + class Container + { + public: + bool Perform; + bool Terminate; + std::thread Thread; + std::string Challenge; + }; + + static Container DiscoveryContainer; + }; +} diff --git a/src/Game/Functions.cpp b/src/Game/Functions.cpp index d97dee34..efd37845 100644 --- a/src/Game/Functions.cpp +++ b/src/Game/Functions.cpp @@ -53,6 +53,8 @@ namespace Game Dvar_InfoString_Big_t Dvar_InfoString_Big = (Dvar_InfoString_Big_t)0x4D98A0; Dvar_SetCommand_t Dvar_SetCommand = (Dvar_SetCommand_t)0x4EE430; + Encode_Init_t Encode_Init = (Encode_Init_t)0x462AB0; + Field_Clear_t Field_Clear = (Field_Clear_t)0x437EB0; FreeMemory_t FreeMemory = (FreeMemory_t)0x4D6640; @@ -129,6 +131,7 @@ namespace Game PartyHost_GetMemberName_t PartyHost_GetMemberName = (PartyHost_GetMemberName_t)0x44BE90; R_AddCmdDrawStretchPic_t R_AddCmdDrawStretchPic = (R_AddCmdDrawStretchPic_t)0x509770; + R_Cinematic_StartPlayback_Now_t R_Cinematic_StartPlayback_Now = (R_Cinematic_StartPlayback_Now_t)0x51C5B0; R_RegisterFont_t R_RegisterFont = (R_RegisterFont_t)0x505670; R_AddCmdDrawText_t R_AddCmdDrawText = (R_AddCmdDrawText_t)0x509D80; R_LoadGraphicsAssets_t R_LoadGraphicsAssets = (R_LoadGraphicsAssets_t)0x506AC0; diff --git a/src/Game/Functions.hpp b/src/Game/Functions.hpp index 170496b9..6f140350 100644 --- a/src/Game/Functions.hpp +++ b/src/Game/Functions.hpp @@ -123,6 +123,9 @@ namespace Game typedef dvar_t* (__cdecl * Dvar_SetCommand_t)(const char* name, const char* value); extern Dvar_SetCommand_t Dvar_SetCommand; + typedef bool(__cdecl * Encode_Init_t)(const char* ); + extern Encode_Init_t Encode_Init; + typedef void(__cdecl * Field_Clear_t)(void* field); extern Field_Clear_t Field_Clear; @@ -311,6 +314,9 @@ namespace Game typedef void(_cdecl * R_AddCmdDrawStretchPic_t)(float x, float y, float w, float h, float xScale, float yScale, float xay, float yay, const float *color, Game::Material* material); extern R_AddCmdDrawStretchPic_t R_AddCmdDrawStretchPic; + typedef bool(__cdecl * R_Cinematic_StartPlayback_Now_t)(); + extern R_Cinematic_StartPlayback_Now_t R_Cinematic_StartPlayback_Now; + typedef void(__cdecl * R_LoadGraphicsAssets_t)(); extern R_LoadGraphicsAssets_t R_LoadGraphicsAssets;