From 4db29589a61f2e7cb663c5734f911c02206c7997 Mon Sep 17 00:00:00 2001 From: boris Date: Wed, 9 Jan 2019 20:51:16 +1300 Subject: whole buncha shit FIXME: loader currently corrupts heap on injection because i am retarded --- .../csgo-module/Security/SyscallManager.cpp | 159 +++++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 csgo-loader/csgo-module/Security/SyscallManager.cpp (limited to 'csgo-loader/csgo-module/Security/SyscallManager.cpp') diff --git a/csgo-loader/csgo-module/Security/SyscallManager.cpp b/csgo-loader/csgo-module/Security/SyscallManager.cpp new file mode 100644 index 0000000..0338d88 --- /dev/null +++ b/csgo-loader/csgo-module/Security/SyscallManager.cpp @@ -0,0 +1,159 @@ +#include + +// Global accessor for SyscallManager. +Wrapper::SyscallManagerPtr Syscalls = std::make_unique(); + +namespace Wrapper +{ + void SyscallStub::SetIndex(uint32_t Index) + { + DWORD 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 :-) + uintptr_t SyscallManager::GetRawOffsetByRva(IMAGE_SECTION_HEADER *SectionHeader, uintptr_t Sections, uintptr_t FileSize, uintptr_t Rva) + { + IMAGE_SECTION_HEADER *Header = GetSectionByRva(SectionHeader, Sections, Rva); + + if(!Header) + return 0; + + uintptr_t Delta = Rva - Header->VirtualAddress; + uintptr_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, uintptr_t Sections, uintptr_t Rva) + { + IMAGE_SECTION_HEADER *Header = SectionHeader; + + for(size_t i{}; i < Sections; ++i, ++Header) + { + uintptr_t VirtualAddress = Header->VirtualAddress; + uintptr_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(); + size_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; + + uintptr_t ExportRva = NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; + uintptr_t ExportSize = NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size; + uintptr_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; + + + for(uint32_t n{}; n < ExportDirectory->NumberOfNames; ++n) + { + uint32_t NameRva = Names[n]; + uint32_t FunctionRva = Functions[Ordinals[n]]; + + uintptr_t NameRawOffset = GetRawOffsetByRva(SectionHeader, SectionCount, FileSize, NameRva); + uintptr_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); + + // Get hash of syscall name. + 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