REx@Skill — агентный навык обратного проектирования для поиска уязвимостей в бинарных файлах
![]()
Ghidra · radare2 · rizin · qemu-user · angr · z3 · AFL++ · valgrind · capa · Unicorn · Triton · Frida · semgrep · clang · Python · Nix
все закреплены, все воспроизводимы
1 · Claude Code — пропустите, если он у вас уже есть.```bash curl -fsSL https://claude.ai/install.sh | bash
**2 · REx@Skill** — 1 навык, 12 ссылок, **7 субагентов**, **33 скрипта**.```bash
curl -fsSL https://raw.githubusercontent.com/tihanyin/REx-skill/main/install.sh | sh
3 · анализ бинарного файла.```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> записывает только в <code>~/.claude/</code> — навык и его 33 скрипта конвейера, 7 агентов, <code>/re-analyze</code>.<br>Он никогда не устанавливает Claude Code за вас; он создаёт резервные копии всего, что мог бы перезаписать, а <code>--uninstall</code> полностью удаляет его.</sub>
</div>
<br>
<details>
<summary><b>Предпочитаете клонировать?</b> · <i>или установить в другое место, или удалить</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 использует передовые инструменты, собранные экспертами по реверс-инжинирингу. Каждый из них попал в набор потому, что заслужил своё место на известных бенчмарках и реальных задачах бинарного анализа — а не потому, что его было удобно установить. Здесь ничего не переписывается заново; задача самого навыка — знать, какой инструмент отвечает на стоящий перед ним вопрос и чего стоит его ответ.
| Инструмент | Что он делает |
|---|---|
| Ghidra | превращает скомпилированный бинарник обратно в читаемый C |
| radare2 / rizin | второй декомпилятор, используемый для перекрёстной проверки первого |
| qemu-user | запускает бинарники ARM, MIPS, PowerPC и RISC-V на обычной машине x86 |
| z3 | решатель математических задач — доказывает, может ли индекс выйти за пределы буфера или делитель быть нулём |
| angr | выясняет, какой ввод позволит достичь заданной строки кода |
| AFL++ | обрушивает на программу миллионы сгенерированных вводов, чтобы вызвать её падение |
| valgrind | ловит ошибки памяти, которые иначе не вызывают видимой ошибки |
| libdislocator | заставляет чтение одного байта за пределами буфера немедленно приводить к падению |
| capa | перечисляет, что умеет бинарник: шифровать, открывать сокеты, внедряться в процессы |
| floss | находит скрытый текст, который пропускает обычная команда strings |
| Unicorn | запускает отдельную функцию на выбранных вами вводах, не запуская программу |
| Triton | отслеживает, куда перемещаются контролируемые атакующим данные во время выполнения |
| Frida | наблюдает за программой и изменяет её во время выполнения |
| semgrep / cppcheck | сканируют декомпилированный C на известные плохие шаблоны |
| pwntools | вспомогательная библиотека для смещений, разбора ELF и работы с эксплойтами |
Вот точные версии, с которыми он был собран и измерен:
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
Каждый из них необязателен. scripts/capabilities.sh сообщает, что есть на этой машине,
каждый скрипт называет инструмент, который не может найти, а отсутствующий инструмент сужает анализ
до limitations, а не отказывает молча.
Три команды — и каждый инструмент выше оказывается в вашем PATH, ровно этих версий —
ничего не нужно искать, ничего не остаётся наполовину настроенным.```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** | клонирует репозиторий или обновляет его, если он у вас уже есть — однострочный установщик навыка выше **не** оставляет после себя клон, он работает из временного чекаута и удаляет его, поэтому инструментарию и скриптам нужен собственный |
| **1** | устанавливает Nix, менеджер пакетов, который выполняет пининг — затем **откройте новый терминал**. *Уже есть Nix? Пропустите это.* Повторный запуск установщика поверх существующей установки завершается ошибкой `Found existing plan in /nix/receipt.json` — это он отказывается трогать то, что у вас уже есть, а не ошибка, которую нужно исправлять |
| **2** | входит в оболочку из корня репозитория, чтобы `scripts/` оставался под рукой. В первый раз скачивается много; каждый раз после — секунды |
| **3** | подтверждает это: `ghidra pyghidra r2 rizin`, `qemu-user architectures: 7`, `angr`, `z3`, `afl` — вместо строк `MISS`, которые выдаёт голая машина |
`exit` возвращает ваш `PATH` ровно таким, каким он был. *Протестировано на Ubuntu 22.04.5 LTS
(x86-64), Determinate Nix 3.22.4.*
<details>
<summary><b>Зачем вообще пинить инструментарий?</b></summary>
- **Сопоставимые запуски.** Вывод декомпилятора *и есть* вход аналитика. Два человека
на двух версиях Ghidra не проводят один и тот же эксперимент, и ни один из них не может проверить
результат другого.
- **Ничего не установлено на вашей машине.** Nix хранит каждый пакет под хешем того,
что его собрало, поэтому вход в оболочку меняет `PATH` и ничего больше. Выйдите из
оболочки — и ваша система ровно такая, какой была.
- **Это всё ещё работает через пять лет.** Три зафиксированных ревизии пересобирают весь
инструментарий, и именно это делает опубликованное число перепроверяемым позже.
Три ревизии пересобирают весь инструментарий на любой машине в любой момент в
будущем:```
nixpkgs ffb3c9b700e759be2ef13237c9d8f953b32a1e46
nixpkgs-angr ac62194c3917d5f474c1a844b6fd6da2db95077d
capa-rules v9.4.0
devshell/flake.lock — источник истины; devshell/DEVSHELL.md
перечисляет каждый инструмент с его версией и назначением.
REx@Skill — это метод для определения того, есть ли в бинарном файле дефект, — и его доказательства. Семь субагентов выполняют его, используя один общий каталог доказательств.
Один агент превращает бинарный файл в доказательства: декомпилированный C, дизассемблированный код, строки, карту того, какой код доходит до какого, и что происходит при его фактическом запуске. Затем пять агентов одновременно читают эти доказательства, каждый охотится за своим типом дефекта, и ни один из них не может видеть, что нашли другие — пять читателей, использующих один декомпилятор, совершают одни и те же ошибки, поэтому их разделение даёт пять независимых прочтений вместо одного мнения, повторённого пять раз. Седьмой сначала читает код, затем их находки и решает, какие из них выдерживают проверку.
Ничто не сообщается как ошибка, если в бинарном файле не названы и не локализованы четыре вещи: куда попадают контролируемые злоумышленником данные (источник), операция, которую они могут нарушить (сток), проверка, которая должна была это остановить (сломанная защита), и кто пострадал (затронутый субъект). Пропустите одну — и это выйдет как недоказанная зацепка, а не как находка.
Каждый запуск выдаёт одно и то же три вещи: находки, что было исключено и почему, и что хост не смог запустить.
Набор навыков протестирован на десяти архитектурах — x86-64, i686, ARM, AArch64, MIPS и MIPS64 в обеих порядках байтов, 32-битный PowerPC, RISC-V и Apple arm64 — на ELF, PE и Mach-O, прошивках и необработанных блобах. Ничто не ограничивает его этим: любая архитектура, которую может поднять ваш декомпилятор, входит в область применения.
| Агент | Запуск | В одной строке | |
|---|---|---|---|
| 01 | re-recon | первым, в одиночку | Извлекает доказательства. Не ищет ошибки — уверенная находка здесь и есть режим отказа. |
| 02 | re-bughunt | всегда | Строит сильнейший честный довод о существовании дефекта. Перечисляет каждый сток. |
| 03 | re-safety | всегда | Пытается доказать его корректность и сообщает о каждом обязательстве, которое не может выполнить. |
| 04 | re-arithmetic | если есть индексация или размеры | Размер, индекс, разрядность и знаковость на границах вызовов — решается солвером, а не в чьей-то голове. |
| 05 | re-lifecycle | если есть выделение памяти | Выделение, освобождение, владение, инициализация и пути ошибок. Путь ошибки — тот, который никто не тестировал. |
| 06 | re-logic | если есть аутентификация | Авторизация, конечные автоматы, криптография, validate-here-use-there. Нет сигнатуры, по которой можно искать. |
| 07 | re-reconcile | последним, в одиночку | Читает код прежде, чем читает чьи-либо выводы, затем выносит решение и отчитывается. |
Один каталог на бинарный файл с именем <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
**Почему хеш в имени.** Две сборки программы имеют одинаковое имя файла, но не
SHA-256, поэтому доказательство и бинарник не могут незаметно разойтись: перекомпилируйте цель и
получите новый каталог вместо загрязнённого.
`pipeline_status.py` проверяет это дерево и сообщает, какие этапы никогда не запускались — потому что
этап, который никогда не запускался, не оставляет после себя ошибки, только отсутствующий каталог, который читается
ровно как «запускался, ничего не нашёл».
</details>
---
## 4. Инвентарь инструментов — какой скрипт что вызывает
#### Декомпиляция и чтение
| Инструмент | Версия | Используется в | Для |
|---|---|---|---|
| **Ghidra** | 12.1.2 | `ghidra_export.py` `batch_decompile.sh` `decompile_addr.py` | декомпилятор — несущий инструмент |
| **pyghidra** | 3.1.0 | те же три | управление им в headless-режиме |
| radare2 | 6.2.0 | `run_tools.sh` `strings_report.py` `brief.py` | JSON из каждой команды |
| rizin | 0.9.1 | `capabilities.sh` `preflight.sh` | **второй** декомпилятор — перекрёстная проверка |
| binutils | 2.46 | `triage.py` `inventory.py` `run_tools.sh` | readelf, objdump, nm, strings, size |
| file | 5.48 | каждая точка входа | первая команда, каждый раз |
#### Триаж — что это, что оно умеет
| Инструмент | Версия | Используется в | Для |
|---|---|---|---|
| **capa** | 9.4.0 | `run_tools.sh` `brief.py` | возможности из правил, с адресами |
| **floss** | 3.1.1 | `strings_report.py` | строки, которые `strings` не видит |
| yara | 4.5.7 | `run_tools.sh` `analyze.sh` | упаковщики, криптоконстанты, версии библиотек |
| detect-it-easy | 3.21 | `run_tools.sh` | идентификация упаковщика и компилятора |
| checksec | pwntools | `triage.py` `brief.py` | NX / RELRO / canary / PIE |
#### Выполнение — самый крупный отдельный рычаг
| Инструмент | Версия | Используется в | Для |
|---|---|---|---|
| **qemu-user** | 11.1.0 | `dynamic_probe.py` `quick_dynamic.sh` | запуск бинарников чужой архитектуры |
| **9 cross-sysroots** | glibc | `setup_sysroots.sh` | без них qemu даже не может загрузить чужой динамический бинарник |
| gdb / ltrace / strace | 17.2 | `capabilities.sh` сообщает о них | трассировки; `ltrace` — самый недоиспользуемый инструмент здесь |
> В одном измеренном сравнении та же модель показала примерно **в 3 раза больший recall**
> при наличии выполнения, чем без него. Эта строка — причина, по которой sysroots поставляются вместе с flake.
#### Сделать тихие баги громкими
| Инструмент | Версия | Используется в | Для |
|---|---|---|---|
| **valgrind** | 3.27.1 | `sanitize_run.sh` | ближайший аналог ASan для бинарника, который вы не можете пересобрать |
| **AFL++** | 5.00c | `fuzz_target.sh` `quick_dynamic.sh` | покрытийно-ориентированный фаззинг, режим QEMU |
| libdislocator | вместе с AFL++ | `sanitize_run.sh` `quick_dynamic.sh` | страница на каждое выделение — превращает тихое OOB-чтение в сбой |
| clang | 21.1.8 | `triage.py` | `-fsanitize=...` на лифтингованном коде |
#### Решение и эмуляция
| Инструмент | Версия | Используется в | Для |
|---|---|---|---|
| **z3** | 4.16.0 | `check_bound.py` | опровергает утверждение о границах — 9 режимов плюс универсальный обходной путь |
| **angr** | 9.2.154 | `symfn.py` | символьная обвязка на каждую функцию: перехват, OOB-запись, деление на ноль |
| **unicorn** | 2.1.4 | `emulate.py` | запуск ОДНОЙ функции изолированно на выбранных вами входных данных |
| triton | 3.7.0 | доступен | concolic-выполнение и taint по конкретной трассе |
| pwntools | 4.15.0 | `brief.py` `run_tools.sh` | смещения `cyclic()`, разбор ELF/GOT |
#### Статический анализ декомпилированного C
| Инструмент | Версия | Используется в | Для |
|---|---|---|---|
| cppcheck | 2.21.1 | `run_tools.sh` `analyze.sh` | терпит код, который не компилируется — а вывод декомпилятора не компилируется |
| semgrep | 1.172.0 | `run_tools.sh` `analyze.sh` | правила по шаблонам, сборка не нужна |
| flawfinder | 2.0.20 | `capabilities.sh` | лексический; grep с мнением |
<details>
<summary><b>Также в оболочке</b> — прошивки, форматы, эксплуатируемость</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
Полный инвентарь со всеми версиями: [`devshell/DEVSHELL.md`](https://github.com/tihanyin/rex-skill/blob/main/devshell/DEVSHELL.md)
</details>
---
## 5. Используйте это с чем-то кроме Claude
`general-skill/SKILL-RE.md` — это **один самодостаточный файл** — 3 750 строк простого
Markdown с frontmatter `name`/`description`. Всё, что есть в бандле для Claude,
в одном куске: тот же стандарт доказательств, тот же пайплайн, те же правила насчёт
фаззинга чужой архитектуры. Клонируйте репозиторий, чтобы `scripts/` лежал рядом с ним, затем:
| Раннер | Как |
|---|---|
| **Codex** | укажите `AGENTS.md` на него или вставьте его как системный промпт |
| **opencode** | `{"instructions": ["SKILL-RE.md"]}` в `opencode.json` |
| **Cursor / Windsurf** | добавьте его как правило проекта |
| **Обычный цикл API** | это просто Markdown — добавьте его в начало |
| **Человек** | он читается как учебник; в этом и была суть |
> **Почему две формы?** Бандл для Claude — это ядро на 16 КБ плюс двенадцать справочных файлов,
> загружаемых по требованию — небольшой контекст, пока конкретный вопрос не потребует конкретной
> главы. Только Claude Code следует этим указателям, поэтому все остальные раннеры получают
> единый файл вместо этого.
---
---
## 6. Что внутри```
.
├── 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
Навык работает везде, где работает Claude Code — Linux, macOS, WSL. Это markdown:
ядро, 12 справочников, 7 субагентов и /re-analyze. Ничто в нём не
привязано к платформе, а скрипты — переносимые Python и bash. Что варьируется —
так это инструменты под ними.
DEVSHELL собирается и тестируется на Linux — x86-64 (Ubuntu 22.04.5 LTS) и aarch64. macOS — это место, где он редеет, потому что одиннадцать инструментов вообще не существуют на Darwin:
qemu-user транслирует Linux-системные вызовы, так что он по определению
относится к Linux, и девять кросс-архитектурных sysroot идут вместе с ним.
Что это оставляет на Mac. Каждый статический этап: декомпиляция Ghidra, radare2 и rizin, angr и z3, статические анализаторы, триаж, строки и достижимость. Что вы теряете — так это исполнение: динамическое зондирование, запуски с санитайзерами, фаззинг и любой бинарник чужой архитектуры. Это реальная потеря: падение — самое сильное доказательство, которое есть у этой методологии, и ничто статическое его не заменяет.
Ничто не притворяется иначе. scripts/capabilities.sh сообщает, что хост
действительно может, scripts/pipeline_status.py помечает этап как отсутствующий,
а цена попадает в limitations отчёта. Этап, который не выполнялся, никогда не
сообщается как этап, который выполнился и ничего не нашёл — см. §9.1 навыка.
Короче говоря: анализируйте на Linux. Читайте, планируйте и пишите отчёт где угодно.
Norbert Tihanyi · x.com/@TihanyiNorbert
находка = источник · сток · сломанная защита · затронутый субъект.
всё меньшее — гипотеза.
capabilities.sh | что этот хост действительно может — проверяйте перед планированием |
analyze.sh | весь конвейер по порядку, шаги 0-5, затем передача управления |
batch_analyze.sh | тот же конвейер по каталогу целей |
pipeline_status.py | аудит дерева доказательств: какие этапы выполнялись и чего стоит каждое отсутствие |
overview.py | форма программы: счётчики, дерево вызовов, стоки, источники |
brief.py | вывод каждого инструмента для одной цели, консолидированный, с указанием пробелов |
fn.py | читать одну функцию вместо всей декомпиляции |
reach.py | пути источник → сток по графу вызовов |
bounds_worklist.py | арифметические утверждения, требующие доказательства, в трёх уровнях |
check_bound.py | доказать одно с помощью z3 — 9 режимов плюс универсальный обходной путь |
symfn.py | символьная обвязка для одной функции |
emulate.py | запустить одну функцию изолированно на выбранных вами входных данных |
quick_dynamic.sh | просто запустить: без входных данных, затем входные данные, ломающие большинство вещей |
fuzz_target.sh | фаззинг, нацеленный на канал, который программа действительно читает |
sanitize_run.sh | враждебные аллокаторы — заставить тихий баг кучи упасть |
sanitize.py | карантин текста, управляемого моделью, прежде чем что-либо его прочитает |
| отсутствуют на macOS | qemu-user · gdb · gef · ltrace · strace · valgrind · AFL++ · honggfuzz · frida · bpftrace · rr |
| также | закреплённая сборка capa не проходит собственный набор тестов на Darwin |
| и | фаззинг argv подменяет __libc_start_main, который относится к glibc — эквивалента на macOS нет |