aboutsummaryrefslogtreecommitdiff
path: root/client/src/injection/process.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'client/src/injection/process.cpp')
-rw-r--r--client/src/injection/process.cpp222
1 files changed, 211 insertions, 11 deletions
diff --git a/client/src/injection/process.cpp b/client/src/injection/process.cpp
index 23a7e2f..38a676b 100644
--- a/client/src/injection/process.cpp
+++ b/client/src/injection/process.cpp
@@ -2,9 +2,200 @@
#include "../util/io.h"
#include "../util/util.h"
#include "../util/apiset.h"
+#include "../util/syscalls.h"
#include "process.h"
-uintptr_t util::process32::module_export(const uintptr_t base, const std::string_view func) {
+bool util::base_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;
+
+ 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 util::base_process::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 util::base_process::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 util::base_process::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 util::base_process::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 util::base_process::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 util::base_process::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 util::base_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::log_error("failed to allocate in {}, status {:#X}.", m_name, (status & 0xFFFFFFFF));
+ return {};
+ }
+
+ return uintptr_t(alloc);
+}
+
+template<typename T>
+bool util::process<T>::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;
+}
+
+template<typename T>
+uintptr_t util::process<T>::peb() {
+ constexpr 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;
+}
+
+template<typename T>
+uintptr_t util::process<T>::module_export(const uintptr_t base, const std::string_view func) {
if (!base) {
return {};
}
@@ -18,7 +209,8 @@ uintptr_t util::process32::module_export(const uintptr_t base, const std::string
if (dos.e_magic != IMAGE_DOS_SIGNATURE)
return {};
- native::nt_headers_t<false> nt{};
+ constexpr bool is64 = sizeof(T) == sizeof(uint64_t);
+ native::nt_headers_t<is64> nt{};
if (!read(base + dos.e_lfanew, &nt, sizeof(nt))) {
io::log_error("failed to read nt header for {}", m_name);
return {};
@@ -96,9 +288,12 @@ uintptr_t util::process32::module_export(const uintptr_t base, const std::string
return {};
}
-uintptr_t util::process32::map(const std::string_view module_name) {
- std::string mod{module_name};
- g_apiset(mod);
+template<typename T>
+uintptr_t util::process<T>::map(const std::string_view module_name) {
+ std::string mod{ module_name };
+ if (g_apiset(mod)) {
+ io::log("resolved {} -> {}", module_name, mod);
+ }
auto base = m_modules[mod];
if (base) {
@@ -107,7 +302,8 @@ uintptr_t util::process32::map(const std::string_view module_name) {
io::log("mapping {}", module_name);
- std::string path{"C:\\Windows\\SysWOW64\\"};
+ constexpr bool is64 = sizeof(T) == sizeof(uint64_t);
+ std::string path{ is64 ? "C:\\Windows\\System32\\" : "C:\\Windows\\SysWOW64\\" };
path.append(mod);
std::vector<char> local_image;
@@ -115,7 +311,7 @@ uintptr_t util::process32::map(const std::string_view module_name) {
return {};
}
- pe::image img(local_image);
+ pe::image<is64> img(local_image);
if (!img) {
io::log_error("failed to init image.");
@@ -132,11 +328,11 @@ uintptr_t util::process32::map(const std::string_view module_name) {
img.relocate(remote_image, base);
- for (auto &[mod, funcs] : img.imports()) {
- for (auto &func : funcs) {
+ for (auto& [mod, funcs] : img.imports()) {
+ for (auto& func : funcs) {
auto addr = module_export(map(mod), func.name);
//io::log("{}:{}->{:x}", mod, func.name, addr);
- *reinterpret_cast<uint32_t *>(&remote_image[func.rva]) = addr;
+ *reinterpret_cast<T*>(&remote_image[func.rva]) = addr;
}
}
@@ -152,6 +348,10 @@ uintptr_t util::process32::map(const std::string_view module_name) {
return base;
}
+// explicit template instantiation
+template class util::process<uint64_t>;
+template class util::process<uint32_t>;
+
bool util::fetch_system_data(system_data_t& out) {
static auto info = g_syscalls.get<native::NtQuerySystemInformation>("NtQuerySystemInformation");
@@ -180,7 +380,7 @@ bool util::fetch_system_data(system_data_t& out) {
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});
+ threads.emplace_back(thread_data_t{ int(dat.ClientId.UniqueProcess), uintptr_t(dat.ClientId.UniqueThread), dat.ThreadState });
}
pi = reinterpret_cast<SYSTEM_PROCESS_INFORMATION*>(uintptr_t(pi) + pi->NextEntryOffset);