
![]() | Binlex: un marco Lexer de rasgo genético binario Si Maldevs piensa que su binario es FUD, están a punto de tener una crisis existencial. |
Binlex es una herramienta para analistas e investigadores de malware que extrae instrucciones , bloques básicos y funciones de archivos binarios y los organiza en una jerarquía estructurada de genomas , cromosomas , pares de alelos y genes . ?
Esta desglose jerárquica permite a Binlex analizar y comparar binarios de malware tratando su estructura de código como una "huella digital de ADN", lo que facilita la detección de patrones, similitudes y variaciones entre las muestras.
A diferencia de las herramientas que se basan en Python puro , ¿que puede ser lento?, Binlex está diseñado para la velocidad, la simplicidad y la flexibilidad. Su interfaz de línea de comandos ayuda a los analistas a buscar patrones en cientos o miles de muestras de malware , ahorrando tiempo ⏳ y recursos ?
Para los desarrolladores, Binlex ofrece una API de óxido y enlaces de pitón para construir herramientas de detección personalizadas con restricciones de licencia mínima. ?
Como parte de la lucha contra el malware, Binlex es de uso gratuito: solo descargue los binarios de la página de lanzamiento. ?
¡La última versión de Binlex proporciona las siguientes características sorprendentes!
| Característica | Descripción |
|---|---|
| Plataformas | - Windows? - macOS? - Linux? |
| Formatos | - PE - Macho - elfo |
| Arquitecturas | - AMD64 - i386 - CIL |
| ? Múltiple | - cola de desmontaje segura de hilo -? Herramientas multiproceso para la máxima eficiencia |
| Rendimiento personalizable | Activar las funciones/apagado para optimizar para su caso de uso |
| ? Compresión de cadena json | Guardar memoria con compresión JSON |
| ? Similitud hashing | -? Minhash - TLSH -? SHA256 |
| ? Símbolos de funciones | - Pase los símbolos de la función al binlex como entrada estándar usando BLPDB , BLELFSYM o BLMACHOSYM o sus propias herramientas |
| ? ️ Etiquetado | Etiquetado para una organización fácil |
| Comodín | ¡Perfecto para generar reglas de Yara y ahora a una resolución de bordes! |
| API | -? API de óxido -Api de pítigo |
| ? Características de aprendizaje automático | - Características normalizadas para consistencia -? Utilidad de escalador de funciones -? Filtrado de rasgos - Entrenamiento de muestra ONNX -? Clasificación de muestra |
| Imagen virtual | - Cache de mapeo eficiente para imágenes virtuales -? ️ Compatible con ZFS / BTRFS - acelera las tareas repetitivas y el filtrado - Velocidad de aligeramiento ⚡ |
Al almacenar en caché las imágenes virtuales, Binlex puede funcionar a mejores velocidades, lo que hace que la repetición funcione más rápido y más eficiente.
Para construir binlex necesitas óxido.
La instalación es recta Foward en Linux y MacOS.
cargo build --release cd src/bindings/python/
virtualenv -p python3 venv/
source venv/bin/activate
pip install maturin[patchelf]
maturin develop
python
>> import binlex Para construir paquetes para varias plataformas, use Makefile .
make zst # Make Arch Linux Package
make deb # Make Debian Package
make wheel # Make Python Wheel Los paquetes resultantes estarán en el target/ directorio.
Instalar el complemento IDA es fácil de instalar, solo asegúrese de instalar los enlaces de Python en el entorno Python para IDA.
Ahora copie el directorio para el complemento Binlex en su directorio de complementos.
mkdir -p ~ /.idapro/plugins/
cp -r scripts/plugins/ida/binlex/ ~ /.idapro/plugins/Una vez que abra Ida, debe ser recibido con el mensaje de bienvenida Binlex .

Utilizando el complemento IDA, tiene varias características que se proporcionan para ayudarlo con la redacción de reglas de Yara y el análisis de similitud.
Menú principal:
Menú contextual de desmoronamiento:
El patrón de copia y la función Hex de copia están destinadas a ayudar con las reglas de Yara y la copia de los hashes y el escaneo de similitud es para buscar datos similares.
Para comparar una base de datos con otra, use la función de exportación para exportar el archivo JSON, luego haga clic en Compare Functions , que pueblará una tabla una vez completada.
cargo docTambién puedes abrir los documentos.
cargo doc --openEn Binlex , se usa una jerarquía de términos inspirados en genéticos para describir y simbolizar la estructura y los rasgos del código binario. Esta terminología refleja las relaciones entre diferentes abstracciones y sus analogías genéticas:
Genoma : representa que cada objeto que se analiza, como una función o bloque. Encapsula toda la información, incluidos metadatos, cromosomas y otros atributos.
Cromosoma : representa los patrones o secuencias centrales extraídos de un bloque o función. Un cromosoma actúa como un plan para identificar las características clave del binario sin abordar la memoria como lo indican los comodines como los comodines ? , donde un solo comodín representa un solo gen.
AlelePair : una unidad dentro del cromosoma que consta de dos genes . Los pares de alelos son los bloques de construcción del cromosoma, que combinan genes en pares significativos.
Gen : la unidad más pequeña de información genética, que representa un solo mordisco de datos (medio byte).
La relación entre estas abstracciones se puede visualizar de la siguiente manera:
Genome (function / block)
└── Chromosome (pattern / sequence)
└── AllelePair (two genes / single byte / two nibbles)
└── Gene (single nibble)
{
"type" : " block " ,
"architecture" : " amd64 " ,
"address" : 6442934577 ,
"next" : null ,
"to" : [],
"edges" : 0 ,
"prologue" : false ,
"conditional" : false ,
"chromosome" : {
"pattern" : " 4c8b47??498bc0 " ,
"feature" : [ 4 , 12 , 8 , 11 , 4 , 7 , 4 , 9 , 8 , 11 , 12 , 0 ],
"entropy" : 2.2516291673878226 ,
"sha256" : " 1f227bf409b0d9fbc576e747de70139a48e42edec60a18fe1e6efdacb598f551 " ,
"minhash" : " 09b8b1ad1142924519f601854444c6c904a3063942cda4da445721dd0703f290208f3e32451bf5d52741e381a13f12f9142b5de21828a00b2cf90cf77948aac4138443c60bf77ec31199247042694ebb2e4e14a41369eddc7d9f84351be34bcf61458425383a03a55f80cbad420bb6e638550c15876fd0c6208da7b50816847e62d72b2c13a896f4849aa6a36188be1d4a5333865eab570e3939fab1359cbd16758f36fa290164d0259f83c07333df535b2e38f148298db255ac05612cae04d60bb0dd810a91b80a7df9615381e9dc242969dd052691d044287ac2992f9092fa0a75d970100d48362f62b58f7f1d9ec594babdf52f58180c30f4cfca142e76bf " ,
"tlsh" : null
},
"size" : 7 ,
"bytes" : " 4c8b4708498bc0 " ,
"functions" : {},
"number_of_instructions" : 3 ,
"entropy" : 2.5216406363433186 ,
"sha256" : " 84d4485bfd833565fdf41be46c1a499c859f0a5f04c8c99ea9c34404729fd999 " ,
"minhash" : " 20c995de6a15c8a524fa7e325a6e42b217b636ab03b00812732f877f4739eeee41d7dde92ceac73525e541f9091d8dc928f6425b84a6f44b3f01d17912ec6e8c6f913a760229f685088d2528447e40c768c06d680afe63cb219a1b77a097f679122804dd5a1b9d990aa2579e75f8ef201eeb20d5650da5660efa3a281983a37f28004f9f2a57af8f81728c7d1b02949609c7ad5a30125ff836d8cc3106f2531f306e679a11cabf992556802a3cb2a75a7fe3773e37e3d5ab107a23bf22754aee15a5f41056859b06120f86cb5d39071425855ec90628687741aa0402030d73e04bc60adb0bd2430560442c4309ae258517fc1605438c95485ac4c8621026a1bb " ,
"tlsh" : null ,
"contiguous" : true ,
"attributes" : [
{
"type" : " tag " ,
"value" : " corpus:malware "
},
{
"type" : " tag " ,
"value" : " malware:lummastealer "
},
{
"entropy" : 6.55061550644311 ,
"sha256" : " ec1426109420445df8e9799ac21a4c13364dc12229fb16197e428803bece1140 " ,
"size" : 725696 ,
"tlsh" : " T17AF48C12AF990595E9BBC23DD1974637FAB2B445232047CF426489BD0E1BBE4B73E381 " ,
"type" : " file "
}
]
}Dado este ejemplo del genoma JSON.
"4c8b47??498bc0""4c" o "8b""4" o "c"Usando la API binlex , es posible mutar estos cromosomas, sus pares y genes alelos para facilitar la programación genética.
La programación genética en este contexto puede tener varios beneficios, incluidos, entre otros::
La forma más sencilla de comenzar es con la línea de comandos, aprovechando una herramienta de filtrado JSON como jq .
El siguiente comando desmonta sample.dll con 16 subprocesos, los rasgos relevantes son los objetos JSON, uno por línea y se canalizan en jq para filtrar y embellecer.
Para ver qué opciones están disponibles al usar la línea de comandos binlex , use -h o --help .
A Binary Pattern Lexer
Version: 2.0.0
Usage: binlex [OPTIONS] --input < INPUT >
Options:
-i, --input < INPUT >
-o, --output < OUTPUT >
-a, --architecture < ARCHITECTURE > [amd64, i386, cil]
-c, --config < CONFIG >
-t, --threads < THREADS >
--tags < TAGS >
--minimal
-d, --debug
--enable-instructions
--enable-block-instructions
--disable-hashing
--disable-disassembler-sweep
--disable-heuristics
--enable-mmap-cache
--mmap-directory < MMAP_DIRECTORY >
-h, --help Print help
-V, --version Print version
Author: @c3rb3ru5d3d53cA continuación se proporciona un ejemplo simple de usar la línea de comandos.
binlex -i sample.dll --threads 16 | jq Tenga en cuenta que Binlex detectará el formato de archivo Fort Usted y actualmente admite formatos binarios PE , ELF y MACHO .
Tras su primera ejecución de Binlex , almacenará el archivo de configuración en su directorio de configuración en binlex/binlex.toml .
Este binlex encuentra el directorio de configuración predeterminado en función de su sistema operativo como se indica en la tabla a continuación para su configuración.
| Sistema operativo | Variable de entorno | Ejemplo de ruta de configuración binlex |
|---|---|---|
| Linux | $XDG_CONFIG_HOME o $HOME/.config | /home/alice/.config/binlex/binlex.toml |
| macosa | $HOME/Library/Application Support | /Users/Alice/Library/Application Support/binlex/binlex.toml |
| Windows | {FOLDERID_RoamingAppData} | C:UsersAliceAppDataRoamingbinlexbinlex.toml |
El nombre de configuración predeterminado binlex.toml para Binlex se proporciona a continuación.
[ general ]
threads = 16
minimal = false
debug = false
[ formats . file . hashing . sha256 ]
enabled = true
[ formats . file . hashing . tlsh ]
enabled = true
minimum_byte_size = 50
threshold = 200
[ formats . file . hashing . minhash ]
enabled = true
number_of_hashes = 64
shingle_size = 4
maximum_byte_size_enabled = false
maximum_byte_size = 50
seed = 0
threshold = 0.75
[ formats . file . heuristics . features ]
enabled = true
[ formats . file . heuristics . entropy ]
enabled = true
[ instructions ]
enabled = false
[ instructions . hashing . sha256 ]
enabled = true
[ instructions . hashing . tlsh ]
enabled = true
minimum_byte_size = 50
threshold = 200
[ instructions . hashing . minhash ]
enabled = true
number_of_hashes = 64
shingle_size = 4
maximum_byte_size_enabled = false
maximum_byte_size = 50
seed = 0
threshold = 0.75
[ instructions . heuristics . features ]
enabled = true
[ instructions . heuristics . entropy ]
enabled = true
[ blocks ]
enabled = true
[ blocks . instructions ]
enabled = false
[ blocks . hashing . sha256 ]
enabled = true
[ blocks . hashing . tlsh ]
enabled = true
minimum_byte_size = 50
threshold = 200
[ blocks . hashing . minhash ]
enabled = true
number_of_hashes = 64
shingle_size = 4
maximum_byte_size_enabled = false
maximum_byte_size = 50
seed = 0
threshold = 0.75
[ blocks . heuristics . features ]
enabled = true
[ blocks . heuristics . entropy ]
enabled = true
[ functions ]
enabled = true
[ functions . blocks ]
enabled = true
[ functions . hashing . sha256 ]
enabled = true
[ functions . hashing . tlsh ]
enabled = true
minimum_byte_size = 50
threshold = 200
[ functions . hashing . minhash ]
enabled = true
number_of_hashes = 64
shingle_size = 4
maximum_byte_size_enabled = false
maximum_byte_size = 50
seed = 0
threshold = 0.75
[ functions . heuristics . features ]
enabled = true
[ functions . heuristics . entropy ]
enabled = true
[ chromosomes . hashing . sha256 ]
enabled = true
[ chromosomes . hashing . tlsh ]
enabled = true
minimum_byte_size = 50
threshold = 200
[ chromosomes . hashing . minhash ]
enabled = true
number_of_hashes = 64
shingle_size = 4
maximum_byte_size_enabled = false
maximum_byte_size = 50
seed = 0
threshold = 0.75
[ chromosomes . heuristics . features ]
enabled = true
[ chromosomes . heuristics . entropy ]
enabled = true
[ chromosomes . homologues ]
enabled = true
maximum = 4
[ mmap ]
directory = " /tmp/binlex "
[ mmap . cache ]
enabled = false
[ disassembler . sweep ]
enabled = trueSi las opciones de línea de comandos no son suficientes, el archivo de configuración proporciona el control más granular de todas las opciones.
Si desea anular el archivo de configuración predeterminado y especificar otro archivo de configuración, use el parámetro de línea de comandos.
binlex -c config.toml -i sample.dllCuando ejecuta Binlex , utiliza el archivo de configuración y anula cualquier configuración cuando se utiliza el parámetro de línea de comandos respectivo.
Aquí hay un flujo de trabajo general que comienza con la fabricación de reglas de Yara, donde obtenemos 10 cuerdas Hex de Yara únicas de una muestra dada.
binlex -i sample.dll --threads 16 | jq -r ' select(.size >= 16 and .size <= 32 and .chromosome.pattern != null) | .chromosome.pattern ' | sort | uniq | head -10
016b ?? 8b4b ?? 8bc74c6bd858433b4c0b2c0f83c5 ??????
01835404 ???? c6836a0400 ???? 837e04 ??
03c04c8d05 ???????? 4863c8420fb60401460fb64401018942 ?? 85c074 ??
03c38bf0488d140033c9ff15 ???????? 488bd84885c075 ??
03c6488d55 ?? 41ffc58945a ? 41b804000000418bcce8b8fd01 ?? eb ??
03c6488d55 ?? 41ffc58945a ? 41b804000000418bcce8e3fb01 ?? eb ??
03f7488d05 ???????? 4883c310483bd87c ??
03fb4c8bc6498bd7498bcc448d0c7d04000000e89409 ???? 8bd84885f6
03fe448bc6488bd3418bcee8d8e501 ?? 85ed
03fe897c24 ?? 397c24 ?? 0f867301 ???? Para dar un paso más allá, puede ejecutarlo a través de la herramienta blyara para hacer una firma rápida de Yara.
binlex -i sample.dll --threads 16 | jq -r ' select(.size >= 16 and .size <= 32 and .chromosome.pattern != null) | .chromosome.pattern ' | sort | uniq | head -10 | blyara -n example
rule example {
strings:
$trait_0 = {016b ?? 8b4b ?? 8bc74c6bd858433b4c0b2c0f83c5 ?????? }
$trait_1 = {01835404 ???? c6836a0400 ???? 837e04 ?? }
$trait_2 = {03c04c8d05 ???????? 4863c8420fb60401460fb64401018942 ?? 85c074 ?? }
$trait_3 = {03c38bf0488d140033c9ff15 ???????? 488bd84885c075 ?? }
$trait_4 = {03c6488d55 ?? 41ffc58945a ? 41b804000000418bcce8b8fd01 ?? eb ?? }
$trait_5 = {03c6488d55 ?? 41ffc58945a ? 41b804000000418bcce8e3fb01 ?? eb ?? }
$trait_6 = {03f7488d05 ???????? 4883c310483bd87c ?? }
$trait_7 = {03fb4c8bc6498bd7498bcc448d0c7d04000000e89409 ???? 8bd84885f6}
$trait_8 = {03fe448bc6488bd3418bcee8d8e501 ?? 85ed}
$trait_9 = {03fe897c24 ?? 397c24 ?? 0f867301 ???? }
condition:
1 of them Para obtener resultados aún mejores si exportó los genomas utilizando el complemento Binlex IDA o por otro medio, puede filtrar para que se inicien los prefijos como mw:: , para malware , lo cual es bastante común.
cat dump.json | jq -r ' select(.type == "function" and .size > 32 and (.attributes[] | .type == "symbol" and (.name | startswith("mw::")))) | .blocks[] | select(.size > 32) | .chromosome.pattern ' | blyara -n example Para usar binlex con ghidra, use el script blghidra/blghidra.py en el directorio de scripts.
Para aprovechar los nombres de las funciones y las direcciones virtuales de sus proyectos Ghidra y proporcionarlos a Binlex , use el script analyzeHeadless en su directorio de instalación Ghidra .
./analyzeHeadless
< project-directory >
< project-name >
-process sample.dll
-noanalysis
-postscript blghidra.py 2> /dev/null | grep -P " ^{ " type " | binlex -i sample.dll Tenga en cuenta que analyzeHeadless imprime mensajes de registro en stdout y otra salida de registro a stderr , que no sirve de utilidad de interoperabilidad con otras utilidades de línea de comandos.
Como tal, para recopilar la salida del script debe filtrarse con 2>/dev/null | grep -P "^{"type" .
Para aprovechar el poder de la detección de funciones de rizin y el nombre de la función en binlex , ejecute rizin en su proyecto utilizando aflj para enumerar las funciones en formato JSON.
Luego, vaya esta salida a blrizin , que analiza rizin JSON a un formato de binlex que no sean.
Además, puede combinar esto con otras herramientas como blpdb para analizar los símbolos PDB para obtener direcciones y nombres de función.
Luego puede hacer cualquier análisis como generalmente usaría jq , en este ejemplo contamos las funciones procesadas por Binlex para ver si estamos detectando más de ellas.
rizin -c ' aaa;aflj; ' -q sample.dll |
blrizin |
blpdb -i sample.pdb |
binlex -i sample.dll |
jq ' select(.type == "function") | .address ' | wc -l Nota : En este momento, blrizin también es compatiable con la salida de radare2 usando blrizin .
Si desea hacer algo de aprendizaje automático, puede obtener características que representan los bocadillos sin dirigir la memoria de Binlex como este.
binlex -i sample.dll --threads 16 | jq -r -c ' select(.size >= 16 and .size <= 32 and .signature.feature != null)| .signature.feature ' | head -10
[4,9,8,11,12,0,4,1,11,9,0,3,0,0,1,15,0,0,4,5,3,3,12,0,8,5,13,2,4,8,8,11,13,0,4,1,0,15,9,5,12,0,4,8,15,15,2,5]
[4,4,8,11,5,1,4,5,3,3,12,0,3,3,12,0,4,8,8,3,12,1,3,0,4,1,0,15,10,3,12,2]
[4,8,8,3,14,12,4,12,8,11,12,10,4,4,8,9,4,4,2,4,11,2,0,1,4,4,0,15,11,7,12,1,8,10,12,10,14,8,5,11,4,8,8,3,12,4,12,3]
[4,8,8,3,14,12,4,4,8,9,4,4,2,4,4,12,8,11,12,10,4,4,0,15,11,7,12,1,11,2,0,1,3,3,12,9,14,8,0,11,4,8,8,3,12,4,12,3]
[4,0,5,3,4,8,8,3,14,12,15,15,1,5,8,11,12,8,8,11,13,8,15,15,1,5,8,11,12,3,4,8,8,3,12,4,5,11,12,3]
[11,9,2,0,0,3,15,14,7,15,4,8,8,11,8,11,0,4,2,5,4,8,0,15,10,15,12,1,4,8,12,1,14,8,1,8,12,3]
[8,11,0,12,2,5,11,8,2,0,0,3,15,14,7,15,4,8,12,1,14,1,2,0,4,8,8,11,4,8,12,1,14,0,0,8,4,8,15,7,14,1,4,8,8,11,12,2,12,3]
[4,8,8,11,0,5,4,8,8,5,12,0,7,5,12,3,4,8,15,15,2,5]
[4,8,8,11,0,13,3,3,12,0,3,8,8,1,11,0,0,8,0,15,9,5,12,0,12,3]
[4,8,8,11,0,5,4,8,8,5,12,0,7,5,12,3,4,8,15,15,2,5] Si desea refinar esto para su modelo de aprendizaje automático normalizándolos entre 0 y 1 valores de flotación, Binlex lo cubre con la herramienta blscaler .
binlex -i sample.dll --threads 16 | jq -r -c ' select(.size >= 16 and .size <= 32 and .signature.feature != null) ' | blscaler --threads 16 | jq -c -r ' .signature.feature ' | head -1
[0.26666666666666666,0.6,0.5333333333333333,0.7333333333333333,0.8,0.0,0.26666666666666666,0.06666666666666667,0.7333333333333333,0.6,0.0,0.2,0.0,0.0,0.06666666666666667,1.0,0.0,0.0,0.26666666666666666,0.3333333333333333,0.2,0.2,0.8,0.0,0.5333333333333333,0.3333333333333333,0.8666666666666667,0.13333333333333333,0.26666666666666666,0.5333333333333333,0.5333333333333333,0.7333333333333333,0.8666666666666667,0.0,0.26666666666666666,0.06666666666666667,0.0,1.0,0.6,0.3333333333333333,0.8,0.0,0.26666666666666666,0.5333333333333333,1.0,1.0,0.13333333333333333,0.3333333333333333]Para aprovechar la potente característica de FileMapping para reducir el uso de la memoria, pero aún así, a partir de imágenes virtuales.
# Install BTRFS
sudo pacman -S btrfs-progs compsize
# Enable the Kernel Module on Boot
echo " btrfs " | sudo tee /etc/modules-load.d/btrfs.conf
# Reboot
reboot
# Create Virtual Image Cache Storage Pool
dd if=/dev/zero of=btrfs.img bs=1M count=2048
# Make it BTRFS
mkfs.btrfs btrfs.img
# Make a Cache Directory in /tmp/
mkdir -p /tmp/binlex/
# Mount the Cache (Multiple Compression Options Available)
sudo mount -o compress=lzo btrfs.img /tmp/binlex/
# Run Binlex
binlex -i sample.dll --threads 16 --enable-file-mapping --file-mapping-directory /tmp/binlex/ --enable-file-mapping-cache
sudo compsize ec1426109420445df8e9799ac21a4c13364dc12229fb16197e428803bece1140
# Virtual Image 6GB vs Stored Size of 192MB
# Processed 1 file, 49156 regular extents (49156 refs), 0 inline.
# Type Perc Disk Usage Uncompressed Referenced
# TOTAL 3% 192M 6.0G 6.0G
# none 100% 384K 384K 384K
# lzo 3% 192M 6.0G 6.0G Esto puede establecer esto en disco o si /tmp/ directorio se asigna a RAM.
Cuando se asigna a RAM, estamos aprovechando el desmontaje de la imagen virtual, pero sin la penalización adicional de RAM, donde las tareas repetitivas casi se duplican en velocidad de procesamiento.
Dado que btrfs abstra el acceso al archivo asignado en el núcleo, podemos acceder a él, ya que lo haríamos con cualquier archivo asignado pero con el beneficio de la compresión.
Para ahorrar tiempo si elige esta opción, haga que el montaje del grupo btrfs ocurra en el arranque y haga que su archivo de configuración binlex esté configurado para preferir el almacenamiento en caché de la imagen virtual en el directorio del grupo montado. Este enfoque asegura que no deba confiar en los parámetros de la línea de comandos cada vez.
La Filophsia del Proyecto Binlex se centra en la seguridad, la simplicidad, la velocidad y la extensibilidad.
Parte de esto es proporcionar una API para que los desarrolladores escriban su propia detección y lógica de caza.
En este momento, Binlex proporciona ataduras de óxido y pitón.
El óxido, la API hace es fácil comenzar
use std :: process ;
use binlex :: Config ;
use binlex :: formats :: PE ;
use binlex :: disassemblers :: capstone :: Disassembler ;
use binlex :: controlflow :: Graph ;
// Get Default Configuration
let mut config = Config ( ) ;
// Use 16 Threads for Multi-Threaded Operations
config . general . threads = 16 ;
// Read PE File
let pe = PE . new ( "./sample.dll" , config )
. unwrap_or_else ( |error| {
eprintln ! ( "{}" , error ) ;
process :: exit ( 1 ) ;
} ) ;
// To check if DotNet PE use pe.is_dotnet()
// Get Memory Mapped File
let mapped_file = pe . image ( )
. unwrap_or_else ( |error| {
eprintln ! ( "{}" , error ) ;
process :: exit ( 1 )
} ) ;
// Get Mapped File Virtual Image
let image = mapped_file
. mmap ( )
. unwrap_or_else ( |error| {
eprintln ! ( "{}" , error ) ;
process :: exit ( 1 ) ;
} ) ;
// Create Disassembler
let disassembler = Disassembler ( pe . architecture ( ) , & image , pe . executable_virtual_address_ranges ( ) , config )
. unwrap_or_else ( |error| {
eprintln ! ( "{}" , error ) ;
process :: exit ( 1 ) ;
} ) ;
// Create Control Flow Graph
let cfg = Graph ( pe . architecture ( ) , config ) ;
// Disassemble Control Flow
disassembler . disassemble_controlflow ( pe . entrypoint_virtual_addresses ( ) , & mut cfg ) ; use std :: process ;
use binlex :: Config ;
use binlex :: formats :: PE ;
use binlex :: disassemblers :: custom :: cil :: Disassembler ;
use binlex :: controlflow :: Graph ;
// Get Default Configuration
let mut config = Config ( ) ;
// Use 16 Threads for Multi-Threaded Operations
config . general . threads = 16 ;
// Read PE File
let pe = PE . new ( "./sample.exe" , config )
. unwrap_or_else ( |error| {
eprintln ! ( "{}" , error ) ;
process :: exit ( 1 ) ;
} ) ;
// To check if DotNet PE use pe.is_dotnet()
// Get Memory Mapped File
let mapped_file = pe . image ( )
. unwrap_or_else ( |error| {
eprintln ! ( "{}" , error ) ;
process :: exit ( 1 )
} ) ;
// Get Mapped File Virtual Image
let image = mapped_file
. mmap ( )
. unwrap_or_else ( |error| {
eprintln ! ( "{}" , error ) ;
process :: exit ( 1 ) ;
} ) ;
// Create Disassembler
let disassembler = Disassembler ( pe . architecture ( ) , & image , pe . dotnet_metadata_token_virtual_addresses ( ) , pe . dotnet_executable_virtual_address_ranges ( ) , config )
. unwrap_or_else ( |error| {
eprintln ! ( "{}" , error ) ;
process :: exit ( 1 ) ;
} ) ;
// Create Control Flow Graph
let cfg = Graph ( pe . architecture ( ) , config ) ;
// Disassemble Control Flow
disassembler . disassemble_controlflow ( pe . dotnet_entrypoint_virtual_addresses ( ) , & mut cfg ) ; use std :: process ;
use binlex :: Config ;
use binlex :: formats :: ELF ;
use binlex :: disassemblers :: custom :: cil :: Disassembler ;
use binlex :: controlflow :: Graph ;
// Get Default Configuration
let mut config = Config ( ) ;
// Use 16 Threads for Multi-Threaded Operations
config . general . threads = 16 ;
// Read PE File
let elf = ELF . new ( "./sample.exe" , config )
. unwrap_or_else ( |error| {
eprintln ! ( "{}" , error ) ;
process :: exit ( 1 ) ;
} ) ;
// Get Memory Mapped File
let mapped_file = elf . image ( )
. unwrap_or_else ( |error| {
eprintln ! ( "{}" , error ) ;
process :: exit ( 1 )
} ) ;
// Get Mapped File Virtual Image
let image = mapped_file
. mmap ( )
. unwrap_or_else ( |error| {
eprintln ! ( "{}" , error ) ;
process :: exit ( 1 ) ;
} ) ;
// Create Disassembler
let disassembler = Disassembler ( elf . architecture ( ) , & image , elf . executable_virtual_address_ranges ( ) , config )
. unwrap_or_else ( |error| {
eprintln ! ( "{}" , error ) ;
process :: exit ( 1 ) ;
} ) ;
// Create Control Flow Graph
let cfg = Graph ( elf . architecture ( ) , config ) ;
// Disassemble Control Flow
disassembler . disassemble_controlflow ( elf . entrypoint_virtual_addresses ( ) , & mut cfg ) ; use std :: process ;
use binlex :: Config ;
use binlex :: formats :: MACHO ;
use binlex :: disassemblers :: custom :: cil :: Disassembler ;
use binlex :: controlflow :: Graph ;
// Get Default Configuration
let mut config = Config ( ) ;
// Use 16 Threads for Multi-Threaded Operations
config . general . threads = 16 ;
// Read PE File
let macho = MACHO . new ( "./sample.app" , config )
. unwrap_or_else ( |error| {
eprintln ! ( "{}" , error ) ;
process :: exit ( 1 ) ;
} ) ;
// Iterate the MACHO Fat Binary Slices
for index in macho . number_of_slices ( ) {
// Get Memory Mapped File
let mapped_file = macho . image ( index )
. unwrap_or_else ( |error| {
eprintln ! ( "{}" , error ) ;
process :: exit ( 1 )
} ) ;
// Get Mapped File Virtual Image
let image = mapped_file
. mmap ( )
. unwrap_or_else ( |error| {
eprintln ! ( "{}" , error ) ;
process :: exit ( 1 ) ;
} ) ;
// Create Disassembler
let disassembler = Disassembler ( macho . architecture ( index ) , & image , macho . executable_virtual_address_ranges ( index ) , config )
. unwrap_or_else ( |error| {
eprintln ! ( "{}" , error ) ;
process :: exit ( 1 ) ;
} ) ;
// Create Control Flow Graph
let cfg = Graph ( macho . architecture ( index ) , config ) ;
// Disassemble Control Flow
disassembler . disassemble_controlflow ( macho . entrypoints ( index ) , & mut cfg ) ;
} use binlex :: controlflow :: Instruction ;
use binlex :: controlflow :: Block ;
use binlex :: controlflow :: Function ;
for address in cfg . instructions . valid_addresses ( ) {
// Read Instruction from Control Flow
instruction = Instruction ( address , & cfg ) ;
// Print Instruction from Control Flow
instruction . print ( ) ;
}
for address in cfg . blocks . valid_addresses ( ) {
// Read Block from Control Flow
block = Block ( address , & cfg ) ;
// Print Block from Control Flow
block . print ( ) ;
}
for address in cfg . functions . valid_addresses ( ) {
// Read Function from Control Flow
function = Function ( address , & cfg ) ;
// Print Function from Control Flow
function . print ( ) ;
}La API Binlex Python ahora está diseñada para abstraer el desascado y el gráfico Controlflow.
Para desmontar una imagen mapeada de memoria PE, use los siguientes ejemplos.
Hay más ejemplos en los examples/python/ directorio.
from binlex . formats import PE
from binlex . disassemblers . capstone import Disassembler
from binlex . controlflow import Graph
from binlex import Config
# Get Default Configuration
config = Config ()
# Use 16 Threads for Multi-Threaded Operations
config . general . threads = 16
# Open the PE File
pe = PE ( './sample.exe' , config )
# To check if a DotNet PE use ps.is_dotnet()
# Get the Memory Mapped File
mapped_file = pe . image ()
# Get the Memory Map
image = mapped_file . as_memoryview ()
# Create Disassembler on Mapped PE Image and PE Architecture
disassembler = Disassembler ( pe . architecture (), image , pe . executable_virtual_address_ranges (), config )
# Create the Controlflow Graph
cfg = Graph ( pe . architecture (), config )
# Disassemble the PE Image Entrypoints Recursively
disassembler . disassemble_controlflow ( pe . entrypoint_virtual_addresses (), cfg ) from binlex . formats import PE
from binlex . disassemblers . custom . cil import Disassembler
from binlex . controlflow import Graph
from binlex import Config
# Get Default Configuration
config = Config ()
# Use 16 Threads for Multi-Threaded Operations
config . general . threads = 16
# Open the PE File
pe = PE ( './sample.exe' , config )
# To check if a DotNet PE use ps.is_dotnet()
# Get the Memory Mapped File
mapped_file = pe . image ()
# Get the Memory Map
image = mapped_file . as_memoryview ()
# Create Disassembler on Mapped PE Image and PE Architecture
disassembler = Disassembler ( pe . architecture (), image , pe . dotnet_metadata_token_virtual_addresses (), pe . dotnet_executable_virtual_address_ranges (), config )
# Create the Controlflow Graph
cfg = Graph ( pe . architecture (), config )
# Disassemble the PE Image Entrypoints Recursively
disassembler . disassemble_controlflow ( pe . dotnet_entrypoint_virtual_addresses (), cfg ) from binlex . formats import ELF
from binlex . disassemblers . capstone import Disassembler
from binlex . controlflow import Graph
from binlex import Config
# Get Default Configuration
config = Config ()
# Use 16 Threads for Multi-Threaded Operations
config . general . threads = 16
# Open the ELF File
elf = ELF ( './sample.so' , config )
# Get the Memory Mapped File
mapped_file = pe . image ()
# Get the Memory Map
image = mapped_file . as_memoryview ()
# Create Disassembler on Mapped ELF Image and ELF Architecture
disassembler = Disassembler ( elf . architecture (), image , elf . executable_virtual_address_ranges (), config )
# Create the Controlflow Graph
cfg = Graph ( elf . architecture (), config )
# Disassemble the PE Image Entrypoints Recursively
disassembler . disassemble_controlflow ( elf . entrypoint_virtual_addresses (), cfg ) from binlex . formats import MACHO
from binlex . disassemblers . capstone import Disassembler
from binlex . controlflow import Graph
from binlex import Config
# Get Default Configuration
config = Config ()
# Use 16 Threads for Multi-Threaded Operations
config . general . threads = 16
# Open the ELF File
macho = MACHO ( './sample.app' , config )
# MachO Fat Binary Can Support Multiple Architectures
for index in macho . number_of_slices ():
# Get the Memory Mapped File
mapped_file = macho . image ( index )
# Get the Memory Map
image = mapped_file . as_memoryview ()
# Create Disassembler on Mapped MACHO Image and MACHO Architecture
disassembler = Disassembler ( macho . architecture ( index ), image , macho . executable_virtual_address_ranges ( index ), config )
# Create the Controlflow Graph
cfg = Graph ( macho . architecture ( index ), config )
# Disassemble the MACHO Image Entrypoints Recursively
disassembler . disassemble_controlflow ( macho . entrypoints ( index ), cfg )A veces, tal vez es NESSARY analizar el gráfico de flujo de control de control generado.
En este caso, puede usar la siguiente técnica.
from binlex . controlflow import Instruction
from binlex . controlflow import Block
from binlex . controlflow import Function
# Iterate Valid Instructions
for address in cfg . instructions . valid_addresses ():
# Read Instruction from Control Flow
instruction = Instruction ( address , cfg )
# Print Instruction from Control Flow
instruction . print ()
# Iterate Valid Blocks
for address in cfg . blocks . valid_addresses ():
# Read Block from Control Flow
block = Block ( address , cfg )
# Print Block from Control Flow
block . print ()
# Iterate Valid Functions
for address in cfg . functions . valid_addresses ():
# Read Function from Control Flow
function = Function ( address , cfg )
# Print Function from Control Flow
function . print ()En lugar de analizar, puede acceder a las instrucciones, bloques y funciones más directamente.
for instruction in cfg . instructions ():
instruction . print ()
for block in cfg . blocks ():
block . print ()
for function in cfg . functions ():
function . print ()También es posible iterar de funciones a bloques, instrucciones, pares de alelos, a genes.
Esto representa pasar de la abstracción de nivel más alto a la abstracción más baja.
for function in cfg . functions ():
for block in function . blocks ():
for instruction in block . instructions ():
for allelepair in instruction . chromosome (). allelepairs ():
for gene in allelepair . genes ():
print ( gene )Una de las herramientas más poderosas que puede usar en Binlex es comparar funciones, bloques e instrucciones utilizando el hash de similitud.
Realizar estas comparaciones es tan simple como llamar al método compare .
for lhs in lhs_cfg . functions ():
for rhs in rhs_cfg . functions ():
similarity = lhs . compare ( rhs )
similarity . print ()
for lhs in lhs_cfg . blocks ():
for rhs in rhs_cfg . blocks ():
similarity = lhs . compare ( rhs )
similarity . print ()
for lhs in lhs_cfg . instructions ():
for rhs in rhs_cfg . instructions ():
similarity = lhs . compare ( rhs )
similarity . print ()Cualquier algoritmos de hash de similitud compatibles se calcualizará si están habilitados con su configuración.
Aunque puede ser un desafío, Binlex admite realizar análisis de similitud en funciones no contiguas utilizando su propio algoritmo para encontrar las mejores coincidencias de similitud.
Al menos el 75% o más de los datos de una función no contigua deben ser Hashable para producir un hash de similitud.
Cada instrucción, bloque y función o genoma tiene un cromosoma asociado a la que se puede acceder a través de la API.
Puede seguir estas abstracciones a los pares de alelos y sus respectivos genes.
# Iterate Block Chromosome
chromosome = block . chromosome ()
for allelepair in chromosome . allelepairs ():
for gene in allelepair . genes ()
gene . print ()
# Iterate Block Chromosome
chromosome = function . chromosome ()
for allelepair in chromosome . allelepairs ():
for gene in allelepair . genes ()
gene . print ()
# Iterate Block Chromosome
chromosome = function . chromosome ()
for allelepair in chromosome . allelepairs ():
for gene in allelepair . genes ()
gene . print ()Si está buscando realizar tareas de programación genética, también puede mutar cromosomas, alelo y genes y realizan un seguimiento de su propia cantidad de mutaciones.
chromosome = block . chromosome ()
chromosome . mutate ( 'deadbe?f' )
chromosome . number_of_mutations ()
chromosome . print ()
for allelepair in chromosome . allelepairs ():
allelepair . mutate ( 'dead' )
allelepair . number_of_mutations ()
allelepair . print ()
for gene in allelepair . genes ():
gene . mutate ( 'd' )
gene . number_of_mutations ()
gene . print ()Esto facilita las mutaciones con algoritmos genéticos que puede emplear para sus artículos de uso.
Si está utilizando binlex en una publicación de revista, o un modelo de IA de código abierto, use la siguiente cita.
@misc { binlex ,
author = { c3rb3ru5d3d53c } ,
title = { binlex: A Binary Genetic Trait Lexer Framework } ,
year = { 2024 } ,
note = { Available at url{https://github.com/c3rb3ru5d3d53c/binlex-rs} }
}Si el uso de binlex es para fines corporativos y personales, o para generar resultados que no son modelos de IA de código abierto, no se necesita cita.
Por ejemplo, si usa Binlex para crear reglas de Yara, no se necesita cita.
Esto garantiza que Binlex se mantenga relevante, pero también garantiza un uso corporativo y personal permisivo.