diff options
| author | auth12 <[email protected]> | 2020-07-27 09:46:17 -0700 |
|---|---|---|
| committer | auth12 <[email protected]> | 2020-07-27 09:46:17 -0700 |
| commit | a2e89fde1acc5b189c55e0b8b38146194e455cd0 (patch) | |
| tree | 1f130027975733e0704a583aebb1a1832a22ec11 /client/src/injection/process.cpp | |
| parent | Compile fix. (diff) | |
| download | loader-a2e89fde1acc5b189c55e0b8b38146194e455cd0.tar.xz loader-a2e89fde1acc5b189c55e0b8b38146194e455cd0.zip | |
Removed spdlog, using fmt wrapper instead.
More process class changes, support for 32/64bit processes.
Injection process improvements.
Other small changes.
Diffstat (limited to 'client/src/injection/process.cpp')
| -rw-r--r-- | client/src/injection/process.cpp | 422 |
1 files changed, 110 insertions, 312 deletions
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; } |