REx@Skill - Habilidade de Execução de Engenharia Reversa Agêntica para descoberta de vulnerabilidades em binários
Ghidra · radare2 · rizin · qemu-user · angr · z3 · AFL++ · valgrind · capa · Unicorn · Triton · Frida · semgrep · clang · Python · Nix
todos fixados, todos reproduzíveis
1 · Claude Code — pule se você já o tem.```bash curl -fsSL https://claude.ai/install.sh | bash
**2 · REx@Skill** — 1 skill, 12 referências, **7 subagentes**, **33 scripts**.```bash
curl -fsSL https://raw.githubusercontent.com/tihanyin/REx-skill/main/install.sh | sh
3 · analisar um binário.```bash claude
/re-analyze path/to/binary # one target /re-analyze path/to/directory/ # a whole corpus, evidence gathered in parallel
<div align="center">
<sub><code>install.sh</code> grava apenas em <code>~/.claude/</code> — a skill e seus 33 scripts de pipeline, os 7 agentes, <code>/re-analyze</code>.<br>Ele nunca instala o Claude Code para você; ele faz backup de qualquer coisa que iria sobrescrever, e <code>--uninstall</code> o remove de forma limpa.</sub>
</div>
<br>
<details>
<summary><b>Prefere clonar?</b> · <i>ou instalar em outro lugar, ou removê-lo</i></summary>```bash
git clone https://github.com/tihanyin/REx-skill && cd REx-skill
./install.sh # into ~/.claude
./install.sh --prefix ~/.config/claude # somewhere else
./install.sh --uninstall # take it back out
![]()
Ghidra · radare2 · rizin · qemu-user · angr · z3 · AFL++ · valgrind · capa
![]()
Unicorn · Triton · Frida · semgrep · clang · Python · Nix · Linux · Claude
REx@Skill usa ferramentas de ponta reunidas por especialistas em engenharia reversa. Cada uma está no conjunto porque conquista seu lugar em benchmarks conhecidos e desafios reais de análise de binários — não porque era conveniente de instalar. Nada aqui é reimplementado; o trabalho da própria skill é saber qual ferramenta responde à pergunta à sua frente, e quanto vale sua resposta.
| Ferramenta | O que ela faz |
|---|---|
| Ghidra | transforma um binário compilado de volta em C legível |
| radare2 / rizin | um segundo decompilador, usado para verificar o primeiro |
| qemu-user | executa binários ARM, MIPS, PowerPC e RISC-V em uma máquina x86 comum |
| z3 | um solucionador matemático — prova se um índice pode sair do seu buffer, ou se um divisor pode ser zero |
| angr | descobre qual entrada alcançaria uma determinada linha de código |
| AFL++ | lança milhões de entradas geradas contra o programa para fazê-lo travar |
| valgrind | captura bugs de memória que de outra forma não causam erro visível |
| libdislocator | faz a leitura de um byte além do buffer travar imediatamente |
| capa | lista o que o binário pode fazer: criptografar, abrir sockets, injetar em processos |
| floss | encontra texto oculto que o strings comum não vê |
| Unicorn | executa uma única função com entradas que você escolhe, sem executar o programa |
| Triton | acompanha por onde dados controlados pelo atacante trafegam durante uma execução |
| Frida | observa e altera um programa enquanto ele está em execução |
| semgrep / cppcheck | escaneiam o C decompilado em busca de padrões ruins conhecidos |
| pwntools | a biblioteca auxiliar para offsets, parsing de ELF e trabalho de exploit |
Estas são as versões exatas com que foi construída e medida:
Ghidra 12.1.2 · radare2 6.2.0 · rizin 0.9.1 · qemu-user 11.1.0 + 9 cross-sysroots · angr 9.2.154 · z3 4.16.0 · AFL++ 5.00c · valgrind 3.27.1 · capa 9.4.0 · Unicorn 2.1.4 · Triton 3.7.0 · Frida 17.17.0 · clang 21.1.8 · semgrep 1.172.0 · floss 3.1.1 · yara 4.5.7 · binwalk 3.1.0 · pwntools 4.15.0 · cppcheck 2.21.1
Todas são opcionais. scripts/capabilities.sh relata o que esta máquina tem,
cada script nomeia a ferramenta que não consegue encontrar, e uma ferramenta ausente restringe a análise
em limitations em vez de falhar silenciosamente.
Três comandos e todas as ferramentas acima estão no seu PATH, exatamente nestas versões —
nada para procurar, nada deixado pela metade na configuração.```bash
git clone https://github.com/tihanyin/REx-skill 2>/dev/null || git -C REx-skill pull
cd REx-skill
curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install --no-confirm
nix develop ./devshell
scripts/capabilities.sh
| | |
|---|---|
| **0** | clona o repositório, ou o atualiza se você já tiver um — o instalador de habilidade de uma linha acima **não** deixa um clone para trás, ele funciona a partir de um checkout temporário e o remove, então o toolchain e os scripts precisam de um próprio |
| **1** | instala o Nix, o gerenciador de pacotes que faz o pinning — depois **abra um novo terminal**. *Já tem o Nix? Pule esta etapa.* Reexecutar o instalador sobre uma instalação existente falha com `Found existing plan in /nix/receipt.json`, o que significa que ele está se recusando a tocar no que você já tem, não é um erro a corrigir |
| **2** | entra no shell, a partir da raiz do repositório para que `scripts/` permaneça à mão. Na primeira vez baixa muita coisa; todas as vezes seguintes são segundos |
| **3** | confirma isso: `ghidra pyghidra r2 rizin`, `qemu-user architectures: 7`, `angr`, `z3`, `afl` — em vez das linhas `MISS` que uma máquina sem preparo fornece |
`exit` restaura seu `PATH` exatamente como estava. *Testado no Ubuntu 22.04.5 LTS
(x86-64), Determinate Nix 3.22.4.*
<details>
<summary><b>Por que fixar o toolchain afinal?</b></summary>
- **Execuções comparáveis.** A saída do decompilador *é* a entrada do analista. Duas pessoas
em duas versões do Ghidra não estão fazendo o mesmo experimento, e nenhuma consegue verificar
o resultado da outra.
- **Nada instalado na sua máquina.** O Nix mantém cada pacote sob um hash daquilo que o construiu,
então entrar no shell altera o `PATH` e nada mais. Saia do shell e seu sistema estará exatamente como estava.
- **Ainda funciona em cinco anos.** Três revisões fixadas reconstroem todo o
toolchain, o que torna um número publicado re-verificável mais tarde.
Três revisões reconstroem todo o toolchain, em qualquer máquina, em qualquer momento no
futuro:```
nixpkgs ffb3c9b700e759be2ef13237c9d8f953b32a1e46
nixpkgs-angr ac62194c3917d5f474c1a844b6fd6da2db95077d
capa-rules v9.4.0
devshell/flake.lock é a autoridade; devshell/DEVSHELL.md
lista cada ferramenta com a sua versão e para que serve.
REx@Skill é um método para decidir se um binário tem um defeito — e prová-lo. Sete subagentes executam-no, partilhando um único diretório de evidências.
Um agente transforma o binário em evidências: C descompilado, desassemblagem, strings, um mapa de que código alcança o quê, e o que acontece quando o executas de facto. Cinco agentes leem então essas evidências ao mesmo tempo, cada um à caça de um tipo diferente de defeito, e nenhum deles consegue ver o que os outros encontraram — cinco leitores a partilhar um descompilador cometem os mesmos erros, por isso mantê-los separados rende cinco leituras independentes em vez de uma opinião repetida cinco vezes. Um sétimo lê o código primeiro, depois as suas descobertas, e decide quais se sustentam.
Nada é reportado como bug a menos que quatro coisas sejam nomeadas e localizadas no binário: onde entram dados controlados pelo atacante (source), a operação que podem quebrar (sink), a verificação que os deveria ter travado (broken guard), e quem é prejudicado (affected principal). Falha uma e sai como pista não provada, não como descoberta.
Cada execução entrega as mesmas três coisas: as descobertas, o que foi excluído e porquê, e o que o host não conseguiu executar.
O conjunto de competências foi testado em dez arquiteturas — x86-64, i686, ARM, AArch64, MIPS e MIPS64 em ambas as endiannesses, PowerPC de 32 bits, RISC-V e Apple arm64 — em ELF, PE e Mach-O, firmware e blobs em bruto. Nada o limita aí: qualquer arquitetura que o teu descompilador consiga levantar está no âmbito.
| Agente | Executa | Numa linha | |
|---|---|---|---|
| 01 | re-recon | primeiro, sozinho | Extrai as evidências. Não caça bugs — uma descoberta confiante aqui é o modo de falha. |
| 02 | re-bughunt | sempre | Constrói o caso honesto mais forte de que existe um defeito. Enumera todos os sinks. |
| 03 | re-safety | sempre | Tenta provar que é sólido, e reporta todas as obrigações que não consegue cumprir. |
| 04 | re-arithmetic | se indexa ou dimensiona | Tamanho, índice, largura e sinalização através de fronteiras de chamadas — resolvido por um solver, não na cabeça de alguém. |
| 05 | re-lifecycle | se aloca | Alocação, libertação, propriedade, init e caminhos de erro. O caminho de erro é o que ninguém testou. |
| 06 | re-logic | se autentica | Autorização, máquinas de estado, criptografia, validar-aqui-usar-ali. Sem assinatura para procurar. |
| 07 | re-reconcile | último, sozinho | Lê o código antes de ler as conclusões de alguém, depois adjudica e reporta. |
Um diretório por binário, com o nome <filename>-<first 8 hex of its SHA-256>:```
results/
├── index.json every sha256 analysed -> its directory
└── httpd-4f2a9c1e/ <- "httpd", sha256 4f2a9c1e...
├── decomp/ decompiled C ├── reach/ source -> sink paths
├── disasm/ disassembly, real VAs ├── bounds/ arithmetic to discharge
├── meta/ function map + base ├── sanitize/ hostile-allocator runs
├── strings/ inventory, by family ├── fuzz/ coverage-guided search
├── dynamic/ crafted-input battery ├── quarantine/ text aimed at YOU
└── notes/ the threat model └── pipeline.json what ran, what did not
**Por que o hash está no nome.** Duas compilações de um programa compartilham um nome de arquivo, mas não um
SHA-256, então a evidência e o binário não podem se desviar silenciosamente: recompile o alvo e
você obtém um novo diretório em vez de um poluído.
`pipeline_status.py` audita essa árvore e relata quais estágios nunca foram executados — porque um
estágio que nunca foi executado não deixa erro algum, apenas um diretório ausente, que é lido
exatamente como "executou, não encontrou nada".
</details>
---
## 4. Inventário de ferramentas — qual script chama o quê
#### Descompilar e ler
| Ferramenta | Versão | Usada por | Para |
|---|---|---|---|
| **Ghidra** | 12.1.2 | `ghidra_export.py` `batch_decompile.sh` `decompile_addr.py` | o descompilador — a ferramenta que sustenta tudo |
| **pyghidra** | 3.1.0 | as mesmas três | conduzi-lo em modo headless |
| radare2 | 6.2.0 | `run_tools.sh` `strings_report.py` `brief.py` | JSON de cada comando |
| rizin | 0.9.1 | `capabilities.sh` `preflight.sh` | um **segundo** descompilador — verificação cruzada |
| binutils | 2.46 | `triage.py` `inventory.py` `run_tools.sh` | readelf, objdump, nm, strings, size |
| file | 5.48 | todo ponto de entrada | primeiro comando, todas as vezes |
#### Triagem — o que é, o que pode fazer
| Ferramenta | Versão | Usada por | Para |
|---|---|---|---|
| **capa** | 9.4.0 | `run_tools.sh` `brief.py` | capacidades a partir de regras, com endereços |
| **floss** | 3.1.1 | `strings_report.py` | strings que o `strings` não consegue ver |
| yara | 4.5.7 | `run_tools.sh` `analyze.sh` | packers, constantes criptográficas, versões de bibliotecas |
| detect-it-easy | 3.21 | `run_tools.sh` | identificação de packer e compilador |
| checksec | pwntools | `triage.py` `brief.py` | NX / RELRO / canary / PIE |
#### Executar — a maior alavanca individual
| Ferramenta | Versão | Usada por | Para |
|---|---|---|---|
| **qemu-user** | 11.1.0 | `dynamic_probe.py` `quick_dynamic.sh` | executar binários de arquitetura estrangeira |
| **9 cross-sysroots** | glibc | `setup_sysroots.sh` | sem eles o qemu não consegue nem carregar um binário dinâmico estrangeiro |
| gdb / ltrace / strace | 17.2 | `capabilities.sh` os reporta | traces; `ltrace` é a ferramenta mais subutilizada aqui |
> Em uma comparação medida, o mesmo modelo obteve aproximadamente **3× o recall** com
> execução disponível do que sem. Esta linha é o motivo pelo qual os sysroots vêm com o flake.
#### Tornar bugs silenciosos ruidosos
| Ferramenta | Versão | Usada por | Para |
|---|---|---|---|
| **valgrind** | 3.27.1 | `sanitize_run.sh` | a coisa mais próxima de ASan para um binário que você não pode recompilar |
| **AFL++** | 5.00c | `fuzz_target.sh` `quick_dynamic.sh` | fuzzing guiado por cobertura, modo QEMU |
| libdislocator | com AFL++ | `sanitize_run.sh` `quick_dynamic.sh` | página por alocação — transforma uma leitura OOB silenciosa em uma falha |
| clang | 21.1.8 | `triage.py` | `-fsanitize=...` em código levantado |
#### Resolver e emular
| Ferramenta | Versão | Usada por | Para |
|---|---|---|---|
| **z3** | 4.16.0 | `check_bound.py` | descarrega uma afirmação de limites — 9 modos mais uma saída de escape genérica |
| **angr** | 9.2.154 | `symfn.py` | harness simbólico por função: hijack, escrita OOB, divisão por zero |
| **unicorn** | 2.1.4 | `emulate.py` | executar UMA função isoladamente com entradas que você escolher |
| triton | 3.7.0 | disponível | execução concolica e taint sobre um trace concreto |
| pwntools | 4.15.0 | `brief.py` `run_tools.sh` | offsets de `cyclic()`, parsing de ELF/GOT |
#### Análise estática sobre C descompilado
| Ferramenta | Versão | Usada por | Para |
|---|---|---|---|
| cppcheck | 2.21.1 | `run_tools.sh` `analyze.sh` | tolera código que não compila — a saída do descompilador não compila |
| semgrep | 1.172.0 | `run_tools.sh` `analyze.sh` | regras de padrão, sem necessidade de build |
| flawfinder | 2.0.20 | `capabilities.sh` | lexical; um grep com opiniões |
<details>
<summary><b>Também no shell</b> — firmware, formatos, explorabilidade</summary>
`binwalk` 3.1.0 · `unsquashfs` · `sasquatch` · `jefferson` · `ubi_reader` ·
`kaitai-struct-compiler` 0.11 · `tshark` 4.6.8 · `hexyl` · `pev` 0.81 ·
`osslsigncode` · `diffoscope` 328 · `patchelf` 0.15.2 · `ROPgadget` 7.7 ·
`one_gadget` 1.9.0 · `honggfuzz` · `radamsa` 0.7 · `bitwuzla` 0.9.1 · `rr` 5.9.0 ·
`bpftrace` 0.26.0 · `upx` 5.2.0
Inventário completo com todas as versões: [`devshell/DEVSHELL.md`](https://github.com/tihanyin/rex-skill/blob/main/devshell/DEVSHELL.md)
</details>
---
## 5. Use com algo diferente do Claude
`general-skill/SKILL-RE.md` é **um arquivo autocontido** — 3 750 linhas de Markdown
simples com frontmatter `name`/`description`. Tudo o que o pacote do Claude tem,
em uma única peça: o mesmo padrão de evidência, o mesmo pipeline, as mesmas regras sobre
fuzzing de uma arquitetura estrangeira. Clone o repositório para que `scripts/` fique ao lado dele, então:
| Executor | Como |
|---|---|
| **Codex** | aponte `AGENTS.md` para ele, ou cole-o como o prompt de sistema |
| **opencode** | `{"instructions": ["SKILL-RE.md"]}` em `opencode.json` |
| **Cursor / Windsurf** | coloque-o como uma regra de projeto |
| **Um loop de API simples** | é apenas Markdown — coloque-o no início |
| **Um humano** | lê-se como um livro didático; essa era a intenção |
> **Por que duas formas?** O pacote do Claude é um núcleo de 16 KB mais doze arquivos de referência
> carregados sob demanda — contexto pequeno até que uma pergunta específica precise de um capítulo
> específico. Apenas o Claude Code segue esses ponteiros, então todo outro executor recebe o
> arquivo único.
---
---
## 6. O que está dentro```
.
├── claude-skill/ the Claude Code form
│ ├── skills/reverse-engineering/
│ │ ├── SKILL.md 16 KB core, loaded on every trigger
│ │ └── references/ 12 files, pulled in on demand
│ ├── agents/ 7 subagents
│ └── commands/ /re-analyze — orchestrates all three phases
│
├── general-skill/ the portable form
│ ├── SKILL-RE.md the whole methodology, one file, 32 sections
│ └── AGENTS.md points any agent at it
│
├── scripts/ 32 tools — the pipeline and its parts
├── devshell/ flake.nix + flake.lock + DEVSHELL.md
├── images/ logo and figures
└── install.sh one command into ~/.claude
A skill roda em qualquer lugar onde o Claude Code roda — Linux, macOS, WSL. É markdown:
o núcleo, 12 referências, 7 subagentes e /re-analyze. Nada nela é
específico de plataforma, e os scripts são Python e bash portáveis. O que varia são
as ferramentas por baixo deles.
O DEVSHELL é construído e testado em Linux — x86-64 (Ubuntu 22.04.5 LTS) e aarch64. O macOS é onde ele se esvazia, porque onze das ferramentas não existem no Darwin de forma alguma:
qemu-user traduz syscalls Linux, então é Linux por definição, e os
nove sysroots de arquitetura cruzada vão junto.
O que isso deixa em um Mac. Todo estágio estático: descompilação Ghidra, radare2 e rizin, angr e z3, os analisadores estáticos, triagem, strings e alcançabilidade. O que você perde é execução — a sonda dinâmica, execuções de sanitizer, fuzzing, e qualquer binário de arquitetura estrangeira. Isso é uma perda real: um crash é a evidência mais forte que esta metodologia tem, e nada estático o substitui.
Nada finge o contrário. scripts/capabilities.sh reporta o que o host
realmente consegue fazer, scripts/pipeline_status.py marca o estágio como ausente, e o
custo recai no limitations do relatório. Um estágio que não rodou nunca é
reportado como um estágio que rodou e não encontrou nada — veja §9.1 da skill.
Em resumo: analise no Linux. Leia, planeje e escreva o relatório em qualquer lugar.
Norbert Tihanyi · x.com/@TihanyiNorbert
um achado = source · sink · guarda quebrada · principal afetado.
qualquer coisa menos que isso é uma hipótese.
capabilities.sh | o que este host realmente consegue fazer — verifique antes de planejar |
analyze.sh | todo o pipeline em ordem, passos 0-5, depois repassa |
batch_analyze.sh | o mesmo pipeline em um diretório de alvos |
pipeline_status.py | audita uma árvore de evidências: quais estágios rodaram, e o que cada ausência custa |
overview.py | a forma de um programa: contagens, árvore de chamadas, sinks, sources |
brief.py | a saída de cada ferramenta para um alvo, consolidada, lacunas nomeadas |
fn.py | lê uma função em vez de toda a descompilação |
reach.py | caminhos source → sink sobre o grafo de chamadas |
bounds_worklist.py | as afirmações aritméticas que precisam ser descarregadas, em três níveis |
check_bound.py | descarrega uma com z3 — 9 modos mais uma saída genérica de escape |
symfn.py | harness simbólico para uma função |
emulate.py | executa uma função isoladamente com entradas que você escolher |
quick_dynamic.sh | apenas execute: sem entrada, depois entradas que quebram a maioria das coisas |
fuzz_target.sh | fuzzing direcionado ao canal que o programa realmente lê |
sanitize_run.sh | alocadores hostis — faça um bug silencioso de heap travar |
sanitize.py | coloca em quarentena texto direcionado por modelo antes que qualquer coisa o leia |
| ausentes no macOS | qemu-user · gdb · gef · ltrace · strace · valgrind · AFL++ · honggfuzz · frida · bpftrace · rr |
| também | a build fixada do capa não passa na própria suíte de testes no Darwin |
| e | o fuzzing de argv interpõe __libc_start_main, que é glibc — não há equivalente no macOS |