diff options
Diffstat (limited to 'csgo-loader/csgo-client/Security/RuntimeSecurity.cpp')
| -rw-r--r-- | csgo-loader/csgo-client/Security/RuntimeSecurity.cpp | 271 |
1 files changed, 259 insertions, 12 deletions
diff --git a/csgo-loader/csgo-client/Security/RuntimeSecurity.cpp b/csgo-loader/csgo-client/Security/RuntimeSecurity.cpp index 96e22bc..aceab25 100644 --- a/csgo-loader/csgo-client/Security/RuntimeSecurity.cpp +++ b/csgo-loader/csgo-client/Security/RuntimeSecurity.cpp @@ -1,31 +1,278 @@ #include <Security/RuntimeSecurity.hpp>
+#include <Security/BretHart.hpp>
+
#include <UserExperience/UserInterface.hpp>
+#include <Networking/TCPClient.hpp>
// Global accessor to security instance.
Security::RuntimeSecurityPtr Protection = std::make_unique<Security::RuntimeSecurity>();
+
namespace Security
{
- /*
- decltype(&MessageBoxA) oMessageBox;
- int __stdcall Hooked_MessageBox(HWND Window, char *Message, char *Caption, uint32_t Type)
+ // Hooked functions.
+ ///////////////////////////////////////////////////////////
+
+ decltype(&OpenProcess) oOpenProcess;
+ HANDLE __stdcall Hooked_OpenProcess(DWORD AccessLevel, bool Inherit, DWORD ProcessId)
+ {
+ // 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);
+
+ if(ReturnModule != LoaderModule)
{
- // TODO: Replace this with a Syscall so we cannot get hooked.
- MEMORY_BASIC_INFORMATION Query;
- if(!VirtualQuery(_ReturnAddress(), &Query, sizeof MEMORY_BASIC_INFORMATION))
- ExitProcess(0);
+ Protection->SecurityCallback();
- HMODULE ReturnModule = (HMODULE)Query.AllocationBase;
+ [&](decltype(&OpenProcess) A)
+ {
+ // Again, let's meme anyone who tries to reverse this.
+ uintptr_t NullPointer = *(uintptr_t *)0x00000000;
+ A(NullPointer, NullPointer, NullPointer);
+ }(OpenProcess);
+ }
+
+ // Call original function
+ return oOpenProcess(AccessLevel, Inherit, ProcessId);
+ }
- if (ReturnModule != GetModuleHandleA(0))
- ExitProcess(0);
+ 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);
- return oMessageBox(Window, Message, Caption, Type);
+ if(ReturnModule != LoaderModule)
+ {
+ Protection->SecurityCallback();
+
+ [&](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);
+ }
+
+ decltype(&recv) oWSARecv;
+ int __stdcall Hooked_WSARecv(SOCKET Socket, char *Buffer, int Length, int Flags)
+ {
+ // 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);
+
+ if(ReturnModule != LoaderModule)
+ // Let's meme anyone who tries to reverse this.
+ return []() { Protection->SecurityCallback(); return -1; }();
+
+ // Call original function
+ return oWSARecv(Socket, Buffer, Length, Flags);
+ }
+
+ decltype(&send) oWSASend;
+ int __stdcall Hooked_WSASend(SOCKET Socket, char *Buffer, int Length, int Flags)
+ {
+ // 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);
+
+ if(ReturnModule != LoaderModule)
+ // Let's meme anyone who tries to reverse this.
+ return []() { Protection->SecurityCallback(); return -1; }();
+
+ // Call original function
+ return oWSASend(Socket, Buffer, Length, Flags);
+ }
+
+ // The following functions are only called internally.
+ ///////////////////////////////////////////////////////////
+
+ // Sick macros, retard.
+#define CreateMinHook() MH_STATUS Status; Status = MH_Initialize();
+#define CheckStatus() if(Status != MH_OK) { return false; }
+#define SafeCallTo(Function) Status = Function; CheckStatus();
+
+ bool RuntimeSecurity::ApplyApiHooks()
+ {
+ // Make sure that MinHook is initialized properly.
+ CreateMinHook();
+ CheckStatus();
+
+ // 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));
+
+ SafeCallTo(MH_CreateHook(&recv, Hooked_WSARecv, (void **)&oWSARecv));
+ SafeCallTo(MH_EnableHook(&recv));
+
+ SafeCallTo(MH_CreateHook(&send, Hooked_WSASend, (void **)&oWSASend));
+ SafeCallTo(MH_EnableHook(&send));
+
+ return true;
+ }
+
+ void RuntimeSecurity::PatchDebugFunctions()
+ {
+ WRAP_IF_RELEASE(VM_DOLPHIN_WHITE_START);
+ WRAP_IF_RELEASE(STR_ENCRYPT_START);
+
+ HMODULE Module = GetModuleHandleA("ntdll.dll");
+
+ if(!Module)
+ ERROR_ASSERT("[000F:00001A00] Failed to initialize. Please contact an administrator.");
+
+ // Grab exports from ntdll.dll
+ uintptr_t Export_DbgUiRemoteBreakin = (uintptr_t)GetProcAddress(Module, "DbgUiRemoteBreakin");
+ uintptr_t Export_DbgBreakPoint = (uintptr_t)GetProcAddress(Module, "DbgBreakPoint");
+
+ // Most plugins for OllyDBG / IDA only fix DbgUiRemoteBreakin/DbgBreakPoint,
+ // however, NtContinue is never touched although it is used.
+ // 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,
+ Export_DbgBreakPoint,
+ Export_NtContinue
+ };
+
+ for(auto &It : Exports)
+ {
+ DWORD OldProtection;
+ if(!VirtualProtect((void *)It, sizeof Shellcode, 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);
+ }
+
+ WRAP_IF_RELEASE(STR_ENCRYPT_END);
+ WRAP_IF_RELEASE(VM_DOLPHIN_WHITE_END);
+ }
+
+ void RuntimeSecurity::DispatchSecurityThreads()
+ {
+ 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();
+
+ WRAP_IF_RELEASE(MUTATE_END);
+ }
+
+ // The following functions are only called internally.
+ // The reason these are seperate is in order to maintain
+ // code readability.
+ ///////////////////////////////////////////////////////////
+
+ void RuntimeSecurity::CheckForVirtualMachine()
+ {
+
+ }
+
+ void RuntimeSecurity::CheckForDebugger()
+ {
+ // 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();
+ }
+
+ void RuntimeSecurity::CheckForDrivers()
+ {
+
+ }
+
+ void RuntimeSecurity::CheckForThreads()
+ {
+
+ }
+
+ // The following functions are exposed publicly.
+ ///////////////////////////////////////////////////////////
bool RuntimeSecurity::Start()
{
+ // If hooking API functions fails, exit the program.
+ if(!ApplyApiHooks())
+ return false;
+
+ // Dispatch threads before patching NtContinue & co.
+ DispatchSecurityThreads();
+
+ // Patch DbgUiRemoteBreakin, DbgBreakPoint, NtContinue
+ PatchDebugFunctions();
+
return true;
}
+
+ HardwareIdentifier RuntimeSecurity::GetHardwareId()
+ {
+ return HardwareIdentifier{};
+ }
+
+ MEMORY_BASIC_INFORMATION RuntimeSecurity::QueryMemory(void *Address)
+ {
+ MEMORY_BASIC_INFORMATION Result;
+
+ VirtualQuery(Address, &Result, sizeof MEMORY_BASIC_INFORMATION);
+
+ return Result;
+ }
+
+ __forceinline void RuntimeSecurity::SecurityCallback()
+ {
+ // 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);
+ }
}
\ No newline at end of file |
