This repository contains the source code for an advanced implementation of the VEH² (Vectored Exception Handling²) technique. This tool functions as a sophisticated loader that can execute .NET assemblies directly from memory, while bypassing the Anti-Malware Scan Interface (AMSI) without patching the AmsiScanBuffer function.
- Patchless AMSI Bypass: Utilizes a double Vectored Exception Handler (VEH) setup to intercept and neutralize AMSI scans at runtime.
- .NET CLR Hosting: Hosts the Common Language Runtime (CLR) from a native C++ process, allowing it to load and manage .NET code.
- In-Memory Assembly Execution: Reads a target .NET assembly from disk into a memory buffer and executes it from there, avoiding direct execution from the file that resides on disk.
- Stealthy Module Loading: Forces
amsi.dllinto the process's address space by loading a sacrificial, embedded dummy assembly. This allows the tool to find theAmsiScanBufferaddress without making a potentially monitoredLoadLibrarycall.
-
CLR and AMSI Initialization:
- The program first hosts the .NET CLR.
- It then loads a tiny, embedded sacrificial .NET assembly from a byte array. The sole purpose of this action is to trigger the CLR to load
amsi.dllinto the process. - With
amsi.dllnow in memory, the program dynamically resolves the address ofAmsiScanBufferusingGetModuleHandle. - Two Vectored Exception Handlers (VEHs) are registered: VEH1 for
EXCEPTION_BREAKPOINTand VEH2 forEXCEPTION_SINGLE_STEP.
-
Arming the Bypass:
- The program intentionally triggers a breakpoint using
DebugBreak(). - This invokes VEH1, which sets a hardware breakpoint on the
AmsiScanBufferfunction's address by modifying the debug registers (Dr0-Dr7).
- The program intentionally triggers a breakpoint using
-
Triggering the Bypass:
- The user-specified .NET assembly is read from disk into a memory buffer.
- The program instructs the CLR to load this assembly from the memory buffer.
- As the CLR prepares to execute the code, it first attempts to scan the memory buffer for malicious content by calling
AmsiScanBuffer. - The instant the CPU tries to execute
AmsiScanBuffer, the hardware breakpoint is triggered, raising anEXCEPTION_SINGLE_STEP. - This exception invokes VEH2.
-
The Bypass Execution:
- Inside VEH2, the magic happens:
- The hardware breakpoint is cleared to prevent an infinite loop.
- The return value of
AmsiScanBuffer(in theRAXregister) is set toS_OK(0). - The
amsiResultparameter on the stack is set toAMSI_RESULT_CLEAN. - The instruction pointer (
RIP) is manipulated to skip the entireAmsiScanBufferfunction, jumping directly to its return address.
- Execution continues as if
AmsiScanBufferhad run and found nothing malicious. The user's assembly is then executed.
- Inside VEH2, the magic happens:
This method is considered "patchless" because it doesn't alter the code of AmsiScanBuffer itself, making it potentially stealthier than traditional patching techniques.
This project is configured to be built with the Microsoft Visual C++ compiler (cl.exe) and nmake. You will need to have the Visual Studio Build Tools or a full Visual Studio installation with the C++ toolchain.
Open a developer command prompt (like the "x64 Native Tools Command Prompt for VS") and run:
nmakeThis will create a build directory and place the VEH2_Release.exe executable inside it.
To remove all build artifacts, run:
nmake cleanExecute the compiled program, passing the path to the .NET assembly you wish to load as an argument.
.\build\VEH2_Release.exe C:\path\to\your\assembly.exeThe core bypass technique was described in detail by CrowdStrike: CrowdStrike Blog: Investigating the Threat of Patchless AMSI Bypass Attacks
