From d786e65a9a262638e74f6ebcf1b296917897ae49 Mon Sep 17 00:00:00 2001 From: boris Date: Sun, 30 Dec 2018 15:00:51 +1300 Subject: unban marcus or suffer my wrath grr --- .../csgo-client/Security/RuntimeSecurity.cpp | 197 ++++++++++++++++----- 1 file changed, 148 insertions(+), 49 deletions(-) (limited to 'csgo-loader/csgo-client/Security/RuntimeSecurity.cpp') diff --git a/csgo-loader/csgo-client/Security/RuntimeSecurity.cpp b/csgo-loader/csgo-client/Security/RuntimeSecurity.cpp index 739ce5d..4551b5d 100644 --- a/csgo-loader/csgo-client/Security/RuntimeSecurity.cpp +++ b/csgo-loader/csgo-client/Security/RuntimeSecurity.cpp @@ -1,5 +1,6 @@ #include -#include +#include +#include #include #include @@ -13,9 +14,13 @@ namespace Security // Hooked functions. /////////////////////////////////////////////////////////// +#pragma optimize("", off) + decltype(&OpenProcess) oOpenProcess; HANDLE __stdcall Hooked_OpenProcess(DWORD AccessLevel, bool Inherit, DWORD ProcessId) { + WRAP_IF_RELEASE(VM_EAGLE_WHITE_START); + // Determine where the return address of the function actually points. void *Address = _ReturnAddress(); MEMORY_BASIC_INFORMATION Query = Protection->QueryMemory(Address); @@ -27,7 +32,9 @@ namespace Security if(ReturnModule != LoaderModule) { - Protection->SecurityCallback(); + WRAP_IF_RELEASE(STR_ENCRYPT_START); + Protection->SecurityCallback(__FUNCSIG__); + WRAP_IF_RELEASE(STR_ENCRYPT_END); [&](decltype(&OpenProcess) A) { @@ -39,59 +46,62 @@ namespace Security // Call original function return oOpenProcess(AccessLevel, Inherit, ProcessId); + + WRAP_IF_RELEASE(VM_EAGLE_WHITE_END); } decltype(&ExitProcess) oExitProcess; void __stdcall Hooked_ExitProcess(DWORD ExitCode) { - // Determine where the return address of the function actually points. - void *Address = _ReturnAddress(); - MEMORY_BASIC_INFORMATION Query = Protection->QueryMemory(Address); - - // If the return address points outside of the loader module, - // fail the function. - HMODULE ReturnModule = (HMODULE)Query.AllocationBase; - HMODULE LoaderModule = GetModuleHandleA(NULL); + WRAP_IF_RELEASE(VM_EAGLE_WHITE_START); - if(ReturnModule != LoaderModule) - { - Protection->SecurityCallback(); + WRAP_IF_DEBUG(oExitProcess(ExitCode)); + WRAP_IF_RELEASE( [&](decltype(&ExitProcess) A) { // Again, let's meme anyone who tries to reverse this. uintptr_t NullPointer = *(uintptr_t *)0x00000000; A(NullPointer); }(oExitProcess); - } + ); - // Call original function - oExitProcess(ExitCode); + WRAP_IF_RELEASE(VM_EAGLE_WHITE_END); } decltype(&recv) oWSARecv; int __stdcall Hooked_WSARecv(SOCKET Socket, char *Buffer, int Length, int Flags) { + WRAP_IF_RELEASE(VM_EAGLE_WHITE_START); + // Determine where the return address of the function actually points. - void *Address = _ReturnAddress(); + void *Address = _ReturnAddress(); MEMORY_BASIC_INFORMATION Query = Protection->QueryMemory(Address); // If the return address points outside of the loader module, // fail the function. HMODULE ReturnModule = (HMODULE)Query.AllocationBase; HMODULE LoaderModule = GetModuleHandleA(NULL); - + + // Let's meme anyone who tries to reverse this. if(ReturnModule != LoaderModule) - // Let's meme anyone who tries to reverse this. - return []() { Protection->SecurityCallback(); return -1; }(); + { + WRAP_IF_RELEASE(STR_ENCRYPT_START); + return []() { Protection->SecurityCallback(__FUNCSIG__); return -1; }(); + WRAP_IF_RELEASE(STR_ENCRYPT_END); + } // Call original function return oWSARecv(Socket, Buffer, Length, Flags); + + WRAP_IF_RELEASE(VM_EAGLE_WHITE_END); } decltype(&send) oWSASend; int __stdcall Hooked_WSASend(SOCKET Socket, char *Buffer, int Length, int Flags) { + WRAP_IF_RELEASE(VM_EAGLE_WHITE_START); + // Determine where the return address of the function actually points. void *Address = _ReturnAddress(); MEMORY_BASIC_INFORMATION Query = Protection->QueryMemory(Address); @@ -101,14 +111,22 @@ namespace Security HMODULE ReturnModule = (HMODULE)Query.AllocationBase; HMODULE LoaderModule = GetModuleHandleA(NULL); + // Let's meme anyone who tries to reverse this. if(ReturnModule != LoaderModule) - // Let's meme anyone who tries to reverse this. - return []() { Protection->SecurityCallback(); return -1; }(); + { + WRAP_IF_RELEASE(STR_ENCRYPT_START); + return []() { Protection->SecurityCallback(__FUNCSIG__); return -1; }(); + WRAP_IF_RELEASE(STR_ENCRYPT_END); + } // Call original function return oWSASend(Socket, Buffer, Length, Flags); + + WRAP_IF_RELEASE(VM_EAGLE_WHITE_END); } +#pragma optimize("", on) + // The following functions are only called internally. /////////////////////////////////////////////////////////// @@ -126,7 +144,7 @@ namespace Security // Apply any hooks. SafeCallTo(MH_CreateHook(&OpenProcess, Hooked_OpenProcess, (void **)&oOpenProcess)); SafeCallTo(MH_EnableHook(&OpenProcess)); - + SafeCallTo(MH_CreateHook(&ExitProcess, Hooked_ExitProcess, (void **)&oExitProcess)); SafeCallTo(MH_EnableHook(&ExitProcess)); @@ -158,15 +176,7 @@ namespace Security // This should prevent any such plugins from effectively attaching the debugger. // NOTE: This does not work on x64dbg for whatever reason.. uintptr_t Export_NtContinue = (uintptr_t)GetProcAddress(Module, "NtContinue"); - - // Our small shellcode that calls oExitProcess. - uint8_t Shellcode[] = { - 0xB8, 0x00, 0x00, 0x00, 0x00, // mov eax, dword ptr[0] - 0xFF, 0xE0 // jmp eax - }; - - std::memcpy(&Shellcode[1], oExitProcess, sizeof uint32_t); - + // Ensure that the program gets closed if a debugger is attached. uintptr_t Exports[] = { Export_DbgUiRemoteBreakin, @@ -177,14 +187,14 @@ namespace Security for(auto &It : Exports) { DWORD OldProtection; - if(!VirtualProtect((void *)It, sizeof Shellcode, PAGE_EXECUTE_READWRITE, &OldProtection)) + if(!VirtualProtect((void *)It, sizeof uintptr_t + 1, PAGE_EXECUTE_READWRITE, &OldProtection)) ERROR_ASSERT("[000F:00001A00] Failed to initialize. Please contact an administrator."); // Patch to __asm { jmp oExitProcess; }; *(uint8_t *)It = 0xE9; *(uint32_t *)(It + 1) = (uintptr_t)oExitProcess; - VirtualProtect((void *)It, sizeof Shellcode, OldProtection, &OldProtection); + VirtualProtect((void *)It, sizeof uintptr_t + 1, OldProtection, &OldProtection); } WRAP_IF_RELEASE(STR_ENCRYPT_END); @@ -195,10 +205,10 @@ namespace Security { WRAP_IF_RELEASE(MUTATE_START); - std::thread DebugThread (&RuntimeSecurity::CheckForDebugger, this); DebugThread.detach(); - std::thread VMThread (&RuntimeSecurity::CheckForVirtualMachine, this); VMThread.detach(); - std::thread DriverThread(&RuntimeSecurity::CheckForDrivers, this); DriverThread.detach(); - std::thread TamperThread(&RuntimeSecurity::CheckForThreads, this); TamperThread.detach(); + std::thread DebugThread (&RuntimeSecurity::CheckForDebugger, this); DebugThread.detach(); + std::thread VMThread (&RuntimeSecurity::CheckForVirtualMachine, this); VMThread.detach(); + std::thread DriverThread(&RuntimeSecurity::CheckForDrivers, this); DriverThread.detach(); + std::thread TamperThread(&RuntimeSecurity::CheckForTampering, this); TamperThread.detach(); WRAP_IF_RELEASE(MUTATE_END); } @@ -208,33 +218,95 @@ namespace Security // code readability. /////////////////////////////////////////////////////////// +#pragma optimize("", off) + void RuntimeSecurity::CheckForVirtualMachine() { + WRAP_IF_RELEASE(VM_EAGLE_BLACK_START); + + // Yeah, um, your code did absolutely fuck all in my analysis VM. + int32_t VirtualMachineChecksum = 0x4000; + + WRAP_IF_RELEASE( + CHECK_VIRTUAL_PC(VirtualMachineChecksum, 0x2000); + + WRAP_IF_RELEASE(STR_ENCRYPT_START); + if(VirtualMachineChecksum != 0x2000) + SecurityCallback(__FUNCSIG__); + WRAP_IF_RELEASE(STR_ENCRYPT_END); + ); + + // Don't put too much stress on the CPU. + Sleep(VirtualMachineChecksum); + WRAP_IF_RELEASE(VM_EAGLE_BLACK_END); } void RuntimeSecurity::CheckForDebugger() { + WRAP_IF_RELEASE(VM_EAGLE_BLACK_START); + // Read the PEB from the TIB. // Offset for x86 is 0x30 ; mov ..., dword ptr fs:[0x30] // Offset for x64 is 0x60 ; mov ..., qword ptr gs:[0x60] + PEB *ProcessEnvBlock = (PEB *)__readgsqword(0x60); + + // if(ProcessEnvBlock->BeingDebugged) + // SecurityCallback(); + + // TODO: Check for x64dbg window? + + + // Don't put too much stress on the CPU. + Sleep(150); - //PEB *ProcessEnvBlock = (PEB *)__readgsqword(0x60); - // - //if(ProcessEnvBlock->BeingDebugged) - // SecurityCallback(); + WRAP_IF_RELEASE(VM_EAGLE_BLACK_END); } void RuntimeSecurity::CheckForDrivers() { + WRAP_IF_RELEASE(VM_EAGLE_BLACK_START); + + // TODO: + + // Don't put too much stress on the CPU. + Sleep(150); + WRAP_IF_RELEASE(VM_EAGLE_BLACK_END); } - void RuntimeSecurity::CheckForThreads() + void RuntimeSecurity::CheckForTampering() { + WRAP_IF_RELEASE(VM_EAGLE_BLACK_START); + + int32_t CodeIntegrityChecksum = 0x2000; + + WRAP_IF_RELEASE( + CHECK_CODE_INTEGRITY(CodeIntegrityChecksum, 0x4000); + WRAP_IF_RELEASE(STR_ENCRYPT_START); + if(CodeIntegrityChecksum != 0x4000) + SecurityCallback(__FUNCSIG__); + WRAP_IF_RELEASE(STR_ENCRYPT_END); + ); + + WRAP_IF_RELEASE( + CHECK_PROTECTION(CodeIntegrityChecksum, 0x4000); + + WRAP_IF_RELEASE(STR_ENCRYPT_START); + if(CodeIntegrityChecksum != 0x4000) + SecurityCallback(__FUNCSIG__); + WRAP_IF_RELEASE(STR_ENCRYPT_END); + ); + + // Don't put too much stress on the CPU. + Sleep(CodeIntegrityChecksum); + + WRAP_IF_RELEASE(VM_EAGLE_BLACK_END); } +#pragma optimize("", on) + // The following functions are exposed publicly. /////////////////////////////////////////////////////////// @@ -261,20 +333,47 @@ namespace Security MEMORY_BASIC_INFORMATION RuntimeSecurity::QueryMemory(void *Address) { + static auto ZwQueryVirtualMemory = Syscalls->Find(FNV("ZwQueryVirtualMemory")); + MEMORY_BASIC_INFORMATION Result; - VirtualQuery(Address, &Result, sizeof MEMORY_BASIC_INFORMATION); + WRAP_IF_RELEASE(MUTATE_START); + { + NTSTATUS Status = ZwQueryVirtualMemory(GetCurrentProcess(), Address, 0, &Result, sizeof Result, nullptr); + + if(NT_ERROR(Status)) + { + WRAP_IF_RELEASE(STR_ENCRYPT_START); + + char ReasonParameter[64]; + sprintf_s(ReasonParameter, "ZQVM failed! NTSTATUS: %08x", Status); + + // yeet + SecurityCallback(ReasonParameter); + + WRAP_IF_RELEASE(STR_ENCRYPT_END); + } + } + WRAP_IF_RELEASE(MUTATE_END); return Result; } - __forceinline void RuntimeSecurity::SecurityCallback() + void RuntimeSecurity::SecurityCallback(const char *Reason) { // TODO: Implement something that bans the user or notifies // you if someone tampers with the loader. - // For convenience sake, I'll just put a small .WAV file of - // Bret Hart screaming in here for now :^) - PlaySoundA((char *)Resource::BretWAV, NULL, SND_MEMORY); - oExitProcess(0); + static bool TriggeredCallback = false; + + if(!TriggeredCallback) + { + WRAP_IF_RELEASE(STR_ENCRYPT_START); + char Buffer[2048]; + sprintf_s(Buffer, "Security callback was called. Reason parameter: \"%s\"\n", Reason); + + MessageBoxA(0, Buffer, "Information", MB_ICONINFORMATION | MB_OK); + TriggeredCallback = true; + WRAP_IF_RELEASE(STR_ENCRYPT_END); + } } } \ No newline at end of file -- cgit v1.2.3