
![]() | Binlex - un cadre de trait génétique binaire Lexer Si Maldevs pense que leur binaire est FUD, ils sont sur le point d'avoir une crise existentielle. |
Binlex est un outil pour les analystes et les chercheurs de logiciels malveillants qui extrait les instructions , les blocs de base et les fonctions des fichiers binaires et les organise en une hiérarchie structurée de génomes , de chromosomes , de paires d'allèles et de gènes . ??
Cette dégradation hiérarchique permet à Binlex d'analyser et de comparer les binaires de logiciels malveillants en traitant leur structure de code comme une "empreinte digitale d'ADN", ce qui facilite la détection des modèles, des similitudes et des variations entre les échantillons.
Contrairement aux outils reposant sur Pure Python , qui peut être lent?, Binlex est conçu pour la vitesse, la simplicité et la flexibilité. Son interface de ligne de commande aide les analystes à rechercher des modèles sur des centaines ou des milliers d'échantillons de logiciels malveillants , en gagnant du temps ⏳ et des ressources ?.
Pour les développeurs, Binlex propose une API de rouille et des liaisons Python pour créer des outils de détection personnalisés avec un minimum de restrictions de licence. ?
Dans le cadre de la lutte contre les logiciels malveillants, Binlex est libre à utiliser - téléchargez simplement les binaires à partir de la page de version. ?
La dernière version de Binlex offre les fonctionnalités incroyables suivantes!
| Fonctionnalité | Description |
|---|---|
| Plates-formes | - Windows? - macOS? - Linux? |
| Formats | - pe - Macho - elfe |
| Architectures | - AMD64 - i386 - CIL |
| ? Multi-threading | - File d'attente -? Outillage multithread pour une efficacité maximale |
| Performances personnalisables | Basculer les fonctionnalités actives pour optimiser votre cas d'utilisation |
| ? Compression de chaîne JSON | Enregistrer la mémoire avec la compression JSON |
| ? Hachage de similitude | -? Minhash - Tlsh -? Sha256 |
| ? Symboles de fonction | - Passez des symboles de fonction à Binlex comme entrée standard à l'aide de BLPDB , BellfSym ou Blmachosym ou votre propre outillage |
| ? Taging | Taging pour une organisation facile |
| Farouche | Parfait pour générer des règles Yara et maintenant à une résolution de Grinbbles! |
| API | -? API Rust -PIP API |
| ? Caractéristiques d'apprentissage automatique | - Caractéristiques normalisées pour la cohérence -? Utilitaire Scaleur de fonctionnalités -? Filtrage de traits - Formation sur l'échantillon ONNX -? Classification des échantillons |
| Imagerie virtuelle | - Cache de cartographie efficace pour les images virtuelles -? ️ compatible avec ZFS / BTRFS - accélère les tâches répétitives et le filtrage - Vitesse d'éclair ⚡ |
En mettant en cache des images virtuelles, Binlex est capable de fonctionner à de meilleures vitesses, ce qui rend les répétitions plus rapides et plus efficaces.
Pour construire le binlex, vous avez besoin de rouille.
L'installation est droite Foward sur Linux et 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 Pour créer des packages pour diverses plates-formes, utilisez le Makefile .
make zst # Make Arch Linux Package
make deb # Make Debian Package
make wheel # Make Python Wheel Les packages résultants seront dans la target/ répertoire.
L'installation du plugin IDA est facile à installer, assurez-vous simplement d'installer les liaisons Python dans l'environnement Python pour IDA.
Copiez maintenant le répertoire du plugin Binlex dans votre répertoire de plugin.
mkdir -p ~ /.idapro/plugins/
cp -r scripts/plugins/ida/binlex/ ~ /.idapro/plugins/Une fois que vous avez ouvert IDA, vous devez être accueilli avec le message de bienvenue binlex .

En utilisant le plugin IDA, vous disposez de diverses fonctionnalités qui sont fournies pour vous aider avec la rédaction des règles YARA et l'analyse de similitude.
Menu principal:
Menu contextuel de démontrant:
La fonction de copie et de copie hexadécimale est destinée à aider avec les règles YARA et la copie des hachages de similitude et de la numérisation consiste à chasser des données similaires.
Pour comparer une base de données avec une autre, utilisez la fonction d'exportation pour exporter le fichier JSON, puis cliquez sur Compare Functions , qui remplira un tableau une fois terminé.
cargo docVous pouvez également ouvrir les documents.
cargo doc --openDans Binlex , une hiérarchie de termes d'inspiration génétique est utilisée pour décrire et symboliser la structure et les traits du code binaire. Cette terminologie reflète les relations entre différentes abstractions et leurs analogies génétiques:
Génome : représente chaque objet analysé, comme une fonction ou un bloc. Il résume toutes les informations, y compris les métadonnées, les chromosomes et d'autres attributs.
Chromosome : représente les modèles ou séquences de noyau extraits d'un bloc ou d'une fonction. Un chromosome agit comme le plan pour identifier les caractéristiques clés du binaire sans adressage de la mémoire comme indiqué par les caractères génériques ? , où un seul wildcard représente un seul gène.
Allelepair : une unité dans le chromosome composée de deux gènes . Les paires d'allèles sont les éléments constitutifs du chromosome, combinant des gènes en paires significatives.
Gene : la plus petite unité d'informations génétiques, représentant une seule grignotage de données (demi-octet).
La relation entre ces abstractions peut être visualisée comme suit:
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 "
}
]
}Compte tenu de cet exemple de génome JSON.
"4c8b47??498bc0""4c" ou "8b""4" ou "c"À l'aide de l'API binlex , il est possible de muter ces chromosomes, leurs paires d'allèles et leurs gènes pour faciliter la programmation génétique.
La programmation génétique dans ce contexte peut avoir plusieurs bébés, y compris, mais sans s'y limiter:
Le moyen le plus simple de commencer est avec la ligne de commande, en tirant parti d'un outil de filtrage JSON comme jq .
La commande suivante démonte sample.dll avec 16 threads, les traits pertinents sont des objets JSON, un par ligne et sont tués dans jq pour filtrer et embellir.
Pour voir quelles options sont disponibles lors de l'utilisation de la ligne de commande Binlex USE -h ou --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: @c3rb3ru5d3d53cUn exemple simple d'utilisation de la ligne de commande est fourni ci-dessous.
binlex -i sample.dll --threads 16 | jq Veuillez noter que Binlex détectera le format de fichier FORT YOU et prend en charge actuellement les formats PE , ELF et MACHO binaires.
Lors de votre première exécution de Binlex , il stockera le fichier de configuration dans votre répertoire de configuration dans binlex/binlex.toml .
Ce binlex trouve le répertoire de configuration par défaut en fonction de votre système d'exploitation comme indiqué dans le tableau ci-dessous pour sa configuration.
| OS | Variable d'environnement | Exemple de chemin de configuration binlex |
|---|---|---|
| Linux | $XDG_CONFIG_HOME ou $HOME/.config | /home/alice/.config/binlex/binlex.toml |
| macos | $HOME/Library/Application Support | /Users/Alice/Library/Application Support/binlex/binlex.toml |
| Fenêtre | {FOLDERID_RoamingAppData} | C:UsersAliceAppDataRoamingbinlexbinlex.toml |
Le nom de configuration par défaut binlex.toml pour Binlex est fourni ci-dessous.
[ 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 les options de ligne de commande ne sont pas suffisantes, le fichier de configuration fournit le contrôle le plus granulaire de toutes les options.
Si vous souhaitez remplacer le fichier de configuration par défaut et spécifier un autre fichier de configuration, utilisez le paramètre de ligne de commande.
binlex -c config.toml -i sample.dllLorsque vous exécutez Binlex , il utilise le fichier de configuration et remplace tous les paramètres lorsque le paramètre de ligne de commande respectif est utilisé.
Voici un flux de travail général qui commence par la création de règles de Yara, où nous obtenons 10 cordes hexadécimales Yara à caractéristiques génériques uniques d'un échantillon donné.
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 ???? Pour aller plus loin, vous pouvez l'exécuter dans l'outil blyara pour faire une signature Yara rapide.
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 Pour des résultats encore meilleurs si vous avez exporté les génomes à l'aide du plugin Binlex IDA ou par autre moyen, vous pouvez filtrer pour le démarrage des préfixes comme mw:: , pour malware , ce qui est assez courant.
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 Pour utiliser Binlex avec Ghidra, utilisez le script blghidra/blghidra.py dans le répertoire des scripts.
Pour tirer parti des noms de fonction et des adresses virtuelles de vos projets Ghidra et fournissez-les à Binlex, utilisez le script d' analyzeHeadless dans votre répertoire d'installation Ghidra .
./analyzeHeadless
< project-directory >
< project-name >
-process sample.dll
-noanalysis
-postscript blghidra.py 2> /dev/null | grep -P " ^{ " type " | binlex -i sample.dll Veuillez noter que analyzeHeadless imprime les messages de journal imprimées à stdout et d'autres sorties de journal à stderr qui ne sont d'aucune utilité d'interopérabilité avec d'autres utilitaires de ligne de commande.
En tant que tel, pour collecter la sortie du script, il doit être filtré avec 2>/dev/null | grep -P "^{"type" .
Pour tirer parti de la puissance de la détection de fonction Rizin et de la dénomination des fonctions dans Binlex , exécutez rizin sur votre projet en utilisant aflj pour répertorier les fonctions au format JSON.
Ensuite, tuyau cette sortie vers blrizin , qui analyse rizin JSON à un format Binlex Unsestands.
De plus, vous pouvez combiner cela avec d'autres outils comme blpdb pour analyser les symboles PDB pour obtenir des adresses et des noms de fonction.
Vous pouvez ensuite faire n'importe quel analyse comme vous le feriez généralement en utilisant jq , dans cet exemple, nous comptons les fonctions traitées par Binlex pour voir si nous en détectons davantage.
rizin -c ' aaa;aflj; ' -q sample.dll |
blrizin |
blpdb -i sample.pdb |
binlex -i sample.dll |
jq ' select(.type == "function") | .address ' | wc -l Remarque : À l'heure actuelle, blrizin est également compatiable avec la sortie de radare2 à l'aide blrizin .
Si vous souhaitez faire un peu d'apprentissage automatique, vous pouvez obtenir des fonctionnalités représentant les amuse-gueules sans adressage de mémoire de Binlex comme celui-ci.
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 vous souhaitez affiner cela pour votre modèle d'apprentissage automatique en les normalisant entre 0 et 1 Valeurs de flottants Binlex vous a couvert avec l'outil 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]Pour tirer parti de la puissante caractéristique du fichier de fichiers pour réduire l'utilisation de la mémoire, mais toujours Benifit à partir d'images virtuelles.
# 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 Cela peut configurer cela pour être sur le disque ou si /tmp/ répertoire est mappé à RAM.
Lorsqu'elles sont cartographiées en RAM, nous profitons du démontage de l'image virtuelle, mais sans la pénalité RAM supplémentaire où les tâches répétitives doublent presque en vigueur.
Étant donné que btrfs résume l'accès au fichier mappé dans le noyau, nous pouvons y accéder car nous aurions n'importe quel fichier mappé mais avec le bénéfice de la compression.
Pour gagner du temps si vous choisissez cette option, faites en sorte que le montage du pool btrfs se produise sur le démarrage et demandez à votre fichier de configuration binlex pour préférer la mise en cache d'image virtuelle dans le répertoire du pool monté. Cette approche garantit que vous n'avez pas besoin de compter sur les paramètres de ligne de commande à chaque fois.
La philophsie du projet binlex se concentre sur la sécurité, la simplicité, la vitesse et l'extensibilité.
Une partie de cela consiste à fournir une API aux développeurs pour écrire leur propre logique de détection et de chasse.
À l'heure actuelle, Binlex fournit à la fois des liaisons rouille et python.
La rouille, l'API fait est facile à démarrer
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 ( ) ;
}L'API Binlex Python est désormais conçue pour résumer le désassembleur et le graphique de contrôle.
Pour démonter une image mappée de mémoire PE, utilisez les exemples suivants.
Il y a plus d'exemples dans les examples/python/ répertoire.
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 )Parfois, il est peut-être possible d'analyser le graphique de contrôle généré.
Dans ce cas, vous pouvez utiliser la technique suivante.
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 ()Au lieu de l'analyse, vous pouvez accéder plus directement aux instructions, aux blocs et aux fonctions.
for instruction in cfg . instructions ():
instruction . print ()
for block in cfg . blocks ():
block . print ()
for function in cfg . functions ():
function . print ()Il est également possible d'itérer des fonctions aux blocs, aux instructions, aux paires d'allèles, aux gènes.
Cela représente passer de l'abstraction le plus élevé à l'abstraction la plus faible.
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 )L'un des outils les plus puissants que vous puissiez utiliser dans Binlex est de comparer les fonctions, les blocs et les instructions en utilisant le hachage de similitude.
Faire ces comparaisons est aussi simple que d'appeler la méthode 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 ()Tous les algorithmes de hachage de similitude pris en charge seront calculés s'ils sont activés avec votre configuration.
Bien que cela puisse être difficile, Binlex prend en charge une analyse de similitude sur des fonctions non contiguës en utilisant son propre algorithme pour trouver les meilleures correspondances de similitude.
Au moins 75% ou plus des données d'une fonction non contigu doivent être présentables pour donner un hachage de similitude.
Chaque instruction, bloc et fonction ou génome a un chromosome associé qui peut être accessible via l'API.
Vous pouvez suivre ces abstractions jusqu'aux paires d'allèles et à leurs gènes respectifs.
# 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 vous cherchez à effectuer des tâches de programmation génétique, vous pouvez également muter les chromosomes, les allélepaires et les gènes et ils gardent une trace de leur propre nombre de mutations.
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 ()Cela facilite les mutations avec des algorithmes génétiques que vous pouvez utiliser pour vos usécases.
Si vous utilisez Binlex dans une publication de journal ou un modèle d'IA open-source, utilisez la citation suivante.
@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 l'utilisation de Binlex est à des fins personnelles, ou pour générer des sorties qui ne sont pas des modèles d'IA open-source, aucune citation n'est nécessaire.
Par exemple, si vous utilisez Binlex pour créer des règles YARA, aucune citation n'est nécessaire.
Cela garantit que le binlex reste pertinent, mais garantit également une utilisation personnelle et personnelle permissive.