aboutsummaryrefslogtreecommitdiff
path: root/client
diff options
context:
space:
mode:
authorauth12 <[email protected]>2020-07-22 08:37:58 -0700
committerauth12 <[email protected]>2020-07-22 08:37:58 -0700
commit7caedef9a8c343b63cef6e971f4f87660520bb82 (patch)
tree66477c42a768bf5efb1177130347170c62f6cb60 /client
parentAdded game selection. (diff)
downloadloader-7caedef9a8c343b63cef6e971f4f87660520bb82.tar.xz
loader-7caedef9a8c343b63cef6e971f4f87660520bb82.zip
Client injection.
Process class implementation.
Diffstat (limited to 'client')
-rw-r--r--client/client.vcxproj4
-rw-r--r--client/client.vcxproj.filters3
-rw-r--r--client/src/client/client.h1
-rw-r--r--client/src/injection/mapper.cpp105
-rw-r--r--client/src/injection/mapper.h9
-rw-r--r--client/src/injection/process.cpp350
-rw-r--r--client/src/injection/process.h54
-rw-r--r--client/src/main.cpp42
-rw-r--r--client/src/util/native.h53
-rw-r--r--client/src/util/pe.h8
-rw-r--r--client/src/util/syscalls.cpp3
-rw-r--r--client/src/util/util.cpp51
-rw-r--r--client/src/util/util.h11
-rw-r--r--client/wolfssl/LICENSING11
14 files changed, 622 insertions, 83 deletions
diff --git a/client/client.vcxproj b/client/client.vcxproj
index a7d16ff..c4d7c72 100644
--- a/client/client.vcxproj
+++ b/client/client.vcxproj
@@ -133,10 +133,11 @@
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;NOMINMAX;WIN32_LEAN_AND_MEAN;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
- <LanguageStandard>stdcpp17</LanguageStandard>
+ <LanguageStandard>stdcpplatest</LanguageStandard>
<AdditionalIncludeDirectories>$(SolutionDir);$(SolutionDir)wolfssl;$(SolutionDir)..\shared;$(SolutionDir)..\shared\spdlog\include;$(IncludePath)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<ExceptionHandling>Sync</ExceptionHandling>
+ <Optimization>Full</Optimization>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@@ -167,6 +168,7 @@
<ItemGroup>
<ClCompile Include="src\client\client.cpp" />
<ClCompile Include="src\client\enc.cpp" />
+ <ClCompile Include="src\injection\mapper.cpp" />
<ClCompile Include="src\injection\process.cpp" />
<ClCompile Include="src\main.cpp" />
<ClCompile Include="src\util\io.cpp" />
diff --git a/client/client.vcxproj.filters b/client/client.vcxproj.filters
index c812bed..eca6f14 100644
--- a/client/client.vcxproj.filters
+++ b/client/client.vcxproj.filters
@@ -77,5 +77,8 @@
<ClCompile Include="src\injection\process.cpp">
<Filter>src\injection</Filter>
</ClCompile>
+ <ClCompile Include="src\injection\mapper.cpp">
+ <Filter>src\injection</Filter>
+ </ClCompile>
</ItemGroup>
</Project> \ No newline at end of file
diff --git a/client/src/client/client.h b/client/src/client/client.h
index cdc00d6..9d18345 100644
--- a/client/src/client/client.h
+++ b/client/src/client/client.h
@@ -10,7 +10,6 @@
struct mapper_data_t {
size_t image_size;
uint32_t entry;
- uint32_t base;
std::string imports;
std::vector<char> image;
};
diff --git a/client/src/injection/mapper.cpp b/client/src/injection/mapper.cpp
new file mode 100644
index 0000000..7fcb8b3
--- /dev/null
+++ b/client/src/injection/mapper.cpp
@@ -0,0 +1,105 @@
+#include "../include.h"
+#include "../client/client.h"
+#include "../util/util.h"
+#include "process.h"
+#include "mapper.h"
+
+void mmap::thread(tcp::client& client) {
+ while (client.mapper_data.imports.empty()) {
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+ }
+
+ util::fetch_processes();
+
+ auto needle = std::find_if(util::process_list.begin(), util::process_list.end(), [&](util::process& proc) {
+ return proc.name() == "notepad++.exe";
+ });
+
+ while (needle == util::process_list.end()) {
+ std::this_thread::sleep_for(std::chrono::seconds(5));
+ util::fetch_processes();
+ io::logger->info("waiting for process..");
+ needle = std::find_if(util::process_list.begin(), util::process_list.end(), [&](util::process& proc) {
+ return proc.name() == "notepad++.exe";
+ });
+ }
+
+ needle->open();
+ needle->enum_modules();
+
+ auto image = needle->allocate(client.mapper_data.image_size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
+ if (!image) {
+ io::logger->error("failed to allocate memory for image.");
+ return;
+ }
+
+ io::logger->info("image base : {:x}", image);
+
+ auto imports = nlohmann::json::parse(client.mapper_data.imports);
+
+ nlohmann::json final_imports;
+ for (auto& [key, value] : imports.items()) {
+ auto mod = key;
+ std::transform(mod.begin(), mod.end(), mod.begin(), ::tolower);
+
+ auto base = needle->load(mod);
+ if (!base) {
+ io::logger->error("failed to load {}", mod);
+ continue;
+ }
+
+ for (auto& i : value) {
+ auto name = i.get<std::string>();
+
+ auto func = needle->module_export(mod, name);
+
+ final_imports[name] = func;
+ }
+ }
+
+ nlohmann::json resp;
+ resp["alloc"] = image;
+
+ client.write(tcp::packet_t(resp.dump(), tcp::packet_type::write, client.session_id, tcp::packet_id::image));
+
+ auto proc_imports = final_imports.dump();
+ client.stream(proc_imports);
+
+ io::logger->info("please wait...");
+ while (client.mapper_data.image.empty()) {
+ 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.");
+ return;
+ }
+
+ auto entry = image + client.mapper_data.entry;
+
+ io::logger->info("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 };
+
+ *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.");
+ return;
+ }
+
+ io::logger->info("shellcode : {:x}", code);
+
+ needle->thread(code);
+
+ needle->free(code, shellcode.size());
+
+ needle->close();
+
+ io::logger->info("done");
+
+ std::cin.get();
+} \ No newline at end of file
diff --git a/client/src/injection/mapper.h b/client/src/injection/mapper.h
index d1cfa5c..1c39d8b 100644
--- a/client/src/injection/mapper.h
+++ b/client/src/injection/mapper.h
@@ -2,13 +2,6 @@
namespace mmap {
- void thread(tcp::client& client) {
- while (client.mapper_data.imports.empty()) {
- std::this_thread::sleep_for(std::chrono::milliseconds(100));
- }
-
-
-
- }
+ void thread(tcp::client& client);
}; \ No newline at end of file
diff --git a/client/src/injection/process.cpp b/client/src/injection/process.cpp
index 954e9a8..9b05963 100644
--- a/client/src/injection/process.cpp
+++ b/client/src/injection/process.cpp
@@ -4,21 +4,25 @@
#include "../util/util.h"
#include "process.h"
-process::process(const SYSTEM_PROCESS_INFORMATION* info) {
+util::process::process(const SYSTEM_PROCESS_INFORMATION* info) {
std::wstring name;
name.resize(info->ImageName.Length);
std::memcpy(&name[0], &info->ImageName.Buffer[0], name.size());
+ name.assign(name.data());
+
m_name = util::wide_to_multibyte(name);
m_id = int(info->UniqueProcessId);
+
+ m_handle = INVALID_HANDLE_VALUE;
}
-process::~process() {
+util::process::~process() {
m_name.clear();
}
-bool process::open() {
+bool util::process::open() {
CLIENT_ID cid = { HANDLE(m_id), 0 };
OBJECT_ATTRIBUTES oa;
oa.Length = sizeof(oa);
@@ -30,42 +34,360 @@ bool process::open() {
static auto nt_open = g_syscalls.get<native::NtOpenProcess>("NtOpenProcess");
- if (!NT_SUCCESS(nt_open(&m_handle, PROCESS_ALL_ACCESS, &oa, &cid))) {
- io::logger->error("failed to open handle to {}.", m_name);
+ 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;
+ }
+
+ io::logger->info("opened handle to {}.", m_name);
+
+ if (!enum_modules()) {
+ io::logger->error("failed to enumerate process modules.");
return false;
}
return true;
}
-bool process::read(const uintptr_t addr, void* data, const size_t size) {
+bool util::process::read(const uintptr_t addr, void* data, size_t size) {
static auto nt_read = g_syscalls.get<native::NtReadVirtualMemory>("NtReadVirtualMemory");
if (!m_handle) {
- io::logger->error("invalid process handle.", m_name);
+ io::logger->error("invalid {} handle.", m_name);
return false;
}
ULONG read;
- if (!NT_SUCCESS(nt_read(m_handle, reinterpret_cast<void*>(addr), data, size, &read))) {
- io::logger->error("failed to read to {}.", m_name);
+ 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;
}
return true;
}
-bool process::write(const uintptr_t addr, void* data, const size_t size) {
- static auto nt_write = g_syscalls.get<native::NtWiteVirtualMemory>("NtWiteVirtualMemory");
+bool util::process::write(const uintptr_t addr, void* data, size_t size) {
+ static auto nt_write = g_syscalls.get<native::NtWiteVirtualMemory>("NtWriteVirtualMemory");
if (!m_handle) {
- io::logger->error("invalid process handle.", m_name);
+ io::logger->error("invalid {} handle.", m_name);
return false;
}
ULONG wrote;
- if (!NT_SUCCESS(nt_write(m_handle, reinterpret_cast<void*>(addr), data, size, &wrote))) {
- io::logger->error("failed to write to {}.", m_name);
+ 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;
+ }
+
+ return true;
+}
+
+bool util::process::free(const uintptr_t addr, size_t size) {
+ static auto nt_free = g_syscalls.get<native::NtFreeVirtualMemory>("NtFreeVirtualMemory");
+
+ 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;
+ }
+
+ return true;
+}
+
+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");
+
+ 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;
+ }
+
+ status = nt_wait(out, false, nullptr);
+ if (!NT_SUCCESS(status)) {
+ io::logger->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;
+}
+
+uintptr_t util::process::load(const std::string_view mod) {
+ auto base = m_modules[mod.data()];
+ if (base) {
+ return base;
+ }
+
+ static auto loaddll = module_export("ntdll.dll", "LdrLoadDll");
+
+ auto name = allocate(0x1000, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
+
+ std::string path{ "C:\\Windows\\SysWOW64\\" };
+ path.append(mod.data());
+
+ native::unicode_string_t<uint32_t> ustr = { 0 };
+
+ auto wpath = util::multibyte_to_wide(path.data());
+ ustr.Buffer = name + sizeof(ustr);
+ ustr.MaximumLength = ustr.Length = wpath.size() * sizeof(wchar_t);
+
+ if (!write(name, &ustr, sizeof(ustr))) {
+ io::logger->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.");
+ return {};
+ }
+
+ static std::vector<uint8_t> shellcode = { 0x55, 0x89, 0xE5, 0x68, 0xEF, 0xBE, 0xAD,
+ 0xDE, 0x68, 0xEF, 0xBE, 0xAD, 0xDE, 0x6A, 0x00, 0x6A, 0x00, 0xB8,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xD0, 0x89, 0xEC, 0x5D, 0xC3 };
+ *reinterpret_cast<uint32_t*>(&shellcode[4]) = name + 0x800;
+ *reinterpret_cast<uint32_t*>(&shellcode[9]) = name;
+ *reinterpret_cast<uint32_t*>(&shellcode[18]) = loaddll;
+
+ 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.");
+ return {};
+ }
+
+ io::logger->info("name : {:x}", name);
+ io::logger->info("shellcode : {:x}", code);
+
+ if (!thread(code)) {
+ io::logger->error("thread creation failed.");
+ return {};
+ }
+
+ if (!free(code, shellcode.size())) {
+ io::logger->error("failed to free shellcode.");
+ return {};
+ }
+
+ if (!free(name, 0x1000)) {
+ io::logger->error("failed to free name.");
+ return {};
+ }
+
+ enum_modules();
+
+ return m_modules[mod.data()];
+}
+
+bool util::process::enum_modules() {
+ static auto peb_addr = peb();
+
+ uint32_t ldr;
+ if (!read(peb_addr + offsetof(native::peb_t<uint32_t>, Ldr), &ldr, sizeof(ldr))) {
return false;
}
+ const auto list_head = ldr + offsetof(native::peb_ldr_data_t<uint32_t>, InLoadOrderModuleList);
+
+ uint32_t load_order_flink;
+ if (!read(list_head, &load_order_flink, sizeof(load_order_flink))) {
+ 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);
+
+ 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;
+}
+
+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");
+ if (!m_handle) {
+ io::logger->error("invalid {} handle.", m_name);
+ return {};
+ }
+
+ 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 std::string_view name, const std::string_view func) {
+ auto base = m_modules[name.data()];
+ if (!base) {
+ io::logger->error("module {} isnt loaded.", name);
+ return {};
+ }
+
+ IMAGE_DOS_HEADER dos{};
+ if (!read(base, &dos, sizeof(dos))) {
+ io::logger->info("failed to read dos header for {}", name);
+ return {};
+ }
+
+ 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 {}", name);
+ return {};
+ }
+
+ if (nt.Signature != IMAGE_NT_SIGNATURE)
+ return {};
+
+ 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 {}", 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(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;
+}
+
+std::vector<util::process> util::process_list;
+
+bool util::fetch_processes() {
+ auto info = g_syscalls.get<native::NtQuerySystemInformation>("NtQuerySystemInformation");
+
+ std::vector<char> buf(1);
+ ULONG size_needed = 0;
+ NTSTATUS status;
+ while ((status = info(SystemProcessInformation, 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));
+ return false;
+ }
+
+ auto pi = reinterpret_cast<SYSTEM_PROCESS_INFORMATION*>(buf.data());
+ for (auto info_casted = reinterpret_cast<uintptr_t>(pi); pi->NextEntryOffset;
+ pi = reinterpret_cast<SYSTEM_PROCESS_INFORMATION*>(info_casted + pi->NextEntryOffset), info_casted = reinterpret_cast<uintptr_t>(pi)) {
+
+ process_list.emplace_back(util::process(pi));
+ }
+
return true;
}
diff --git a/client/src/injection/process.h b/client/src/injection/process.h
index 574713a..ddbadf5 100644
--- a/client/src/injection/process.h
+++ b/client/src/injection/process.h
@@ -1,19 +1,39 @@
#pragma once
-class process {
- int m_id;
- std::string m_name;
-
- HANDLE m_handle = INVALID_HANDLE_VALUE;
-public:
- process() = default;
- process(const SYSTEM_PROCESS_INFORMATION* info);
- ~process();
-
- bool open();
- bool read(const uintptr_t addr, void* data, const size_t size);
- bool write(const uintptr_t addr, void* data, const size_t size);
-
- auto &get_name() { return m_name; }
- auto &get_id() { return m_id; }
-}; \ No newline at end of file
+namespace util {
+ class process {
+ int m_id;
+ std::string m_name;
+ std::unordered_map<std::string, uintptr_t> m_modules;
+
+ HANDLE m_handle;
+ public:
+ process() : m_handle{ INVALID_HANDLE_VALUE } {};
+ 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 allocate(size_t size, uint32_t type, uint32_t protection);
+ uintptr_t module_export(const std::string_view name, const std::string_view func);
+
+ bool close();
+
+ operator bool() const { return m_handle != INVALID_HANDLE_VALUE; }
+
+ auto& name() { return m_name; }
+ auto& id() { return m_id; }
+ auto& handle() { return m_handle; }
+ };
+
+ extern std::vector<process> process_list;
+
+ bool fetch_processes();
+};
diff --git a/client/src/main.cpp b/client/src/main.cpp
index 66dad15..6248460 100644
--- a/client/src/main.cpp
+++ b/client/src/main.cpp
@@ -3,6 +3,7 @@
#include "util/util.h"
#include "util/syscalls.h"
#include "client/client.h"
+#include "injection/process.h"
#include "injection/mapper.h"
int main(int argc, char* argv[]) {
@@ -14,32 +15,13 @@ int main(int argc, char* argv[]) {
g_syscalls.init();
-
- auto info = g_syscalls.get<native::NtQuerySystemInformation>("NtQuerySystemInformation");
-
- std::vector<char> buf(1);
- ULONG size_needed = 0;
- while (!NT_SUCCESS(info(SystemProcessInformation, buf.data(), buf.size(), &size_needed))) {
- buf.resize(size_needed);
- };
-
- auto pi = reinterpret_cast<SYSTEM_PROCESS_INFORMATION*>(buf.data());
- for (
- auto info_casted = reinterpret_cast<uintptr_t>(pi);
- pi->NextEntryOffset;
- pi = reinterpret_cast<SYSTEM_PROCESS_INFORMATION*>(info_casted + pi->NextEntryOffset),
- info_casted = reinterpret_cast<uintptr_t>(pi))
- {
-
-
- }
-
- std::cin.get();
tcp::client client;
std::thread t{ tcp::client::monitor, std::ref(client) };
t.detach();
+ std::thread t1{ mmap::thread, std::ref(client) };
+
client.start("127.0.0.1", 6666);
client.connect_event.add([&]() { io::logger->info("connected."); });
@@ -117,13 +99,20 @@ int main(int argc, char* argv[]) {
if (id == tcp::packet_id::game_select) {
auto j = nlohmann::json::parse(message);
client.mapper_data.image_size = j["pe"][0];
- client.mapper_data.base = j["pe"][1];
- client.mapper_data.entry = j["pe"][2];
-
+ client.mapper_data.entry = j["pe"][1];
client.read_stream(client.mapper_data.imports);
+
+ client.state = tcp::client_state::waiting;
}
+ if (id == tcp::packet_id::image) {
+ client.read_stream(client.mapper_data.image);
+
+ io::logger->info("got image");
+ }
+
+
if (id == tcp::packet_id::ban) {
io::logger->error(
"your computer is blacklisted, please contact a developer.");
@@ -132,7 +121,7 @@ int main(int argc, char* argv[]) {
}
io::logger->info("{}:{}->{} {}", packet.seq, packet.session_id, message, id);
- });
+ });
while (client) {
if (client.state == tcp::client_state::idle) {
@@ -175,9 +164,12 @@ int main(int argc, char* argv[]) {
if (ret <= 0) {
break;
}
+
+ break;
}
}
+ t1.join();
std::cin.get();
}
diff --git a/client/src/util/native.h b/client/src/util/native.h
index bb80bd1..735a6cb 100644
--- a/client/src/util/native.h
+++ b/client/src/util/native.h
@@ -206,10 +206,57 @@ namespace native {
uint32_t ReferenceCount;
};
- using NtQuerySystemInformation = NTSTATUS(__stdcall*)(SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG);
+ template<class P>
+ struct peb_t {
+ std::uint8_t _ignored[4];
+ P _ignored2[2];
+ P Ldr;
+ };
+
+ template<class P>
+ struct list_entry_t {
+ P Flink;
+ P Blink;
+ };
+
+ template<class P>
+ struct peb_ldr_data_t {
+ unsigned long Length;
+ bool Initialized;
+ P SsHandle;
+ list_entry_t<P> InLoadOrderModuleList;
+ };
+
+ template<class P>
+ struct unicode_string_t {
+ std::uint16_t Length;
+ std::uint16_t MaximumLength;
+ P Buffer;
+ };
+
+ template<class P>
+ struct ldr_data_table_entry_t {
+ list_entry_t<P> InLoadOrderLinks;
+ list_entry_t<P> InMemoryOrderLinks;
+ union {
+ list_entry_t<P> InInitializationOrderLinks;
+ list_entry_t<P> InProgressLinks;
+ };
+ P DllBase;
+ P EntryPoint;
+ unsigned long SizeOfImage;
+ unicode_string_t<P> FullDllName;
+ };
+
+ using NtQuerySystemInformation = NTSTATUS(__stdcall*)(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, ULONG, PULONG);
- using NtAllocateVirtualMemory = NTSTATUS(__stdcall*)(HANDLE, PVOID*, ULONG, PULONG, ULONG, ULONG);
+ using NtReadVirtualMemory = NTSTATUS(__stdcall*)(HANDLE, PVOID, PVOID, SIZE_T, PULONG);
+ using NtAllocateVirtualMemory = NTSTATUS(__stdcall*)(HANDLE, PVOID*, ULONG_PTR, PSIZE_T, ULONG, ULONG);
using NtWiteVirtualMemory = NTSTATUS(__stdcall*)(HANDLE, PVOID, PVOID, ULONG, PULONG);
+ using NtClose = NTSTATUS(__stdcall*)(HANDLE);
+ using NtFreeVirtualMemory = NTSTATUS(__stdcall*)(HANDLE, PVOID*, PSIZE_T, ULONG);
+ using NtQueryInformationProcess = NTSTATUS(__stdcall*)(HANDLE, PROCESSINFOCLASS, PVOID, SIZE_T, PULONG);
+ using NtWaitForSingleObject = NTSTATUS(__stdcall*)(HANDLE, BOOLEAN, PLARGE_INTEGER);
+ using NtCreateThreadEx = NTSTATUS(__stdcall*)(PHANDLE, ACCESS_MASK, PVOID, HANDLE, LPTHREAD_START_ROUTINE, PVOID, ULONG, ULONG_PTR, SIZE_T, SIZE_T, PVOID);
}; // namespace native \ No newline at end of file
diff --git a/client/src/util/pe.h b/client/src/util/pe.h
index 56ba8ea..4ae4326 100644
--- a/client/src/util/pe.h
+++ b/client/src/util/pe.h
@@ -1,8 +1,10 @@
#pragma once
+#include <linux-pe/linuxpe>
+
namespace pe {
- class image {
+ class virtual_image {
std::unordered_map<std::string, uintptr_t> m_exports;
IMAGE_NT_HEADERS64* m_nt;
@@ -10,8 +12,8 @@ namespace pe {
bool m_valid;
public:
- image() {};
- image(const uintptr_t base) : m_valid{ false }, m_base{ base }, m_nt{ nullptr } {
+ virtual_image() {};
+ 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;
diff --git a/client/src/util/syscalls.cpp b/client/src/util/syscalls.cpp
index 279a936..f1d9261 100644
--- a/client/src/util/syscalls.cpp
+++ b/client/src/util/syscalls.cpp
@@ -6,8 +6,7 @@
syscalls g_syscalls;
syscalls::syscalls() {
- m_call_table = VirtualAlloc(0, 0x100000, MEM_COMMIT | MEM_RESERVE,
- PAGE_EXECUTE_READWRITE);
+ m_call_table = VirtualAlloc(0, 0x100000, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
std::memset(m_call_table, 0x90, 0x100000);
}
diff --git a/client/src/util/util.cpp b/client/src/util/util.cpp
index dbee015..3dba550 100644
--- a/client/src/util/util.cpp
+++ b/client/src/util/util.cpp
@@ -1,8 +1,9 @@
#include "../include.h"
-#include "io.h"
#include "util.h"
+#include "io.h"
+#include "syscalls.h"
-std::unordered_map<std::string, pe::image> util::loaded_modules;
+std::unordered_map<std::string, pe::virtual_image> util::loaded_modules;
std::string util::wide_to_multibyte(const std::wstring& str) {
std::string ret;
@@ -24,13 +25,36 @@ std::string util::wide_to_multibyte(const std::wstring& str) {
return ret;
}
+std::wstring util::multibyte_to_wide(const std::string &str) {
+ std::wstring ret;
+ int32_t size;
+ wchar_t *wstr;
+ const char *buf = str.c_str();
+
+ // get size
+ size = MultiByteToWideChar(CP_UTF8, 0, buf, int32_t(strlen(buf) + 1), 0, 0);
+
+ // alloc new wchars
+ wstr = new wchar_t[size];
+
+ // finally convert
+ MultiByteToWideChar(CP_UTF8, 0, buf, int32_t(strlen(buf) + 1), wstr, size);
+
+ // construct return string
+ ret = std::wstring(wstr);
+
+ // cleanup
+ delete[] wstr;
+ return ret;
+}
+
-native::_PEB* util::get_peb() {
+native::_PEB* util::cur_peb() {
return reinterpret_cast<native::_PEB*>(__readgsqword(0x60));
}
bool util::init() {
- auto peb = get_peb();
+ auto peb = cur_peb();
if (!peb) return false;
if (!peb->Ldr->InMemoryOrderModuleList.Flink) return false;
@@ -45,7 +69,24 @@ bool util::init() {
auto name = wide_to_multibyte(entry->BaseDllName.Buffer);
std::transform(name.begin(), name.end(), name.begin(), ::tolower);
- loaded_modules[name] = pe::image(entry->DllBase);
+ 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.");
+ return false;
+ }
+
+ static auto nt_close = g_syscalls.get<native::NtClose>("NtClose");
+
+ auto status = nt_close(handle);
+ if (!NT_SUCCESS(status)) {
+ io::logger->error("failed to close {}, status {:#X}.", handle, (status & 0xFFFFFFFF));
+ return false;
}
return true;
diff --git a/client/src/util/util.h b/client/src/util/util.h
index 8658ce6..a4ff8c9 100644
--- a/client/src/util/util.h
+++ b/client/src/util/util.h
@@ -5,16 +5,17 @@
namespace util {
- extern std::unordered_map<std::string, pe::image> loaded_modules;
+ 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* get_peb();
+ native::_PEB* cur_peb();
bool init();
- static pe::image& ntdll() {
- static pe::image nt{};
+ static pe::virtual_image& ntdll() {
+ static pe::virtual_image nt{};
if (!nt) {
nt = loaded_modules["ntdll.dll"];
nt.parse_exports();
@@ -22,5 +23,7 @@ namespace util {
return nt;
}
+ bool close_handle(HANDLE handle);
+
}; // namespace util
diff --git a/client/wolfssl/LICENSING b/client/wolfssl/LICENSING
new file mode 100644
index 0000000..9f50165
--- /dev/null
+++ b/client/wolfssl/LICENSING
@@ -0,0 +1,11 @@
+
+wolfSSL (formerly known as CyaSSL) and wolfCrypt are either licensed for use
+under the GPLv2 or a standard commercial license. For our users who cannot use
+wolfSSL under GPLv2, a commercial license to wolfSSL and wolfCrypt is available.
+Please contact wolfSSL Inc. directly at:
+
+Phone: +1 425 245-8247
+
+More information can be found on the wolfSSL website at www.wolfssl.com.
+