diff options
Diffstat (limited to 'loader/server')
| -rw-r--r-- | loader/server/client.cpp | 252 | ||||
| -rw-r--r-- | loader/server/fnv.hpp | 64 | ||||
| -rw-r--r-- | loader/server/manual_map.cpp | 275 | ||||
| -rw-r--r-- | loader/server/manual_map.hpp | 79 | ||||
| -rw-r--r-- | loader/server/server.vcxproj | 3 | ||||
| -rw-r--r-- | loader/server/server.vcxproj.filters | 3 | ||||
| -rw-r--r-- | loader/server/server_windows.cpp | 1 |
7 files changed, 127 insertions, 550 deletions
diff --git a/loader/server/client.cpp b/loader/server/client.cpp index fd2ba65..b749f16 100644 --- a/loader/server/client.cpp +++ b/loader/server/client.cpp @@ -1,125 +1,127 @@ -#include "client.hpp" -#include "server.hpp" - -/* -std::vector< byte > server::c_client::receive_message( ) { - std::vector< uint8_t > ret; - char buffer[ BUFFER_SIZE ]{ }; - int received = 0; - - while( true ) { - received = recv( m_socket, buffer, BUFFER_SIZE, 0 ); - if( received < 0 ) - break; - - for( int i{ }; i < received; ++i ) - ret.push_back( buffer[ i ] ); - - if( received < BUFFER_SIZE ) - break; - } - - if( ret.size( ) ) { - decode_buffer( ret.data( ), ret.size( ) ); - ret.push_back( 0 ); - ret.erase( ret.begin( ) ); - } - - return ret; -} -*/ - -void server::c_client::kill() { - closesocket(m_socket); - printf("%s disconnected\n", get_ip()); -} - -std::string server::c_client::get_msg() { - std::string ret{ }; - char buffer[BUFFER_SIZE]{ }; - int received = 0; - - while(true) { - received = recv(m_socket, buffer, BUFFER_SIZE, 0); - if(received < 0) - break; - - for(int i{ }; i < received; ++i) - ret.push_back(buffer[i]); - - if(received < BUFFER_SIZE) - break; - } - - if(ret.size()) { - decode_buffer((uint8_t*)ret.data(), ret.size()); - // ret.push_back( 0 ); somehow broke things :/ - ret.erase(ret.begin()); - } - - return ret; -} - -bool server::c_client::send_msg(byte* msg, size_t length) { - auto buffer = std::make_unique< uint8_t[] >(length + 1); - uint8_t key = util::random_number(0, 255) & 0xff; - - buffer[0] = key; - memcpy(buffer.get() + 1, - msg, - length); - - for(size_t i = 1; i <= length; ++i) { - buffer[i] ^= key; - } - - int result = send(m_socket, (char*)buffer.get(), (int)length + 1, 0); - if(result == -1) { - #if WIN64 - printf("error sending message to %s: %d\n", - get_ip(), WSAGetLastError()); - #else - printf("error sending message to %s\n", - get_ip()); - #endif - return false; - } - - return true; -} - -bool server::c_client::send_msg(const char* msg) { - auto length = strlen(msg); - auto buffer = std::make_unique< uint8_t[] >(length + 1); - uint8_t key = util::random_number(0, 255) & 0xff; - - memset(buffer.get(), 0, length + 1); - - buffer[0] = key; - memcpy(buffer.get() + 1, - msg, - length); - - for(size_t i = 1; i <= length; ++i) { - buffer[i] ^= key; - } - - int result = send(m_socket, (char*)buffer.get(), (int)length + 1, 0); - if(result == -1) { - #if WIN64 - printf("error sending message to %s: %d\n", - get_ip(), WSAGetLastError()); - #else - printf("error sending message to %s\n", - get_ip()); - #endif - return false; - } - - return true; -} - -bool server::c_client::handle() { - - return true; -} +#include "client.hpp"
+#include "server.hpp"
+
+/*
+std::vector< byte > server::c_client::receive_message( ) {
+ std::vector< uint8_t > ret;
+ char buffer[ BUFFER_SIZE ]{ };
+ int received = 0;
+
+ while( true ) {
+ received = recv( m_socket, buffer, BUFFER_SIZE, 0 );
+ if( received < 0 )
+ break;
+
+ for( int i{ }; i < received; ++i )
+ ret.push_back( buffer[ i ] );
+
+ if( received < BUFFER_SIZE )
+ break;
+ }
+
+ if( ret.size( ) ) {
+ decode_buffer( ret.data( ), ret.size( ) );
+ ret.push_back( 0 );
+ ret.erase( ret.begin( ) );
+ }
+
+ return ret;
+}
+*/
+
+void server::c_client::kill() {
+ closesocket(m_socket);
+ printf("%s disconnected\n", get_ip());
+}
+
+std::string server::c_client::get_msg() {
+ std::string ret{ };
+ char buffer[BUFFER_SIZE]{ };
+ int received = 0;
+
+ while(true) {
+ received = recv(m_socket, buffer, BUFFER_SIZE, 0);
+ if(received < 0)
+ break;
+
+ for(int i{ }; i < received; ++i)
+ ret.push_back(buffer[i]);
+
+ if(received < BUFFER_SIZE)
+ break;
+ }
+
+ if(ret.size()) {
+ decode_buffer((uint8_t*)ret.data(), ret.size());
+ // ret.push_back( 0 ); somehow broke things :/
+ ret.erase(ret.begin());
+ }
+
+ return ret;
+}
+
+bool server::c_client::send_msg(byte* msg, size_t length) {
+ auto buffer = std::make_unique< uint8_t[] >(length + 1);
+ uint8_t key = util::random_number(0, 255) & 0xff;
+
+ buffer[0] = key;
+ memcpy(buffer.get() + 1,
+ msg,
+ length);
+
+ for(size_t i = 1; i <= length; ++i) {
+ buffer[i] ^= key;
+ }
+
+ int result = send(m_socket, (char*)buffer.get(), (int)length + 1, 0);
+ if(result == -1) {
+ #if WIN64
+ printf("error sending message to %s: %d\n",
+ get_ip(), WSAGetLastError());
+ #else
+ printf("error sending message to %s\n",
+ get_ip());
+ #endif
+ return false;
+ }
+
+ return true;
+}
+
+bool server::c_client::send_msg(const char* msg) {
+ auto length = strlen(msg);
+ auto buffer = std::make_unique< uint8_t[] >(length + 1);
+ uint8_t key = util::random_number(0, 255) & 0xff;
+
+ memset(buffer.get(), 0, length + 1);
+
+ buffer[0] = key;
+ memcpy(buffer.get() + 1,
+ msg,
+ length);
+
+ for(size_t i = 1; i <= length; ++i) {
+ buffer[i] ^= key;
+ }
+
+ int result = send(m_socket, (char*)buffer.get(), (int)length + 1, 0);
+ if(result == -1) {
+ #if WIN64
+ printf("error sending message to %s: %d\n",
+ get_ip(), WSAGetLastError());
+ #else
+ printf("error sending message to %s\n",
+ get_ip());
+ #endif
+ return false;
+ }
+
+ return true;
+}
+
+bool server::c_client::handle() {
+ if(get_msg() != "hello")
+ return false;
+
+ return true;
+}
diff --git a/loader/server/fnv.hpp b/loader/server/fnv.hpp deleted file mode 100644 index 08a478b..0000000 --- a/loader/server/fnv.hpp +++ /dev/null @@ -1,64 +0,0 @@ -#pragma once - -#pragma warning( disable : 4307 ) // '*': integral constant overflow -#pragma warning( disable : 4244 ) // possible loss of data - -#include <cstdint> -#include <string> - -using hash_t = unsigned int; - -// used for compile-time FNV-1a 32bit hashes. -#define fnv( str ) \ - [&]() { \ - constexpr hash_t out = hash::fnv1a( str ); \ - \ - return out; \ - }() - -// used for compile-time FNV-1a 32bit hashes when above macro cant be used for constexpr variables. -#define fnv_const( str ) Hash::fnv1a_32( str ) - -namespace hash // FNV-1a ( Fowler-Noll-Vo hash ). -{ - // FNV-1a constants. - enum : hash_t { - FNV1A_PRIME = 0x1000193, - FNV1A_BASIS = 0x811C9DC5 - }; - - // compile-time strlen. - __forceinline constexpr size_t ct_strlen( const char *str ) { - size_t out = 1; - - for( ; str[ out ] != '\0'; ++out ); - - return out; - } - - // hash data. - __forceinline constexpr hash_t fnv1a( const uint8_t *data, const size_t len ) { - hash_t out = FNV1A_BASIS; - - for( size_t i = 0; i < len; ++i ) - out = ( out ^ data[ i ] ) * FNV1A_PRIME; - - return out; - } - - // hash c-style string. - __forceinline constexpr hash_t fnv1a( const char *str ) { - hash_t out = FNV1A_BASIS; - size_t len = ct_strlen( str ); - - for( size_t i = 0; i < len; ++i ) - out = ( out ^ str[ i ] ) * FNV1A_PRIME; - - return out; - } - - // hash C++-style string ( runtime only ). - __forceinline hash_t fnv1a( const std::string &str ) { - return fnv1a( ( uint8_t* )str.c_str( ), str.length( ) ); - } -}
\ No newline at end of file diff --git a/loader/server/manual_map.cpp b/loader/server/manual_map.cpp deleted file mode 100644 index 9e7dad7..0000000 --- a/loader/server/manual_map.cpp +++ /dev/null @@ -1,275 +0,0 @@ -#include "manual_map.hpp"
-
-namespace remote_code {
- //i really hope you do this the turbochad way and sigscan your own shellcode for 69696969
- // u rite
- constexpr size_t shellcode_size = 83;
- constexpr uint8_t shellcode_code[] = {
- 0x55, // push ebp
- 0x8B, 0xEC, // mov ebp, esp
- 0x51, // push ecx
- 0x56, // push esi
- 0x8D, 0x45, 0xFC, // lea eax, dword ptr[ ebp-4 ]
- 0xC7, 0x45, 0xFC, 0x00, 0x00, 0x00, 0x00, // mov dword ptr[ ebp-4 ], 0
- // ; remove memory protection so we can write
- 0x50, // push eax
- 0x6A, 0x40, // push 40h
- 0x6A, 0x04, // push 4h
- 0x68, 0x69, 0x69, 0x69, 0x69, // push dword ptr[ vmt_endscene ]
- 0xBE, 0xEF, 0xBE, 0xAD, 0xDE, // mov esi, dword ptr[ virtual_protect ]
- 0xFF, 0xD6, // call esi
- 0x84, 0xC0, // test al, al
- 0x74, 0x2A, // jz clean_up
- 0x8D, 0x45, 0xFC, // lea eax, dword ptr[ ebp-4 ]
- // ; restore endscene ptr
- 0xC7, 0x05, 0x69, 0x69, 0x69, 0x69, 0x0F, 0xD0, 0x0F, 0xD0, // mov [ vmt_endscene ], [ vmt_endscene_o ]
- // ; restore memory protection
- 0x50, // push eax
- 0xFF, 0x75, 0xFC, // push dword ptr[ ebp-4 ]
- 0x6A, 0x04, // push 4h
- 0x68, 0x69, 0x69, 0x69, 0x69, // push dword ptr[ vmt_endscene ]
- 0xFF, 0xD6, // call esi
- // ; call cheat entrypoint
- 0x6A, 0x00, // push 0h
- 0x6A, 0x01, // push 1h
- 0x68, 0xDE, 0xC0, 0xAD, 0xDE, // push dword ptr[ cheat_header ]
- 0xB8, 0x0D, 0xF0, 0xAD, 0xDE, // mov eax, dword ptr[ cheat_entry ]
- 0xFF, 0xD0, // call eax
- // clean_up:
- 0x5E, // pop esi
- 0x8B, 0xE5, // mov esp, ebp
- 0x5D, // pop ebp
- 0xC3 // retn
- };
-
- // reminder client must pass these to the server at some point..
- struct shellcode_args_t {
- uint32_t m_virtual_protect; // 0xDEADBEEF
- uint32_t m_cheat_entrypoint; // 0xDEADF00D
- uint32_t m_cheat_header; // 0xDEADC0DE
- uint32_t m_endscene; // 0x69696969
- uint32_t m_endscene_o; // 0xD00FD00F
- };
-
- // turbo chad sig scanner (c) bowis
- int32_t find_byte_pattern(std::vector<uint8_t> &code, std::vector<uint8_t> pattern) {
- for (int32_t n = 0; n < code.size(); ++n) {
- // check if code matches
- if ((code.size() - n) >= pattern.size()) {
- if (!memcmp(&code[n], pattern.data(), pattern.size()))
- return n;
- }
- }
-
- return -1;
- }
-
- // turbo chad code patcher (c) bowis
- void patch_code(std::vector<uint8_t> &code, int32_t offset, uint32_t value) {
- std::memset(&code[offset], value, sizeof uint32_t);
- }
-
- // turbo chad shellcode maker (c) bowis
- std::vector<uint8_t> make_code(shellcode_args_t *arg) {
- std::vector<uint8_t> code;
- code.insert(code.begin(), shellcode_code, shellcode_code + shellcode_size);
-
- patch_code(code, find_byte_pattern(code, { 0xEF, 0xBE, 0xAD, 0xDE }), arg->m_virtual_protect);
- patch_code(code, find_byte_pattern(code, { 0x0D, 0xF0, 0xAD, 0xDE }), arg->m_cheat_entrypoint);
- patch_code(code, find_byte_pattern(code, { 0xDE, 0xC0, 0xAD, 0xDE }), arg->m_cheat_header);
- patch_code(code, find_byte_pattern(code, { 0x0F, 0xD0, 0x0F, 0xD0 }), arg->m_endscene_o);
-
- // there are three occurences of endscene
- // nave i hope ur happy
- for (int n = 0; n < 3; ++n)
- patch_code(code, find_byte_pattern(code, { 0x69, 0x69, 0x69, 0x69 }), arg->m_endscene);
-
- return code;
- }
-}
-
-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);
-
- auto pe_size = pe_file.tellg();
- m_file.resize(pe_size);
-
- pe_file.seekg(0, pe_file.beg);
-
- // AAAAAAAAAAAA BAD
- pe_file.read((char*)m_file.data(), pe_size);
-
- pe_file.close();
- }
-
- bool c_pe_file::valid() {
- IMAGE_DOS_HEADER *dos_header;
- IMAGE_NT_HEADERS *nt_headers;
-
- // check dos header
- dos_header = reinterpret_cast<decltype(dos_header)>(data());
-
- if (dos_header->e_magic != 0x45DA)
- return false;
-
- // check nt header
- nt_headers = reinterpret_cast<decltype(nt_headers)>(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
- return m_file.data();
- }
-
- size_t c_pe_file::size() const {
- return m_file.size();
- }
-
- // implementation of mapper
- c_mapper::c_mapper(c_pe_file &pe_file) {
- if (!pe_file.valid()) {
- printf("pe file error, check nt/dos headers\n");
- }
-
- m_pe = std::move(pe_file);
- }
-
- // returns size of module to allocate on client
- size_t c_mapper::initialise(std::vector<process_export_t> &exports) {
- if (exports.empty()) {
- printf("no process exports received, invalid input\n");
- return 0;
- }
-
- m_exports = std::move(exports);
-
- return m_pe.size();
- }
-
- bool c_mapper::process_imports(uint32_t /*remote_address*/) {
- IMAGE_DOS_HEADER *dos_header;
- IMAGE_NT_HEADERS *nt_headers;
-
- dos_header = reinterpret_cast<decltype(dos_header)>(m_pe.data());
- nt_headers = reinterpret_cast<decltype(nt_headers)>(m_pe.data() + dos_header->e_lfanew);
-
- IMAGE_THUNK_DATA* orig_first_thunk;
- IMAGE_THUNK_DATA* first_thunk;
- IMAGE_IMPORT_DESCRIPTOR* import_dir;
- IMAGE_IMPORT_BY_NAME* import_table;
-
- import_dir = reinterpret_cast<decltype(import_dir)>(m_pe.data()
- + nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
-
- while (import_dir->Characteristics) {
- orig_first_thunk = reinterpret_cast<decltype(orig_first_thunk)>(m_pe.data() + import_dir->OriginalFirstThunk);
- first_thunk = reinterpret_cast<decltype(first_thunk)>(m_pe.data() + import_dir->FirstThunk);
-
- // functions are imported by the fnv hash of func name
- while (orig_first_thunk->u1.AddressOfData) {
- // ordinals are homo
- if (orig_first_thunk->u1.Ordinal & IMAGE_ORDINAL_FLAG) {
- const uint16_t ordinal = orig_first_thunk->u1.Ordinal & 0xFFFF;
- for (auto &it : m_exports) {
- if (it.m_ordinal == ordinal)
- first_thunk->u1.Function = it.m_address;
- }
- }
- else {
- import_table = reinterpret_cast<decltype(import_table)>(m_pe.data() + orig_first_thunk->u1.AddressOfData);
-
- // look up export by hash
- const auto hash = hash::fnv1a(import_table->Name);
- for (auto &it : m_exports) {
- if (it.m_hash == hash)
- first_thunk->u1.Function = it.m_address;
- }
- }
-
- // advance
- orig_first_thunk++;
- first_thunk++;
- }
-
- // advance
- import_dir++;
- }
-
- return true;
- }
-
- bool c_mapper::process_reloc(uint32_t remote_address) {
- IMAGE_DOS_HEADER *dos_header;
- IMAGE_NT_HEADERS *nt_headers;
-
- dos_header = reinterpret_cast<decltype(dos_header)>(m_pe.data());
- nt_headers = reinterpret_cast<decltype(nt_headers)>(m_pe.data() + dos_header->e_lfanew);
-
- if (nt_headers->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED) {
- printf("no reloc necessary\n");
- return true;
- }
-
- IMAGE_BASE_RELOCATION *reloc;
-
- uintptr_t address = nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress;
- uintptr_t delta = remote_address - nt_headers->OptionalHeader.ImageBase;
-
- reloc = reinterpret_cast<decltype(reloc)>(m_pe.data() + address);
-
- while (reloc->VirtualAddress) {
- if (reloc->SizeOfBlock >= sizeof IMAGE_BASE_RELOCATION) {
- size_t count = (reloc->SizeOfBlock - sizeof IMAGE_BASE_RELOCATION) / sizeof uint16_t;
-
- uint16_t *list = (uint16_t *)reloc + 1;
-
- uintptr_t* ptr{ };
- for (size_t i{ }; i < count; ++i) {
- if (list[i]) {
- ptr = (uintptr_t*)((uintptr_t)(m_pe.data()) + (reloc->VirtualAddress + (list[i] & 0xfff)));
- *ptr += delta;
- }
- }
- }
-
- // advance
- reloc = (IMAGE_BASE_RELOCATION *)((uintptr_t)reloc + reloc->SizeOfBlock);
- }
-
- return true;
- }
-
- // handles reloc and fixing imports
- bool c_mapper::process_pe_file(uint32_t remote_address) {
- if (remote_address < 0x10000000 || remote_address > 0x7FF00000) {
- printf("invalid base address received, fail\n");
- return false;
- }
-
- if (!process_reloc(remote_address))
- return false;
-
- if (!process_imports(remote_address))
- return false;
-
- return true;
- }
-
- std::vector<memory_section_t> c_mapper::get_pe_sections() {
- return m_sections;
- }
-}
\ No newline at end of file diff --git a/loader/server/manual_map.hpp b/loader/server/manual_map.hpp deleted file mode 100644 index 34159da..0000000 --- a/loader/server/manual_map.hpp +++ /dev/null @@ -1,79 +0,0 @@ -#pragma once
-
-// TODO: get stripped down version of what we need and shove it in here
-#include <windows.h>
-
-#include <cstdint>
-#include <cstdio>
-#include <fstream>
-#include <iterator>
-#include <vector>
-
-#include "fnv.hpp"
-
-// 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 {
- // used as generic wrapper for pe, tells client how much to allocate, etc.
- class c_pe_file {
- protected:
- std::vector< uint8_t > m_file;
- public:
- c_pe_file() = default;
- c_pe_file(const char *file);
- bool valid();
- uint8_t *data();
- size_t size() const;
- };
-
- // used for fixing imports
- struct process_export_t {
- uint32_t m_hash;
- uint32_t m_ordinal;
- uint32_t m_address;
- };
-
- // used for writing memory in client
- struct memory_page_t {
- uint32_t m_address;
- uint32_t m_protection;
- };
-
- // container for sections
- using byte_array_t = std::vector<uint8_t>;
- using memory_section_t = std::pair<memory_page_t, byte_array_t>;
-
- // used as server wrapper for the manual mapper
- class c_mapper {
- protected:
- std::vector<process_export_t> m_exports;
- std::vector<memory_section_t> m_sections;
-
- c_pe_file m_pe;
-
- private:
- bool process_reloc(uint32_t remote_address);
- bool process_imports(uint32_t remote_address);
-
- public:
- c_mapper() = default;
- c_mapper(c_pe_file &pe_file);
-
- // returns size of module to allocate on client
- size_t initialise(std::vector<process_export_t> &exports);
-
- // handles reloc and fixing imports
- bool process_pe_file(uint32_t remote_address);
-
- // returns all sections
- std::vector<memory_section_t> get_pe_sections();
- };
-}
\ No newline at end of file diff --git a/loader/server/server.vcxproj b/loader/server/server.vcxproj index b911221..543a42f 100644 --- a/loader/server/server.vcxproj +++ b/loader/server/server.vcxproj @@ -36,15 +36,12 @@ </ItemGroup>
<ItemGroup>
<ClInclude Include="client.hpp" />
- <ClInclude Include="fnv.hpp" />
- <ClInclude Include="manual_map.hpp" />
<ClInclude Include="message.hpp" />
<ClInclude Include="server.hpp" />
<ClInclude Include="util.hpp" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="client.cpp" />
- <ClCompile Include="manual_map.cpp" />
<ClCompile Include="server.cpp" />
<ClCompile Include="server_windows.cpp" />
</ItemGroup>
diff --git a/loader/server/server.vcxproj.filters b/loader/server/server.vcxproj.filters index 4600793..5ef28fc 100644 --- a/loader/server/server.vcxproj.filters +++ b/loader/server/server.vcxproj.filters @@ -5,13 +5,10 @@ <ClInclude Include="server.hpp" />
<ClInclude Include="util.hpp" />
<ClInclude Include="client.hpp" />
- <ClInclude Include="manual_map.hpp" />
- <ClInclude Include="fnv.hpp" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="server.cpp" />
<ClCompile Include="server_windows.cpp" />
<ClCompile Include="client.cpp" />
- <ClCompile Include="manual_map.cpp" />
</ItemGroup>
</Project>
\ No newline at end of file diff --git a/loader/server/server_windows.cpp b/loader/server/server_windows.cpp index 4d22c0e..4521135 100644 --- a/loader/server/server_windows.cpp +++ b/loader/server/server_windows.cpp @@ -21,7 +21,6 @@ #include <thread>
#include "server.hpp"
-#include "manual_map.hpp"
server::c_server g_server;
|
