
Recupere o que a ofuscação esconde em binários Rust (strings, crates, funções de biblioteca, fluxo de controle achatado) por meio de análise estática + emulação Unicorn, sem executá-los. Para triagem de malware, auditorias de aplicativos protegidos. ELF/PE/Mach-O, x86-64/ARM64/32 bits.
strings não vê nada. FLOSS não vê nada. rust-deobf vê o C2.
rust-deobf recupera o que binários Rust ofuscados escondem — endereços C2, caminhos de arquivo, mutexes, chaves de registro, configuração — sem nunca executar a amostra.
Demonstração · Use a partir de um agente de IA · Início rápido · Resultados · Malware real · Limitações
Um programa Rust sem símbolos, compilado da forma como o malware é distribuído (opt-level="z", LTO fat, panic=abort),
com seus oito indicadores criptografados pelo obfstr — as strings
ficam em uma struct, em braços de match, em comparações e em um branch que nunca é executado. Nenhuma delas é jamais impressa.
Gerado a partir da saída capturada de uma execução real (Linux x86-64, rustc 1.97): o texto é literal, as cores e a animação de digitação foram adicionadas, a espera de ~8 s de emulação está acelerada e a saída foi reduzida às strings decodificadas. A saída em texto simples abaixo é da mesma execução.
O que o arquivo mostra a você:
$ B=build/scatter_obfstr__elf__size-lto__strip
$ strings $B | grep -ciE 'northwind|10\.66|NW-5c1e9a|skip-update'
0
O que o rust-deobf recupera (estático + emulação Unicorn; o binário nunca é executado):
$ python3 scripts/recover.py $B
binary: scatter_obfstr__elf__size-lto__strip format=ELF arch=x86_64
static x86-64 (recover_callsite): 0 strings decoders=9 seconds=0.2
emulation (recover_emulate): 8 strings functions=416/416 timed_out=False workers=1 seconds=6.8
== decoded strings ==
10.66.12.7:8443 [ip]
function 0xf20c (emulation)
C:\ProgramData\NorthwindSvc\state.db [path]
function 0xf20c (emulation)
Mozilla/5.0 (Windows NT 10.0; Win64; x64) NorthwindAgent/2.1
function 0xf20c (emulation)
--skip-update-check
function 0xf443 (emulation)
Software\Northwind\Agent\Settings [registry]
function 0xf51b (emulation)
Global\NW-5c1e9a [mutex]
function 0xf5a8 (emulation)
https://telemetry.northwind.example/api/v3/beacon [url]
function 0xfd58 (emulation)
nw-agent::stage=collect
function 0xfd58 (emulation)
8/8 em menos de 10 segundos, cada string marcada e rastreada até a função que a constrói.
Reproduza com ONLY=scatter_obfstr PROFILES=size-lto FORMATS=elf bash scripts/build_all.sh
(saída reduzida às strings decodificadas). (A entrada é um programa de benchmark benigno;
cada string plantada está listada em bench_src/manifest.json.)
O malware em Rust está crescendo, e suas ferramentas de desofuscação são efetivamente ausentes. FLOSS — o desofuscador de strings open-source padrão — não recupera nada dos crates de ofuscação comuns em Rust:
| ofuscador | strings | FLOSS | rust-deobf |
|---|---|---|---|
| litcrypt / litcrypt2 | 0/5 | 0/5 | 5/5 |
| obfstr (XOR+ADD inlined) | 0/5 | 0/5 | 5/5 |
| cryptify (chave padrão) | 0/5 | 0/5 | 5/5 |
| muddy (ChaCha20-Poly1305 AEAD) | 0/5 | 0/5 | 5/5 |
| strings compactas na pilha | 0/5 | 0/5 | 5/5 |
| XOR / ADD / SUB feitos à mão | 0/5 | 0/5 | 5/5 |
Benchmark canário, builds release, ELF e PE x86-64 e AArch64, com e sem strip. Tabela completa, incluindo o único caso que requer recuperação dinâmica (cryptify com chave personalizada), em Resultados.
Em amostras reais: EDDIESTEALER (PE) — 32 strings ofuscadas, incluindo seu domínio C2 oculto e caminho de URL, onde ferramentas estáticas e o FLOSS recuperam 0. AmnesiaStealer (macOS Mach-O) — URL de exfiltração C2, configuração do crypto-clipper, caminhos de staging. Mais abaixo.
Desofuscação de strings — recuperação estática no local da chamada (segundos) + um motor de emulação Unicorn com
um loader real, um runtime C, exploração de caminhos e replay de construtores globais. Recupera strings construídas
apenas em um braço de match ou em um ramo que nunca executa.
Triagem SOC em uma tela — soc_triage.py: formato/arquitetura, toolchain Rust, fingerprint de capacidades de crates
(networking / crypto / recon / persistence / staging), indicadores agrupados por tipo, e
um sinal calibrado LOW / MEDIUM / HIGH com suas evidências. --json para um SIEM, --fail-on HIGH
para gating em scripts. --fast (metadados + indicadores literais, sem decodificação) escala com o tamanho do binário:
menos de um segundo em uma amostra pequena, ~20 s em um binário de 20 MB.
Multi-arquitetura, multi-formato — x86-64, ARM64 e x86 de 32 bits em ELF, PE e Mach-O.
Encaixa no seu fluxo de trabalho — exportação compatível com FLOSS (--floss-json), anotação headless no Ghidra
(comentários de plate, bookmarks, renomeações), identificação de funções de biblioteca por assinatura de bytes
(lib_<name> em binários com strip), modo em lote sobre um diretório (--jsonl).
Além de strings — extração de config/C2, resolução de imports de API ofuscados por hash, carving de stage-2
desempacotado, detecção de control-flow-flattening e reconstrução (x86-64 e AArch64,
validado em goldberg, OLLVM -fla e um passe real de flattening do LLVM-18), simplificação de MBA / predicados opacos
com Z3, recuperação de vtable de trait-object Rust (recover_types.py), e
reversão de otimizações (desativação de jump-table, detecção de loops desenrolados — premium/opt_reverse.py).
Virtualização de código — detect_vm.py sinaliza VMs de bytecode no estilo VMProtect/Themida/Tigress; o
devirtualizador premium as eleva de volta. De uma VM com opcodes randomizados e operandos criptografados,
ele reconstrói:
return (((a0 > 1000) & (((((a0 * 31) + a1) ^ (a0 >> 3)) % 97) == 0)) ? (a1 + a0) : 0xffffffff);
— o código-fonte exato da função.
Seguro por design — estático + emulação por padrão: a emulação executa funções do binário sob o Unicorn, nunca o próprio binário. A recuperação dinâmica (Frida) é opcional e apenas para VMs isoladas.
Metadados Rust que sobrevivem ao strip — versão do rustc, crates de terceiros com versões exatas,
e locais de panic, reconstruídos a partir dos caminhos de origem que o compilador deixa em cada binário Rust (sem
necessidade de cargo-auditable).