valak: asm arg1 fix, NT_SUCCESS i32, byte scan off-by-one, etw guids

This commit is contained in:
2026-07-18 09:30:00 +01:00
committed by JYenn
parent cc60a24d98
commit a1f467199f
17 changed files with 552 additions and 910 deletions
+14 -5
View File
@@ -12,11 +12,11 @@ ngl this is just for fun, im still running through the ziglings course etc tryin
## Why Zig over C
No CRT. C programs pull in the C Runtime Library which adds DLL imports to your IAT. Zig just calls the OS. Smaller binary, less for AV to see.
No CRT. C programs pull in the C Runtime Library which adds DLL imports to your IAT. Zig just calls the OS. Smaller binary, less for AV to see. [Zig ships its own libc, doesn't depend on it.](https://ziglang.org/learn/overview/)
Detection engines mostly know C, C++, Rust, Go.
Detection engines mostly know C, C++, Rust, Go. As of mid-2026, [only one confirmed APT-grade Zig implant exists (VoidLink, Chinese-affiliated).](https://research.checkpoint.com/2026/voidlink-the-cloud-native-malware-framework/)
Ghidra struggles with Zig binaries (open bug). IDA doesn't properly support it either. Makes reverse engineering harder.
[Ghidra struggles with Zig binaries (open bug).](https://github.com/NationalSecurityAgency/ghidra/issues/8694) IDA doesn't properly support it either. Makes reverse engineering harder.
Comptime makes sure struct layouts match the PE spec. Same low level control as C.
@@ -37,6 +37,11 @@ Every time Sliver would normally call `time.Sleep(interval)`, Valak runs this in
The callstack during sleep shows kernel32!BaseThreadInitThunk → ntdll!RtlUserThreadStart — what every legitimate Windows thread looks like. No gap, no zeroed return address.
Call `patch_amsi()` first, then `patch_etw()`. Both use DR0 on the current thread,
so the second call overwrites the first. AMSI is higher priority — one scan block
saves your whole process. ETW falls back to NtTraceControl which stops providers
at the kernel level without needing DR0.
## Evasion stack
| Technique | How |
@@ -44,15 +49,19 @@ The callstack during sleep shows kernel32!BaseThreadInitThunk → ntdll!RtlUserT
| ChaCha20 encrypted .text sleep | SystemFunction040/041 → NtDelayExecution + PAGE_NOACCESS |
| Synthetic callstack frames | kernel32!BaseThreadInitThunk → ntdll!RtlUserThreadStart |
| HWBP AMSI bypass | DR0 + VEH, no memory modified |
| HWBP ETW bypass | DR0 + VEH, no memory modified |
| ETW bypass | NtTraceControl on EDR GUIDs, fallback to HWBP on EtwEventWrite |
| FreshyCalls syscall extraction | ntdll export table sorted by RVA, immune to inline hooks |
| Indirect syscalls | Random gadget pool (64+ `syscall;ret` from ntdll .text) |
| Module stomping | .text overwrite into signed Microsoft DLL + PE header wipe |
| ntdll unhooking | Clean .text from \KnownDlls\ntdll.dll section object |
| Token theft | NtOpenProcess → NtOpenProcessToken → NtDuplicateToken |
| Memory wipe | @memset to zero on cleanup |
| CRT-free | No libc import, minimal IAT footprint |
## Build
```
cd evasion && zig build -Doptimize=ReleaseFast
cd evasion && zig build -Dtarget=x86_64-windows-gnu -Doptimize=ReleaseFast
# → zig-out/bin/valak.dll
```