From 813e464a2f7a6ebfe073b1cade577f9f803ae700 Mon Sep 17 00:00:00 2001 From: auth12 <67507608+auth12@users.noreply.github.com> Date: Tue, 6 Jul 2021 23:21:34 +0100 Subject: Replaced create thread with thread hijacking --- sysmap/src/main.cpp | 17 +++++-- sysmap/src/mapper/process.h | 114 +++++++++++++++++++++++++++++++++++++++----- sysmap/sysmap.vcxproj | 8 ++-- 3 files changed, 120 insertions(+), 19 deletions(-) diff --git a/sysmap/src/main.cpp b/sysmap/src/main.cpp index 4c73340..d775e6c 100644 --- a/sysmap/src/main.cpp +++ b/sysmap/src/main.cpp @@ -24,17 +24,20 @@ int main(int argc, char* argv[]) { if (args.size() < 2) { io::log("Invalid arguments specified."); + std::cin.get(); + return 0; } - spdlog::set_pattern("[%^%l%$] %v"); - for (auto& arg : args) { if (arg == "--debug") { spdlog::set_level(spdlog::level::debug); } } + spdlog::set_pattern("[%^%l%$] %v"); + spdlog::set_level(spdlog::level::debug); + g_ctx.local_modules = std::move(util::get_modules()); auto ntdll = g_ctx.local_modules[1]; @@ -45,13 +48,21 @@ int main(int argc, char* argv[]) { io::log("waiting for {}", args[0]); + auto buf = io::read_file(args[1]); + if (buf.empty()) { + io::log("failed to read file."); + std::cin.get(); + + return 0; + } + process::process_x64_t proc; if (NT_SUCCESS(proc.attach(args[0]))) { io::log("attached!"); proc.modules = proc.get_modules(); - proc.map(io::read_file(args[1])); + proc.map(buf); proc.close(proc.handle); } diff --git a/sysmap/src/mapper/process.h b/sysmap/src/mapper/process.h index 9d6da35..ba37585 100644 --- a/sysmap/src/mapper/process.h +++ b/sysmap/src/mapper/process.h @@ -2,9 +2,60 @@ namespace process { + struct thread_t { + SYSTEM_THREAD_INFORMATION info; + HANDLE handle; + + NTSTATUS open() { + static auto nt_open_thread = g_syscalls.get("NtOpenThread"); + CLIENT_ID cid; + cid.UniqueProcess = 0; + cid.UniqueThread = info.ClientId.UniqueThread; + + OBJECT_ATTRIBUTES oa; + oa.Length = sizeof(oa); + oa.Attributes = 0; + oa.RootDirectory = 0; + oa.SecurityDescriptor = 0; + oa.ObjectName = 0; + oa.SecurityQualityOfService = 0; + + auto ret = nt_open_thread(&handle, THREAD_ALL_ACCESS, &oa, &cid); + + io::log("NtOpenThread on {}, returned {:x}.", uintptr_t(cid.UniqueThread), ret & 0xFFFFFFFF); + + return ret; + } + + NTSTATUS suspend() { + static auto nt_suspend = g_syscalls.get("NtSuspendThread"); + + return nt_suspend(handle, nullptr); + } + + NTSTATUS resume() { + static auto nt_resume = g_syscalls.get("NtResumeThread"); + + return nt_resume(handle, nullptr); + } + + NTSTATUS get_ctx(CONTEXT* out) { + static auto nt_get_ctx = g_syscalls.get("NtGetContextThread"); + + return nt_get_ctx(handle, out); + } + + NTSTATUS set_ctx(CONTEXT *ctx) { + static auto nt_set_ctx = g_syscalls.get("NtSetContextThread"); + + return nt_set_ctx(handle, ctx); + } + }; + struct process_info_t { std::string name; u16 pid; + std::vector threads; }; struct process_iterator { @@ -49,7 +100,19 @@ namespace process { continue; } - out.emplace_back(process_info_t{ util::to_multibyte(s), reinterpret_cast(pi->UniqueProcessId) }); + process_info_t ret; + ret.name = util::to_multibyte(s); + ret.pid = PtrToUshort(pi->UniqueProcessId); + + auto ti = reinterpret_cast(pi->Threads); + for (int i = 0; i < pi->NumberOfThreads; i++) { + thread_t t; + std::memcpy(&t.info, &ti[i], sizeof(SYSTEM_THREAD_INFORMATION)); + + ret.threads.emplace_back(t); + } + + out.emplace_back(std::move(ret)); ptr = iter.get_next(); } @@ -63,9 +126,12 @@ namespace process { std::vector modules; - NTSTATUS open_handle() { + NTSTATUS open() { static auto nt_open = g_syscalls.get("NtOpenProcess"); - CLIENT_ID cid = { HANDLE(info.pid), 0 }; + CLIENT_ID cid; + cid.UniqueProcess = HANDLE(info.pid); + cid.UniqueThread = 0; + OBJECT_ATTRIBUTES oa; oa.Length = sizeof(oa); oa.Attributes = 0; @@ -99,7 +165,7 @@ namespace process { info = *it; - return open_handle(); + return open(); } NTSTATUS read(uintptr_t addr, void* buf, size_t size) { @@ -160,7 +226,7 @@ namespace process { return nt_create(out, THREAD_ALL_ACCESS, nullptr, handle, reinterpret_cast(start), 0, 0x4, 0, 0, 0, 0); } - NTSTATUS wait(HANDLE h) { + static NTSTATUS wait(HANDLE h) { static auto nt_wait = g_syscalls.get("NtWaitForSingleObject"); return nt_wait(h, false, nullptr); @@ -446,12 +512,14 @@ namespace process { return {}; } - static std::vector shellcode = { 0x48, 0x83, 0xEC, 0x28, 0x48, 0xB9, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x48, 0xC7, 0xC2,0x01, 0x00, 0x00, 0x00, 0x4D, 0x31, 0xC0, - 0x48, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xD0, 0x48, 0x83, 0xC4, 0x28, 0xC3 }; + std::vector shellcode = { 0x9C, 0x50, 0x53, 0x51, 0x52, 0x55, 0x56, 0x57, 0x41, 0x50, 0x41, 0x51, 0x41, 0x52, 0x41, 0x53, 0x41, 0x54, 0x41, 0x55, 0x41, 0x56, 0x41, 0x57, 0x48, 0x83, 0xEC, + 0x28, 0x48, 0xB9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0xC7, 0xC2, 0x01, 0x00, 0x00, 0x00, 0x4D, 0x31, 0xC0, 0x48, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, + 0xD0, 0x48, 0x83, 0xC4, 0x28, 0x41, 0x5F, 0x41, 0x5E, 0x41, 0x5D, 0x41, 0x5C, 0x41, 0x5B, 0x41, 0x5A, 0x41, 0x59, 0x41, 0x58, 0x5F, 0x5E, 0x5D, 0x5A, 0x59, 0x5B, 0x58, 0x9D, 0xc3 }; + + *reinterpret_cast(&shellcode[30]) = allocation_base; + *reinterpret_cast(&shellcode[50]) = allocation_base + nt->optional_header.entry_point - headers_size; - *reinterpret_cast(&shellcode[6]) = allocation_base; - *reinterpret_cast(&shellcode[26]) = allocation_base + nt->optional_header.entry_point - headers_size; + io::log("entry {:x}", allocation_base + nt->optional_header.entry_point - headers_size); uintptr_t shellcode_base; alloc(&shellcode_base, shellcode.size(), MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); @@ -460,9 +528,29 @@ namespace process { write(shellcode_base, shellcode.data(), shellcode.size()); - HANDLE thread_handle; - create_thread(shellcode_base, &thread_handle); - wait(thread_handle); + for (auto& t : info.threads) { + if (t.info.ThreadState == Waiting) { + io::log("found viable thread {}, hijacking...", uintptr_t(t.info.ClientId.UniqueThread)); + + CONTEXT ctx; + ctx.ContextFlags = CONTEXT_FULL; + + t.open(); + t.suspend(); + t.get_ctx(&ctx); + + io::log("thread RIP: {:x}", ctx.Rip); + io::log("thread stack pointer: {:x}", ctx.Rsp); + + ctx.Rip = shellcode_base; + + t.set_ctx(&ctx); + t.resume(); + + close(t.handle); + break; + } + } io::log("mapped target image"); diff --git a/sysmap/sysmap.vcxproj b/sysmap/sysmap.vcxproj index a42f5d0..dc6b77d 100644 --- a/sysmap/sysmap.vcxproj +++ b/sysmap/sysmap.vcxproj @@ -81,9 +81,10 @@ false - $(SolutionDir)bin\$(Platform)\$(Configuration)\ - obj\$(Platform)\$(Configuration)\ + $(SolutionDir)bin\$(Configuration)\$(Platform)\ + obj\$(Configuration)\$(Platform)\ $(SolutionDir)modules\phnt\;$(SolutionDir)modules\linuxpe\includes\;$(SolutionDir)modules\spdlog\include\;$(IncludePath) + $(LibraryPath) @@ -141,7 +142,8 @@ true true true - RequireAdministrator + AsInvoker + %(AdditionalDependencies) -- cgit v1.2.3