From 77b52da44b263df4884be2f35f885d8edccbb6fa Mon Sep 17 00:00:00 2001 From: boris Date: Wed, 19 Dec 2018 00:13:24 +1300 Subject: added new loader project :) merry christmas --- .../csgo-client/Security/SyscallManager.cpp | 149 +++++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 csgo-loader/csgo-client/Security/SyscallManager.cpp (limited to 'csgo-loader/csgo-client/Security/SyscallManager.cpp') diff --git a/csgo-loader/csgo-client/Security/SyscallManager.cpp b/csgo-loader/csgo-client/Security/SyscallManager.cpp new file mode 100644 index 0000000..55d68a3 --- /dev/null +++ b/csgo-loader/csgo-client/Security/SyscallManager.cpp @@ -0,0 +1,149 @@ +#include +#include + +// Global accessor for SyscallManager. +Wrapper::SyscallManagerPtr Syscalls = std::make_unique(); + +namespace Wrapper { + void SyscallStub::SetIndex(uint32_t Index) { + unsigned long OldProtection{}; + + // Make the code executable and set the index. + if(VirtualProtect(m_Shellcode, sizeof m_Shellcode, PAGE_EXECUTE_READWRITE, &OldProtection)) { + *(uint32_t *)(&m_Shellcode[4]) = Index; + } + } + + ByteArray SyscallManager::GetNtdllFromDisk() { + char SystemPath[MAX_PATH]; + GetSystemDirectoryA(SystemPath, MAX_PATH); + + // Append 'ntdll.dll' to path. + strcat_s(SystemPath, "\\ntdll.dll"); + + // Open handle to 'ntdll.dll'. + std::ifstream FileHandle(SystemPath, std::ios::in | std::ios::binary); + FileHandle.unsetf(std::ios::skipws); + + if(!FileHandle.is_open()) + return ByteArray{}; + + // Read bytes to ByteArray. + ByteArray Bytes; + Bytes.insert( + Bytes.begin(), + std::istream_iterator(FileHandle), + std::istream_iterator() + ); + + FileHandle.close(); + + return Bytes; + } + + // Stolen :-) + uint64_t SyscallManager::GetRawOffsetByRva(IMAGE_SECTION_HEADER *SectionHeader, uint64_t Sections, uint64_t FileSize, uint64_t Rva) { + IMAGE_SECTION_HEADER *Header = GetSectionByRva(SectionHeader, Sections, Rva); + + if(!Header) + return 0; + + uint64_t Delta = Rva - Header->VirtualAddress; + uint64_t Offset = Header->PointerToRawData + Delta; + + // Sanity check, otherwise this would crash on versions below Windows 10... + // for whatever reason.. + if(Offset >= FileSize) + return 0; + + return Offset; + } + + IMAGE_SECTION_HEADER *SyscallManager::GetSectionByRva(IMAGE_SECTION_HEADER *SectionHeader, uint64_t Sections, uint64_t Rva) { + IMAGE_SECTION_HEADER *Header = SectionHeader; + + for(size_t i{}; i < Sections; ++i, ++Header) { + uint64_t VirtualAddress = Header->VirtualAddress; + uint64_t AddressBounds = VirtualAddress + Header->SizeOfRawData; + + if(Rva >= VirtualAddress && Rva < AddressBounds) + return Header; + } + + return nullptr; + } + + // Sick macros, retard. + #define GetRvaPointer(Rva) (Buffer + GetRawOffsetByRva(SectionHeader, SectionCount, FileSize, Rva)) + + bool SyscallManager::Start() { + // Read contents of NTDLL. + ByteArray Ntdll = GetNtdllFromDisk(); + + if(Ntdll.empty()) + return false; + + uint8_t *Buffer = Ntdll.data(); + uint64_t FileSize = Ntdll.size(); + + // Ghetto check to see if the file is a valid PE. + if(*(uint16_t*)Buffer != IMAGE_DOS_SIGNATURE) + return false; + + // Read PE headers. + IMAGE_DOS_HEADER *DosHeader = (IMAGE_DOS_HEADER *)Buffer; + IMAGE_NT_HEADERS *NtHeaders = (IMAGE_NT_HEADERS *)(Buffer + DosHeader->e_lfanew); + + uint64_t SectionCount = NtHeaders->FileHeader.NumberOfSections; + + // Read the first section header. + IMAGE_SECTION_HEADER *SectionHeader = (IMAGE_SECTION_HEADER *)(Buffer + DosHeader->e_lfanew + sizeof IMAGE_NT_HEADERS); + + if(!SectionHeader) + return false; + + uint64_t ExportRva = NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; + uint64_t ExportSize = NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size; + uint64_t ExportRaw = GetRawOffsetByRva(SectionHeader, SectionCount, FileSize, ExportRva); + + if(!ExportRva || !ExportSize || !ExportRaw) + return false; + + // Now let's parse the export directory. + IMAGE_EXPORT_DIRECTORY *ExportDirectory = (IMAGE_EXPORT_DIRECTORY *)(Buffer + ExportRaw); + + uint32_t *Functions = (uint32_t *)GetRvaPointer(ExportDirectory->AddressOfFunctions); + uint16_t *Ordinals = (uint16_t *)GetRvaPointer(ExportDirectory->AddressOfNameOrdinals); + uint32_t *Names = (uint32_t *)GetRvaPointer(ExportDirectory->AddressOfNames); + + if(!Functions || !Ordinals || !Names) + return false; + + // Loop each exported symbol. + for(uint32_t n{}; n < ExportDirectory->NumberOfNames; ++n) { + uint32_t NameRva = Names[n]; + uint32_t FunctionRva = Functions[Ordinals[n]]; + + uint64_t NameRawOffset = GetRawOffsetByRva(SectionHeader, SectionCount, FileSize, NameRva); + uint64_t FunctionRawOffset = GetRawOffsetByRva(SectionHeader, SectionCount, FileSize, FunctionRva); + + // We've found a syscall. + uint8_t *Opcodes = (uint8_t *)(Buffer + FunctionRawOffset); + + if(!memcmp(Opcodes, "\x4C\x8B\xD1\xB8", 4)) { + uint32_t SyscallIndex = *(uint32_t *)(Buffer + FunctionRawOffset + 4); + + char *SyscallName = (char *)(Buffer + NameRawOffset); + uint64_t SyscallNameHash = fnv::hash_runtime(SyscallName); + + // Emplace the syscall in the syscall map. + m_Syscalls[SyscallNameHash].SetIndex(SyscallIndex); + } + } + + if(m_Syscalls.empty()) + return false; + + return true; + } +} \ No newline at end of file -- cgit v1.2.3