aboutsummaryrefslogtreecommitdiff
path: root/client/src
diff options
context:
space:
mode:
authorauth12 <[email protected]>2020-07-27 09:46:17 -0700
committerauth12 <[email protected]>2020-07-27 09:46:17 -0700
commita2e89fde1acc5b189c55e0b8b38146194e455cd0 (patch)
tree1f130027975733e0704a583aebb1a1832a22ec11 /client/src
parentCompile fix. (diff)
downloadloader-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.cpp12
-rw-r--r--client/src/client/client.h50
-rw-r--r--client/src/client/enc.cpp35
-rw-r--r--client/src/client/enc.h28
-rw-r--r--client/src/client/packet.h4
-rw-r--r--client/src/hwid/hwid.h10
-rw-r--r--client/src/include.h4
-rw-r--r--client/src/injection/mapper.cpp90
-rw-r--r--client/src/injection/mapper.h2
-rw-r--r--client/src/injection/pe.h44
-rw-r--r--client/src/injection/process.cpp422
-rw-r--r--client/src/injection/process.h257
-rw-r--r--client/src/main.cpp80
-rw-r--r--client/src/util/io.cpp12
-rw-r--r--client/src/util/io.h27
-rw-r--r--client/src/util/native.h94
-rw-r--r--client/src/util/syscalls.cpp23
-rw-r--r--client/src/util/syscalls.h5
-rw-r--r--client/src/util/util.cpp33
-rw-r--r--client/src/util/util.h17
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);