diff options
| author | auth12 <[email protected]> | 2020-07-27 09:46:17 -0700 |
|---|---|---|
| committer | auth12 <[email protected]> | 2020-07-27 09:46:17 -0700 |
| commit | a2e89fde1acc5b189c55e0b8b38146194e455cd0 (patch) | |
| tree | 1f130027975733e0704a583aebb1a1832a22ec11 /client/src | |
| parent | Compile fix. (diff) | |
| download | loader-a2e89fde1acc5b189c55e0b8b38146194e455cd0.tar.xz loader-a2e89fde1acc5b189c55e0b8b38146194e455cd0.zip | |
Removed spdlog, using fmt wrapper instead.
More process class changes, support for 32/64bit processes.
Injection process improvements.
Other small changes.
Diffstat (limited to 'client/src')
| -rw-r--r-- | client/src/client/client.cpp | 12 | ||||
| -rw-r--r-- | client/src/client/client.h | 50 | ||||
| -rw-r--r-- | client/src/client/enc.cpp | 35 | ||||
| -rw-r--r-- | client/src/client/enc.h | 28 | ||||
| -rw-r--r-- | client/src/client/packet.h | 4 | ||||
| -rw-r--r-- | client/src/hwid/hwid.h | 10 | ||||
| -rw-r--r-- | client/src/include.h | 4 | ||||
| -rw-r--r-- | client/src/injection/mapper.cpp | 90 | ||||
| -rw-r--r-- | client/src/injection/mapper.h | 2 | ||||
| -rw-r--r-- | client/src/injection/pe.h | 44 | ||||
| -rw-r--r-- | client/src/injection/process.cpp | 422 | ||||
| -rw-r--r-- | client/src/injection/process.h | 257 | ||||
| -rw-r--r-- | client/src/main.cpp | 80 | ||||
| -rw-r--r-- | client/src/util/io.cpp | 12 | ||||
| -rw-r--r-- | client/src/util/io.h | 27 | ||||
| -rw-r--r-- | client/src/util/native.h | 94 | ||||
| -rw-r--r-- | client/src/util/syscalls.cpp | 23 | ||||
| -rw-r--r-- | client/src/util/syscalls.h | 5 | ||||
| -rw-r--r-- | client/src/util/util.cpp | 33 | ||||
| -rw-r--r-- | client/src/util/util.h | 17 |
20 files changed, 658 insertions, 591 deletions
diff --git a/client/src/client/client.cpp b/client/src/client/client.cpp index 3fa55fc..d1b09e0 100644 --- a/client/src/client/client.cpp +++ b/client/src/client/client.cpp @@ -10,7 +10,7 @@ void tcp::client::start(const std::string_view server_ip, const uint16_t port) { int ret = wolfSSL_CTX_load_verify_buffer(m_ssl_ctx, reinterpret_cast<const unsigned char*>(root_cert.data()), root_cert.size(), SSL_FILETYPE_PEM); if (ret != 1) { - io::logger->error("failed to load ca."); + io::log_error("failed to load ca."); return; } wolfSSL_CTX_set_verify(m_ssl_ctx, SSL_VERIFY_PEER, 0); @@ -18,13 +18,13 @@ void tcp::client::start(const std::string_view server_ip, const uint16_t port) { WSADATA data; ret = WSAStartup(MAKEWORD(2, 2), &data); if (ret != 0) { - io::logger->error("failed to initialize WSA."); + io::log_error("failed to initialize WSA."); return; } m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (m_socket == -1) { - io::logger->error("failed to create socket."); + io::log_error("failed to create socket."); return; } @@ -37,7 +37,7 @@ void tcp::client::start(const std::string_view server_ip, const uint16_t port) { ret = connect(m_socket, reinterpret_cast<sockaddr*>(&server_addr), sizeof(server_addr)); if (ret < 0) { - io::logger->error("failed to connect to server."); + io::log_error("failed to connect to server."); return; } @@ -48,11 +48,11 @@ void tcp::client::start(const std::string_view server_ip, const uint16_t port) { if (ret != 1) { ret = wolfSSL_get_error(m_server_ssl, ret); - io::logger->error("secure connection failed, code {}", ret); + io::log_error("secure connection failed, code {}", ret); return; } - m_active = true; + m_active.store(true); connect_event.call(); } diff --git a/client/src/client/client.h b/client/src/client/client.h index 4e6af90..d840538 100644 --- a/client/src/client/client.h +++ b/client/src/client/client.h @@ -14,22 +14,22 @@ struct mapper_data_t { std::vector<char> image; }; -namespace tcp { +struct game_data_t { + std::string name; + std::string version; + std::string process_name; + uint8_t id; +}; +namespace tcp { struct version_t { uint8_t major; uint8_t minor; uint8_t patch; }; - struct game_data_t { - std::string name; - std::string version; - int id; - }; - enum client_state { - idle = 0, logged_in, waiting, injected + idle = 0, logged_in, waiting, imports_ready, image_ready, injected }; enum login_result { @@ -51,54 +51,54 @@ namespace tcp { int state; mapper_data_t mapper_data; std::vector<game_data_t> games; - + game_data_t selected_game; + std::string session_id; event<packet_t&> receive_event; event<> connect_event; - client() : m_socket{ -1 }, m_active{ false }, state{ client_state::idle }, m_server_ssl{ nullptr } {} + client() : m_socket{ -1 }, m_active{ false }, state{ client_state::idle }, m_server_ssl{ nullptr }, m_ssl_ctx{ nullptr } {} void start(const std::string_view server_ip, const uint16_t port); - int write(const packet_t& packet) { + __forceinline int write(const packet_t& packet) { if (!packet) return 0; - return write(packet.message.data(), - packet.message.size()); + return write(packet.message.data(), packet.message.size()); } - int write(const void* data, int size) { + __forceinline int write(const void* data, int size) { return wolfSSL_write(m_server_ssl, data, size); } - int read(void* data, int size) { + __forceinline int read(void* data, int size) { return wolfSSL_read(m_server_ssl, data, size); } int read_stream(std::vector<char>& out); int stream(std::vector<char>& data); - int stream(std::string& str) { + __forceinline int stream(const std::string_view str) { std::vector<char> vec(str.begin(), str.end()); return stream(vec); } - int read_stream(std::string& str) { + __forceinline int read_stream(std::string& str) { std::vector<char> out; int ret = read_stream(out); str.assign(out.begin(), out.end()); return ret; } - int get_socket() { return m_socket; } + __forceinline int get_socket() { return m_socket; } + + operator bool() { return m_active.load(); } - operator bool() const { return m_active; } + __forceinline void shutdown() { + m_active.store(false); - void shutdown() { closesocket(m_socket); wolfSSL_shutdown(m_server_ssl); wolfSSL_free(m_server_ssl); - - m_active = false; } static void monitor(client& client) { @@ -108,7 +108,11 @@ namespace tcp { while (client) { int ret = client.read(&buf[0], buf.size()); if (ret <= 0) { - io::logger->error("connection lost."); + if (!client) { + break; + } + + io::log_error("connection lost."); break; } std::string msg(buf.data(), ret); diff --git a/client/src/client/enc.cpp b/client/src/client/enc.cpp deleted file mode 100644 index b1287aa..0000000 --- a/client/src/client/enc.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "../include.h" -#include "enc.h" - -namespace enc { - - std::random_device r; - - void encrypt_message(std::string& str) { - std::default_random_engine e1(r()); - std::uniform_int_distribution<int> gen(0, 255); - - char k1 = static_cast<char>(gen(e1)); - char k2 = static_cast<char>(gen(e1)); - for (int i = 0; i < str.size(); i++) { - char k = (i % 2) ? k1 : k2; - str[i] ^= k; - } - str.insert(str.begin(), k1); - str.insert(str.end(), k2); - } - - void decrypt_message(std::string& str) { - char k1 = str[0]; - char k2 = str[str.size() - 1]; - - str.erase(str.begin()); - str.erase(str.end() - 1); - - for (int i = 0; i < str.size(); i++) { - char k = (i % 2) ? k1 : k2; - str[i] ^= k; - } - } - -}; // namespace enc
\ No newline at end of file diff --git a/client/src/client/enc.h b/client/src/client/enc.h index e85e296..1780fe0 100644 --- a/client/src/client/enc.h +++ b/client/src/client/enc.h @@ -1,8 +1,32 @@ #pragma once namespace enc { + __forceinline void encrypt_message(std::string& str) { + std::random_device r; + std::default_random_engine e1(r()); + std::uniform_int_distribution<int> gen(0, 255); - void encrypt_message(std::string& str); - void decrypt_message(std::string& str); + char k1 = static_cast<char>(gen(e1)); + char k2 = static_cast<char>(gen(e1)); + for (int i = 0; i < str.size(); i++) { + char k = (i % 2) ? k1 : k2; + str[i] ^= k; + } + str.insert(str.begin(), k1); + str.insert(str.end(), k2); + } + + __forceinline void decrypt_message(std::string& str) { + char k1 = str[0]; + char k2 = str[str.size() - 1]; + + str.erase(str.begin()); + str.erase(str.end() - 1); + + for (int i = 0; i < str.size(); i++) { + char k = (i % 2) ? k1 : k2; + str[i] ^= k; + } + } }; // namespace enc
\ No newline at end of file diff --git a/client/src/client/packet.h b/client/src/client/packet.h index ebefe46..0c8df0e 100644 --- a/client/src/client/packet.h +++ b/client/src/client/packet.h @@ -22,10 +22,10 @@ namespace tcp { }; struct packet_t { + uint8_t seq; + uint8_t id; std::string message; std::string session_id; - uint16_t seq; - int id; packet_t() {} packet_t(const std::string_view msg, const packet_type type, diff --git a/client/src/hwid/hwid.h b/client/src/hwid/hwid.h new file mode 100644 index 0000000..8fae489 --- /dev/null +++ b/client/src/hwid/hwid.h @@ -0,0 +1,10 @@ +#pragma once + + +namespace hwid { + __forceinline std::string fetch() { + nlohmann::json j; + j["uid"] = 0; + return j.dump(); + } +};
\ No newline at end of file diff --git a/client/src/include.h b/client/src/include.h index d378325..4119f0e 100644 --- a/client/src/include.h +++ b/client/src/include.h @@ -32,6 +32,4 @@ #include <atomic> #include <mutex> #include <future> -#include <any> - -#include <spdlog/fmt/fmt.h>
\ No newline at end of file +#include <any>
\ No newline at end of file diff --git a/client/src/injection/mapper.cpp b/client/src/injection/mapper.cpp index 0b993a0..052dc39 100644 --- a/client/src/injection/mapper.cpp +++ b/client/src/injection/mapper.cpp @@ -5,94 +5,84 @@ #include "mapper.h" void mmap::thread(tcp::client& client) { - while (client.mapper_data.imports.empty()) { - std::this_thread::sleep_for(std::chrono::seconds(2)); + while (client.state != tcp::client_state::imports_ready) { + std::this_thread::sleep_for(std::chrono::seconds(1)); } - std::vector<util::process> process_list; - util::fetch_processes(process_list); + util::system_data_t dat; + util::fetch_system_data(dat); - auto needle = std::find_if(process_list.begin(), process_list.end(), [&](util::process& proc) { - return proc.name() == "notepad++.exe"; + auto needle = std::find_if(dat.processes.begin(), dat.processes.end(), [&](util::process_data_t& dat) { + return dat.name == client.selected_game.process_name; }); - while (needle == process_list.end()) { - std::this_thread::sleep_for(std::chrono::seconds(2)); - - util::fetch_processes(process_list); - - io::logger->info("size {}", process_list.size()); - - io::logger->info("waiting for process.."); - - needle = std::find_if(process_list.begin(), process_list.end(), [&](util::process& proc) { - return proc.name() == "notepad++.exe"; - }); + if (needle == dat.processes.end()) { + io::log_error("failed to find process."); + return; } - if (!needle->open()) { + util::process32 proc(*needle); + + if (!proc.open()) { return; } - if (!needle->enum_modules()) { - io::logger->error("failed to enum {} modules", needle->name()); + if (!proc.enum_modules()) { + io::log_error("failed to enum {} modules", proc.name()); return; } - auto image = needle->allocate(client.mapper_data.image_size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); + auto image = proc.allocate(client.mapper_data.image_size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); if (!image) { - io::logger->error("failed to allocate memory for image."); + io::log_error("failed to allocate memory for image."); return; } - io::logger->info("image base : {:x}", image); + io::log("image base : {:x}", image); auto imports = nlohmann::json::parse(client.mapper_data.imports); nlohmann::json final_imports; for (auto& [key, value] : imports.items()) { - auto base = needle->load(key); + auto base = proc.load(key); if (!base) { - io::logger->error("failed to load {}", key); + io::log_error("failed to load {}", key); continue; } for (auto& i : value) { auto name = i.get<std::string>(); - final_imports[name] = needle->module_export(base, name); + final_imports[name] = proc.module_export(base, name); } } + imports.clear(); nlohmann::json resp; resp["alloc"] = image; + resp["id"] = client.selected_game.id; client.write(tcp::packet_t(resp.dump(), tcp::packet_type::write, client.session_id, tcp::packet_id::image)); + resp.clear(); - auto proc_imports = final_imports.dump(); - client.stream(proc_imports); - - proc_imports.clear(); + client.stream(final_imports.dump()); final_imports.clear(); - imports.clear(); - client.mapper_data.imports.clear(); - io::logger->info("please wait..."); - while (client.mapper_data.image.size() != client.mapper_data.image_size) { - std::this_thread::sleep_for(std::chrono::seconds(2)); + io::log("please wait..."); + while (client.state != tcp::client_state::image_ready) { + std::this_thread::sleep_for(std::chrono::seconds(1)); } - if (!needle->write(image, client.mapper_data.image.data(), client.mapper_data.image.size())) { - io::logger->error("failed to write image."); + if (!proc.write(image, client.mapper_data.image.data(), client.mapper_data.image.size())) { + io::log_error("failed to write image."); return; } - client.mapper_data.image.clear(); auto entry = image + client.mapper_data.entry; - io::logger->info("entry : {:x}", entry); + io::log("entry : {:x}", entry); static std::vector<uint8_t> shellcode = { 0x55, 0x89, 0xE5, 0x6A, 0x00, 0x6A, 0x01, 0x68, 0xEF, 0xBE, 0xAD, 0xDE, 0xB8, 0xEF, 0xBE, 0xAD, 0xDE, 0xFF, 0xD0, 0x89, 0xEC, 0x5D, 0xC3 }; @@ -100,23 +90,23 @@ void mmap::thread(tcp::client& client) { *reinterpret_cast<uint32_t*>(&shellcode[8]) = image; *reinterpret_cast<uint32_t*>(&shellcode[13]) = entry; - auto code = needle->allocate(shellcode.size(), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); - if (!needle->write(code, shellcode.data(), shellcode.size())) { - io::logger->error("failed to write shellcode."); + auto code = proc.allocate(shellcode.size(), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); + if (!proc.write(code, shellcode.data(), shellcode.size())) { + io::log_error("failed to write shellcode."); return; } - io::logger->info("shellcode : {:x}", code); - - needle->thread(code); + io::log("shellcode : {:x}", code); - needle->free(code, shellcode.size()); + proc.thread(code); - needle->close(); + proc.free(code, shellcode.size()); - io::logger->info("done"); + //proc.free(image, client.mapper_data.image_size); - client.shutdown(); + proc.close(); client.state = tcp::client_state::injected; + + io::log("done"); }
\ No newline at end of file diff --git a/client/src/injection/mapper.h b/client/src/injection/mapper.h index 1c39d8b..0ce7b8f 100644 --- a/client/src/injection/mapper.h +++ b/client/src/injection/mapper.h @@ -1,7 +1,5 @@ #pragma once namespace mmap { - void thread(tcp::client& client); - };
\ No newline at end of file diff --git a/client/src/injection/pe.h b/client/src/injection/pe.h index b5f9faa..4709872 100644 --- a/client/src/injection/pe.h +++ b/client/src/injection/pe.h @@ -7,22 +7,34 @@ namespace pe { IMAGE_NT_HEADERS64* m_nt; uintptr_t m_base; - bool m_valid; - public: - virtual_image() : m_nt{ nullptr }, m_valid{ false }, m_base{ 0 } {}; - virtual_image(const uintptr_t base) : m_valid{ false }, m_base{ base }, m_nt{ nullptr } { - auto dos = reinterpret_cast<IMAGE_DOS_HEADER*>(base); - if (!dos || dos->e_magic != IMAGE_DOS_SIGNATURE) { - return; - } + virtual_image() : m_nt{ nullptr }, m_base{ 0 } {}; + virtual_image(const std::string_view mod) { + auto peb = util::peb(); + if (!peb) return; - m_nt = reinterpret_cast<IMAGE_NT_HEADERS64*>(base + dos->e_lfanew); - if (m_nt->Signature != IMAGE_NT_SIGNATURE) { - return; - } + if (!peb->Ldr->InMemoryOrderModuleList.Flink) return; + + auto* list = &peb->Ldr->InMemoryOrderModuleList; + + for (auto i = list->Flink; i != list; i = i->Flink) { + auto entry = CONTAINING_RECORD(i, native::LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks); + if (!entry) + continue; - m_valid = true; + auto name = util::wide_to_multibyte(entry->BaseDllName.Buffer); + std::transform(name.begin(), name.end(), name.begin(), ::tolower); + + if (name == mod) { + m_base = uintptr_t(entry->DllBase); + auto dos = reinterpret_cast<IMAGE_DOS_HEADER*>(m_base); + + m_nt = reinterpret_cast<native::nt_headers_t<true>*>(m_base + dos->e_lfanew); + + parse_exports(); + break; + } + } } void parse_exports() { @@ -34,8 +46,7 @@ namespace pe { auto names = reinterpret_cast<uint32_t*>(m_base + exp->AddressOfNames); auto funcs = reinterpret_cast<uint32_t*>(m_base + exp->AddressOfFunctions); - auto ords = - reinterpret_cast<uint16_t*>(m_base + exp->AddressOfNameOrdinals); + auto ords = reinterpret_cast<uint16_t*>(m_base + exp->AddressOfNameOrdinals); if (!names || !funcs || !ords) return; @@ -48,8 +59,7 @@ namespace pe { } auto& exports() { return m_exports; } - - operator bool() { return m_valid; } + operator bool() { return m_base != 0; } }; }; // namespace pe
\ No newline at end of file diff --git a/client/src/injection/process.cpp b/client/src/injection/process.cpp index 06e5ea8..6093bf3 100644 --- a/client/src/injection/process.cpp +++ b/client/src/injection/process.cpp @@ -1,111 +1,102 @@ #include "../include.h" #include "../util/io.h" -#include "../util/syscalls.h" #include "../util/util.h" #include "process.h" -util::process::process(const SYSTEM_PROCESS_INFORMATION* info) { - std::wstring name(info->ImageName.Buffer, info->ImageName.Length / sizeof(wchar_t)); - - m_name = util::wide_to_multibyte(name); - m_id = int(info->UniqueProcessId); -} - -util::process::~process() { - m_name.clear(); -} +uintptr_t util::process32::module_export(const uintptr_t base, const std::string_view func) { + if (!base) { + io::log_error("module {} isnt loaded.", m_name); + return {}; + } -bool util::process::open() { - CLIENT_ID cid = { HANDLE(m_id), 0 }; - OBJECT_ATTRIBUTES oa; - oa.Length = sizeof(oa); - oa.Attributes = 0; - oa.RootDirectory = 0; - oa.SecurityDescriptor = 0; - oa.ObjectName = 0; - oa.SecurityQualityOfService = 0; + IMAGE_DOS_HEADER dos{}; + if (!read(base, &dos, sizeof(dos))) { + io::log_error("failed to read dos header for {}", m_name); + return {}; + } - static auto nt_open = g_syscalls.get<native::NtOpenProcess>("NtOpenProcess"); + if (dos.e_magic != IMAGE_DOS_SIGNATURE) + return {}; - auto status = nt_open(&m_handle, PROCESS_ALL_ACCESS, &oa, &cid); - if (!NT_SUCCESS(status)) { - io::logger->error("failed to open handle to {}, status {:#X}.", m_name, (status & 0xFFFFFFFF)); - return false; + native::nt_headers_t<false> nt{}; + if (!read(base + dos.e_lfanew, &nt, sizeof(nt))) { + io::log_error("failed to read nt header for {}", m_name); + return {}; } - io::logger->info("opened handle to {}.", m_name); - + if (nt.Signature != IMAGE_NT_SIGNATURE) + return {}; - return true; -} + IMAGE_EXPORT_DIRECTORY exp_dir{}; + auto exp_va = nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT] + .VirtualAddress; + auto exp_dir_size = + nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size; -bool util::process::read(const uintptr_t addr, void* data, size_t size) { - static auto nt_read = g_syscalls.get<native::NtReadVirtualMemory>("NtReadVirtualMemory"); + auto exp_dir_start = base + exp_va; + auto exp_dir_end = exp_dir_start + exp_dir_size; - ULONG read; - auto status = nt_read(m_handle, reinterpret_cast<void*>(addr), data, size, &read); - if (!NT_SUCCESS(status)) { - io::logger->error("failed to read at {:x}, status {:#X}.", addr, (status & 0xFFFFFFFF)); - return false; + if (!read(exp_dir_start, &exp_dir, sizeof(exp_dir))) { + io::log_error("failed to read export dir for {}", m_name); + return {}; } - return true; -} + auto funcs = base + exp_dir.AddressOfFunctions; + auto ords = base + exp_dir.AddressOfNameOrdinals; + auto names = base + exp_dir.AddressOfNames; -bool util::process::write(const uintptr_t addr, void* data, size_t size) { - static auto nt_write = g_syscalls.get<native::NtWiteVirtualMemory>("NtWriteVirtualMemory"); + for (int i = 0; i < exp_dir.NumberOfFunctions; ++i) { + uint32_t name_rva{}; + uint32_t func_rva{}; + uint16_t ordinal{}; - ULONG wrote; - auto status = nt_write(m_handle, reinterpret_cast<void*>(addr), data, size, &wrote); - if (!NT_SUCCESS(status)) { - io::logger->error("failed to write to {}, status {:#X}.", m_name, (status & 0xFFFFFFFF)); - return false; - } + if (!read(names + (i * sizeof(uint32_t)), &name_rva, sizeof(uint32_t))) { + continue; + } + std::string name; + name.resize(func.size()); - return true; -} + if (!read(base + name_rva, &name[0], name.size())) { + continue; + } -bool util::process::free(const uintptr_t addr, size_t size) { - static auto nt_free = g_syscalls.get<native::NtFreeVirtualMemory>("NtFreeVirtualMemory"); + if (name == func) { + if (!read(ords + (i * sizeof(uint16_t)), &ordinal, sizeof(uint16_t))) { + return {}; + } - void* cast_addr = reinterpret_cast<void*>(addr); - SIZE_T win_size = size; - auto status = nt_free(m_handle, &cast_addr, &win_size, MEM_RELEASE); - if (!NT_SUCCESS(status)) { - io::logger->error("failed to free at {:x}, status {:#X}.", addr, (status & 0xFFFFFFFF)); - return false; - } + if (!read(funcs + (ordinal * sizeof(uint32_t)), &func_rva, sizeof(uint32_t))) { + return {}; + } - return true; -} + auto proc_addr = base + func_rva; + if (proc_addr >= exp_dir_start && proc_addr < exp_dir_end) { + std::array<char, 255> forwarded_name; + read(proc_addr, &forwarded_name[0], forwarded_name.size()); -bool util::process::thread(const uintptr_t start) { - static auto nt_create = g_syscalls.get<native::NtCreateThreadEx>("NtCreateThreadEx"); - static auto nt_wait = g_syscalls.get<native::NtWaitForSingleObject>("NtWaitForSingleObject"); + std::string name_str(forwarded_name.data()); - HANDLE out; - auto status = nt_create(&out, THREAD_ALL_ACCESS, nullptr, m_handle, reinterpret_cast<LPTHREAD_START_ROUTINE>(start), 0, 0x4, 0, 0, 0, 0); - if (!NT_SUCCESS(status)) { - io::logger->error("failed to create thread in {}, status {:#X}.", m_name, (status & 0xFFFFFFFF)); - return false; - } + size_t delim = name_str.find('.'); + if (delim == std::string::npos) return {}; - status = nt_wait(out, false, nullptr); - if (!NT_SUCCESS(status)) { - io::logger->error("failed to wait for handle {}, status {:#X}.", out, (status & 0xFFFFFFFF)); + std::string fwd_mod_name = name_str.substr(0, delim + 1); + fwd_mod_name += "dll"; - util::close_handle(out); - return false; - } + std::transform(fwd_mod_name.begin(), fwd_mod_name.end(), fwd_mod_name.begin(), ::tolower); - if (!util::close_handle(out)) { - return false; + std::string fwd_func_name = name_str.substr(delim + 1); + + return module_export(load(fwd_mod_name), fwd_func_name); + } + + return proc_addr; + } } - return true; + return {}; } -uintptr_t util::process::load(const std::string_view mod) { +uintptr_t util::process32::load(const std::string_view mod) { auto base = m_modules[mod.data()]; if (base) { return base; @@ -125,12 +116,12 @@ uintptr_t util::process::load(const std::string_view mod) { ustr.MaximumLength = ustr.Length = wpath.size() * sizeof(wchar_t); if (!write(name, &ustr, sizeof(ustr))) { - io::logger->error("failed to write name."); + io::log_error("failed to write name."); return {}; } if (!write(name + sizeof(ustr), wpath.data(), wpath.size() * sizeof(wchar_t))) { - io::logger->error("failed to write path."); + io::log_error("failed to write path."); return {}; } @@ -143,25 +134,25 @@ uintptr_t util::process::load(const std::string_view mod) { auto code = allocate(shellcode.size(), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); if (!write(code, shellcode.data(), shellcode.size())) { - io::logger->error("failed to write shellcode."); + io::log_error("failed to write shellcode."); return {}; } - io::logger->info("name : {:x}", name); - io::logger->info("shellcode : {:x}", code); + io::log("name : {:x}", name); + io::log("shellcode : {:x}", code); if (!thread(code)) { - io::logger->error("thread creation failed."); + io::log_error("thread creation failed."); return {}; } if (!free(code, shellcode.size())) { - io::logger->error("failed to free shellcode."); + io::log_error("failed to free shellcode."); return {}; } if (!free(name, 0x1000)) { - io::logger->error("failed to free name."); + io::log_error("failed to free name."); return {}; } @@ -170,261 +161,68 @@ uintptr_t util::process::load(const std::string_view mod) { return m_modules[mod.data()]; } -uintptr_t util::process::map(const std::string_view mod) { - auto base = m_modules[mod.data()]; - if (base) { - return base; - } - - std::string path{ "C:\\Windows\\SysWOW64\\" }; - path.append(mod.data()); - - std::vector<char> buf; - if (!io::read_file(path, buf)) { - return {}; - } - - std::vector<char> final_image; - - auto dos = reinterpret_cast<IMAGE_DOS_HEADER*>(buf.data()); - auto nt = reinterpret_cast<IMAGE_NT_HEADERS32*>(buf.data() + dos->e_lfanew); - - - final_image.resize(nt->OptionalHeader.SizeOfImage); - - // headers - std::memcpy(&final_image[0], &buf[0], nt->OptionalHeader.SizeOfHeaders); - - // copy image - auto secs = IMAGE_FIRST_SECTION(nt); - for (int i = 0; i < nt->FileHeader.NumberOfSections; i++) { - auto sec = secs[i]; - std::memcpy(&final_image[sec.VirtualAddress], &buf[sec.PointerToRawData], sec.SizeOfRawData); - } - - auto image = allocate(final_image.size(), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); - if (!image) { - io::logger->error("failed to alloc buffer for {}.", path); - return {}; - } - - io::logger->info("{:x}->{}", image, mod); - - // fix relocations - - - if (!write(image, final_image.data(), final_image.size())) { - io::logger->error("failed to write final image."); - return {}; - } - - m_modules[mod.data()] = image; - - return image; -} - -bool util::process::enum_modules() { - m_modules.clear(); - - static auto peb_addr = peb(); +bool util::fetch_system_data(system_data_t& out) { + static auto info = g_syscalls.get<native::NtQuerySystemInformation>("NtQuerySystemInformation"); - uint32_t ldr; - if (!read(peb_addr + offsetof(native::peb_t<uint32_t>, Ldr), &ldr, sizeof(ldr))) { - return false; - } + std::vector<uint8_t> buf(1); - const auto list_head = ldr + offsetof(native::peb_ldr_data_t<uint32_t>, InLoadOrderModuleList); + ULONG size_needed = 0; + NTSTATUS status; + while ((status = info(native::SystemProcessInformation, buf.data(), buf.size(), &size_needed)) == STATUS_INFO_LENGTH_MISMATCH) { + buf.resize(size_needed); + }; - uint32_t load_order_flink; - if (!read(list_head, &load_order_flink, sizeof(load_order_flink))) { + if (!NT_SUCCESS(status)) { + io::log_error("failed to get system process info, status {:#X}.", (status & 0xFFFFFFFF)); return false; } - native::ldr_data_table_entry_t<uint32_t> entry; - for (auto list_curr = load_order_flink; list_curr != list_head;) { - if (!read(list_curr, &entry, sizeof(entry))) { - return false; - } - - list_curr = uint32_t(entry.InLoadOrderLinks.Flink); - - std::vector<wchar_t> name_vec(entry.FullDllName.Length); + std::vector<thread_data_t> threads; + std::vector<process_data_t> processes; + auto pi = reinterpret_cast<SYSTEM_PROCESS_INFORMATION*>(buf.data()); - if (!read(entry.FullDllName.Buffer, &name_vec[0], name_vec.size())) { - continue; - } + while (pi->NextEntryOffset) { + std::wstring name(pi->ImageName.Buffer, pi->ImageName.Length / sizeof(wchar_t)); + processes.emplace_back(process_data_t{ util::wide_to_multibyte(name), int(pi->UniqueProcessId) }); - auto name = util::wide_to_multibyte(name_vec.data()); - auto pos = name.rfind('\\'); - if (pos != std::string::npos) { - name = name.substr(pos + 1); - std::transform(name.begin(), name.end(), name.begin(), ::tolower); + auto ti = reinterpret_cast<SYSTEM_THREAD_INFORMATION*>(uintptr_t(pi) + sizeof(SYSTEM_PROCESS_INFORMATION)); - m_modules[name] = entry.DllBase; + for (auto i = 0; i < pi->NumberOfThreads; ++i) { + auto dat = ti[i]; + threads.emplace_back(thread_data_t{int(dat.ClientId.UniqueProcess), uintptr_t(dat.ClientId.UniqueThread), dat.ThreadState}); } - } - - return true; -} - -uintptr_t util::process::peb() { - static auto nt_proc_info = g_syscalls.get<native::NtQueryInformationProcess>("NtQueryInformationProcess"); - - uintptr_t addr; - auto status = nt_proc_info(m_handle, ProcessWow64Information, &addr, sizeof(addr), nullptr); - if (!NT_SUCCESS(status)) { - io::logger->error("failed to query {} info, status {:#X}.", m_name, (status & 0xFFFFFFFF)); - return {}; - } - - return addr; -} - -uintptr_t util::process::allocate(size_t size, uint32_t type, uint32_t protection) { - static auto nt_alloc = g_syscalls.get<native::NtAllocateVirtualMemory>("NtAllocateVirtualMemory"); - - void* alloc = nullptr; - SIZE_T win_size = size; - auto status = nt_alloc(m_handle, &alloc, 0, &win_size, type, protection); - if (!NT_SUCCESS(status)) { - io::logger->error("failed to allocate in {}, status {:#X}.", m_name, (status & 0xFFFFFFFF)); - return {}; - } - - return uintptr_t(alloc); -} -uintptr_t util::process::module_export(const uintptr_t base, const std::string_view func) { - if (!base) { - io::logger->error("module {} isnt loaded.", m_name); - return {}; - } - - IMAGE_DOS_HEADER dos{}; - if (!read(base, &dos, sizeof(dos))) { - io::logger->info("failed to read dos header for {}", m_name); - return {}; + pi = reinterpret_cast<SYSTEM_PROCESS_INFORMATION*>(uintptr_t(pi) + pi->NextEntryOffset); } - if (dos.e_magic != IMAGE_DOS_SIGNATURE) - return {}; - - IMAGE_NT_HEADERS32 nt{}; - if (!read(base + dos.e_lfanew, &nt, sizeof(nt))) { - io::logger->info("failed to read nt header for {}", m_name); - return {}; - } - if (nt.Signature != IMAGE_NT_SIGNATURE) - return {}; + out.processes = std::move(processes); + out.threads = std::move(threads); - IMAGE_EXPORT_DIRECTORY exp_dir{}; - auto exp_va = nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT] - .VirtualAddress; - auto exp_dir_size = - nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size; - - auto exp_dir_start = base + exp_va; - auto exp_dir_end = exp_dir_start + exp_dir_size; - - if (!read(exp_dir_start, &exp_dir, sizeof(exp_dir))) { - io::logger->info("failed to read export dir for {}", m_name); - return {}; - } - - auto funcs = base + exp_dir.AddressOfFunctions; - auto ords = base + exp_dir.AddressOfNameOrdinals; - auto names = base + exp_dir.AddressOfNames; - - for (int i = 0; i < exp_dir.NumberOfFunctions; ++i) { - uint32_t name_rva{}; - uint32_t func_rva{}; - uint16_t ordinal{}; - - if (!read(names + (i * sizeof(uint32_t)), &name_rva, sizeof(uint32_t))) { - continue; - } - std::string name; - name.resize(func.size()); - - if (!read(base + name_rva, &name[0], name.size())) { - continue; - } - - if (name == func) { - if (!read(ords + (i * sizeof(uint16_t)), &ordinal, sizeof(uint16_t))) { - return {}; - } - - if (!read(funcs + (ordinal * sizeof(uint32_t)), &func_rva, sizeof(uint32_t))) { - return {}; - } - - auto proc_addr = base + func_rva; - if (proc_addr >= exp_dir_start && proc_addr < exp_dir_end) { - std::array<char, 255> forwarded_name; - read(proc_addr, &forwarded_name[0], forwarded_name.size()); - - std::string name_str(forwarded_name.data()); - - size_t delim = name_str.find('.'); - if (delim == std::string::npos) return {}; - - std::string fwd_mod_name = name_str.substr(0, delim + 1); - fwd_mod_name += "dll"; - - std::transform(fwd_mod_name.begin(), fwd_mod_name.end(), fwd_mod_name.begin(), ::tolower); - - std::string fwd_func_name = name_str.substr(delim + 1); - - return module_export(load(fwd_mod_name), fwd_func_name); - } - - return proc_addr; - } - } - - return {}; -} - -bool util::process::close() { - auto ret = util::close_handle(m_handle); - if (ret) { - io::logger->info("closed handle to {}.", m_name); - } - m_handle = INVALID_HANDLE_VALUE; - return ret; + return true; } -bool util::fetch_processes(std::vector<process> &out) { +bool util::fetch_process_handles(const int pid, std::vector<handle_info_t>& out) { static auto info = g_syscalls.get<native::NtQuerySystemInformation>("NtQuerySystemInformation"); std::vector<uint8_t> buf(1); ULONG size_needed = 0; NTSTATUS status; - while ((status = info(SystemProcessInformation, buf.data(), buf.size(), &size_needed)) == STATUS_INFO_LENGTH_MISMATCH) { + while ((status = info(native::SystemHandleInformation, buf.data(), buf.size(), &size_needed)) == STATUS_INFO_LENGTH_MISMATCH) { buf.resize(size_needed); }; if (!NT_SUCCESS(status)) { - io::logger->error("failed to get system process info, status {:#X}.", (status & 0xFFFFFFFF)); + io::log_error("failed to get system handle info, status {:#X}.", (status & 0xFFFFFFFF)); return false; } - out.clear(); - auto pi = reinterpret_cast<SYSTEM_PROCESS_INFORMATION*>(buf.data()); - while (pi->NextEntryOffset) { - out.emplace_back(util::process(pi)); - pi = reinterpret_cast<SYSTEM_PROCESS_INFORMATION*>(uintptr_t(pi) + pi->NextEntryOffset); + auto hi = reinterpret_cast<native::SYSTEM_HANDLE_INFORMATION*>(buf.data()); + for (ULONG i = 0; i < hi->NumberOfHandles; i++) { + auto handle = &hi->Handles[i]; + if (handle->UniqueProcessId == pid) { + out.emplace_back(handle_info_t{ handle->GrantedAccess, uintptr_t(handle->HandleValue), handle->ObjectTypeIndex }); + } } - /*std::set_difference(new_list.begin(), new_list.end(), process_list.begin(), process_list.end(), std::inserter(diff, diff.begin()), [&](util::process &l, util::process &r) { - return l.id() != r.id(); - }); - - for (auto& p : diff) { - io::logger->info("{} is new", p.name()); - }*/ - - return true; } diff --git a/client/src/injection/process.h b/client/src/injection/process.h index 8e2c4f1..002c399 100644 --- a/client/src/injection/process.h +++ b/client/src/injection/process.h @@ -1,38 +1,249 @@ #pragma once +#include "../util/syscalls.h" namespace util { - class process { + template<typename T = uint32_t> + class base_process { + protected: + HANDLE m_handle; int m_id; std::string m_name; + std::unordered_map<std::string, uintptr_t> m_modules; + public: + base_process() = default; + ~base_process() = default; - HANDLE m_handle; + bool open() { + CLIENT_ID cid = { HANDLE(m_id), 0 }; + OBJECT_ATTRIBUTES oa; + oa.Length = sizeof(oa); + oa.Attributes = 0; + oa.RootDirectory = 0; + oa.SecurityDescriptor = 0; + oa.ObjectName = 0; + oa.SecurityQualityOfService = 0; + + static auto nt_open = g_syscalls.get<native::NtOpenProcess>("NtOpenProcess"); + + auto status = nt_open(&m_handle, PROCESS_ALL_ACCESS, &oa, &cid); + if (!NT_SUCCESS(status)) { + io::log_error("failed to open handle to {}, status {:#X}.", m_name, (status & 0xFFFFFFFF)); + return false; + } + + io::log("opened handle to {}.", m_name); + + return true; + } + + bool read(const uintptr_t addr, void* data, size_t size) { + static auto nt_read = g_syscalls.get<native::NtReadVirtualMemory>("NtReadVirtualMemory"); + + ULONG read; + auto status = nt_read(m_handle, reinterpret_cast<void*>(addr), data, size, &read); + if (!NT_SUCCESS(status)) { + io::log_error("failed to read at {:x}, status {:#X}.", addr, (status & 0xFFFFFFFF)); + return false; + } + + return true; + } + + bool write(const uintptr_t addr, void* data, size_t size) { + static auto nt_write = g_syscalls.get<native::NtWiteVirtualMemory>("NtWriteVirtualMemory"); + + ULONG wrote; + auto status = nt_write(m_handle, reinterpret_cast<void*>(addr), data, size, &wrote); + if (!NT_SUCCESS(status)) { + io::log_error("failed to write to {}, status {:#X}.", m_name, (status & 0xFFFFFFFF)); + return false; + } + + return true; + } + + bool free(const uintptr_t addr, size_t size, uint32_t type = MEM_RELEASE) { + static auto nt_free = g_syscalls.get<native::NtFreeVirtualMemory>("NtFreeVirtualMemory"); + + SIZE_T win_size = size; + void *addr_cast = reinterpret_cast<void*>(addr); + auto status = nt_free(m_handle, &addr_cast, &win_size, MEM_RELEASE); + if (!NT_SUCCESS(status)) { + io::log_error("failed to free at {:x}, status {:#X}.", addr, (status & 0xFFFFFFFF)); + return false; + } + + return true; + } + + bool info(PROCESSINFOCLASS proc_info, void* data, size_t size) { + static auto nt_proc_info = g_syscalls.get<native::NtQueryInformationProcess>("NtQueryInformationProcess"); + auto status = nt_proc_info(m_handle, proc_info, data, size, nullptr); + if (!NT_SUCCESS(status)) { + io::log_error("failed to query {} info, status {:#X}.", m_name, (status & 0xFFFFFFFF)); + return false; + } + + return true; + } + + bool thread(const uintptr_t func) { + static auto nt_create = g_syscalls.get<native::NtCreateThreadEx>("NtCreateThreadEx"); + static auto nt_wait = g_syscalls.get<native::NtWaitForSingleObject>("NtWaitForSingleObject"); + + HANDLE out; + auto status = nt_create(&out, THREAD_ALL_ACCESS, nullptr, m_handle, reinterpret_cast<LPTHREAD_START_ROUTINE>(func), 0, 0x4, 0, 0, 0, 0); + if (!NT_SUCCESS(status)) { + io::log_error("failed to create thread in {}, status {:#X}.", m_name, (status & 0xFFFFFFFF)); + return false; + } + + status = nt_wait(out, false, nullptr); + if (!NT_SUCCESS(status)) { + io::log_error("failed to wait for handle {}, status {:#X}.", out, (status & 0xFFFFFFFF)); + + util::close_handle(out); + return false; + } + + if (!util::close_handle(out)) { + return false; + } + + return true; + } + + bool enum_modules() { + m_modules.clear(); + + static auto peb_addr = peb(); + + T ldr; + if (!read(peb_addr + offsetof(native::peb_t<T>, Ldr), &ldr, sizeof(ldr))) { + return false; + } + + const auto list_head = ldr + offsetof(native::peb_ldr_data_t<T>, InLoadOrderModuleList); + + T load_order_flink; + if (!read(list_head, &load_order_flink, sizeof(load_order_flink))) { + return false; + } + + native::ldr_data_table_entry_t<T> entry; + for (auto list_curr = load_order_flink; list_curr != list_head;) { + if (!read(list_curr, &entry, sizeof(entry))) { + return false; + } + + list_curr = entry.InLoadOrderLinks.Flink; + + std::vector<wchar_t> name_vec(entry.FullDllName.Length); + + if (!read(entry.FullDllName.Buffer, &name_vec[0], name_vec.size())) { + continue; + } + + auto name = util::wide_to_multibyte(name_vec.data()); + auto pos = name.rfind('\\'); + if (pos != std::string::npos) { + name = name.substr(pos + 1); + std::transform(name.begin(), name.end(), name.begin(), ::tolower); + + m_modules[name] = entry.DllBase; + } + } + + return true; + } + + bool close() { + auto ret = util::close_handle(m_handle); + if (ret) { + io::log("closed handle to {}.", m_name); + } + m_handle = INVALID_HANDLE_VALUE; + return ret; + } + + uintptr_t peb() { + bool is64 = sizeof(T) == sizeof(uint64_t); + if (is64) { + native::PROCESS_EXTENDED_BASIC_INFORMATION proc_info; + proc_info.Size = sizeof(proc_info); + if (!info(ProcessBasicInformation, &proc_info, sizeof(proc_info))) { + return {}; + } + + return uintptr_t(proc_info.BasicInfo.PebBaseAddress); + } + + uintptr_t addr; + if (!info(ProcessWow64Information, &addr, sizeof(addr))) { + return {}; + } + + return addr; + } + + uintptr_t allocate(size_t size, uint32_t type, uint32_t protection) { + static auto nt_alloc = g_syscalls.get<native::NtAllocateVirtualMemory>("NtAllocateVirtualMemory"); + + void* alloc = nullptr; + SIZE_T win_size = size; + auto status = nt_alloc(m_handle, &alloc, 0, &win_size, type, protection); + if (!NT_SUCCESS(status)) { + io::log_error("failed to allocate in {}, status {:#X}.", m_name, (status & 0xFFFFFFFF)); + return {}; + } + + return uintptr_t(alloc); + } + + auto &modules() { return m_modules; } + auto &handle() { return m_handle; } + auto &name() { return m_name; } + auto &id() { return m_id; } + }; + + struct process_data_t { + std::string name; + int id; + }; + + struct thread_data_t { + int id; + uintptr_t handle; + uint32_t state; + }; + + struct system_data_t { + std::vector<process_data_t> processes; + std::vector<thread_data_t> threads; + }; + + class process32 : public base_process<uint32_t> { public: - process() : m_handle{ INVALID_HANDLE_VALUE }, m_id{ -1 } {}; - process(const SYSTEM_PROCESS_INFORMATION* info); - ~process(); - - bool open(); - bool read(const uintptr_t addr, void* data, size_t size); - bool write(const uintptr_t addr, void* data, size_t size); - bool free(const uintptr_t addr, size_t size); - bool thread(const uintptr_t start); - bool enum_modules(); - - uintptr_t peb(); - uintptr_t load(const std::string_view mod); - uintptr_t map(const std::string_view path); - uintptr_t allocate(size_t size, uint32_t type, uint32_t protection); + process32(const process_data_t &data) { + m_name = data.name; + m_id = data.id; + } + uintptr_t module_export(const uintptr_t base, const std::string_view func); + uintptr_t load(const std::string_view mod); + }; - bool close(); + class process64 : public base_process<uint64_t> { - operator bool() const { return m_handle != INVALID_HANDLE_VALUE; } + }; - auto& name() { return m_name; } - auto& id() { return m_id; } - auto& handle() { return m_handle; } + struct handle_info_t { + uint32_t access; + uintptr_t handle; + uint32_t obj_type; }; - bool fetch_processes(std::vector<process> &out); + bool fetch_system_data(system_data_t &out); + bool fetch_process_handles(const int pid, std::vector<handle_info_t> &out); }; diff --git a/client/src/main.cpp b/client/src/main.cpp index 718b728..0cb08f4 100644 --- a/client/src/main.cpp +++ b/client/src/main.cpp @@ -5,15 +5,10 @@ #include "client/client.h" #include "injection/process.h" #include "injection/mapper.h" +#include "hwid/hwid.h" int main(int argc, char* argv[]) { - io::init(); - - if (!util::init()) { - return 0; - } - - g_syscalls.init(); + io::log("{:x}", g_syscalls()); tcp::client client; @@ -21,11 +16,10 @@ int main(int argc, char* argv[]) { t.detach(); std::thread t1{ mmap::thread, std::ref(client) }; - t1.detach(); client.start("127.0.0.1", 6666); - client.connect_event.add([&]() { io::logger->info("connected."); }); + client.connect_event.add([&]() { io::log("connected."); }); client.receive_event.add([&](tcp::packet_t& packet) { if (!packet) return; @@ -37,20 +31,20 @@ int main(int argc, char* argv[]) { tcp::version_t v{ 0, 1, 0 }; auto version = fmt::format("{}.{}.{}", v.major, v.minor, v.patch); - io::logger->info("current server version {}", message); + io::log("current server version {}.", message); if (version != message) { - io::logger->error("please update your client."); + io::log_error("please update your client."); client.shutdown(); - return; } + auto hwid = hwid::fetch(); int ret = - client.write(tcp::packet_t("hwid", tcp::packet_type::write, + client.write(tcp::packet_t(hwid, tcp::packet_type::write, client.session_id, tcp::packet_id::hwid)); if (ret <= 0) { - io::logger->error("failed to send hwid."); + io::log_error("failed to send hwid."); client.shutdown(); return; } @@ -62,25 +56,25 @@ int main(int argc, char* argv[]) { auto res = j["result"].get<int>(); if (res == tcp::login_result::banned) { - io::logger->error("your account is banned."); + io::log_error("your account is banned."); client.shutdown(); return; } if (res == tcp::login_result::login_fail) { - io::logger->error("please check your username or password."); + io::log_error("please check your username or password."); client.shutdown(); return; } if (res == tcp::login_result::hwid_mismatch) { - io::logger->error("please reset your hwid on the forums."); + io::log_error("please reset your hwid on the forums."); client.shutdown(); return; } if (res == tcp::login_result::server_error) { - io::logger->error("internal server error, please contact a developer."); + io::log_error("internal server error, please contact a developer."); client.shutdown(); return; } @@ -89,12 +83,13 @@ int main(int argc, char* argv[]) { auto games = j["games"]; for (auto& [key, value] : games.items()) { std::string version = value["version"]; - int id = value["id"]; + std::string process = value["process"]; + uint8_t id = value["id"]; - client.games.emplace_back(tcp::game_data_t{ key, version, id }); + client.games.emplace_back(game_data_t{ key, version, process, id }); } - io::logger->info("logged in."); + io::log("logged in."); client.state = tcp::client_state::logged_in; } } @@ -103,27 +98,31 @@ int main(int argc, char* argv[]) { auto j = nlohmann::json::parse(message); client.mapper_data.image_size = j["pe"][0]; client.mapper_data.entry = j["pe"][1]; + int imports_size = j["size"]; - client.read_stream(client.mapper_data.imports); - - client.state = tcp::client_state::waiting; + int size = client.read_stream(client.mapper_data.imports); + if (size == imports_size) { + io::log("got imports"); + client.state = tcp::client_state::imports_ready; + } } if (id == tcp::packet_id::image) { - client.read_stream(client.mapper_data.image); + int size = client.read_stream(client.mapper_data.image); - io::logger->info("got image"); + if (size == client.mapper_data.image_size) { + io::log("got image"); + client.state = tcp::client_state::image_ready; + } } - if (id == tcp::packet_id::ban) { - io::logger->error( - "your computer is blacklisted, please contact a developer."); + io::log_error("your computer is blacklisted, please contact a developer."); client.shutdown(); return; } - io::logger->info("{}:{}->{} {}", packet.seq, packet.session_id, message, id); + io::log("{}:{}->{} {}", packet.seq, packet.session_id, message, id); }); while (client) { @@ -144,19 +143,26 @@ int main(int argc, char* argv[]) { tcp::packet_id::login_req)); if (ret <= 0) { + client.shutdown(); break; } } if (client.state == tcp::client_state::logged_in) { for (auto& dat : client.games) { - io::logger->info("[{}]{} : {}", dat.id, dat.name, dat.version); + io::log("[{}]{} : {}", dat.id, dat.name, dat.version); } - io::logger->info("please select a game :"); + + io::log("please select a game :"); int id; std::cin >> id; + auto it = std::find_if(client.games.begin(), client.games.end(), [&](game_data_t& dat) { + return dat.id == id; + }); + client.selected_game = *it; + nlohmann::json j; j["id"] = id; @@ -165,18 +171,14 @@ int main(int argc, char* argv[]) { tcp::packet_id::game_select)); if (ret <= 0) { + client.shutdown(); break; } + client.state = tcp::client_state::waiting; break; } - } - while (client) { - std::this_thread::sleep_for(std::chrono::seconds(1)); - } - - - std::cin.get(); + t1.join(); } diff --git a/client/src/util/io.cpp b/client/src/util/io.cpp index f6048ba..7e783c2 100644 --- a/client/src/util/io.cpp +++ b/client/src/util/io.cpp @@ -1,20 +1,10 @@ #include "../include.h" #include "io.h" -std::shared_ptr<spdlog::logger> io::logger; - -void io::init() { - spdlog::sink_ptr sink = - std::make_shared<spdlog::sinks::stdout_color_sink_mt>(); - sink->set_pattern("%^~>%$ %v"); - - logger = std::make_shared<spdlog::logger>("client", sink); -} - bool io::read_file(const std::string_view name, std::vector<char>& out) { std::ifstream file(name.data(), std::ios::binary); if (!file.good()) { - io::logger->error("{} isnt valid.", name); + log_error("{} isnt valid.", name); return false; } diff --git a/client/src/util/io.h b/client/src/util/io.h index 0678e9f..c1ee932 100644 --- a/client/src/util/io.h +++ b/client/src/util/io.h @@ -1,12 +1,29 @@ #pragma once -#include <spdlog/spdlog.h> -#include <spdlog/sinks/basic_file_sink.h> -#include <spdlog/sinks/stdout_color_sinks.h> +#include <fmt/format.h> +#include <fmt/color.h> + namespace io { - extern std::shared_ptr<spdlog::logger> logger; + template<typename... Args> + void log(const std::string_view str, Args... params) { + fmt::print(fg(fmt::color::green) | fmt::emphasis::bold, "$> "); + + std::string msg{str}; + msg.append("\n"); + + fmt::print(msg, std::forward<Args>(params)...); + } + + template<typename... Args> + void log_error(const std::string_view str, Args... params) { + fmt::print(fg(fmt::color::red) | fmt::emphasis::bold, "$> "); + + std::string msg{str}; + msg.append("\n"); + + fmt::print(msg, std::forward<Args>(params)...); + } - void init(); bool read_file(const std::string_view name, std::vector<char>& out); }; // namespace io diff --git a/client/src/util/native.h b/client/src/util/native.h index 735a6cb..dada567 100644 --- a/client/src/util/native.h +++ b/client/src/util/native.h @@ -206,6 +206,10 @@ namespace native { uint32_t ReferenceCount; }; + + template<bool x64, typename base_type = typename std::conditional<x64, IMAGE_NT_HEADERS64, IMAGE_NT_HEADERS32>::type> + struct nt_headers_t : base_type {}; + template<class P> struct peb_t { std::uint8_t _ignored[4]; @@ -248,7 +252,95 @@ namespace native { unicode_string_t<P> FullDllName; }; - using NtQuerySystemInformation = NTSTATUS(__stdcall*)(SYSTEM_INFORMATION_CLASS, PVOID, SIZE_T, PULONG); + typedef struct _PROCESS_EXTENDED_BASIC_INFORMATION + { + SIZE_T Size; // set to sizeof structure on input + PROCESS_BASIC_INFORMATION BasicInfo; + union + { + ULONG Flags; + struct + { + ULONG IsProtectedProcess : 1; + ULONG IsWow64Process : 1; + ULONG IsProcessDeleting : 1; + ULONG IsCrossSessionCreate : 1; + ULONG IsFrozen : 1; + ULONG IsBackground : 1; + ULONG IsStronglyNamed : 1; + ULONG IsSecureProcess : 1; + ULONG IsSubsystemProcess : 1; + ULONG SpareBits : 23; + }; + }; + } PROCESS_EXTENDED_BASIC_INFORMATION, *PPROCESS_EXTENDED_BASIC_INFORMATION; + + + typedef enum _SYSTEM_INFORMATION_CLASS { + SystemBasicInformation, + SystemProcessorInformation, + SystemPerformanceInformation, + SystemTimeOfDayInformation, + SystemPathInformation, + SystemProcessInformation, + SystemCallCountInformation, + SystemDeviceInformation, + SystemProcessorPerformanceInformation, + SystemFlagsInformation, + SystemCallTimeInformation, + SystemModuleInformation, + SystemLocksInformation, + SystemStackTraceInformation, + SystemPagedPoolInformation, + SystemNonPagedPoolInformation, + SystemHandleInformation, + SystemObjectInformation, + SystemPageFileInformation, + SystemVdmInstemulInformation, + SystemVdmBopInformation, + SystemFileCacheInformation, + SystemPoolTagInformation, + SystemInterruptInformation, + SystemDpcBehaviorInformation, + SystemFullMemoryInformation, + SystemLoadGdiDriverInformation, + SystemUnloadGdiDriverInformation, + SystemTimeAdjustmentInformation, + SystemSummaryMemoryInformation, + SystemNextEventIdInformation, + SystemEventIdsInformation, + SystemCrashDumpInformation, + SystemExceptionInformation, + SystemCrashDumpStateInformation, + SystemKernelDebuggerInformation, + SystemContextSwitchInformation, + SystemRegistryQuotaInformation, + SystemExtendServiceTableInformation, + SystemPrioritySeperation, + SystemPlugPlayBusInformation, + SystemDockInformation, + SystemPowerInformation, + SystemProcessorSpeedInformation, + SystemCurrentTimeZoneInformation, + SystemLookasideInformation + } SYSTEM_INFORMATION_CLASS, *PSYSTEM_INFORMATION_CLASS; + + typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO { + USHORT UniqueProcessId; + USHORT CreatorBackTraceIndex; + UCHAR ObjectTypeIndex; + UCHAR HandleAttributes; + USHORT HandleValue; + PVOID Object; + ULONG GrantedAccess; + } SYSTEM_HANDLE_TABLE_ENTRY_INFO, * PSYSTEM_HANDLE_TABLE_ENTRY_INFO; + + typedef struct _SYSTEM_HANDLE_INFORMATION { + ULONG NumberOfHandles; + SYSTEM_HANDLE_TABLE_ENTRY_INFO Handles[1]; + } SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION; + + using NtQuerySystemInformation = NTSTATUS(__stdcall*)(native::SYSTEM_INFORMATION_CLASS, PVOID, SIZE_T, PULONG); using NtOpenProcess = NTSTATUS(__stdcall*)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, CLIENT_ID*); using NtReadVirtualMemory = NTSTATUS(__stdcall*)(HANDLE, PVOID, PVOID, SIZE_T, PULONG); using NtAllocateVirtualMemory = NTSTATUS(__stdcall*)(HANDLE, PVOID*, ULONG_PTR, PSIZE_T, ULONG, ULONG); diff --git a/client/src/util/syscalls.cpp b/client/src/util/syscalls.cpp index d7d4254..42f3f8e 100644 --- a/client/src/util/syscalls.cpp +++ b/client/src/util/syscalls.cpp @@ -1,6 +1,7 @@ #include "../include.h" #include "io.h" #include "util.h" +#include "../injection/pe.h" #include "syscalls.h" syscalls g_syscalls; @@ -8,14 +9,8 @@ syscalls g_syscalls; syscalls::syscalls() { m_call_table = VirtualAlloc(0, 0x100000, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); std::memset(m_call_table, 0x90, 0x100000); -} - -syscalls::~syscalls() { - VirtualFree(m_call_table, 0, MEM_RELEASE); -} -void syscalls::init() { - auto nt = util::ntdll(); + static auto nt = pe::virtual_image("ntdll.dll"); for (auto& exp : nt.exports()) { auto addr = exp.second; @@ -31,23 +26,25 @@ void syscalls::init() { m_stub.resize(s); - std::memcpy(&m_stub[0], (void*)addr, s); + std::memcpy(&m_stub[0], reinterpret_cast<void*>(addr), s); } } - io::logger->info("call table : {:x}", uintptr_t(m_call_table)); - - for (auto& syscall : m_indexes) { - auto idx = syscall.second.first; + for (auto& [name, pair] : m_indexes) { + auto& [idx, offset] = pair; auto addr = uintptr_t(m_call_table) + (idx * m_stub.size()); std::memcpy(reinterpret_cast<void*>(addr), m_stub.data(), m_stub.size()); *reinterpret_cast<uint8_t*>(addr + m_stub.size() - 1) = 0xc3; - *reinterpret_cast<uint16_t*>(addr + syscall.second.second + 1) = idx; + *reinterpret_cast<uint16_t*>(addr + offset + 1) = idx; } } +syscalls::~syscalls() { + VirtualFree(m_call_table, 0, MEM_RELEASE); +} + bool syscalls::valid(const uintptr_t addr, const size_t& size) { auto func = reinterpret_cast<uint8_t*>(addr); diff --git a/client/src/util/syscalls.h b/client/src/util/syscalls.h index 45d0ee1..713e24c 100644 --- a/client/src/util/syscalls.h +++ b/client/src/util/syscalls.h @@ -8,7 +8,6 @@ class syscalls { public: syscalls(); ~syscalls(); - void init(); bool valid(const uintptr_t func, const size_t& size); uint16_t get_index(const uintptr_t va, uint16_t& offset); size_t func_size(const uint8_t* func); @@ -17,6 +16,10 @@ public: T get(const std::string_view func) { return reinterpret_cast<T>(uintptr_t(m_call_table) + (m_indexes[func.data()].first * m_stub.size())); }; + + uintptr_t operator()() { + return uintptr_t(m_call_table); + } }; extern syscalls g_syscalls;
\ No newline at end of file diff --git a/client/src/util/util.cpp b/client/src/util/util.cpp index b79f6cd..1847780 100644 --- a/client/src/util/util.cpp +++ b/client/src/util/util.cpp @@ -3,8 +3,6 @@ #include "io.h" #include "syscalls.h" -std::unordered_map<std::string, pe::virtual_image> util::loaded_modules; - std::string util::wide_to_multibyte(const std::wstring& str) { std::string ret; size_t str_len; @@ -40,36 +38,9 @@ std::wstring util::multibyte_to_wide(const std::string& str) { return out; } - -native::_PEB* util::cur_peb() { - return reinterpret_cast<native::_PEB*>(__readgsqword(0x60)); -} - -bool util::init() { - auto peb = cur_peb(); - if (!peb) return false; - - if (!peb->Ldr->InMemoryOrderModuleList.Flink) return false; - - auto* list = &peb->Ldr->InMemoryOrderModuleList; - - for (auto i = list->Flink; i != list; i = i->Flink) { - auto entry = CONTAINING_RECORD(i, native::LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks); - if (!entry) - continue; - - auto name = wide_to_multibyte(entry->BaseDllName.Buffer); - std::transform(name.begin(), name.end(), name.begin(), ::tolower); - - loaded_modules[name] = pe::virtual_image(entry->DllBase); - } - - return true; -} - bool util::close_handle(HANDLE handle) { if (!handle) { - io::logger->error("invalid handle specified to close."); + io::log_error("invalid handle specified to close."); return false; } @@ -77,7 +48,7 @@ bool util::close_handle(HANDLE handle) { auto status = nt_close(handle); if (!NT_SUCCESS(status)) { - io::logger->error("failed to close {}, status {:#X}.", handle, (status & 0xFFFFFFFF)); + io::log_error("failed to close {}, status {:#X}.", handle, (status & 0xFFFFFFFF)); return false; } diff --git a/client/src/util/util.h b/client/src/util/util.h index 8734bd9..0a1e17f 100644 --- a/client/src/util/util.h +++ b/client/src/util/util.h @@ -1,26 +1,13 @@ #pragma once #include "native.h" -#include "../injection/pe.h" namespace util { - - extern std::unordered_map<std::string, pe::virtual_image> loaded_modules; - std::string wide_to_multibyte(const std::wstring& str); std::wstring multibyte_to_wide(const std::string& str); - native::_PEB* cur_peb(); - - bool init(); - - static pe::virtual_image& ntdll() { - static pe::virtual_image nt{}; - if (!nt) { - nt = loaded_modules["ntdll.dll"]; - nt.parse_exports(); - } - return nt; + __forceinline native::_PEB* peb() { + return reinterpret_cast<native::_PEB*>(__readgsqword(0x60)); } bool close_handle(HANDLE handle); |