From 8b5af9cad6589816e121fdbfa4fc81fa71cf38d5 Mon Sep 17 00:00:00 2001 From: boris Date: Sun, 2 Dec 2018 10:03:32 +1300 Subject: bor n inthe usa --- loader/client/syscall.cpp | 211 +++++++++++++++++------------------ loader/server/manual_map.cpp | 55 +++++++++ loader/server/manual_map.hpp | 118 ++++++++++++++++++++ loader/server/server.vcxproj | 2 + loader/server/server.vcxproj.filters | 2 + loader/server/server_windows.cpp | 8 ++ loader/server/test.bin | 1 + 7 files changed, 290 insertions(+), 107 deletions(-) create mode 100644 loader/server/manual_map.cpp create mode 100644 loader/server/manual_map.hpp create mode 100644 loader/server/test.bin diff --git a/loader/client/syscall.cpp b/loader/client/syscall.cpp index 880eabf..c677a81 100644 --- a/loader/client/syscall.cpp +++ b/loader/client/syscall.cpp @@ -4,117 +4,114 @@ // fuck balloon head namespace syscall { - file_t c_syscall_mgr::load_ntdll() { - // load ntdll from disk - char path[MAX_PATH]; - GetSystemDirectoryA(path, MAX_PATH); - - std::string ntdll_path(path); - ntdll_path += xors("\\ntdll.dll"); - - FILE* file; - if (fopen_s(&file, ntdll_path.c_str(), "rb") != 0) - return file_t{ nullptr, 0 }; - - fseek(file, 0, SEEK_END); - size_t ntdll_size = ftell(file); - rewind(file); - - uint8_t* ntdll = new uint8_t[ntdll_size]; - fread(ntdll, ntdll_size, 1, file); - fclose(file); - + file_t c_syscall_mgr::load_ntdll() { + // load ntdll from disk + char path[MAX_PATH]; + GetSystemDirectoryA(path, MAX_PATH); + + std::string ntdll_path(path); + ntdll_path += xors("\\ntdll.dll"); + + FILE* file; + if (fopen_s(&file, ntdll_path.c_str(), "rb") != 0) + return file_t{ nullptr, 0 }; + + fseek(file, 0, SEEK_END); + size_t ntdll_size = ftell(file); + rewind(file); + + uint8_t* ntdll = new uint8_t[ntdll_size]; + fread(ntdll, ntdll_size, 1, file); + fclose(file); + return file_t{ ntdll, ntdll_size }; } bool c_syscall_mgr::start() { - // thing - const auto ntdll_file = load_ntdll(); - - // other thing - const auto ntdll = ntdll_file.first; - const auto ntdll_size = ntdll_file.second; - - if (!ntdll) - return false; - - // read pe - IMAGE_DOS_HEADER* dos_header = (IMAGE_DOS_HEADER*)(&ntdll[0]); - IMAGE_NT_HEADERS* nt_header = (IMAGE_NT_HEADERS*)(&ntdll[dos_header->e_lfanew]); - - if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) { - delete[] ntdll; - return false; - } - - if (nt_header->Signature != IMAGE_NT_SIGNATURE) { - delete[] ntdll; - return false; - } - - // find section - IMAGE_SECTION_HEADER* section_header = (IMAGE_SECTION_HEADER*)(&ntdll[dos_header->e_lfanew + sizeof(IMAGE_NT_HEADERS)]); - uintptr_t export_rva = nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; - - uint32_t delta = 0; - for (size_t i = 0; i < nt_header->FileHeader.NumberOfSections; i++) { - if (export_rva > section_header[i].VirtualAddress) - delta = section_header[i].VirtualAddress - section_header[i].PointerToRawData; - } - - // aaa exports - IMAGE_EXPORT_DIRECTORY* export_directory = (IMAGE_EXPORT_DIRECTORY*)(&ntdll[export_rva - delta]); - - int number_of_functions = export_directory->NumberOfFunctions; - uintptr_t names = export_directory->AddressOfNames - delta; - uintptr_t funcs = export_directory->AddressOfFunctions - delta; - uintptr_t ords = export_directory->AddressOfNameOrdinals - delta; - int i = 0; - for (; i < number_of_functions; i++) { - uint32_t name_rva = *(uint32_t*)(&ntdll[names + i * sizeof(uint32_t)]) - delta; - char* name = (char*)(&ntdll[name_rva]); - - uint16_t ordinal = *(uint16_t*)(&ntdll[ords + i * sizeof(uint16_t)]); - uint32_t func_rva = *(uint32_t*)(&ntdll[funcs + ordinal * sizeof(uint32_t)]); - - uint32_t func_delta = 0; - for (int j = 0; j < nt_header->FileHeader.NumberOfSections; j++) { - if (func_rva > section_header[j].VirtualAddress) - func_delta = section_header[j].VirtualAddress - section_header[j].PointerToRawData; - } - - func_rva -= func_delta; - - // hAHAHAHAHAHAHAHAHHAHA - // okay this isn't code genius - //if (m_syscalls.size() >= 865) - // break; - - // okay now this is epic - const auto offset = (uintptr_t)ntdll + func_rva; - const auto ntdll_bound = (uintptr_t)ntdll + ntdll_size; - - if (offset >= ntdll_bound) - break; - - uint32_t code = *(uint32_t*)(&ntdll[func_rva + 0]); - uint32_t index = *(uint32_t*)(&ntdll[func_rva + 4]); - - // syscall - if (code == 0xB8D18B4C) { - m_syscalls[hash::fnv1a(name)].set_index(index); - printf("n:%s h:%08x i:%08x\n", name, hash::fnv1a(name), index); - } - } - - delete[] ntdll; - - // check if we successfully got the syscalls - hash_t hash = fnv("ZwWriteVirtualMemory"); - - if (m_syscalls.find(hash) != m_syscalls.end()) - return m_syscalls[hash].validate(); - + // thing + const auto ntdll_file = load_ntdll(); + + // other thing + const auto ntdll = ntdll_file.first; + const auto ntdll_size = ntdll_file.second; + + if (!ntdll) + return false; + + // read pe + IMAGE_DOS_HEADER* dos_header = (IMAGE_DOS_HEADER*)(&ntdll[0]); + IMAGE_NT_HEADERS* nt_header = (IMAGE_NT_HEADERS*)(&ntdll[dos_header->e_lfanew]); + + if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) { + delete[] ntdll; + return false; + } + + if (nt_header->Signature != IMAGE_NT_SIGNATURE) { + delete[] ntdll; + return false; + } + + // find section + IMAGE_SECTION_HEADER* section_header = (IMAGE_SECTION_HEADER*)(&ntdll[dos_header->e_lfanew + sizeof(IMAGE_NT_HEADERS)]); + uintptr_t export_rva = nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; + + uint32_t delta = 0; + for (size_t i = 0; i < nt_header->FileHeader.NumberOfSections; i++) { + if (export_rva > section_header[i].VirtualAddress) + delta = section_header[i].VirtualAddress - section_header[i].PointerToRawData; + } + + // aaa exports + IMAGE_EXPORT_DIRECTORY* export_directory = (IMAGE_EXPORT_DIRECTORY*)(&ntdll[export_rva - delta]); + + int number_of_functions = export_directory->NumberOfFunctions; + uintptr_t names = export_directory->AddressOfNames - delta; + uintptr_t funcs = export_directory->AddressOfFunctions - delta; + uintptr_t ords = export_directory->AddressOfNameOrdinals - delta; + int i = 0; + for (; i < number_of_functions; i++) { + uint32_t name_rva = *(uint32_t*)(&ntdll[names + i * sizeof(uint32_t)]) - delta; + char* name = (char*)(&ntdll[name_rva]); + + uint16_t ordinal = *(uint16_t*)(&ntdll[ords + i * sizeof(uint16_t)]); + uint32_t func_rva = *(uint32_t*)(&ntdll[funcs + ordinal * sizeof(uint32_t)]); + + uint32_t func_delta = 0; + for (int j = 0; j < nt_header->FileHeader.NumberOfSections; j++) { + if (func_rva > section_header[j].VirtualAddress) + func_delta = section_header[j].VirtualAddress - section_header[j].PointerToRawData; + } + + func_rva -= func_delta; + + // okay now this is epic + // this crashed on 8.1 but not on 10? + // weird.. + const auto offset = (uintptr_t)ntdll + func_rva; + const auto ntdll_bound = (uintptr_t)ntdll + ntdll_size; + + if (offset >= ntdll_bound) + break; + + uint32_t code = *(uint32_t*)(&ntdll[func_rva + 0]); + uint32_t index = *(uint32_t*)(&ntdll[func_rva + 4]); + + // syscall + if (code == 0xB8D18B4C) { + m_syscalls[hash::fnv1a(name)].set_index(index); + printf("n:%s h:%08x i:%08x\n", name, hash::fnv1a(name), index); + } + } + + delete[] ntdll; + + // check if we successfully got the syscalls + hash_t hash = fnv("ZwWriteVirtualMemory"); + + if (m_syscalls.find(hash) != m_syscalls.end()) + return m_syscalls[hash].validate(); + return false; } } \ No newline at end of file diff --git a/loader/server/manual_map.cpp b/loader/server/manual_map.cpp new file mode 100644 index 0000000..d2de29c --- /dev/null +++ b/loader/server/manual_map.cpp @@ -0,0 +1,55 @@ +#include "manual_map.hpp" + +namespace inject { + // pe file implementation + c_pe_file::c_pe_file(const char *file) { + std::ifstream pe_file(file, std::ifstream::in | std::ifstream::binary); + + if (!pe_file.is_open()) { + printf("file (%s) does not exist\n", file); + return; + } + + pe_file.seekg(0, pe_file.end); + + uint32_t pe_size = pe_file.tellg(); + m_file.resize(pe_size); + + pe_file.seekg(0, pe_file.beg); + + // HOMOSEXUAL CAST FUCKERY PLEASE SKIP THIS LINE + // AAAAAAAAAAAA BAD + pe_file.read((char*)&m_file[0], pe_size); + + pe_file.close(); + } + + bool c_pe_file::valid() { + nt::dos_header_t *dos_header; + nt::nt_headers_t *nt_headers; + + // check dos header + dos_header = reinterpret_cast((uint32_t)data()); + + if (dos_header->e_magic != 0x45DA) + return false; + + // check nt header + nt_headers = reinterpret_cast((uint32_t)data() + dos_header->e_lfanew); + + if (nt_headers->signature != 0x50450000) + return false; + + return true; + } + + uint8_t *c_pe_file::data() { + // go to the beginning of the file + // yes i know i could've just done 'new uint8_t[pe_size]' but fuck u. + return reinterpret_cast(&m_file[0]); + } + + size_t c_pe_file::size() const { + return m_file.size(); + } +} \ No newline at end of file diff --git a/loader/server/manual_map.hpp b/loader/server/manual_map.hpp new file mode 100644 index 0000000..4de64ee --- /dev/null +++ b/loader/server/manual_map.hpp @@ -0,0 +1,118 @@ +#pragma once + +#include +#include +#include +#include +#include + +// if we compile on linux, we won't have access to windows.h (?) +// i'll put there here just so we can access them anyway +namespace nt { + struct data_directory_t { + uint32_t virtual_address; + uint32_t size; + }; + + struct optional_header_t { + uint16_t magic; + uint8_t major_link_version; + uint8_t minor_link_version; + uint32_t size_of_code; + uint32_t size_of_init_data; + uint32_t size_of_uninit_data; + uint32_t entry_point; + uint32_t base_of_code; + uint32_t base_of_data; + uint32_t image_base; + uint32_t section_align; + uint32_t file_align; + uint16_t major_os_version; + uint16_t minor_os_version; + uint16_t major_img_version; + uint16_t minor_img_version; + uint16_t major_sub_version; + uint16_t minor_sub_version; + uint32_t win32_version; + uint32_t size_image; + uint32_t size_headers; + uint32_t checksum; + uint16_t subsystem; + uint16_t dll_characteristics; + uint32_t size_of_stack_reserve; + uint32_t size_of_stack_commit; + uint32_t size_of_heap_reserve; + uint32_t size_of_heap_commit; + uint32_t ldr_flags; + uint32_t number_of_rva_and_sizes; + data_directory_t data_directory[16]; + }; + + struct file_header_t { + uint16_t machine; + uint16_t number_of_sections; + uint32_t time_stamp; + uint32_t ptr_symbol_table; + uint32_t sym_number; + uint16_t opt_header_size; + uint16_t characteristics; + }; + + struct dos_header_t { + uint16_t e_magic; + uint16_t e_cblp; + uint16_t e_cp; + uint16_t e_crlc; + uint16_t e_cparhdr; + uint16_t e_minalloc; + uint16_t e_maxalloc; + uint16_t e_ss; + uint16_t e_sp; + uint16_t e_csum; + uint16_t e_ip; + uint16_t e_cs; + uint16_t e_lfarlc; + uint16_t e_ovno; + uint16_t e_res[4]; + uint16_t e_oemid; + uint16_t e_oeminfo; + uint16_t e_res2[10]; + int32_t e_lfanew; + }; + + struct nt_headers_t { + uint32_t signature; + file_header_t file_header; + optional_header_t opt_header; + }; +} + +// here's the game plan: +// - client runs, waits for game to start and whatnot +// - we wait for serverbrowser.dll to load (if source game, we should have an option in the game struct to wait for module) +// - client walks peb of process, dumps exports and packs them into { fnv, addy }, sends to server +// - server sends module size, client allocates and replies back with module address +// - server resolves imports through { fnv, addy } that were networked to us +// - server fixes reloc +// - we send back addy, then section data to client +// - server packs shellcode with data from client, sends to client +// - client runs shellcode, we're injected +namespace inject { + class c_pe_file { + protected: + std::vector< uint8_t > m_file; + public: + c_pe_file(const char *file); + bool valid(); + uint8_t *data(); + size_t size() const; + + void test() { + for (auto &c : m_file) { + printf("%c", c); + } + printf("\n"); + } + }; + +} \ No newline at end of file diff --git a/loader/server/server.vcxproj b/loader/server/server.vcxproj index 543a42f..44c33ed 100644 --- a/loader/server/server.vcxproj +++ b/loader/server/server.vcxproj @@ -36,12 +36,14 @@ + + diff --git a/loader/server/server.vcxproj.filters b/loader/server/server.vcxproj.filters index 5ef28fc..65f2ba8 100644 --- a/loader/server/server.vcxproj.filters +++ b/loader/server/server.vcxproj.filters @@ -5,10 +5,12 @@ + + \ No newline at end of file diff --git a/loader/server/server_windows.cpp b/loader/server/server_windows.cpp index c1c9036..8e944d1 100644 --- a/loader/server/server_windows.cpp +++ b/loader/server/server_windows.cpp @@ -19,7 +19,9 @@ #include #include #include + #include "server.hpp" +#include "manual_map.hpp" server::c_server g_server; @@ -36,6 +38,8 @@ server::c_server g_server; //i really hope you do this the turbochad way and sigscan your own shellcode for 69696969 +// u rite + uint8_t shellcode[] = { 0x55, // push ebp 0x8B, 0xEC, // mov ebp, esp @@ -75,6 +79,10 @@ uint8_t shellcode[] = { }; int main( ) { + inject::c_pe_file file("test.bin"); + + file.test(); + int result = g_server.init( ); if( !result ) { while( true ) { diff --git a/loader/server/test.bin b/loader/server/test.bin new file mode 100644 index 0000000..9956d07 --- /dev/null +++ b/loader/server/test.bin @@ -0,0 +1 @@ +hello this is a file test \ No newline at end of file -- cgit v1.2.3