Remove anticheat (Gone FNAF)
This commit is contained in:
parent
8bae77a8f6
commit
16f180d08d
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@ -39,7 +39,7 @@ jobs:
|
||||
uses: microsoft/setup-msbuild@v1.1
|
||||
|
||||
- name: Generate project files
|
||||
run: tools/premake5 vs2022 --ac-disable
|
||||
run: tools/premake5 vs2022
|
||||
|
||||
- name: Set up problem matching
|
||||
uses: ammaraskar/msvc-problem-matcher@master
|
||||
|
@ -19,9 +19,6 @@
|
||||
|:----------------------------|:-----------------------------------------------|
|
||||
| `--copy-to=PATH` | Optional, copy the DLL to a custom folder after build, define the path here if wanted. |
|
||||
| `--copy-pdb` | Copy debug information for binaries as well to the path given via --copy-to. |
|
||||
| `--ac-disable` | Disable anticheat. |
|
||||
| `--ac-debug-detections` | Log anticheat detections. |
|
||||
| `--ac-debug-load-library` | Log libraries that get loaded. |
|
||||
| `--force-unit-tests` | Always compile unit tests. |
|
||||
| `--force-exception-handler` | Install custom unhandled exception handler even for Debug builds. |
|
||||
| `--force-minidump-upload` | Upload minidumps even for Debug builds. |
|
||||
|
@ -1,4 +1,4 @@
|
||||
@echo off
|
||||
echo Updating submodules...
|
||||
call git submodule update --init --recursive
|
||||
call tools\premake5 %* vs2022 --ac-disable
|
||||
call tools\premake5 %* vs2022
|
||||
|
24
premake5.lua
24
premake5.lua
@ -71,21 +71,6 @@ newoption {
|
||||
description = "Copy debug information for binaries as well to the path given via --copy-to."
|
||||
}
|
||||
|
||||
newoption {
|
||||
trigger = "ac-disable",
|
||||
description = "Disable anticheat."
|
||||
}
|
||||
|
||||
newoption {
|
||||
trigger = "ac-debug-detections",
|
||||
description = "Log anticheat detections."
|
||||
}
|
||||
|
||||
newoption {
|
||||
trigger = "ac-debug-load-library",
|
||||
description = "Log libraries that get loaded."
|
||||
}
|
||||
|
||||
newoption {
|
||||
trigger = "force-unit-tests",
|
||||
description = "Always compile unit tests."
|
||||
@ -274,15 +259,6 @@ workspace "iw4x"
|
||||
}
|
||||
|
||||
-- Debug flags
|
||||
if _OPTIONS["ac-disable"] then
|
||||
defines {"DISABLE_ANTICHEAT"}
|
||||
end
|
||||
if _OPTIONS["ac-debug-detections"] then
|
||||
defines {"DEBUG_DETECTIONS"}
|
||||
end
|
||||
if _OPTIONS["ac-debug-load-library"] then
|
||||
defines {"DEBUG_LOAD_LIBRARY"}
|
||||
end
|
||||
if _OPTIONS["force-unit-tests"] then
|
||||
defines {"FORCE_UNIT_TESTS"}
|
||||
end
|
||||
|
@ -69,7 +69,6 @@ namespace Components
|
||||
Loader::Register(new Renderer());
|
||||
Loader::Register(new UIFeeder());
|
||||
Loader::Register(new UIScript());
|
||||
Loader::Register(new AntiCheat());
|
||||
Loader::Register(new Changelog());
|
||||
Loader::Register(new Dedicated());
|
||||
Loader::Register(new Discovery());
|
||||
|
@ -99,7 +99,6 @@ namespace Components
|
||||
#include "Modules/RawFiles.hpp"
|
||||
#include "Modules/Renderer.hpp"
|
||||
#include "Modules/UIFeeder.hpp"
|
||||
#include "Modules/AntiCheat.hpp"
|
||||
#include "Modules/Changelog.hpp"
|
||||
#include "Modules/Dedicated.hpp"
|
||||
#include "Modules/Discovery.hpp"
|
||||
|
@ -1,891 +0,0 @@
|
||||
#include <STDInclude.hpp>
|
||||
|
||||
namespace Components
|
||||
{
|
||||
Utils::Time::Interval AntiCheat::LastCheck;
|
||||
Utils::Hook AntiCheat::CreateThreadHook;
|
||||
Utils::Hook AntiCheat::LoadLibHook[6];
|
||||
Utils::Hook AntiCheat::VirtualProtectHook[2];
|
||||
unsigned long AntiCheat::Flags = NO_FLAG;
|
||||
|
||||
std::mutex AntiCheat::ThreadMutex;
|
||||
std::vector<DWORD> AntiCheat::OwnThreadIds;
|
||||
std::map<DWORD, std::shared_ptr<Utils::Hook>> AntiCheat::ThreadHookMap;
|
||||
|
||||
// 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
|
||||
// By returning, the crash procedure will be called, as it hasn't been cleaned from the stack
|
||||
__declspec(naked) void AntiCheat::NullSub()
|
||||
{
|
||||
__asm
|
||||
{
|
||||
push ebp
|
||||
push ecx
|
||||
mov ebp, esp
|
||||
|
||||
xor eax, eax
|
||||
mov eax, [ebp + 8h]
|
||||
mov ecx, [ebp + 0Ch]
|
||||
add eax, ecx
|
||||
|
||||
pop ecx
|
||||
pop ebp
|
||||
retn 4
|
||||
}
|
||||
}
|
||||
|
||||
void AntiCheat::CrashClient()
|
||||
{
|
||||
#ifdef DEBUG_DETECTIONS
|
||||
Logger::Flush();
|
||||
MessageBoxA(nullptr, "Check the log for more information!", "AntiCheat triggered", MB_ICONERROR);
|
||||
ExitProcess(0xFFFFFFFF);
|
||||
#else
|
||||
static std::thread triggerThread;
|
||||
if (!triggerThread.joinable())
|
||||
{
|
||||
triggerThread = std::thread([]()
|
||||
{
|
||||
std::this_thread::sleep_for(43s);
|
||||
Utils::Hook::Set<BYTE>(0x41BA2C, 0xEB);
|
||||
});
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void AntiCheat::AssertCalleeModule(void* callee)
|
||||
{
|
||||
HMODULE hModuleSelf = nullptr, hModuleTarget = nullptr, hModuleProcess = GetModuleHandleA(nullptr);
|
||||
GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, reinterpret_cast<char*>(callee), &hModuleTarget);
|
||||
GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, reinterpret_cast<char*>(AntiCheat::AssertCalleeModule), &hModuleSelf);
|
||||
|
||||
if (!hModuleSelf || !hModuleTarget || !hModuleProcess || (hModuleTarget != hModuleSelf && hModuleTarget != hModuleProcess))
|
||||
{
|
||||
#ifdef DEBUG_DETECTIONS
|
||||
char buffer[MAX_PATH] = { 0 };
|
||||
GetModuleFileNameA(hModuleTarget, buffer, sizeof buffer);
|
||||
|
||||
Logger::Print(Utils::String::VA("AntiCheat: Callee assertion failed: %X %s", reinterpret_cast<uint32_t>(callee), buffer));
|
||||
#endif
|
||||
|
||||
AntiCheat::CrashClient();
|
||||
}
|
||||
}
|
||||
|
||||
void AntiCheat::InitLoadLibHook()
|
||||
{
|
||||
static uint8_t kernel32Str[] = { 0xB4, 0x9A, 0x8D, 0xB1, 0x9A, 0x93, 0xCC, 0xCD, 0xD1, 0x9B, 0x93, 0x93 }; // KerNel32.dll
|
||||
static uint8_t loadLibAStr[] = { 0xB3, 0x90, 0x9E, 0x9B, 0xB3, 0x96, 0x9D, 0x8D, 0x9E, 0x8D, 0x86, 0xBE }; // LoadLibraryA
|
||||
static uint8_t loadLibWStr[] = { 0xB3, 0x90, 0x9E, 0x9B, 0xB3, 0x96, 0x9D, 0x8D, 0x9E, 0x8D, 0x86, 0xA8 }; // LoadLibraryW
|
||||
|
||||
HMODULE kernel32 = GetModuleHandleA(Utils::String::XOR(std::string(reinterpret_cast<char*>(kernel32Str), sizeof kernel32Str), -1).data());
|
||||
if (kernel32)
|
||||
{
|
||||
FARPROC loadLibA = GetProcAddress(kernel32, Utils::String::XOR(std::string(reinterpret_cast<char*>(loadLibAStr), sizeof loadLibAStr), -1).data());
|
||||
FARPROC loadLibW = GetProcAddress(kernel32, Utils::String::XOR(std::string(reinterpret_cast<char*>(loadLibWStr), sizeof loadLibWStr), -1).data());
|
||||
|
||||
std::string libExA = Utils::String::XOR(std::string(reinterpret_cast<char*>(loadLibAStr), sizeof loadLibAStr), -1);
|
||||
std::string libExW = Utils::String::XOR(std::string(reinterpret_cast<char*>(loadLibWStr), sizeof loadLibWStr), -1);
|
||||
|
||||
libExA.insert(libExA.end() - 1, 'E');
|
||||
libExA.insert(libExA.end() - 1, 'x');
|
||||
|
||||
libExW.insert(libExW.end() - 1, 'E');
|
||||
libExW.insert(libExW.end() - 1, 'x');
|
||||
|
||||
FARPROC loadLibExA = GetProcAddress(kernel32, libExA.data());
|
||||
FARPROC loadLibExW = GetProcAddress(kernel32, libExW.data());
|
||||
|
||||
if (loadLibA && loadLibW && loadLibExA && loadLibExW)
|
||||
{
|
||||
#ifdef DEBUG_LOAD_LIBRARY
|
||||
AntiCheat::LoadLibHook[0].initialize(loadLibA, LoadLibaryAStub, HOOK_JUMP);
|
||||
AntiCheat::LoadLibHook[1].initialize(loadLibW, LoadLibaryWStub, HOOK_JUMP);
|
||||
AntiCheat::LoadLibHook[2].initialize(loadLibExA, LoadLibaryExAStub, HOOK_JUMP);
|
||||
AntiCheat::LoadLibHook[3].initialize(loadLibExW, LoadLibaryExWStub, HOOK_JUMP);
|
||||
#else
|
||||
static uint8_t loadLibStub[] = { 0x33, 0xC0, 0xC2, 0x04, 0x00 }; // xor eax, eax; retn 04h
|
||||
static uint8_t loadLibExStub[] = { 0x33, 0xC0, 0xC2, 0x0C, 0x00 }; // xor eax, eax; retn 0Ch
|
||||
AntiCheat::LoadLibHook[0].initialize(loadLibA, loadLibStub, HOOK_JUMP);
|
||||
AntiCheat::LoadLibHook[1].initialize(loadLibW, loadLibStub, HOOK_JUMP);
|
||||
AntiCheat::LoadLibHook[2].initialize(loadLibExA, loadLibExStub, HOOK_JUMP);
|
||||
AntiCheat::LoadLibHook[3].initialize(loadLibExW, loadLibExStub, HOOK_JUMP);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t ldrLoadDllStub[] = { 0x33, 0xC0, 0xC2, 0x10, 0x00 };
|
||||
static uint8_t ldrLoadDll[] = { 0xB3, 0x9B, 0x8D, 0xB3, 0x90, 0x9E, 0x9B, 0xBB, 0x93, 0x93 }; // LdrLoadDll
|
||||
|
||||
HMODULE ntdll = Utils::GetNTDLL();
|
||||
//AntiCheat::LoadLibHook[4].initialize(GetProcAddress(ntdll, Utils::String::XOR(std::string(reinterpret_cast<char*>(ldrLoadDll), sizeof ldrLoadDll), -1).data()), ldrLoadDllStub, HOOK_JUMP);
|
||||
|
||||
// Patch LdrpLoadDll
|
||||
Utils::Hook::Signature::Container container;
|
||||
container.signature = "\x8B\xFF\x55\x8B\xEC\x83\xE4\xF8\x81\xEC\x00\x00\x00\x00\xA1\x00\x00\x00\x00\x33\xC4\x89\x84\x24\x00\x00\x00\x00\x53\x8B\x5D\x10\x56\x57";
|
||||
container.mask = "xxxxxxxxxx????x????xxxxx????xxxxxx";
|
||||
container.callback = [](char* addr)
|
||||
{
|
||||
static uint8_t ldrpLoadDllStub[] = { 0x33, 0xC0, 0xC2, 0x0C, 0x00 };
|
||||
AntiCheat::LoadLibHook[5].initialize(addr, ldrpLoadDllStub, HOOK_JUMP);
|
||||
};
|
||||
|
||||
Utils::Hook::Signature signature(ntdll, Utils::GetModuleSize(ntdll));
|
||||
signature.add(container);
|
||||
//signature.process();
|
||||
}
|
||||
|
||||
void AntiCheat::ReadIntegrityCheck()
|
||||
{
|
||||
#ifdef PROCTECT_PROCESS
|
||||
static Utils::Time::Interval check;
|
||||
|
||||
if (check.elapsed(20s))
|
||||
{
|
||||
check.update();
|
||||
|
||||
if (HANDLE h = OpenProcess(PROCESS_VM_READ, FALSE, GetCurrentProcessId()))
|
||||
{
|
||||
#ifdef DEBUG_DETECTIONS
|
||||
Logger::Print("AntiCheat: Process integrity check failed");
|
||||
#endif
|
||||
|
||||
CloseHandle(h);
|
||||
AntiCheat::CrashClient();
|
||||
}
|
||||
}
|
||||
|
||||
// Set the integrity flag
|
||||
AntiCheat::Flags |= AntiCheat::IntergrityFlag::READ_INTEGRITY_CHECK;
|
||||
#endif
|
||||
}
|
||||
|
||||
void AntiCheat::FlagIntegrityCheck()
|
||||
{
|
||||
static Utils::Time::Interval check;
|
||||
|
||||
if (check.elapsed(30s))
|
||||
{
|
||||
check.update();
|
||||
|
||||
unsigned long flags = ((AntiCheat::IntergrityFlag::MAX_FLAG - 1) << 1) - 1;
|
||||
|
||||
if (AntiCheat::Flags != flags)
|
||||
{
|
||||
#ifdef DEBUG_DETECTIONS
|
||||
Logger::Print(Utils::String::VA("AntiCheat: Flag integrity check failed: %X", AntiCheat::Flags));
|
||||
#endif
|
||||
|
||||
AntiCheat::CrashClient();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AntiCheat::ScanIntegrityCheck()
|
||||
{
|
||||
// If there was no check within the last 40 seconds, crash!
|
||||
if (AntiCheat::LastCheck.elapsed(40s))
|
||||
{
|
||||
#ifdef DEBUG_DETECTIONS
|
||||
Logger::Print("AntiCheat: Integrity check failed");
|
||||
#endif
|
||||
|
||||
AntiCheat::CrashClient();
|
||||
}
|
||||
|
||||
// Set the integrity flag
|
||||
AntiCheat::Flags |= AntiCheat::IntergrityFlag::SCAN_INTEGRITY_CHECK;
|
||||
}
|
||||
|
||||
void AntiCheat::PerformScan()
|
||||
{
|
||||
static std::optional<unsigned int> hashVal;
|
||||
|
||||
// Perform check only every 20 seconds
|
||||
if (!AntiCheat::LastCheck.elapsed(20s)) return;
|
||||
AntiCheat::LastCheck.update();
|
||||
|
||||
// Hash .text segment
|
||||
// Add 1 to each value, so searching in memory doesn't reveal anything
|
||||
size_t textSize = 0x2D6001;
|
||||
char* textBase = reinterpret_cast<char*>(0x401001);
|
||||
|
||||
unsigned int hash = Utils::Cryptography::JenkinsOneAtATime::Compute(textBase - 1, textSize - 1);
|
||||
|
||||
// Set the hash, if none is set
|
||||
if (!hashVal.has_value())
|
||||
{
|
||||
hashVal.emplace(hash);
|
||||
}
|
||||
// Crash if the hashes don't match
|
||||
else if (hashVal.value() != hash)
|
||||
{
|
||||
#ifdef DEBUG_DETECTIONS
|
||||
Logger::Print("AntiCheat: Memory scan failed");
|
||||
#endif
|
||||
|
||||
AntiCheat::CrashClient();
|
||||
}
|
||||
|
||||
// Set the memory scan flag
|
||||
AntiCheat::Flags |= AntiCheat::IntergrityFlag::MEMORY_SCAN;
|
||||
}
|
||||
|
||||
void AntiCheat::QuickCodeScanner1()
|
||||
{
|
||||
static Utils::Time::Interval interval;
|
||||
static std::optional<unsigned int> hashVal;
|
||||
|
||||
if (!interval.elapsed(32s)) return;
|
||||
interval.update();
|
||||
|
||||
// Hash .text segment
|
||||
// Add 1 to each value, so searching in memory doesn't reveal anything
|
||||
size_t textSize = 0x2D5FFF;
|
||||
char* textBase = reinterpret_cast<char*>(0x400FFF);
|
||||
unsigned int hash = Utils::Cryptography::JenkinsOneAtATime::Compute(textBase + 1, textSize + 1);
|
||||
|
||||
if (hashVal.has_value() && hash != hashVal.value())
|
||||
{
|
||||
Utils::Hook::Set<BYTE>(0x42A667, 0x90); // Crash
|
||||
}
|
||||
|
||||
hashVal.emplace(hash);
|
||||
}
|
||||
|
||||
void AntiCheat::QuickCodeScanner2()
|
||||
{
|
||||
static Utils::Time::Interval interval;
|
||||
static std::optional<unsigned int> hashVal;
|
||||
|
||||
if (!interval.elapsed(42s)) return;
|
||||
interval.update();
|
||||
|
||||
// Hash .text segment
|
||||
unsigned int hash = Utils::Cryptography::JenkinsOneAtATime::Compute(reinterpret_cast<char*>(0x401000), 0x2D6000);
|
||||
if (hashVal.has_value() && hash != hashVal.value())
|
||||
{
|
||||
Utils::Hook::Set<BYTE>(0x40797C, 0x90); // Crash
|
||||
}
|
||||
|
||||
hashVal.emplace(hash);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_LOAD_LIBRARY
|
||||
HANDLE AntiCheat::LoadLibary(std::wstring library, HANDLE file, DWORD flags, void* callee)
|
||||
{
|
||||
HMODULE module;
|
||||
char buffer[MAX_PATH] = { 0 };
|
||||
|
||||
GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, reinterpret_cast<char*>(callee), &module);
|
||||
GetModuleFileNameA(module, buffer, sizeof buffer);
|
||||
|
||||
MessageBoxA(nullptr, Utils::String::VA("Loading library %s via %s %X", std::string(library.begin(), library.end()).data(), buffer, reinterpret_cast<uint32_t>(callee)), nullptr, 0);
|
||||
|
||||
AntiCheat::LoadLibHook[3].uninstall();
|
||||
HANDLE h = LoadLibraryExW(library.data(), file, flags);
|
||||
AntiCheat::LoadLibHook[3].install();
|
||||
return h;
|
||||
}
|
||||
|
||||
HANDLE WINAPI AntiCheat::LoadLibaryAStub(const char* library)
|
||||
{
|
||||
std::string lib(library);
|
||||
return AntiCheat::LoadLibary(std::wstring(lib.begin(), lib.end()), nullptr, 0, _ReturnAddress());
|
||||
}
|
||||
|
||||
HANDLE WINAPI AntiCheat::LoadLibaryWStub(const wchar_t* library)
|
||||
{
|
||||
return AntiCheat::LoadLibary(library, nullptr, 0, _ReturnAddress());
|
||||
}
|
||||
|
||||
HANDLE WINAPI AntiCheat::LoadLibaryExAStub(const char* library, HANDLE file, DWORD flags)
|
||||
{
|
||||
std::string lib(library);
|
||||
return AntiCheat::LoadLibary(std::wstring(lib.begin(), lib.end()), file, flags, _ReturnAddress());
|
||||
}
|
||||
|
||||
HANDLE WINAPI AntiCheat::LoadLibaryExWStub(const wchar_t* library, HANDLE file, DWORD flags)
|
||||
{
|
||||
return AntiCheat::LoadLibary(library, file, flags, _ReturnAddress());
|
||||
}
|
||||
#endif
|
||||
|
||||
void AntiCheat::UninstallLibHook()
|
||||
{
|
||||
for (int i = 0; i < ARRAYSIZE(AntiCheat::LoadLibHook); ++i)
|
||||
{
|
||||
AntiCheat::LoadLibHook[i].uninstall();
|
||||
}
|
||||
}
|
||||
|
||||
void AntiCheat::InstallLibHook()
|
||||
{
|
||||
for (int i = 0; i < ARRAYSIZE(AntiCheat::LoadLibHook); ++i)
|
||||
{
|
||||
AntiCheat::LoadLibHook[i].install();
|
||||
}
|
||||
}
|
||||
|
||||
void AntiCheat::PatchWinAPI()
|
||||
{
|
||||
LibUnlocker _;
|
||||
|
||||
// Initialize directx
|
||||
Utils::Hook::Call<void()>(0x5078C0)();
|
||||
}
|
||||
|
||||
void AntiCheat::SoundInitStub(int a1, int a2, int a3)
|
||||
{
|
||||
LibUnlocker _;
|
||||
Game::SND_Init(a1, a2, a3);
|
||||
}
|
||||
|
||||
void AntiCheat::SoundInitDriverStub()
|
||||
{
|
||||
LibUnlocker _;
|
||||
Game::SND_InitDriver();
|
||||
}
|
||||
|
||||
void AntiCheat::LostD3DStub()
|
||||
{
|
||||
LibUnlocker _;
|
||||
|
||||
// Reset directx
|
||||
Utils::Hook::Call<void()>(0x508070)();
|
||||
}
|
||||
|
||||
__declspec(naked) void AntiCheat::CinematicStub()
|
||||
{
|
||||
__asm
|
||||
{
|
||||
pushad
|
||||
call AntiCheat::UninstallLibHook
|
||||
popad
|
||||
|
||||
call Game::R_Cinematic_StartPlayback_Now
|
||||
|
||||
pushad
|
||||
call AntiCheat::InstallLibHook
|
||||
popad
|
||||
|
||||
retn
|
||||
}
|
||||
}
|
||||
|
||||
__declspec(naked) void AntiCheat::DObjGetWorldTagPosStub()
|
||||
{
|
||||
__asm
|
||||
{
|
||||
pushad
|
||||
push [esp + 20h]
|
||||
|
||||
call AntiCheat::AssertCalleeModule
|
||||
|
||||
pop esi
|
||||
popad
|
||||
|
||||
push ecx
|
||||
mov ecx, [esp + 10h]
|
||||
|
||||
push 426585h
|
||||
retn
|
||||
}
|
||||
}
|
||||
|
||||
__declspec(naked) void AntiCheat::AimTargetGetTagPosStub()
|
||||
{
|
||||
__asm
|
||||
{
|
||||
pushad
|
||||
push [esp + 20h]
|
||||
|
||||
call AntiCheat::AssertCalleeModule
|
||||
|
||||
pop esi
|
||||
popad
|
||||
|
||||
sub esp, 14h
|
||||
cmp dword ptr[esi + 0E0h], 1
|
||||
push 56AC6Ah
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
bool AntiCheat::IsPageChangeAllowed(void* callee, void* addr, size_t len)
|
||||
{
|
||||
HMODULE hModuleSelf = nullptr, hModuleTarget = nullptr, hModuleMain = GetModuleHandle(nullptr);
|
||||
GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, reinterpret_cast<char*>(callee), &hModuleTarget);
|
||||
GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, reinterpret_cast<char*>(AntiCheat::IsPageChangeAllowed), &hModuleSelf);
|
||||
|
||||
size_t mainSize = Utils::GetModuleSize(hModuleMain), selfSize = Utils::GetModuleSize(hModuleSelf);
|
||||
DWORD self = DWORD(hModuleSelf), main = DWORD(hModuleMain), address = DWORD(addr);
|
||||
|
||||
// If the address that should be changed is within our module or the main binary, then we need to check if we are changing it or someone else
|
||||
if (Utils::HasIntercection(self, selfSize, address, len) || Utils::HasIntercection(main, mainSize, address, len))
|
||||
{
|
||||
if (!hModuleSelf || !hModuleTarget || (hModuleTarget != hModuleSelf))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
BOOL WINAPI AntiCheat::VirtualProtectStub(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect)
|
||||
{
|
||||
if (!AntiCheat::IsPageChangeAllowed(_ReturnAddress(), lpAddress, dwSize)) return FALSE;
|
||||
|
||||
AntiCheat::VirtualProtectHook[0].uninstall(false);
|
||||
BOOL result = VirtualProtect(lpAddress, dwSize, flNewProtect, lpflOldProtect);
|
||||
AntiCheat::VirtualProtectHook[0].install(false);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
BOOL WINAPI AntiCheat::VirtualProtectExStub(HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect)
|
||||
{
|
||||
if (GetCurrentProcessId() == GetProcessId(hProcess) && !AntiCheat::IsPageChangeAllowed(_ReturnAddress(), lpAddress, dwSize)) return FALSE;
|
||||
|
||||
AntiCheat::VirtualProtectHook[1].uninstall(false);
|
||||
BOOL result = VirtualProtectEx(hProcess, lpAddress, dwSize, flNewProtect, lpflOldProtect);
|
||||
AntiCheat::VirtualProtectHook[1].install(false);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
unsigned long AntiCheat::ProtectProcess()
|
||||
{
|
||||
#ifdef PROCTECT_PROCESS
|
||||
|
||||
Utils::Memory::Allocator allocator;
|
||||
|
||||
HANDLE hToken = nullptr;
|
||||
if (!OpenProcessToken(GetCurrentProcess(), /*TOKEN_ADJUST_PRIVILEGES | */TOKEN_READ, &hToken))
|
||||
{
|
||||
if (!OpenThreadToken(GetCurrentThread(), /*TOKEN_ADJUST_PRIVILEGES | */TOKEN_READ, TRUE, &hToken))
|
||||
{
|
||||
return GetLastError();
|
||||
}
|
||||
}
|
||||
|
||||
auto freeSid = [](void* sid)
|
||||
{
|
||||
if (sid)
|
||||
{
|
||||
FreeSid(reinterpret_cast<PSID>(sid));
|
||||
}
|
||||
};
|
||||
|
||||
allocator.reference(hToken, [](void* hToken)
|
||||
{
|
||||
if (hToken)
|
||||
{
|
||||
CloseHandle(hToken);
|
||||
}
|
||||
});
|
||||
|
||||
//AntiCheat::AcquireDebugPrivilege(hToken);
|
||||
|
||||
DWORD dwSize = 0;
|
||||
PVOID pTokenInfo = nullptr;
|
||||
if (GetTokenInformation(hToken, TokenUser, nullptr, 0, &dwSize) || GetLastError() != ERROR_INSUFFICIENT_BUFFER) return GetLastError();
|
||||
|
||||
if (dwSize)
|
||||
{
|
||||
pTokenInfo = allocator.allocate(dwSize);
|
||||
if (!pTokenInfo) return GetLastError();
|
||||
}
|
||||
|
||||
if (!GetTokenInformation(hToken, TokenUser, pTokenInfo, dwSize, &dwSize) || !pTokenInfo) return GetLastError();
|
||||
|
||||
PSID psidCurUser = reinterpret_cast<TOKEN_USER*>(pTokenInfo)->User.Sid;
|
||||
|
||||
PSID psidEveryone = nullptr;
|
||||
SID_IDENTIFIER_AUTHORITY sidEveryone = SECURITY_WORLD_SID_AUTHORITY;
|
||||
if (!AllocateAndInitializeSid(&sidEveryone, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &psidEveryone) || !psidEveryone) return GetLastError();
|
||||
allocator.reference(psidEveryone, freeSid);
|
||||
|
||||
PSID psidSystem = nullptr;
|
||||
SID_IDENTIFIER_AUTHORITY sidSystem = SECURITY_NT_AUTHORITY;
|
||||
if (!AllocateAndInitializeSid(&sidSystem, 1, SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, &psidSystem) || !psidSystem) return GetLastError();
|
||||
allocator.reference(psidSystem, freeSid);
|
||||
|
||||
PSID psidAdmins = nullptr;
|
||||
SID_IDENTIFIER_AUTHORITY sidAdministrators = SECURITY_NT_AUTHORITY;
|
||||
if (!AllocateAndInitializeSid(&sidAdministrators, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &psidAdmins) || !psidAdmins) return GetLastError();
|
||||
allocator.reference(psidAdmins, freeSid);
|
||||
|
||||
const PSID psidArray[] =
|
||||
{
|
||||
psidEveryone, /* Deny most rights to everyone */
|
||||
psidCurUser, /* Allow what was not denied */
|
||||
psidSystem, /* Full control */
|
||||
psidAdmins, /* Full control */
|
||||
};
|
||||
|
||||
// Determine required size of the ACL
|
||||
dwSize = sizeof(ACL);
|
||||
|
||||
// First the DENY, then the ALLOW
|
||||
dwSize += GetLengthSid(psidArray[0]);
|
||||
dwSize += sizeof(ACCESS_DENIED_ACE) - sizeof(DWORD);
|
||||
|
||||
for (UINT i = 1; i < _countof(psidArray); ++i)
|
||||
{
|
||||
// DWORD is the SidStart field, which is not used for absolute format
|
||||
dwSize += GetLengthSid(psidArray[i]);
|
||||
dwSize += sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD);
|
||||
}
|
||||
|
||||
PACL pDacl = reinterpret_cast<PACL>(allocator.allocate(dwSize));
|
||||
if (!pDacl || !InitializeAcl(pDacl, dwSize, ACL_REVISION)) return GetLastError();
|
||||
|
||||
// Just give access to what steam needs
|
||||
//static const DWORD dwPoison = 0UL | ~(SYNCHRONIZE | GENERIC_EXECUTE | GENERIC_ALL);
|
||||
static const DWORD dwPoison =
|
||||
/*READ_CONTROL |*/ WRITE_DAC | WRITE_OWNER |
|
||||
PROCESS_CREATE_PROCESS | PROCESS_CREATE_THREAD |
|
||||
PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION |
|
||||
PROCESS_SET_QUOTA | PROCESS_SET_INFORMATION |
|
||||
PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE |
|
||||
// In addition to protected process
|
||||
PROCESS_SUSPEND_RESUME | PROCESS_TERMINATE;
|
||||
|
||||
if (!AddAccessDeniedAce(pDacl, ACL_REVISION, dwPoison, psidArray[0])) return GetLastError();
|
||||
|
||||
// Standard and specific rights not explicitly denied
|
||||
//static const DWORD dwAllowed = 0UL | SYNCHRONIZE;
|
||||
static const DWORD dwAllowed = (~dwPoison & 0x1FFF) | SYNCHRONIZE;
|
||||
if (!AddAccessAllowedAce(pDacl, ACL_REVISION, dwAllowed, psidArray[1])) return GetLastError();
|
||||
|
||||
// Because of ACE ordering, System will effectively have dwAllowed even
|
||||
// though the ACE specifies PROCESS_ALL_ACCESS (unless software uses
|
||||
// SeDebugPrivilege or SeTcbName and increases access).
|
||||
// As an exercise, check behavior of tools such as Process Explorer under XP,
|
||||
// Vista, and above. Vista and above should exhibit slightly different behavior
|
||||
// due to Restricted tokens.
|
||||
if (!AddAccessAllowedAce(pDacl, ACL_REVISION, PROCESS_ALL_ACCESS, psidArray[2])) return GetLastError();
|
||||
|
||||
// Because of ACE ordering, Administrators will effectively have dwAllowed
|
||||
// even though the ACE specifies PROCESS_ALL_ACCESS (unless the Administrator
|
||||
// invokes 'discretionary security' by taking ownership and increasing access).
|
||||
// As an exercise, check behavior of tools such as Process Explorer under XP,
|
||||
// Vista, and above. Vista and above should exhibit slightly different behavior
|
||||
// due to Restricted tokens.
|
||||
if (!AddAccessAllowedAce(pDacl, ACL_REVISION, PROCESS_ALL_ACCESS, psidArray[3])) return GetLastError();
|
||||
|
||||
PSECURITY_DESCRIPTOR pSecDesc = allocator.allocate<SECURITY_DESCRIPTOR>();
|
||||
if (!pSecDesc) return GetLastError();
|
||||
|
||||
// InitializeSecurityDescriptor initializes a security descriptor in
|
||||
// absolute format, rather than self-relative format. See
|
||||
// http://msdn.microsoft.com/en-us/library/aa378863(VS.85).aspx
|
||||
if (!InitializeSecurityDescriptor(pSecDesc, SECURITY_DESCRIPTOR_REVISION)) return GetLastError();
|
||||
if (!SetSecurityDescriptorDacl(pSecDesc, TRUE, pDacl, FALSE)) return GetLastError();
|
||||
|
||||
return SetSecurityInfo(
|
||||
GetCurrentProcess(),
|
||||
SE_KERNEL_OBJECT, // process object
|
||||
OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
|
||||
psidCurUser, // NULL, // Owner SID
|
||||
nullptr, // Group SID
|
||||
pDacl,
|
||||
nullptr // SACL
|
||||
);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void AntiCheat::AcquireDebugPrivilege(HANDLE hToken)
|
||||
{
|
||||
LUID luid;
|
||||
TOKEN_PRIVILEGES tp = { 0 };
|
||||
DWORD cb = sizeof(TOKEN_PRIVILEGES);
|
||||
if (!LookupPrivilegeValueA(nullptr, SE_DEBUG_NAME, &luid)) return;
|
||||
|
||||
tp.PrivilegeCount = 1;
|
||||
tp.Privileges[0].Luid = luid;
|
||||
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
||||
AdjustTokenPrivileges(hToken, FALSE, &tp, cb, nullptr, nullptr);
|
||||
//if (GetLastError() != ERROR_SUCCESS) return;
|
||||
}
|
||||
|
||||
void AntiCheat::PatchVirtualProtect(void* vp, void* vpex)
|
||||
{
|
||||
AntiCheat::VirtualProtectHook[1].initialize(vpex, AntiCheat::VirtualProtectExStub, HOOK_JUMP)->install(true, true);
|
||||
AntiCheat::VirtualProtectHook[0].initialize(vp, AntiCheat::VirtualProtectStub, HOOK_JUMP)->install(true, true);
|
||||
}
|
||||
|
||||
NTSTATUS NTAPI AntiCheat::NtCreateThreadExStub(PHANDLE phThread, ACCESS_MASK desiredAccess, LPVOID objectAttributes, HANDLE processHandle, LPTHREAD_START_ROUTINE startAddress, LPVOID parameter, BOOL createSuspended, DWORD stackZeroBits, DWORD sizeOfStackCommit, DWORD sizeOfStackReserve, LPVOID bytesBuffer)
|
||||
{
|
||||
HANDLE hThread = nullptr;
|
||||
std::lock_guard<std::mutex> _(AntiCheat::ThreadMutex);
|
||||
|
||||
AntiCheat::CreateThreadHook.uninstall();
|
||||
NTSTATUS result = NtCreateThreadEx_t(AntiCheat::CreateThreadHook.getAddress())(&hThread, desiredAccess, objectAttributes, processHandle, startAddress, parameter, createSuspended, stackZeroBits, sizeOfStackCommit, sizeOfStackReserve, bytesBuffer);
|
||||
AntiCheat::CreateThreadHook.install();
|
||||
|
||||
if (phThread) *phThread = hThread;
|
||||
|
||||
if (GetProcessId(processHandle) == GetCurrentProcessId())
|
||||
{
|
||||
AntiCheat::OwnThreadIds.push_back(GetThreadId(hThread));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void AntiCheat::PatchThreadCreation()
|
||||
{
|
||||
HMODULE ntdll = Utils::GetNTDLL();
|
||||
if (ntdll)
|
||||
{
|
||||
static uint8_t ntCreateThreadEx[] = { 0xB1, 0x8B, 0xBC, 0x8D, 0x9A, 0x9E, 0x8B, 0x9A, 0xAB, 0x97, 0x8D, 0x9A, 0x9E, 0x9B, 0xBA, 0x87 }; // NtCreateThreadEx
|
||||
FARPROC createThread = GetProcAddress(ntdll, Utils::String::XOR(std::string(reinterpret_cast<char*>(ntCreateThreadEx), sizeof ntCreateThreadEx), -1).data());
|
||||
if (createThread)
|
||||
{
|
||||
AntiCheat::CreateThreadHook.initialize(createThread, AntiCheat::NtCreateThreadExStub, HOOK_JUMP)->install();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int AntiCheat::ValidateThreadTermination(void* addr)
|
||||
{
|
||||
{
|
||||
std::lock_guard<std::mutex> _(AntiCheat::ThreadMutex);
|
||||
|
||||
DWORD id = GetCurrentThreadId();
|
||||
if (const auto threadHook = AntiCheat::ThreadHookMap.find(id); threadHook != AntiCheat::ThreadHookMap.end())
|
||||
{
|
||||
threadHook->second->uninstall(false);
|
||||
AntiCheat::ThreadHookMap.erase(threadHook); // Uninstall and delete the hook
|
||||
return 1; // Kill
|
||||
}
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
std::lock_guard<std::mutex> _(AntiCheat::ThreadMutex);
|
||||
|
||||
// It would be better to wait for the thread
|
||||
// but we don't know if there are multiple hooks at the same address
|
||||
bool found = false;
|
||||
for (const auto& threadHook : AntiCheat::ThreadHookMap)
|
||||
{
|
||||
if (threadHook.second->getAddress() == addr)
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) break;
|
||||
std::this_thread::sleep_for(10ms);
|
||||
}
|
||||
|
||||
return 0; // Don't kill
|
||||
}
|
||||
|
||||
__declspec(naked) void AntiCheat::ThreadEntryPointStub()
|
||||
{
|
||||
__asm
|
||||
{
|
||||
push eax
|
||||
push eax
|
||||
pushad
|
||||
|
||||
// Reinitialize the return address
|
||||
mov eax, [esp + 28h]
|
||||
sub eax, 5
|
||||
mov [esp + 28h], eax
|
||||
|
||||
push eax
|
||||
call AntiCheat::ValidateThreadTermination
|
||||
add esp, 4h
|
||||
|
||||
mov [esp + 20h], eax
|
||||
|
||||
popad
|
||||
|
||||
pop eax
|
||||
|
||||
test eax, eax
|
||||
jz dontKill
|
||||
|
||||
pop eax
|
||||
add esp, 4h // Remove return address (simulate a jump hook)
|
||||
retn
|
||||
|
||||
dontKill:
|
||||
pop eax
|
||||
retn
|
||||
}
|
||||
}
|
||||
|
||||
void AntiCheat::VerifyThreadIntegrity()
|
||||
{
|
||||
bool kill = true;
|
||||
{
|
||||
std::lock_guard<std::mutex> _(AntiCheat::ThreadMutex);
|
||||
|
||||
auto threadHook = std::find(AntiCheat::OwnThreadIds.begin(), AntiCheat::OwnThreadIds.end(), GetCurrentThreadId());
|
||||
if (threadHook != AntiCheat::OwnThreadIds.end())
|
||||
{
|
||||
AntiCheat::OwnThreadIds.erase(threadHook);
|
||||
kill = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (kill)
|
||||
{
|
||||
static bool first = true;
|
||||
if (first) first = false; // We can't control the main thread, as it's spawned externally
|
||||
else
|
||||
{
|
||||
std::lock_guard<std::mutex> _(AntiCheat::ThreadMutex);
|
||||
|
||||
HMODULE ntdll = Utils::GetNTDLL(), targetModule;
|
||||
if (!ntdll) return; // :(
|
||||
|
||||
void* address = Utils::GetThreadStartAddress(GetCurrentThread());
|
||||
if (address)
|
||||
{
|
||||
GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, reinterpret_cast<char*>(address), &targetModule);
|
||||
if (targetModule == ntdll) return; // Better not kill kernel threads
|
||||
|
||||
DWORD id = GetCurrentThreadId();
|
||||
{
|
||||
auto threadHook = AntiCheat::ThreadHookMap.find(id);
|
||||
if (threadHook != AntiCheat::ThreadHookMap.end())
|
||||
{
|
||||
threadHook->second->uninstall(false);
|
||||
AntiCheat::ThreadHookMap.erase(threadHook);
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<Utils::Hook> hook = std::make_shared<Utils::Hook>();
|
||||
AntiCheat::ThreadHookMap[id] = hook;
|
||||
|
||||
// Hook the entry point of the thread to properly terminate it
|
||||
hook->initialize(address, AntiCheat::ThreadEntryPointStub, HOOK_CALL)->install(true, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AntiCheat::SystemTimeDiff(LPSYSTEMTIME stA, LPSYSTEMTIME stB, LPSYSTEMTIME stC)
|
||||
{
|
||||
FILETIME ftA, ftB, ftC;
|
||||
ULARGE_INTEGER uiA, uiB, uiC;
|
||||
|
||||
SystemTimeToFileTime(stA, &ftA);
|
||||
SystemTimeToFileTime(stB, &ftB);
|
||||
uiA.HighPart = ftA.dwHighDateTime;
|
||||
uiA.LowPart = ftA.dwLowDateTime;
|
||||
uiB.HighPart = ftB.dwHighDateTime;
|
||||
uiB.LowPart = ftB.dwLowDateTime;
|
||||
|
||||
uiC.QuadPart = uiA.QuadPart - uiB.QuadPart;
|
||||
|
||||
ftC.dwHighDateTime = uiC.HighPart;
|
||||
ftC.dwLowDateTime = uiC.LowPart;
|
||||
FileTimeToSystemTime(&ftC, stC);
|
||||
}
|
||||
|
||||
void AntiCheat::CheckStartupTime()
|
||||
{
|
||||
FILETIME creation, exit, kernel, user;
|
||||
SYSTEMTIME current, creationSt, diffSt;
|
||||
|
||||
GetSystemTime(¤t);
|
||||
GetProcessTimes(GetCurrentProcess(), &creation, &exit, &kernel, &user);
|
||||
|
||||
FileTimeToSystemTime(&creation, &creationSt);
|
||||
AntiCheat::SystemTimeDiff(¤t, &creationSt, &diffSt);
|
||||
|
||||
#ifdef DEBUG
|
||||
char buf[512];
|
||||
snprintf(buf, 512, "creation: %d:%d:%d:%d\n", creationSt.wHour, creationSt.wMinute, creationSt.wSecond, creationSt.wMilliseconds);
|
||||
OutputDebugStringA(buf);
|
||||
|
||||
snprintf(buf, 512, "current: %d:%d:%d:%d\n", current.wHour, current.wMinute, current.wSecond, current.wMilliseconds);
|
||||
OutputDebugStringA(buf);
|
||||
|
||||
snprintf(buf, 512, "diff: %d:%d:%d:%d\n", diffSt.wHour, diffSt.wMinute, diffSt.wSecond, diffSt.wMilliseconds);
|
||||
OutputDebugStringA(buf);
|
||||
#endif
|
||||
|
||||
// crash client if they are using process suspension to inject dlls during startup (aka before we got to here)
|
||||
// maybe tweak this value depending on what the above logging reveals during testing,
|
||||
// but 5 seconds seems about right for now
|
||||
int time = diffSt.wMilliseconds + (diffSt.wSecond * 1000) + (diffSt.wMinute * 1000 * 60);
|
||||
if (time > 5000)
|
||||
{
|
||||
Components::AntiCheat::CrashClient();
|
||||
}
|
||||
|
||||
// use below for logging when using StartSuspended.exe
|
||||
// FILE* f = fopen("times.txt", "a");
|
||||
// fwrite(buf, 1, strlen(buf), f);
|
||||
// fclose(f);
|
||||
}
|
||||
|
||||
AntiCheat::AntiCheat()
|
||||
{
|
||||
time(nullptr);
|
||||
AntiCheat::Flags = NO_FLAG;
|
||||
|
||||
#ifndef DISABLE_ANTICHEAT
|
||||
|
||||
Utils::Hook(0x507BD5, AntiCheat::PatchWinAPI, HOOK_CALL).install()->quick();
|
||||
Utils::Hook(0x5082FD, AntiCheat::LostD3DStub, HOOK_CALL).install()->quick();
|
||||
Utils::Hook(0x51C76C, AntiCheat::CinematicStub, HOOK_CALL).install()->quick();
|
||||
Utils::Hook(0x418209, AntiCheat::SoundInitStub, HOOK_CALL).install()->quick();
|
||||
Utils::Hook(0x60BE9D, AntiCheat::SoundInitStub, HOOK_CALL).install()->quick();
|
||||
Utils::Hook(0x60BE8E, AntiCheat::SoundInitDriverStub, HOOK_CALL).install()->quick();
|
||||
Utils::Hook(0x418204, AntiCheat::SoundInitDriverStub, HOOK_CALL).install()->quick();
|
||||
Scheduler::OnFrame(AntiCheat::PerformScan, true);
|
||||
|
||||
// Detect aimbots
|
||||
Utils::Hook(0x426580, AntiCheat::DObjGetWorldTagPosStub, HOOK_JUMP).install()->quick();
|
||||
Utils::Hook(0x56AC60, AntiCheat::AimTargetGetTagPosStub, HOOK_JUMP).install()->quick();
|
||||
|
||||
// TODO: Probably move that :P
|
||||
if (!Dedicated::IsEnabled())
|
||||
{
|
||||
AntiCheat::InitLoadLibHook();
|
||||
}
|
||||
|
||||
// Prevent external processes from accessing our memory
|
||||
AntiCheat::ProtectProcess();
|
||||
Renderer::OnDeviceRecoveryEnd([]()
|
||||
{
|
||||
AntiCheat::ProtectProcess();
|
||||
});
|
||||
|
||||
// Set the integrity flag
|
||||
AntiCheat::Flags |= AntiCheat::IntergrityFlag::INITIALIZATION;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
AntiCheat::~AntiCheat()
|
||||
{
|
||||
AntiCheat::Flags = NO_FLAG;
|
||||
AntiCheat::OwnThreadIds.clear();
|
||||
AntiCheat::ThreadHookMap.clear();
|
||||
|
||||
for (int i = 0; i < ARRAYSIZE(AntiCheat::LoadLibHook); ++i)
|
||||
{
|
||||
AntiCheat::LoadLibHook[i].uninstall();
|
||||
}
|
||||
|
||||
for (int i = 0; i < ARRAYSIZE(AntiCheat::VirtualProtectHook); ++i)
|
||||
{
|
||||
AntiCheat::VirtualProtectHook[i].uninstall(false);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,120 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef DEBUG
|
||||
// Hide AntiCheat in embeded symbol names
|
||||
#define AntiCheat SubComponent
|
||||
#else
|
||||
# ifndef DISABLE_ANTICHEAT
|
||||
# define DISABLE_ANTICHEAT
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// Uncomment to enable process protection (conflicts with steam!)
|
||||
#define PROCTECT_PROCESS
|
||||
|
||||
namespace Components
|
||||
{
|
||||
class AntiCheat : public Component
|
||||
{
|
||||
public:
|
||||
AntiCheat();
|
||||
~AntiCheat();
|
||||
|
||||
class LibUnlocker
|
||||
{
|
||||
public:
|
||||
LibUnlocker()
|
||||
{
|
||||
UninstallLibHook();
|
||||
}
|
||||
~LibUnlocker()
|
||||
{
|
||||
InstallLibHook();
|
||||
}
|
||||
};
|
||||
|
||||
static void CrashClient();
|
||||
|
||||
static void InitLoadLibHook();
|
||||
|
||||
static void ReadIntegrityCheck();
|
||||
static void ScanIntegrityCheck();
|
||||
static void FlagIntegrityCheck();
|
||||
|
||||
static unsigned long ProtectProcess();
|
||||
|
||||
static void PatchVirtualProtect(void* vp, void* vpex);
|
||||
static void PatchThreadCreation();
|
||||
|
||||
static void VerifyThreadIntegrity();
|
||||
|
||||
static void QuickCodeScanner1();
|
||||
static void QuickCodeScanner2();
|
||||
|
||||
static void UninstallLibHook();
|
||||
static void InstallLibHook();
|
||||
|
||||
static void CheckStartupTime();
|
||||
static void SystemTimeDiff(LPSYSTEMTIME stA, LPSYSTEMTIME stB, LPSYSTEMTIME stC);
|
||||
|
||||
private:
|
||||
enum IntergrityFlag
|
||||
{
|
||||
NO_FLAG = (0),
|
||||
INITIALIZATION = (1 << 0),
|
||||
MEMORY_SCAN = (1 << 1),
|
||||
SCAN_INTEGRITY_CHECK = (1 << 2),
|
||||
|
||||
#ifdef PROCTECT_PROCESS
|
||||
READ_INTEGRITY_CHECK = (1 << 3),
|
||||
#endif
|
||||
|
||||
MAX_FLAG,
|
||||
};
|
||||
|
||||
static Utils::Time::Interval LastCheck;
|
||||
static unsigned long Flags;
|
||||
|
||||
static void PerformScan();
|
||||
static void PatchWinAPI();
|
||||
|
||||
static void NullSub();
|
||||
|
||||
static bool IsPageChangeAllowed(void* callee, void* addr, size_t len);
|
||||
static void AssertCalleeModule(void* callee);
|
||||
|
||||
#ifdef DEBUG_LOAD_LIBRARY
|
||||
static HANDLE LoadLibary(std::wstring library, HANDLE file, DWORD flags, void* callee);
|
||||
static HANDLE WINAPI LoadLibaryAStub(const char* library);
|
||||
static HANDLE WINAPI LoadLibaryWStub(const wchar_t* library);
|
||||
static HANDLE WINAPI LoadLibaryExAStub(const char* library, HANDLE file, DWORD flags);
|
||||
static HANDLE WINAPI LoadLibaryExWStub(const wchar_t* library, HANDLE file, DWORD flags);
|
||||
#endif
|
||||
|
||||
static BOOL WINAPI VirtualProtectStub(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect);
|
||||
static BOOL WINAPI VirtualProtectExStub(HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect);
|
||||
|
||||
static void LostD3DStub();
|
||||
static void CinematicStub();
|
||||
static void SoundInitStub(int a1, int a2, int a3);
|
||||
static void SoundInitDriverStub();
|
||||
|
||||
static void DObjGetWorldTagPosStub();
|
||||
static void AimTargetGetTagPosStub();
|
||||
|
||||
static void AcquireDebugPrivilege(HANDLE hToken);
|
||||
|
||||
static NTSTATUS NTAPI NtCreateThreadExStub(PHANDLE hThread, ACCESS_MASK desiredAccess, LPVOID objectAttributes, HANDLE processHandle, LPTHREAD_START_ROUTINE startAddress, LPVOID parameter, BOOL createSuspended, DWORD stackZeroBits, DWORD sizeOfStackCommit, DWORD sizeOfStackReserve, LPVOID bytesBuffer);
|
||||
static int ValidateThreadTermination(void* addr);
|
||||
static void ThreadEntryPointStub();
|
||||
|
||||
static std::mutex ThreadMutex;
|
||||
static std::vector<DWORD> OwnThreadIds;
|
||||
static std::map<DWORD, std::shared_ptr<Utils::Hook>> ThreadHookMap;
|
||||
|
||||
static Utils::Hook CreateThreadHook;
|
||||
static Utils::Hook LoadLibHook[6];
|
||||
static Utils::Hook VirtualProtectHook[2];
|
||||
};
|
||||
}
|
||||
|
@ -218,8 +218,5 @@ namespace Components
|
||||
|
||||
// This is placed here in case the anticheat has been disabled!
|
||||
// This checks specifically for launching the process suspended to inject a dll
|
||||
#if !defined(DISABLE_ANTICHEAT)
|
||||
AntiCheat::CheckStartupTime();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -55,9 +55,5 @@ namespace Components
|
||||
|
||||
// Changelog
|
||||
UIFeeder::Add(62.0f, Changelog::GetChangelogCount, Changelog::GetChangelogText, Changelog::SelectChangelog);
|
||||
|
||||
#ifndef DISABLE_ANTICHEAT
|
||||
Scheduler::OnFrameAsync(AntiCheat::QuickCodeScanner1);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -83,16 +83,6 @@ namespace Components
|
||||
ServerList::InsertRequest(address);
|
||||
}
|
||||
});
|
||||
|
||||
// This is placed here in case the anticheat has been disabled!
|
||||
// Make sure this is called after the memory scan!
|
||||
#ifndef DISABLE_ANTICHEAT
|
||||
Utils::Hook(0x5ACB9E, []() // Somewhere in the renderer, past the scan check
|
||||
{
|
||||
AntiCheat::ScanIntegrityCheck();
|
||||
return Utils::Hook::Call<void()>(0x4AA720)();
|
||||
}, HOOK_CALL).install()->quick();
|
||||
#endif
|
||||
}
|
||||
|
||||
void Discovery::preDestroy()
|
||||
|
@ -137,10 +137,6 @@ namespace Components
|
||||
Utils::IO::CreateDir("minidumps");
|
||||
PathCombineA(filename, "minidumps\\", Utils::String::VA("%s-" VERSION "-%s.dmp", exeFileName, filenameFriendlyTime));
|
||||
|
||||
#ifndef DISABLE_ANTICHEAT
|
||||
AntiCheat::UninstallLibHook();
|
||||
#endif
|
||||
|
||||
DWORD fileShare = FILE_SHARE_READ | FILE_SHARE_WRITE;
|
||||
HANDLE hFile = CreateFileA(filename, GENERIC_WRITE | GENERIC_READ, fileShare, nullptr, (fileShare & FILE_SHARE_WRITE) > 0 ? OPEN_ALWAYS : OPEN_EXISTING, NULL, nullptr);
|
||||
MINIDUMP_EXCEPTION_INFORMATION ex = { GetCurrentThreadId(), ExceptionInfo, FALSE };
|
||||
@ -157,10 +153,6 @@ namespace Components
|
||||
TerminateProcess(GetCurrentProcess(), ExceptionInfo->ExceptionRecord->ExceptionCode);
|
||||
}
|
||||
|
||||
#ifndef DISABLE_ANTICHEAT
|
||||
AntiCheat::InstallLibHook();
|
||||
#endif
|
||||
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
|
@ -98,15 +98,5 @@ namespace Components
|
||||
// Dynamically grab gametypes
|
||||
Utils::Hook(0x5FA46C, Gametypes::BuildGametypeList, HOOK_CALL).install()->quick(); // Scr_UpdateGameTypeList
|
||||
Utils::Hook(0x632155, Gametypes::BuildGametypeList, HOOK_CALL).install()->quick(); // UI_UpdateGameTypesList
|
||||
|
||||
// This is placed here in case the anticheat has been disabled!
|
||||
// Make sure this is called after every onther anticheat check!
|
||||
#ifndef DISABLE_ANTICHEAT
|
||||
Utils::Hook(0x5ACBA3, []() // Somewhere in the renderer, past other renderer hooks!
|
||||
{
|
||||
AntiCheat::FlagIntegrityCheck();
|
||||
return Utils::Hook::Call<void()>(0x50AB20)();
|
||||
}, HOOK_CALL).install()->quick();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -297,13 +297,6 @@ namespace Components
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// #ifndef DISABLE_ANTICHEAT
|
||||
// if (!Dedicated::IsEnabled() && !ZoneBuilder::IsEnabled() && !Utils::IsWineEnvironment() && !Loader::IsPerformingUnitTests())
|
||||
// {
|
||||
// AntiCheat::PatchVirtualProtect(VirtualProtect, VirtualProtectEx);
|
||||
// }
|
||||
// #endif
|
||||
}
|
||||
|
||||
Localization::~Localization()
|
||||
|
@ -70,7 +70,7 @@ namespace Components
|
||||
|
||||
script->next = nullptr;
|
||||
|
||||
Game::source_t* source = allocator->allocate<Game::source_t>();
|
||||
auto* source = allocator->allocate<Game::source_t>();
|
||||
if (!source)
|
||||
{
|
||||
Game::FreeMemory(script);
|
||||
@ -116,7 +116,7 @@ namespace Components
|
||||
{
|
||||
Utils::Memory::Allocator* allocator = Utils::Memory::GetAllocator();
|
||||
|
||||
Game::menuDef_t* menu = allocator->allocate<Game::menuDef_t>();
|
||||
auto* menu = allocator->allocate<Game::menuDef_t>();
|
||||
if (!menu) return nullptr;
|
||||
|
||||
menu->items = allocator->allocateArray<Game::itemDef_s*>(512);
|
||||
@ -284,17 +284,7 @@ namespace Components
|
||||
|
||||
if (menus.empty())
|
||||
{
|
||||
// // Try loading the original menu, if we can't load our custom one
|
||||
// Game::menuDef_t* originalMenu = AssetHandler::FindOriginalAsset(Game::XAssetType::ASSET_TYPE_MENU, menudef->window.name).menu;
|
||||
//
|
||||
// if (originalMenu)
|
||||
// {
|
||||
// menus.push_back({ false, originalMenu });
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
menus.push_back({ false, menudef }); // Native menu
|
||||
// }
|
||||
}
|
||||
|
||||
return menus;
|
||||
@ -308,7 +298,7 @@ namespace Components
|
||||
if (menus.empty()) return nullptr;
|
||||
|
||||
// Allocate new menu list
|
||||
Game::MenuList* newList = allocator->allocate<Game::MenuList>();
|
||||
auto* newList = allocator->allocate<Game::MenuList>();
|
||||
if (!newList) return nullptr;
|
||||
|
||||
newList->menus = allocator->allocateArray<Game::menuDef_t*>(menus.size());
|
||||
@ -319,7 +309,7 @@ namespace Components
|
||||
}
|
||||
|
||||
newList->name = allocator->duplicateString(menu);
|
||||
newList->menuCount = menus.size();
|
||||
newList->menuCount = static_cast<int>(menus.size());
|
||||
|
||||
// Copy new menus
|
||||
for (unsigned int i = 0; i < menus.size(); ++i)
|
||||
@ -759,50 +749,14 @@ namespace Components
|
||||
|
||||
void Menus::RegisterCustomMenusHook()
|
||||
{
|
||||
Game::UiContext* uiInfoArray = (Game::UiContext*)0x62E2858;
|
||||
// Game::MenuList list;
|
||||
|
||||
Utils::Hook::Call<void()>(0x401700)(); // call original load functions
|
||||
//Game::XAssetHeader header = Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_MENULIST, "ui_mp/iw4x.txt");
|
||||
//if (header.data && !(header.menuList->menuCount == 1 && !_stricmp("default_menu", header.menuList->menus[0]->window.name)))
|
||||
//{
|
||||
// // Utils::Hook::Call<void(void*, Game::MenuList*, int)>(0x401700)(uiInfoArray, header.menuList, 1); // add loaded menus
|
||||
// std::memcpy(&list, header.data, sizeof(Game::MenuList));
|
||||
|
||||
// for (int i = 0; i < uiInfoArray->menuCount; i++)
|
||||
// {
|
||||
// for (int j = 0; j < list.menuCount; j++)
|
||||
// {
|
||||
// if (!list.menus[j]) continue; // skip already used entries
|
||||
// if (!stricmp(list.menus[j]->window.name, uiInfoArray->Menus[i]->window.name))
|
||||
// {
|
||||
// uiInfoArray->Menus[i] = list.menus[j]; // overwrite UiContext pointer
|
||||
// list.menus[j] = nullptr; // clear entries that already exist so we don't add them later
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// for (int i = 0; i < list.menuCount; i++)
|
||||
// {
|
||||
// if (list.menus[i])
|
||||
// {
|
||||
// uiInfoArray->Menus[uiInfoArray->menuCount++] = list.menus[i];
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
for (int i = 0; i < uiInfoArray->menuCount; i++)
|
||||
#ifdef _DEBUG
|
||||
for (int i = 0; i < Game::uiContext->menuCount; i++)
|
||||
{
|
||||
OutputDebugStringA(Utils::String::VA("%s\n", uiInfoArray->Menus[i]->window.name));
|
||||
OutputDebugStringA(Utils::String::VA("%s\n", Game::uiContext->Menus[i]->window.name));
|
||||
}
|
||||
|
||||
/*
|
||||
header = Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_MENULIST, "ui_mp/mod.txt");
|
||||
if (header.data && !(header.menuList->menuCount == 1 && !_stricmp("default_menu", header.menuList->menus[0]->window.name)))
|
||||
{
|
||||
Utils::Hook::Call<void(void*, Game::MenuList*, int)>(0x401700)(uiInfoArray, header.menuList, 1); // add loaded menus
|
||||
}
|
||||
*/
|
||||
#endif
|
||||
}
|
||||
|
||||
Menus::Menus()
|
||||
@ -883,10 +837,6 @@ namespace Components
|
||||
}
|
||||
});
|
||||
|
||||
#ifndef DISABLE_ANTICHEAT
|
||||
Scheduler::OnFrameAsync(AntiCheat::QuickCodeScanner2);
|
||||
#endif
|
||||
|
||||
Command::Add("mp_QuickMessage", [](Command::Params*)
|
||||
{
|
||||
Command::Execute("openmenu quickmessage");
|
||||
|
@ -871,11 +871,6 @@ namespace Components
|
||||
|
||||
// Add frame callback
|
||||
Scheduler::OnFrame(ServerList::Frame);
|
||||
|
||||
// This is placed here in case the anticheat has been disabled!
|
||||
#if !defined(DISABLE_ANTICHEAT) && defined(PROCTECT_PROCESS)
|
||||
Scheduler::OnFrame(AntiCheat::ReadIntegrityCheck, true);
|
||||
#endif
|
||||
}
|
||||
|
||||
ServerList::~ServerList()
|
||||
|
@ -424,7 +424,7 @@ namespace Game
|
||||
int* svs_numclients = reinterpret_cast<int*>(0x31D938C);
|
||||
client_t* svs_clients = reinterpret_cast<client_t*>(0x31D9390);
|
||||
|
||||
UiContext *uiContext = reinterpret_cast<UiContext *>(0x62E2858);
|
||||
UiContext* uiContext = reinterpret_cast<UiContext*>(0x62E2858);
|
||||
|
||||
int* arenaCount = reinterpret_cast<int*>(0x62E6930);
|
||||
mapArena_t* arenas = reinterpret_cast<mapArena_t*>(0x62E6934);
|
||||
|
@ -402,7 +402,7 @@ namespace Game
|
||||
typedef void(__cdecl * LargeLocalInit_t)();
|
||||
extern LargeLocalInit_t LargeLocalInit;
|
||||
|
||||
typedef bool(__cdecl * Load_Stream_t)(bool atStreamStart, const void *ptr, unsigned int size);
|
||||
typedef bool(__cdecl * Load_Stream_t)(bool atStreamStart, const void* ptr, unsigned int size);
|
||||
extern Load_Stream_t Load_Stream;
|
||||
|
||||
typedef void(__cdecl * Load_XString_t)(bool atStreamStart);
|
||||
@ -411,64 +411,64 @@ namespace Game
|
||||
typedef void(__cdecl * Load_XModelPtr_t)(bool atStreamStart);
|
||||
extern Load_XModelPtr_t Load_XModelPtr;
|
||||
|
||||
typedef void(__cdecl * Load_XModelSurfsFixup_t)(XModelSurfs **, XModelLodInfo *);
|
||||
typedef void(__cdecl * Load_XModelSurfsFixup_t)(XModelSurfs**, XModelLodInfo*);
|
||||
extern Load_XModelSurfsFixup_t Load_XModelSurfsFixup;
|
||||
|
||||
typedef void(__cdecl * Load_XStringArray_t)(bool atStreamStart, int count);
|
||||
extern Load_XStringArray_t Load_XStringArray;
|
||||
|
||||
typedef void(__cdecl * Load_XStringCustom_t)(const char **str);
|
||||
typedef void(__cdecl * Load_XStringCustom_t)(const char** str);
|
||||
extern Load_XStringCustom_t Load_XStringCustom;
|
||||
|
||||
typedef void(__cdecl *Load_FxEffectDefHandle_t)(bool atStreamStart);
|
||||
typedef void(__cdecl * Load_FxEffectDefHandle_t)(bool atStreamStart);
|
||||
extern Load_FxEffectDefHandle_t Load_FxEffectDefHandle;
|
||||
|
||||
typedef void(__cdecl *Load_FxElemDef_t)(bool atStreamStart);
|
||||
typedef void(__cdecl * Load_FxElemDef_t)(bool atStreamStart);
|
||||
extern Load_FxElemDef_t Load_FxElemDef;
|
||||
|
||||
typedef void(__cdecl *Load_GfxImagePtr_t)(bool atStreamStart);
|
||||
typedef void(__cdecl * Load_GfxImagePtr_t)(bool atStreamStart);
|
||||
extern Load_GfxImagePtr_t Load_GfxImagePtr;
|
||||
|
||||
typedef void(__cdecl *Load_GfxTextureLoad_t)(bool atStreamStart);
|
||||
typedef void(__cdecl * Load_GfxTextureLoad_t)(bool atStreamStart);
|
||||
extern Load_GfxTextureLoad_t Load_GfxTextureLoad;
|
||||
|
||||
typedef int(__cdecl *Load_Texture_t)(GfxImageLoadDef **loadDef, GfxImage *image);
|
||||
typedef int(__cdecl * Load_Texture_t)(GfxImageLoadDef** loadDef, GfxImage* image);
|
||||
extern Load_Texture_t Load_Texture;
|
||||
|
||||
typedef void(__cdecl * Load_SndAliasCustom_t)(snd_alias_list_t** var);
|
||||
extern Load_SndAliasCustom_t Load_SndAliasCustom;
|
||||
|
||||
typedef void(__cdecl *Load_MaterialHandle_t)(bool atStreamStart);
|
||||
typedef void(__cdecl * Load_MaterialHandle_t)(bool atStreamStart);
|
||||
extern Load_MaterialHandle_t Load_MaterialHandle;
|
||||
|
||||
typedef void(__cdecl *Load_PhysCollmapPtr_t)(bool atStreamStart);
|
||||
typedef void(__cdecl * Load_PhysCollmapPtr_t)(bool atStreamStart);
|
||||
extern Load_PhysCollmapPtr_t Load_PhysCollmapPtr;
|
||||
|
||||
typedef void(__cdecl *Load_PhysPresetPtr_t)(bool atStreamStart);
|
||||
typedef void(__cdecl * Load_PhysPresetPtr_t)(bool atStreamStart);
|
||||
extern Load_PhysPresetPtr_t Load_PhysPresetPtr;
|
||||
|
||||
typedef void(__cdecl *Load_TracerDefPtr_t)(bool atStreamStart);
|
||||
typedef void(__cdecl * Load_TracerDefPtr_t)(bool atStreamStart);
|
||||
extern Load_TracerDefPtr_t Load_TracerDefPtr;
|
||||
|
||||
typedef void(__cdecl *Load_snd_alias_list_nameArray_t)(bool atStreamStart, int count);
|
||||
typedef void(__cdecl * Load_snd_alias_list_nameArray_t)(bool atStreamStart, int count);
|
||||
extern Load_snd_alias_list_nameArray_t Load_snd_alias_list_nameArray;
|
||||
|
||||
typedef void(__cdecl * Menus_CloseAll_t)(UiContext *dc);
|
||||
typedef void(__cdecl * Menus_CloseAll_t)(UiContext* dc);
|
||||
extern Menus_CloseAll_t Menus_CloseAll;
|
||||
|
||||
typedef void(__cdecl * Menus_CloseRequest_t)(UiContext *dc, menuDef_t* menu);
|
||||
extern Menus_CloseRequest_t Menus_CloseRequest;
|
||||
|
||||
typedef int(__cdecl * Menus_OpenByName_t)(UiContext *dc, const char *p);
|
||||
typedef int(__cdecl * Menus_OpenByName_t)(UiContext* dc, const char* p);
|
||||
extern Menus_OpenByName_t Menus_OpenByName;
|
||||
|
||||
typedef menuDef_t *(__cdecl * Menus_FindByName_t)(UiContext *dc, const char *name);
|
||||
typedef menuDef_t *(__cdecl * Menus_FindByName_t)(UiContext* dc, const char* name);
|
||||
extern Menus_FindByName_t Menus_FindByName;
|
||||
|
||||
typedef bool(__cdecl * Menu_IsVisible_t)(UiContext *dc, menuDef_t *menu);
|
||||
typedef bool(__cdecl * Menu_IsVisible_t)(UiContext* dc, menuDef_t* menu);
|
||||
extern Menu_IsVisible_t Menu_IsVisible;
|
||||
|
||||
typedef bool(__cdecl * Menus_MenuIsInStack_t)(UiContext *dc, menuDef_t *menu);
|
||||
typedef bool(__cdecl * Menus_MenuIsInStack_t)(UiContext* dc, menuDef_t* menu);
|
||||
extern Menus_MenuIsInStack_t Menus_MenuIsInStack;
|
||||
|
||||
typedef menuDef_t*(__cdecl * Menu_GetFocused_t)(UiContext* ctx);
|
||||
@ -480,16 +480,16 @@ namespace Game
|
||||
typedef bool(__cdecl * UI_KeyEvent_t)(int clientNum, int key, int down);
|
||||
extern UI_KeyEvent_t UI_KeyEvent;
|
||||
|
||||
typedef const char* (__cdecl * UI_SafeTranslateString_t)(const char* reference);
|
||||
typedef const char*(__cdecl * UI_SafeTranslateString_t)(const char* reference);
|
||||
extern UI_SafeTranslateString_t UI_SafeTranslateString;
|
||||
|
||||
typedef void(__cdecl * UI_ReplaceConversions_t)(const char* sourceString, ConversionArguments* arguments, char* outputString, size_t outputStringSize);
|
||||
extern UI_ReplaceConversions_t UI_ReplaceConversions;
|
||||
|
||||
typedef void(__cdecl * MSG_Init_t)(msg_t *buf, char *data, int length);
|
||||
typedef void(__cdecl * MSG_Init_t)(msg_t* buf, char* data, int length);
|
||||
extern MSG_Init_t MSG_Init;
|
||||
|
||||
typedef void(__cdecl * MSG_ReadData_t)(msg_t *msg, void *data, int len);
|
||||
typedef void(__cdecl * MSG_ReadData_t)(msg_t* msg, void* data, int len);
|
||||
extern MSG_ReadData_t MSG_ReadData;
|
||||
|
||||
typedef int(__cdecl * MSG_ReadLong_t)(msg_t* msg);
|
||||
@ -873,16 +873,16 @@ namespace Game
|
||||
typedef void(__cdecl * Sys_SuspendOtherThreads_t)();
|
||||
extern Sys_SuspendOtherThreads_t Sys_SuspendOtherThreads;
|
||||
|
||||
typedef void(__cdecl * UI_AddMenuList_t)(UiContext *dc, MenuList *menuList, int close);
|
||||
typedef void(__cdecl * UI_AddMenuList_t)(UiContext* dc, MenuList* menuList, int close);
|
||||
extern UI_AddMenuList_t UI_AddMenuList;
|
||||
|
||||
typedef uiMenuCommand_t(__cdecl * UI_GetActiveMenu_t)(int localClientNum);
|
||||
extern UI_GetActiveMenu_t UI_GetActiveMenu;
|
||||
|
||||
typedef char* (__cdecl * UI_CheckStringTranslation_t)(char*, char*);
|
||||
typedef char*(__cdecl * UI_CheckStringTranslation_t)(char*, char*);
|
||||
extern UI_CheckStringTranslation_t UI_CheckStringTranslation;
|
||||
|
||||
typedef MenuList *(__cdecl * UI_LoadMenus_t)(const char *menuFile, int imageTrack);
|
||||
typedef MenuList*(__cdecl * UI_LoadMenus_t)(const char* menuFile, int imageTrack);
|
||||
extern UI_LoadMenus_t UI_LoadMenus;
|
||||
|
||||
typedef void(__cdecl * UI_UpdateArenas_t)();
|
||||
@ -985,7 +985,7 @@ namespace Game
|
||||
extern source_t **sourceFiles;
|
||||
extern keywordHash_t **menuParseKeywordHash;
|
||||
|
||||
extern UiContext *uiContext;
|
||||
extern UiContext* uiContext;
|
||||
|
||||
extern int* arenaCount;
|
||||
extern mapArena_t* arenas;
|
||||
|
25
src/Main.cpp
25
src/Main.cpp
@ -55,7 +55,7 @@ BOOL APIENTRY DllMain(HMODULE /*hModule*/, DWORD ul_reason_for_call, LPVOID /*l
|
||||
Steam::Proxy::RunMod();
|
||||
|
||||
// Ensure we're working with our desired binary
|
||||
char* _module = reinterpret_cast<char*>(0x400000);
|
||||
auto* _module = reinterpret_cast<char*>(0x400000);
|
||||
auto hash1 = Utils::Cryptography::JenkinsOneAtATime::Compute(_module + 0x1000, 0x2D531F); // .text
|
||||
auto hash2 = Utils::Cryptography::JenkinsOneAtATime::Compute(_module + 0x2D75FC, 0xBDA04); // .rdata
|
||||
if ((hash1 != 0x54684DBE
|
||||
@ -67,17 +67,6 @@ BOOL APIENTRY DllMain(HMODULE /*hModule*/, DWORD ul_reason_for_call, LPVOID /*l
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#ifndef DISABLE_ANTICHEAT
|
||||
[]()
|
||||
{
|
||||
if (!Components::Dedicated::IsEnabled() && !Components::Loader::IsPerformingUnitTests())
|
||||
{
|
||||
Components::AntiCheat::ProtectProcess();
|
||||
Components::AntiCheat::PatchThreadCreation();
|
||||
}
|
||||
}();
|
||||
#endif
|
||||
|
||||
DWORD oldProtect;
|
||||
VirtualProtect(_module + 0x1000, 0x2D6000, PAGE_EXECUTE_READ, &oldProtect); // Protect the .text segment
|
||||
|
||||
@ -88,18 +77,6 @@ BOOL APIENTRY DllMain(HMODULE /*hModule*/, DWORD ul_reason_for_call, LPVOID /*l
|
||||
{
|
||||
Main::Uninitialize();
|
||||
}
|
||||
else if (ul_reason_for_call == DLL_THREAD_ATTACH)
|
||||
{
|
||||
#ifndef DISABLE_ANTICHEAT
|
||||
[]()
|
||||
{
|
||||
if (!Components::Dedicated::IsEnabled() && !Components::Loader::IsPerformingUnitTests())
|
||||
{
|
||||
Components::AntiCheat::VerifyThreadIntegrity();
|
||||
}
|
||||
}();
|
||||
#endif
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -123,10 +123,6 @@ namespace Utils
|
||||
|
||||
void SafeShellExecute(HWND hwnd, LPCSTR lpOperation, LPCSTR lpFile, LPCSTR lpParameters, LPCSTR lpDirectory, INT nShowCmd)
|
||||
{
|
||||
#ifndef DISABLE_ANTICHEAT
|
||||
Components::AntiCheat::LibUnlocker _;
|
||||
#endif
|
||||
|
||||
[=]()
|
||||
{
|
||||
__try
|
||||
|
Loading…
Reference in New Issue
Block a user