iw4x-client/src/Components/Modules/AntiCheat.cpp

205 lines
5.5 KiB
C++
Raw Normal View History

2016-02-29 08:47:21 -05:00
#include "STDInclude.hpp"
namespace Components
{
2016-02-29 11:30:04 -05:00
int AntiCheat::LastCheck;
2016-02-29 08:47:21 -05:00
std::string AntiCheat::Hash;
2016-03-07 16:52:53 -05:00
Utils::Hook AntiCheat::LoadLibHook[4];
2016-03-14 16:29:21 -04:00
Utils::Hook AntiCheat::VirtualProtectHook;
2016-02-29 08:47:21 -05:00
2016-02-29 14:38:14 -05:00
// 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
void __declspec(naked) 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
}
}
2016-02-29 08:47:21 -05:00
void __declspec(naked) AntiCheat::CrashClient()
{
static uint8_t crashProcedure[] =
{
2016-02-29 14:38:14 -05:00
// Variable space
0xDC, 0xC1, 0xDC, 0x05,
2016-02-29 08:47:21 -05:00
// Uninstall minidump handler
2016-03-01 07:37:51 -05:00
// This doesn't work anymore, due to the SetUnhandledExceptionFilter hook, but that's not important
//0xB8, 0x63, 0xE7, 0x2F, 0x00, // mov eax, 2FE763h
//0x05, 0xAD, 0xAD, 0x3C, 0x00, // add eax, 3CADADh
//0x6A, 0x58, // push 88
//0x8B, 0x80, 0xEA, 0x01, 0x00, 0x00, // mov eax, [eax + 1EAh]
//0xFF, 0x10, // call dword ptr [eax]
2016-02-29 08:47:21 -05:00
// Crash me.
0xB8, 0x4F, 0x91, 0x27, 0x00, // mov eax, 27914Fh
0x05, 0xDD, 0x28, 0x1A, 0x00, // add eax, 1A28DDh
0x80, 0x00, 0x68, // add byte ptr [eax], 68h
0xC3, // retn
2016-02-29 14:38:14 -05:00
// Random stuff
0xBE, 0xFF, 0xC2, 0xF4, 0x3A,
2016-02-29 08:47:21 -05:00
};
__asm
{
// This does absolutely nothing :P
xor eax, eax
mov ebx, [esp + 4h]
shl ebx, 4h
2016-02-29 14:38:14 -05:00
setz bl
// Push the fake var onto the stack
push ebx
// Save the address to our crash procedure
mov eax, offset crashProcedure
push eax
2016-02-29 08:47:21 -05:00
2016-02-29 14:38:14 -05:00
// Unprotect the .text segment
push eax
push 40h
push 2D5FFFh
push 401001h
2016-03-01 07:37:51 -05:00
call VirtualProtect
2016-02-29 14:38:14 -05:00
// Increment to our crash procedure
2016-03-01 07:37:51 -05:00
// Skip variable space
2016-02-29 14:38:14 -05:00
add dword ptr [esp], 4h
// This basically removes the pushed ebx value from the stack, so returning results in a call to the procedure
jmp AntiCheat::NullSub
2016-02-29 08:47:21 -05:00
}
}
// This has to be called when doing .text changes during runtime
void AntiCheat::EmptyHash()
{
2016-02-29 11:30:04 -05:00
AntiCheat::LastCheck = 0;
2016-02-29 08:47:21 -05:00
AntiCheat::Hash.clear();
}
2016-03-07 16:52:53 -05:00
void AntiCheat::InitLoadLibHook()
{
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(LoadLibraryA, loadLibStub, HOOK_JUMP);
AntiCheat::LoadLibHook[1].Initialize(LoadLibraryW, loadLibStub, HOOK_JUMP);
2016-03-14 16:29:21 -04:00
//AntiCheat::LoadLibHook[2].Initialize(LoadLibraryExA, loadLibExStub, HOOK_JUMP);
//AntiCheat::LoadLibHook[3].Initialize(LoadLibraryExW, loadLibExStub, HOOK_JUMP);
2016-03-07 16:52:53 -05:00
}
2016-02-29 14:38:14 -05:00
void AntiCheat::PerformCheck()
2016-02-29 08:47:21 -05:00
{
2016-02-29 14:38:14 -05:00
// Hash .text segment
// Add 1 to each value, so searching in memory doesn't reveal anything
size_t textSize = 0x2D6001;
uint8_t* textBase = reinterpret_cast<uint8_t*>(0x401001);
std::string hash = Utils::Cryptography::SHA512::Compute(textBase - 1, textSize - 1, false);
2016-02-29 08:47:21 -05:00
// Set the hash, if none is set
if (AntiCheat::Hash.empty())
{
AntiCheat::Hash = hash;
}
// Crash if the hashes don't match
2016-02-29 14:38:14 -05:00
else if (AntiCheat::Hash != hash)
2016-02-29 08:47:21 -05:00
{
AntiCheat::CrashClient();
}
}
2016-02-29 14:38:14 -05:00
void AntiCheat::Frame()
{
// Perform check only every 30 seconds
if (AntiCheat::LastCheck && (Game::Com_Milliseconds() - AntiCheat::LastCheck) < 1000 * 30) return;
AntiCheat::LastCheck = Game::Com_Milliseconds();
AntiCheat::PerformCheck();
}
2016-03-01 07:37:51 -05:00
void AntiCheat::PatchWinAPI()
{
2016-03-14 16:29:21 -04:00
for (int i = 0; i < ARRAYSIZE(AntiCheat::LoadLibHook); ++i)
{
AntiCheat::LoadLibHook[i].Uninstall();
}
2016-03-07 16:52:53 -05:00
// Initialize directx :P
Utils::Hook::Call<void()>(0x5078C0)();
AntiCheat::LoadLibHook[0].Install();
AntiCheat::LoadLibHook[1].Install();
2016-03-11 15:49:14 -05:00
//AntiCheat::LoadLibHook[2].Install();
//AntiCheat::LoadLibHook[3].Install();
2016-03-01 07:37:51 -05:00
}
2016-03-14 16:29:21 -04:00
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;
}
2016-02-29 08:47:21 -05:00
AntiCheat::AntiCheat()
{
2016-03-14 16:29:21 -04:00
// This is required for debugging...in release mode :P
//AntiCheat::VirtualProtectHook.Initialize(VirtualProtect, VirtualProtectStub, HOOK_JUMP);
//AntiCheat::VirtualProtectHook.Install(true, true);
2016-02-29 11:30:04 -05:00
AntiCheat::EmptyHash();
2016-02-29 08:47:21 -05:00
#ifdef DEBUG
Command::Add("penis", [] (Command::Params)
{
AntiCheat::CrashClient();
});
2016-03-01 08:08:46 -05:00
#else
2016-03-07 16:52:53 -05:00
Utils::Hook(0x507BD5, AntiCheat::PatchWinAPI, HOOK_CALL).Install()->Quick();
2016-03-11 15:49:14 -05:00
QuickPatch::OnFrame(AntiCheat::Frame);
2016-03-07 16:52:53 -05:00
// TODO: Probably move that :P
AntiCheat::InitLoadLibHook();
2016-02-29 08:47:21 -05:00
#endif
}
AntiCheat::~AntiCheat()
{
AntiCheat::EmptyHash();
2016-03-14 16:29:21 -04:00
AntiCheat::VirtualProtectHook.Uninstall(false);
for (int i = 0; i < ARRAYSIZE(AntiCheat::LoadLibHook); ++i)
{
AntiCheat::LoadLibHook[i].Uninstall();
}
2016-02-29 08:47:21 -05:00
}
}