From 733272ed4960324a20606fba1b7810412c06bac7 Mon Sep 17 00:00:00 2001 From: auth12 <67507608+auth12@users.noreply.github.com> Date: Tue, 28 Jul 2020 07:34:55 -0700 Subject: Process class redesign. --- client/src/injection/process.cpp | 222 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 211 insertions(+), 11 deletions(-) (limited to 'client/src/injection/process.cpp') 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("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("NtReadVirtualMemory"); + + ULONG read; + auto status = nt_read(m_handle, reinterpret_cast(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("NtWriteVirtualMemory"); + + ULONG wrote; + auto status = nt_write(m_handle, reinterpret_cast(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("NtFreeVirtualMemory"); + + SIZE_T win_size = size; + void* addr_cast = reinterpret_cast(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("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("NtCreateThreadEx"); + static auto nt_wait = g_syscalls.get("NtWaitForSingleObject"); + + HANDLE out; + auto status = nt_create(&out, THREAD_ALL_ACCESS, nullptr, m_handle, reinterpret_cast(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("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 +bool util::process::enum_modules() { + m_modules.clear(); + + static auto peb_addr = peb(); + + T ldr; + if (!read(peb_addr + offsetof(native::peb_t, Ldr), &ldr, sizeof(ldr))) { + return false; + } + + const auto list_head = ldr + offsetof(native::peb_ldr_data_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 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 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 +uintptr_t util::process::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 +uintptr_t util::process::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 nt{}; + constexpr bool is64 = sizeof(T) == sizeof(uint64_t); + native::nt_headers_t 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 +uintptr_t util::process::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 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 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(&remote_image[func.rva]) = addr; + *reinterpret_cast(&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; +template class util::process; + bool util::fetch_system_data(system_data_t& out) { static auto info = g_syscalls.get("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(uintptr_t(pi) + pi->NextEntryOffset); -- cgit v1.2.3