
Herramienta de instrumentación binaria estática para ejecutables de Windows x64
peafl64 es una herramienta de instrumentación estática para PE x64 en Windows.
La instrumentación estática consiste en editar archivos ejecutables y añadir código en ubicaciones específicas de los mismos.
La instrumentación añade código al inicio de cada bloque básico del binario, registrando el flujo de ejecución de forma compatible con AFL.
Nos permite hacer fuzzing de binarios en modo usuario (con WinAFL) y en modo kernel (con kAFL) sin acceso a su código fuente.
Existen otras formas de hacer fuzzing sobre binarios de Windows; en este proyecto decidimos centrarnos en la instrumentación estática porque es el método más rápido.
Este proyecto se basa en la herramienta pe-afl de wmliang, con soporte añadido para x64.
El script de instrumentación requiere un análisis de IDA como entrada.
Para crearlo, ejecuta el script ida_dumper.py proporcionado en IDA.
El script requiere IDA 7+ y 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 un binario en modo usuario con 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 un binario en modo kernel con filtrado por ID de proceso
python .\pe_afl.py -l 6 -nt "C:\Work\ntoskrnl.exe" "C:\Work\driver.sys" "C:\Work\driver.sys.dump.json"
Instrumentando un binario en modo kernel con filtrado por ID de hilo y salida detallada
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"
Primero tendrás que comprobar si tu máquina arranca con BIOS o UEFI.
Para máquinas Hyper-V: las máquinas de Gen 1 están basadas en BIOS y las de Gen 2 en UEFI.
Si tu máquina está basada en BIOS, necesitas parchear winload.exe:
ImgpValidateImageHash en ellamov eax, edi por xor eax, eax en el último bloque de código de la funciónbcdedit /set path \Windows\system32\winload2.exeSi tu máquina arranca con UEFI, usa la utilidad EfiGuard para parchear winload.efi.
Hoja de referencia de comandos si usas Hyper-V Manager:
FS1:
cd EFI/Boot
Load EfiGuard.Dxe.efi
FS0:
\EFI\Boot\bootx64.efi
A continuación, instrumenta el controlador que elijas. Para cargar un controlador instrumentado en una máquina Windows debe estar firmado, y un certificado de autofirma es suficiente para cumplir los requisitos del sistema operativo:
# 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
Si el controlador que instrumentaste ya es utilizado por el sistema, usa estos comandos (como administrador) para reemplazar el archivo del controlador:
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
Después ejecuta:
bcdedit /set recoveryenabled no
bcdedit /set nointegritychecks on
shutdown -t 0 -r
La integración con WinAFL se realiza compilando un harness con las cabeceras proporcionadas.
Junto a las cabeceras se incluye example.c, un programa de ejemplo que muestra cómo usarlas.
Las cabeceras proporcionadas son una ligera modificación de las que ya incluye WinAFL para integrarse con
otra herramienta de instrumentación estática de binarios llamada Syzygy.
La forma en que nos integramos con kAFL es bastante sencilla.
Normalmente, un harness de kAFL se ejecuta en una máquina virtual y se comunica con el frontend del fuzzer mediante "hypercalls" especiales.
Estas hypercalls le indican al fuzzer que haga muchas cosas, entre ellas cargar los datos de cobertura de IntelPT y parsearlos como un bitmap de AFL.
Debido a que peafl64 hace obsoleto el rastreo con IntelPT, debemos preparar una forma de transmitir los datos de cobertura al fuzzer.
Por lo tanto, ampliamos qemu y kvm con "hypercalls" que permiten que el harness (en modo usuario) que se ejecuta en una VM envíe los datos de cobertura que recopiló mediante el controlador auxiliar.
Esto se refiere específicamente a la configuración en ESXi, pero debería ser relevante para otras plataformas de virtualización como AWS.
La configuración es bastante sencilla:
install.sh qemu, ejecuta install.sh qemu_sbi