
Ferramenta de instrumentação estática de binários para executáveis Windows x64
O peafl64 é uma ferramenta de instrumentação estática para PEs x64 no Windows.
Instrumentação estática é a prática de editar arquivos executáveis e adicionar código em locais específicos deles.
A instrumentação adiciona código ao início de cada bloco básico no binário, registrando o fluxo de execução de uma forma compatível com AFL.
Isso nos permite fuzzar binários em modo de usuário (usando WinAFL) e em modo kernel (usando kAFL) sem acesso ao código-fonte deles.
Existem outras formas de fuzzar binários Windows; neste projeto optamos por focar em instrumentação estática porque é o método mais rápido.
Este projeto é baseado na ferramenta pe-afl de wmliang, com suporte adicional a x64.
O script de instrumentação requer uma saída de análise do IDA.
Para criá-la, execute o script ida_dumper.py fornecido no IDA.
O script requer IDA 7+ e python3.8+.
usage: pe_afl.py [-h] [-n] [-cb] [-tf] [-te THREAD_ENTRY] [-nt NTOSKRNL] [-e ENTRY] [-l ENLARGE] [-v] [-lf] pefile ida_dump
positional arguments:
pefile Target PE file for instrumentation
ida_dump dump.json from IDA (created by ida_dumper.py)
optional arguments:
-h, --help show this help message and exit
-n, --nop Instrument with NOPs for testing
-cb, --callback Instrument with a callback, which is in the helper driver that's written in C
-tf, --thread-filter Driver instrumentation that filters only on thread ID (must use "-te" with this option)
-te THREAD_ENTRY, --thread-entry THREAD_ENTRY
The address (RVA) of the thread's initialization function
-nt NTOSKRNL, --ntoskrnl NTOSKRNL
ntoskrnl.exe path for offset extraction (non-optional if instrumenting a driver)
-e ENTRY, --entry ENTRY
Inject code on entry point, ie. -e9090
-l ENLARGE, --enlarge ENLARGE
Enlarge factor for sections, default=4
-v, --verbose Print debug log
-lf, --logfile Print log to pe-afl64.log rather than stream
Instrumentando binário em modo de usuário com NOPs
PS pe-afl-64> python .\pe_afl.py -n C:\Work\cmd.exe C:\Work\cmd.exe.dump.json
[*] User-mode binary is being instrumented
[*] Single-thread instrument is on
[*] Preparing new sections
[*] Added section .text^
[*] Added section .cov
[*] Expanding relative jumps
[*] Expanded 3874 of 14353 branches
[*] Building address map
[*] Updating relative instructions
[*] Updating relocations...
[*] Updating Export table
[*] Updating load config
[*] Updating exception records
[*] Updating the PE headers
[*] Finalizing...
[*] Creating instrumented code
[*] Writing address mapping to C:\Work\cmd.exe.mapping.txt
[*] Updating jump tables
[*] Updated .text
...
[*] Removing temporary PE files
[*] Fixing PE checksum
[*] Instrumented binary saved to: C:\Work\cmd.instrumented.exe
Instrumentando binário em modo kernel com filtro por ID de processo
python .\pe_afl.py -l 6 -nt "C:\Work\ntoskrnl.exe" "C:\Work\driver.sys" "C:\Work\driver.sys.dump.json"
Instrumentando binário em modo kernel com filtro por ID de thread e saída detalhada
python .\pe_afl.py -v -tf -te 0x40000 -l 6 -nt "C:\Work\ntoskrnl.exe" "C:\Work\ntoskrnl.exe" "C:\Work\ntoskrnl.exe.dump.json"
Primeiro, você precisará verificar se sua máquina inicializa usando BIOS ou UEFI.
Para máquinas Hyper-V: máquinas Gen 1 são baseadas em BIOS, e as Gen 2 são baseadas em UEFI.
Se sua máquina é baseada em BIOS, então você precisa corrigir o winload.exe:
ImgpValidateImageHash nelamov eax, edi por xor eax, eax no último bloco de código da funçãobcdedit /set path \Windows\system32\winload2.exeSe sua máquina inicializa usando UEFI, use o utilitário EfiGuard para corrigir o winload.efi.
Referência rápida de comandos se estiver usando o Hyper-V Manager:
FS1:
cd EFI/Boot
Load EfiGuard.Dxe.efi
FS0:
\EFI\Boot\bootx64.efi
Em seguida, instrumente o driver de sua escolha. Para carregar um driver instrumentado em uma máquina Windows, ele deve ser assinado, e um certificado autoassinado é suficiente para atender às exigências do sistema operacional:
# In elevated powershell terminal
$c = New-SelfSignedCertificate -Type CodeSigningCert -KeyUsage DigitalSignature -Subject 'CN=Microsoft Windows, O=Microsoft Corporation, L=Redmond, S=Washington, C=US'
Set-AuthenticodeSignature .\driver.instrumented.sys -Certificate $c -Force
Se o driver que você instrumentou já é usado pelo sistema, use estes comandos (como administrador) para substituir o arquivo do driver:
set NAME=mydriver.sys
icacls %NAME% /save C:\windows\temp\%NAME%.icacls
takeown /F %NAME%
icacls %NAME% /grant Everyone:F
move %NAME% %NAME%.bak
move instrumented_driver.sys %NAME%
icacls . /restore C:\windows\temp\%NAME%.icacls
Em seguida, execute:
bcdedit /set recoveryenabled no
bcdedit /set nointegritychecks on
shutdown -t 0 -r
A integração com o WinAFL é feita compilando um harness usando os headers fornecidos.
Junto com os headers, há o example.c, que é um programa de exemplo que mostra como usá-los.
Os headers fornecidos são uma pequena modificação dos headers já fornecidos pelo WinAFL para integrar com
outra ferramenta de instrumentação estática de binários chamada Syzygy.
A forma como integramos com o kAFL é bem simples.
Normalmente, um harness do kAFL executa em uma máquina virtual e se comunica com o frontend do fuzzer usando "hypercalls" especiais.
Essas hypercalls dizem ao fuzzer para fazer muitas coisas, entre elas carregar dados de cobertura do IntelPT e analisá-los como um bitmap AFL.
Como o peafl64 torna o rastreamento IntelPT obsoleto, precisamos preparar uma maneira de transmitir os dados de cobertura ao fuzzer.
Portanto, expandimos o qemu e o kvm com "hypercalls" que permitem que o harness (em modo de usuário) que executa em uma VM envie os dados de cobertura coletados usando o driver auxiliar.
Isso é especificamente sobre a configuração no ESXi, mas deve ser relevante para outras plataformas de virtualização como AWS.
A configuração é bem simples:
install.sh qemu, execute install.sh qemu_sbiPara fuzzar usando kAFL e peafl64, precisamos configurar uma máquina de fuzzing:
Fora isso, fuzzar com nosso fork do kAFL é o mesmo que o fuzzing normal com o kAFL.