[AntiCheat] Patch virtual protect

This commit is contained in:
momo5502 2017-03-26 20:41:37 +02:00
parent 0fa9186db5
commit aa20fc009d
5 changed files with 102 additions and 24 deletions

View File

@ -5,6 +5,7 @@ namespace Components
Utils::Time::Interval AntiCheat::LastCheck; Utils::Time::Interval AntiCheat::LastCheck;
std::string AntiCheat::Hash; std::string AntiCheat::Hash;
Utils::Hook AntiCheat::LoadLibHook[4]; Utils::Hook AntiCheat::LoadLibHook[4];
Utils::Hook AntiCheat::VirtualProtectHook[2];
unsigned long AntiCheat::Flags = NO_FLAG; unsigned long AntiCheat::Flags = NO_FLAG;
// This function does nothing, it only adds the two passed variables and returns the value // This function does nothing, it only adds the two passed variables and returns the value
@ -57,7 +58,7 @@ namespace Components
if (!hModuleSelf || !hModuleTarget || !hModuleProcess || (hModuleTarget != hModuleSelf && hModuleTarget != hModuleProcess)) if (!hModuleSelf || !hModuleTarget || !hModuleProcess || (hModuleTarget != hModuleSelf && hModuleTarget != hModuleProcess))
{ {
#ifdef DEBUG_DETECTIONS #ifdef DEBUG_DETECTIONS
char buffer[MAX_PATH] = { 0 }; char buffer[MAX_PATH] = {0};
GetModuleFileNameA(hModuleTarget, buffer, sizeof buffer); GetModuleFileNameA(hModuleTarget, buffer, sizeof buffer);
Logger::Print(Utils::String::VA("AntiCheat: Callee assertion failed: %X %s", reinterpret_cast<uint32_t>(callee), buffer)); Logger::Print(Utils::String::VA("AntiCheat: Callee assertion failed: %X %s", reinterpret_cast<uint32_t>(callee), buffer));
@ -69,9 +70,9 @@ namespace Components
void AntiCheat::InitLoadLibHook() void AntiCheat::InitLoadLibHook()
{ {
static uint8_t kernel32Str[] = { 0xB4, 0x9A, 0x8D, 0xB1, 0x9A, 0x93, 0xCC, 0xCD, 0xD1, 0x9B, 0x93, 0x93 }; // KerNel32.dll 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 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 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()); HMODULE kernel32 = GetModuleHandleA(Utils::String::XOR(std::string(reinterpret_cast<char*>(kernel32Str), sizeof kernel32Str), -1).data());
if (kernel32) if (kernel32)
@ -115,7 +116,7 @@ namespace Components
#ifdef PROCTECT_PROCESS #ifdef PROCTECT_PROCESS
static Utils::Time::Interval check; static Utils::Time::Interval check;
if(check.elapsed(20s)) if (check.elapsed(20s))
{ {
check.update(); check.update();
@ -207,7 +208,7 @@ namespace Components
HANDLE AntiCheat::LoadLibary(std::wstring library, HANDLE file, DWORD flags, void* callee) HANDLE AntiCheat::LoadLibary(std::wstring library, HANDLE file, DWORD flags, void* callee)
{ {
HMODULE module; HMODULE module;
char buffer[MAX_PATH] = { 0 }; char buffer[MAX_PATH] = {0};
GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, reinterpret_cast<char*>(callee), &module); GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, reinterpret_cast<char*>(callee), &module);
GetModuleFileNameA(module, buffer, sizeof buffer); GetModuleFileNameA(module, buffer, sizeof buffer);
@ -354,6 +355,49 @@ namespace Components
} }
} }
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 (GetCurrentProcess() == 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() unsigned long AntiCheat::ProtectProcess()
{ {
#ifdef PROCTECT_PROCESS #ifdef PROCTECT_PROCESS
@ -370,20 +414,20 @@ namespace Components
} }
auto freeSid = [] (void* sid) auto freeSid = [] (void* sid)
{
if (sid)
{ {
FreeSid(reinterpret_cast<PSID>(sid)); if (sid)
} {
}; FreeSid(reinterpret_cast<PSID>(sid));
}
};
allocator.reference(hToken, [] (void* hToken) allocator.reference(hToken, [] (void* hToken)
{ {
if (hToken) if (hToken)
{ {
CloseHandle(hToken); CloseHandle(hToken);
} }
}); });
//AntiCheat::AcquireDebugPriviledge(hToken); //AntiCheat::AcquireDebugPriviledge(hToken);
@ -419,9 +463,9 @@ namespace Components
const PSID psidArray[] = const PSID psidArray[] =
{ {
psidEveryone, /* Deny most rights to everyone */ psidEveryone, /* Deny most rights to everyone */
psidCurUser, /* Allow what was not denied */ psidCurUser, /* Allow what was not denied */
psidSystem, /* Full control */ psidSystem, /* Full control */
psidAdmins, /* Full control */ psidAdmins, /* Full control */
}; };
// Determine required size of the ACL // Determine required size of the ACL
@ -497,10 +541,11 @@ namespace Components
return 0; return 0;
#endif #endif
} }
void AntiCheat::AcquireDebugPriviledge(HANDLE hToken) void AntiCheat::AcquireDebugPriviledge(HANDLE hToken)
{ {
LUID luid; LUID luid;
TOKEN_PRIVILEGES tp = { 0 }; TOKEN_PRIVILEGES tp = {0};
DWORD cb = sizeof(TOKEN_PRIVILEGES); DWORD cb = sizeof(TOKEN_PRIVILEGES);
if (!LookupPrivilegeValueW(nullptr, SE_DEBUG_NAME, &luid)) return; if (!LookupPrivilegeValueW(nullptr, SE_DEBUG_NAME, &luid)) return;
@ -511,6 +556,12 @@ namespace Components
//if (GetLastError() != ERROR_SUCCESS) return; //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);
}
AntiCheat::AntiCheat() AntiCheat::AntiCheat()
{ {
time(nullptr); time(nullptr);
@ -519,9 +570,9 @@ namespace Components
#ifdef DEBUG #ifdef DEBUG
Command::Add("penis", [] (Command::Params*) Command::Add("penis", [] (Command::Params*)
{ {
AntiCheat::CrashClient(); AntiCheat::CrashClient();
}); });
#else #else
Utils::Hook(0x507BD5, AntiCheat::PatchWinAPI, HOOK_CALL).install()->quick(); Utils::Hook(0x507BD5, AntiCheat::PatchWinAPI, HOOK_CALL).install()->quick();

View File

@ -30,6 +30,8 @@ namespace Components
static unsigned long ProtectProcess(); static unsigned long ProtectProcess();
static void PatchVirtualProtect(void* vp, void* vpex);
private: private:
enum IntergrityFlag enum IntergrityFlag
{ {
@ -54,6 +56,7 @@ namespace Components
static void NullSub(); static void NullSub();
static bool IsPageChangeAllowed(void* callee, void* addr, size_t len);
static void AssertCalleeModule(void* callee); static void AssertCalleeModule(void* callee);
static void UninstallLibHook(); static void UninstallLibHook();
@ -67,6 +70,9 @@ namespace Components
static HANDLE WINAPI LoadLibaryExWStub(const wchar_t* library, HANDLE file, DWORD flags); static HANDLE WINAPI LoadLibaryExWStub(const wchar_t* library, HANDLE file, DWORD flags);
#endif #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 LostD3DStub();
static void CinematicStub(); static void CinematicStub();
static void SoundInitStub(int a1, int a2, int a3); static void SoundInitStub(int a1, int a2, int a3);
@ -78,5 +84,6 @@ namespace Components
static void AcquireDebugPriviledge(HANDLE hToken); static void AcquireDebugPriviledge(HANDLE hToken);
static Utils::Hook LoadLibHook[4]; static Utils::Hook LoadLibHook[4];
static Utils::Hook VirtualProtectHook[2];
}; };
} }

View File

@ -280,6 +280,10 @@ namespace Components
} }
} }
}); });
#if !defined(DEBUG) && !defined(DISABLE_ANTICHEAT)
AntiCheat::PatchVirtualProtect(VirtualProtect, VirtualProtectEx);
#endif
} }
Localization::~Localization() Localization::~Localization()

View File

@ -71,4 +71,16 @@ namespace Utils
return 0; return 0;
} }
size_t GetModuleSize(HMODULE module)
{
PIMAGE_DOS_HEADER header = PIMAGE_DOS_HEADER(module);
PIMAGE_NT_HEADERS ntHeader = PIMAGE_NT_HEADERS(DWORD(module) + header->e_lfanew);
return ntHeader->OptionalHeader.SizeOfImage;
}
bool HasIntercection(unsigned int base1, unsigned int len1, unsigned int base2, unsigned int len2)
{
return !((base1 + len1) < base2 || (base2 + len2) < base1);
}
} }

View File

@ -11,6 +11,10 @@ namespace Utils
unsigned long GetParentProcessId(); unsigned long GetParentProcessId();
size_t GetModuleSize(HMODULE module);
bool HasIntercection(unsigned int base1, unsigned int len1, unsigned int base2, unsigned int len2);
template <typename T> inline void Merge(std::vector<T>* target, T* source, size_t length) template <typename T> inline void Merge(std::vector<T>* target, T* source, size_t length)
{ {
if (source) if (source)