
![]() | Binlex - uma estrutura de traço genético binário Se os Maldevs acham que seu binário é FUD, eles estão prestes a ter uma crise existencial. |
O Binlex é uma ferramenta para analistas e pesquisadores de malware que extraem instruções , blocos básicos e funções de arquivos binários e os organizam em uma hierarquia estruturada de genomas , cromossomos , pares de alelos e genes . ?
Essa quebra hierárquica permite que o Binlex analise e compare binários de malware, tratando sua estrutura de código como uma "impressão digital de DNA", facilitando a detecção de padrões, semelhanças e variações entre amostras.
Ao contrário das ferramentas que contam com python puro , que podem ser lentas?, Binlex foi projetado para velocidade, simplicidade e flexibilidade. Sua interface de linha de comando ajuda os analistas a pesquisar padrões em centenas ou milhares de amostras de malware , economizando tempo e recursos ?
Para os desenvolvedores, o Binlex oferece uma API de ferrugem e ligações de Python para criar ferramentas de detecção personalizadas com restrições mínimas de licenciamento. ?
Como parte da luta contra o malware, o Binlex é gratuito para usar - basta baixar os binários da página de lançamento. ?
A versão mais recente do Binlex fornece os seguintes recursos incríveis!
| Recurso | Descrição |
|---|---|
| Plataformas | - Windows? - macOS? - Linux? |
| Formatos | - pe - Macho - elfo |
| Arquiteturas | - AMD64 - I386 - CIL |
| ? Multi-threading | - fila de desmontagem segura para tópicos -? Ferramentas multi-thread para obter a máxima eficiência |
| Desempenho personalizável | ATENDE os recursos ligados/desligados para otimizar para o seu caso de uso |
| ? JSON String Compression | Salvar memória com compressão JSON |
| ? Hash de similaridade | -? Minhash - tlsh -? SHA256 |
| ? Símbolos de função | - Passe os símbolos da função para Binlex como entrada padrão usando BLPDB , BLELFSYM ou BLMachosym ou sua própria ferramenta |
| ? Iqudging | Marcação para fácil organização |
| Curinga | Perfeito para gerar regras YARA e agora em uma resolução de petiscos! |
| API | -? API de ferrugem -Python api |
| ? Recursos de aprendizado de máquina | - Recursos normalizados para consistência -? Recurso utilitário escaleiro -? Filtragem de características - Treinamento de amostra de Onnx -? Classificação de amostra |
| Imagem virtual | - Cache de mapeamento eficiente para imagens virtuais -? ️ Compatível com ZFS / BTRFS - acelera tarefas repetitivas e filtragem - Velocidade de iluminação ⚡ |
Ao armazenar em cache imagens virtuais, o Binlex é capaz de executar em melhores velocidades, tornando as corridas repetidas mais rápidas e eficientes.
Para construir binlex , você precisa de ferrugem.
A instalação é uma foward reta no Linux e 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 criar pacotes para várias plataformas, use o Makefile .
make zst # Make Arch Linux Package
make deb # Make Debian Package
make wheel # Make Python Wheel Os pacotes resultantes estarão no target/ diretório.
A instalação do plug -in do IDA é fácil de instalar, apenas certifique -se de instalar as ligações do Python no ambiente Python para a IDA.
Agora copie o diretório para o plug -in binlex para o diretório do plug -in.
mkdir -p ~ /.idapro/plugins/
cp -r scripts/plugins/ida/binlex/ ~ /.idapro/plugins/Depois de abrir o IDA, você deve ser recebido com a mensagem Binlex Welcome.

Usando o plug -in IDA, você tem vários recursos fornecidos para ajudá -lo com a redação de regras YARA e análise de similaridade.
Menu principal:
Menu de contexto desmontador:
O padrão de cópia e o recurso Hex Hex destinam -se a ajudar nas regras YARA e a cópia de hashes e varredura de similaridade é para caçar dados semelhantes.
Para comparar um banco de dados com outro, use o recurso de exportação para exportar o arquivo JSON e clique em Compare Functions , que preencherão uma tabela depois de concluída.
cargo docVocê também pode abrir os documentos.
cargo doc --openNo Binlex , uma hierarquia de termos de inspiração genética é usada para descrever e simbolizar a estrutura e as características do código binário. Essa terminologia reflete as relações entre diferentes abstrações e suas analogias genéticas:
Genoma : representa cada objeto que está sendo analisado, como uma função ou bloco. Ele encapsula todas as informações, incluindo metadados, cromossomos e outros atributos.
Cromossomo : representa os padrões ou seqüências principais extraídas de um bloco ou função. Um cromossomo atua como o plano para identificar as principais características do binário sem a memória, como indicado por curingas como ? , onde um único curinga representa um único gene.
ALELEPAIR : Uma unidade dentro do cromossomo que consiste em dois genes . Os pares de alelos são os blocos de construção do cromossomo, combinando genes em pares significativos.
Gene : a menor unidade de informação genética, representando uma única mordidela de dados (meio byte).
A relação entre essas abstrações pode ser visualizada da seguinte maneira:
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 exemplo do genoma do JSON.
"4c8b47??498bc0""4c" ou "8b""4" ou "c"Usando a API binlex , é possível mutações desses cromossomos, seus pares de alelos e genes para facilitar a programação genética.
A programação genética nesse contexto pode ter vários benifados, incluindo, entre outros,:
A maneira mais simples de começar é com a linha de comando, aproveitando uma ferramenta de filtragem JSON como jq .
O seguinte comando desmonta sample.dll com 16 threads, as características relevantes são objetos JSON, um por linha e são canalizados para jq para filtragem e embelezamento.
Para ver quais opções estão disponíveis ao usar a linha de comando 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: @c3rb3ru5d3d53cUm exemplo simples de uso da linha de comando é fornecido abaixo.
binlex -i sample.dll --threads 16 | jq Observe que o Binlex detectará o formato de arquivo em você e atualmente suporta formatos de PE , ELF e MACHO .
Após a sua primeira execução do Binlex , ele armazenará o arquivo de configuração no seu diretório de configuração em binlex/binlex.toml .
Este binlex encontra o diretório de configuração padrão com base no seu sistema operacional, conforme indicado na tabela abaixo para sua configuração.
| OS | Variável de ambiente | Exemplo de caminho de configuração 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 |
| Windows | {FOLDERID_RoamingAppData} | C:UsersAliceAppDataRoamingbinlexbinlex.toml |
O nome da configuração padrão binlex.toml para binlex é fornecido abaixo.
[ 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 = trueSe as opções da linha de comando não forem suficientes, o arquivo de configuração fornecer o controle mais granular de todas as opções.
Se você deseja substituir o arquivo de configuração padrão e especificar outro arquivo de configuração, use o parâmetro da linha de comando.
binlex -c config.toml -i sample.dllQuando você executa o Binlex , ele usa o arquivo de configuração e substitui todas as configurações quando o respectivo parâmetro da linha de comando é usado.
Aqui está um fluxo de trabalho geral para a criação de regras YARA, onde obtemos 10 cordas hexáticas Yara com currega exclusivos de uma determinada amostra.
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 um passo adiante, você pode executá -lo pela ferramenta blyara para fazer uma assinatura YARA rápida.
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 obter resultados ainda melhores se você exportar os genomas usando o plug -in Binlex IDA ou por outros meios, você pode filtrar prefixos iniciais da função como mw:: , para malware , o que é bastante comum.
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 o binlex com ghidra, use o script blghidra/blghidra.py no diretório scripts.
Para aproveitar os nomes de funções e endereços virtuais de seus projetos Ghidra e fornecê -los ao Binlex , use o script analyzeHeadless no seu diretório de instalação Ghidra .
./analyzeHeadless
< project-directory >
< project-name >
-process sample.dll
-noanalysis
-postscript blghidra.py 2> /dev/null | grep -P " ^{ " type " | binlex -i sample.dll Observe que o analyzeHeadless sem mensagens de log para stdout e outras saídas de log para stderr que não adiam a interoperabilidade com outros utilitários da linha de comando.
Como tal, para coletar a saída do script, ele deve ser filtrado com 2>/dev/null | grep -P "^{"type" .
Para alavancar o poder da detecção e nomeação de funções de Rizin no Binlex , execute rizin em seu projeto usando aflj para listar as funções no formato JSON.
Em seguida, punha essa saída para blrizin , que analisa rizin JSON para um formato Binlex Undends.
Além disso, você pode combinar isso com outras ferramentas, como blpdb para analisar símbolos PDB para obter endereços e nomes de funções.
Você pode fazer qualquer análise como geralmente usaria jq ; neste exemplo, contamos as funções processadas pelo Binlex para ver se estamos detectando mais delas.
rizin -c ' aaa;aflj; ' -q sample.dll |
blrizin |
blpdb -i sample.pdb |
binlex -i sample.dll |
jq ' select(.type == "function") | .address ' | wc -l NOTA : Nesse momento, blrizin também é compatível com a saída do radare2 usando blrizin .
Se você quiser fazer algum aprendizado de máquina, você pode obter recursos representando as petiscos sem o endereço de memória do 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] Se você deseja refinar isso para o seu modelo de aprendizado de máquina normalizando -os entre os valores de 0 e 1 float binlex, você cobriu com a ferramenta 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 alavancar o poderoso recurso do Filemapping para reduzir o uso da memória, mas ainda assim, Benifit de imagens virtuais.
# 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 Isso pode configurar isso para estar no disco ou se /tmp/ diretório é mapeado para RAM.
Quando mapeado para a RAM, estamos aproveitando a desmontagem da imagem virtual, mas sem a penalidade adicional da RAM, onde tarefas repetitivas quase dobram na velocidade de processamento.
Como btrfs abstrai o acesso ao arquivo mapeado no kernel, somos capazes de acessá -lo como faria qualquer arquivo mapeado, mas com o benefício da compactação.
Para economizar tempo se você escolher esta opção, faça com que a montagem do pool btrfs ocorra na inicialização e tenha seu arquivo de configuração Binlex definido para preferir cache de imagem virtual no diretório de pool montado. Essa abordagem garante que você não precise confiar nos parâmetros da linha de comando de cada vez.
A filofia do projeto Binlex está focada em segurança, simplicidade, velocidade e extensão.
Parte disso está fornecendo uma API para os desenvolvedores escreverem sua própria lógica de detecção e caça.
Neste momento, o Binlex fornece ligações de ferrugem e Python.
A ferrugem, a API faz é fácil começar
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 ( ) ;
}A API Binlex Python agora foi projetada para abstrair o gráfico de desmontagem e controle do ControlFlow.
Para desmontar uma imagem mapeada de memória PE, use os seguintes exemplos.
Existem mais exemplos nos examples/python/ diretório.
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 )Às vezes, talvez seja necessário analisar o gráfico Controlflow gerado.
Nesse caso, você pode usar a seguinte 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 ()Em vez de analisar, você pode acessar as instruções, blocos e funções mais diretamente.
for instruction in cfg . instructions ():
instruction . print ()
for block in cfg . blocks ():
block . print ()
for function in cfg . functions ():
function . print ()Também é possível iterar de funções a blocos, instruções, pares de alelos, genes.
Isso representa a abstração de mais alto nível para a menor abstração.
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 )Uma das ferramentas mais poderosas que você pode usar no Binlex é comparar funções, blocos e instruções usando hash de similaridade.
Para executar essas comparações, é tão simples quanto chamar o 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 ()Quaisquer algoritmos de hash de similaridade suportados serão calculados se forem ativados com sua configuração.
Embora possa ser um desafio, o Binlex suporta a análise de similaridade em funções não contigiosas usando seu próprio algoritmo para encontrar as melhores correspondências de similaridade.
Pelo menos 75% ou mais dos dados de uma função não contígua devem ser hashable para produzir um hash de similaridade.
Cada instrução, bloco e função ou genoma possui um cromossomo associado que pode ser acessado através da API.
Você pode seguir essas abstrações até pares de alelos e seus 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 ()Se você deseja executar tarefas de programação genética, também pode sofrer mutações de cromossomos, alehairs e genes e eles acompanham seu próprio número de mutações.
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 ()Isso facilita mutações com algoritmos genéticos que você pode empregar para suas redes de uso.
Se você estiver usando o Binlex em uma publicação de periódicos ou um modelo de IA de código aberto, use a seguinte citação.
@misc { binlex ,
author = { c3rb3ru5d3d53c } ,
title = { binlex: A Binary Genetic Trait Lexer Framework } ,
year = { 2024 } ,
note = { Available at url{https://github.com/c3rb3ru5d3d53c/binlex-rs} }
}Se o uso do Binlex for para fins corporativos, pessoais ou para gerar saídas que não são modelos de IA de código aberto, nenhuma citação é necessária.
Por exemplo, se você usar o Binlex para criar regras YARA, nenhuma citação será necessária.
Isso garante que o Binlex permaneça relevante, mas também garante o uso corporativo e pessoal permissivo.