Ghidra анализ бинарных файлов: поиск секретов и уязвимостей в stripped-бинаре

На внутреннем аудите IoT-шлюза мне попался stripped ELF без единого символа — 4 МБ голого кода, тысячи функций с именами вроде FUN_00401a3c. Через 40 минут работы в Ghidra из псевдокода торчал захардкоженный API-ключ AWS и JWT-секрет, которым прошивка валидировала токены авторизации. Разработчики были уверены: «скомпилированный бинарь — это как шифрование». Спойлер: нет. Ниже — пошаговый разбор, как повторить такой поиск самостоятельно: от импорта файла до аннотированного псевдокода с найденными секретами и логическими уязвимостями.
Место реверс-инжиниринга в цепочке пентеста
Реверс-инжиниринг бинарных файлов — это восстановление логики программы из скомпилированного кода. Не самоцель, а инструмент для перехода к следующему этапу атаки.
Когда аналитик открывает декомпилятор:
- Внутренний пентест, этап post-exploitation. На скомпрометированном хосте нашёлся проприетарный агент мониторинга или утилита деплоя. Задача — вытащить захардкоженные учётные данные для подключения к БД или API и использовать их для lateral movement (горизонтального перемещения по сети). Реверс здесь — мост между «есть доступ к хосту» и «есть доступ ко всей инфраструктуре».
- Анализ прошивки (firmware), этап разведки. С IoT-устройства через
binwalk(утилита для извлечения файловых систем из firmware-образов) получен бинарь. Нужно найти ключи шифрования, API-эндпоинты и логические обходы авторизации. - Bug bounty, анализ клиентского приложения. Десктопная или мобильная программа использует бинарную библиотеку. Исследователь ищет уязвимости в логике валидации лицензий или токенов.
В терминах MITRE ATT&CK (открытая база тактик и техник атак — каждая техника имеет T-код, например T1552) захардкоженные секреты в бинарях описываются несколькими техниками. Credentials In Files (T1552.001, тактика credential-access) — пароли и ключи хранятся прямо в файлах программы. Private Keys (T1552.004) — приватный ключ зашит в бинарь или конфигурационный файл рядом. А удаление символов из бинаря для затруднения анализа — Stripped Payloads (T1027.008, тактика defense-evasion).
Зачем это знать: найденные через реверс секреты — не просто «интересная находка». Они конвертируются в конкретные шаги атаки: подключение к внутренним сервисам с извлечённым API-ключом, аутентификация на управляющем сервере с JWT-секретом из прошивки, доступ к БД через захардкоженный пароль.
Ghidra для статического анализа stripped binary: статус и сравнение
Ghidra — бесплатный open-source фреймворк для реверс-инжиниринга от NSA, выпущенный в 2019 году. Главная фишка — встроенный декомпилятор. Это компонент, который преобразует машинный код обратно в читаемый псевдокод, похожий на C. Работает «из коробки» для x86, x64, ARM, MIPS и кучи других архитектур — не нужно докупать лицензии.
Статус проекта: репозиторий на GitHub (NationalSecurityAgency/ghidra) активно поддерживается, более 50 000 звёзд, релизы выходят регулярно.
| Критерий | Ghidra | IDA Pro | radare2 |
|---|---|---|---|
| Стоимость | Бесплатно | От $1000+ (коммерческая лицензия) | Бесплатно |
| Декомпилятор | Встроенный, бесплатный | Hex-Rays — отдельная дорогая лицензия | Через плагин r2ghidra |
| Скриптинг | Java, Jython (Python 2.7) | IDAPython (Python 3) | r2pipe (Python, JS) |
| Когда использовать | Бесплатный декомпилятор, анализ firmware, множество архитектур, командная работа | Профессиональный RE с бюджетом, глубокий анализ PE/COM | Быстрый анализ из CLI, автоматизация в CI/CD |
| Когда НЕ использовать | Динамическая отладка (дебаггер экспериментален), анализ .NET/Java (лучше dnSpy/jadx) | Ограниченный бюджет, нестандартные MCU-архитектуры | Нужна визуальная навигация для новичка |
Ghidra плохо справляется с обфусцированными и упакованными бинарями (VMProtect, Themida, UPX). Если при импорте декомпилятор выдаёт бессмысленный мусор — бинарь, скорее всего, упакован. Определить упаковщик можно через file в терминале (покажет формат и архитектуру) или DIE (Detect It Easy — бесплатная утилита для распознавания упаковщиков и компиляторов).
Импорт бинаря в Ghidra и автоматический анализ
Требования к окружению
- ОС: Windows 10/11, Linux (Ubuntu 20.04+), macOS 12+
- RAM: минимум 4 ГБ, рекомендуется 8 ГБ для бинарей крупнее 10 МБ
- JDK: версия 17 или выше (рекомендуется Adoptium Temurin)
- Ghidra: актуальный релиз с GitHub (github.com/NationalSecurityAgency/ghidra/releases)
- Права: обычный пользователь, root не требуется
- Сеть: не нужна, Ghidra работает полностью offline
Пошаговый импорт stripped-бинаря
Допустим, на руках stripped ELF-бинарь target_app, снятый с устройства или найденный на хосте при пентесте.
Шаг 1. Предварительная разведка. Перед загрузкой в Ghidra соберите базовую информацию. Выполните file target_app в терминале. Ожидаемый вывод: target_app: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, stripped. Слово «stripped» подтверждает: символы отладки удалены, имена функций и переменных потеряны.
Затем выполните strings target_app | grep -iE "key|secret|pass|token|AKIA" — грубый, но быстрый фильтр. Если уже здесь видны подозрительные строки, Ghidra покажет, как именно они используются в логике программы.
Шаг 2. Создание проекта. Запустите Ghidra (ghidraRun на Linux/macOS, ghidraRun.bat на Windows). В главном окне: File → New Project → Non-Shared Project → укажите папку и имя. Проект в Ghidra — контейнер для хранения результатов анализа нескольких файлов, аналог рабочей директории.
Шаг 3. Импорт файла. File → Import File → выберите target_app. Ghidra автоматически определит формат (ELF, PE) и архитектуру. В диалоге импорта проверьте поле Language — оно должно соответствовать ожиданиям (например, x86:LE:64:default для 64-битного x86). Нажмите OK. Признак успеха: в менеджере проекта появится запись с именем файла и иконкой формата.
Шаг 4. Запуск автоанализа. Двойной клик по файлу откроет CodeBrowser — основное рабочее окно. Появится предложение запустить автоматический анализ. Нажмите Yes, оставьте все опции по умолчанию. Анализ занимает от нескольких секунд до нескольких минут в зависимости от размера бинаря. Результат: в нижней панели — сообщение «Analysis completed», а в панели Symbol Tree слева появятся категории Functions, Labels, Imports.
Анализ бинарных файлов без символов: как найти main
В stripped-бинаре окно Functions покажет список вроде FUN_00401020, FUN_00401a3c, FUN_004023f0 — безликие адреса вместо осмысленных имён. Тысячи таких функций выглядят устрашающе, но паниковать рано. Задача — найти точки входа в логику программы, а не разбирать каждую из тысяч функций по очереди.
Entry point и путь к main
Для ELF-бинарей, скомпилированных из C/C++, даже в stripped-варианте сохраняются имена функций из динамических библиотек. Функция __libc_start_main из libc вызывается при старте программы и принимает адрес main как первый аргумент. Вот как через неё найти главную функцию:
- В Symbol Tree раскройте раздел Functions и найдите
entry(точку входа ELF). Двойной клик откроет её в окне Decompiler — панели справа, показывающей псевдокод на языке, похожем на C. - В псевдокоде
entryнайдите вызов__libc_start_main. Первый аргумент — адресmain. - Кликните по адресу (выглядит как
FUN_004010xx) — Ghidra перейдёт в тело этой функции. - Переименуйте: правый клик → Rename Function →
main. Все перекрёстные ссылки обновятся автоматически.
Ghidra decompiler и перекрёстные ссылки
Окно Decompiler — главный инструмент для поиска секретов в Ghidra. Оно показывает псевдокод, который приближённо восстанавливает структуру программы: условия, циклы, вызовы функций. Псевдокод не идентичен исходному коду — он может содержать лишние приведения типов и временные переменные — но логика передаётся верно.
Перекрёстные ссылки (cross-references, xrefs) — механизм навигации. Они показывают, откуда вызывается функция и где используется конкретная строка или переменная. Чтобы увидеть xrefs: выделите имя функции или строку и нажмите клавишу X. Запомните эту клавишу — xrefs связывают найденную строку с местом в коде, где она используется, и именно через них вы будете находить 80% всего интересного.
Поиск хардкодных секретов в бинаре через Ghidra
Хардкодные секреты — API-ключи, пароли, JWT-секреты, приватные ключи — попадают в бинарь вместе с исходным кодом и остаются в секциях данных (.data, .rodata) даже после удаления символов. Компиляция не шифрует строки. Она просто убирает метаинформацию.
Defined Strings: первый проход
Откройте окно строк: Window → Defined Strings. Ghidra покажет все строки, распознанные при автоанализе. Что искать:
- Прямые секреты: строки с фрагментами
password,secret,api_key,token,-----BEGIN RSA PRIVATE KEY-----,Bearer. - Паттерны облачных ключей:
AKIA(AWS Access Key ID),AIza(Google API Key),sk-(OpenAI API Key),ghp_(GitHub Personal Access Token). - Base64-блоки: длинные строки из символов A-Za-z0-9+/= — часто закодированные ключи или сертификаты.
- URL с credentials: строки вида
https://user:pass@hostили URL с API-ключами в query-параметрах.
Фильтр в окне Defined Strings поддерживает поиск по подстроке. Последовательно введите key, secret, pass, token и просмотрите результаты. На бинарь в 4 МБ этот процесс занимает 5–10 минут.
От строки к контексту: перекрёстные ссылки
Найденная строка без контекста — полдела. Нужно понять, как она используется в логике программы. Кликните по строке правой кнопкой → Show References To (или выделите и нажмите X). Ghidra покажет все функции, где строка упоминается. Перейдите в указанную функцию — в Decompiler появится псевдокод с этой строкой.
Пример: вы нашли строку supersecretkey123. Xref ведёт в функцию FUN_004023f0. Переходите и видите:
if (strcmp(param_1, "supersecretkey123") == 0) {
iVar1 = FUN_00402500(param_2);
}
Это паттерн захардкоженной проверки: строковое сравнение входного параметра с константой. Вы нашли точку, где бинарь валидирует аутентификацию по вшитому паролю. По классификации OWASP — A02:2021, Cryptographic Failures (ошибки криптографии, ведущие к раскрытию конфиденциальных данных).
Косвенные паттерны: когда секрет не лежит в открытом виде
Не все разработчики оставляют пароли plain-text. Вот распространённые приёмы маскировки и как их распознать в псевдокоде Ghidra:
XOR-обфускация. В псевдокоде виден цикл, где каждый байт массива XOR-ится (^) с фиксированным значением. По MITRE ATT&CK это T1140 (Deobfuscate/Decode Files or Information). Чтобы получить исходную строку, примените тот же XOR к данным из секции .rodata — операция обратима.
Побайтовая сборка. Вместо цельной строки "password" в коде стоит s[0]='p'; s[1]='a'; s[2]='s'; .... Ghidra покажет это как серию присваиваний. Собрать строку по символам можно вручную — муторно, но работает.
Хеш-сравнение. Бинарь считает хеш от ввода и сравнивает с захардкоженным значением. В псевдокоде это выглядит как вызовы функций с характерными константами (0x5A827999 для SHA-1, 0x6A09E667 для SHA-256). Сам хеш — не пароль, но его можно попробовать сбрутить через hashcat или john.
[Применимо: внутренний пентест и аудит прошивок. Для внешнего пентеста веб-приложений бинари обычно недоступны.]
Ghidra аннотирование кода: от FUN_00401a3c к осмысленной логике
Ghidra не знает, что делает FUN_00401a3c. Но после анализа строк и xrefs вы уже понимаете: это функция валидации токена. Аннотирование — фиксация этого понимания в проекте, чтобы бинарь стал читаемым для отчёта и для повторного анализа.
Переименование функций. Правый клик на имени функции в Decompiler или Listing → Rename Function. Называйте по смыслу: validate_auth_token, decrypt_config, connect_to_backend. Все xrefs обновятся автоматически — если функция вызывается из десяти мест, во всех десяти появится новое имя.
Ретайпинг и переименование переменных. Псевдокод часто показывает переменные как param_1, iVar1, local_28. После анализа контекста: правый клик → Rename Variable (param_1 → user_input), правый клик → Retype Variable. Если Ghidra определила тип как undefined8, а по контексту это строка — измените на char *. Псевдокод сразу станет читабельнее.
Комментарии. Правый клик в строке псевдокода → Set Comment. Типы: EOL (конец строки), Pre (перед блоком), Post (после). Фиксируйте: «здесь сравнивается хардкодный API-ключ», «XOR-деобфускация с ключом 0x42», «условие обхода: если param_2 == 0, авторизация пропускается».
Результат: функция FUN_00401a3c превращается в validate_auth_token с понятными переменными и комментариями. Этот аннотированный псевдокод можно приложить к отчёту пентеста как доказательство уязвимости.
Ghidra логические уязвимости: что видно в псевдокоде
Помимо хардкодных секретов, декомпилятор помогает находить логические уязвимости — ошибки в условиях, позволяющие обойти проверки безопасности.
Обход авторизации через debug-флаг. Разработчик оставил отладочное условие:
if ((debug_mode != 0) ||
(iVar1 = check_password(input), iVar1 != 0)) {
grant_access();
}
Если debug_mode — глобальная переменная в секции .data, проверьте через xrefs, откуда она получает значение. Частый случай: переменная устанавливается через аргумент командной строки (--debug) или переменную окружения (DEBUG=1). Прямой обход аутентификации — и такое я видел в продакшн-прошивках не раз.
Жёстко заданные тестовые пути. Бинарь проверяет серийный номер устройства, но для значений вроде SN000000 или TEST_DEVICE пропускает лицензирование. Xrefs на такие строки покажут, в каких ветках условий они используются.
Целочисленное переполнение. Функция проверяет if (len < 256), но len объявлен как знаковый int. Отрицательное значение проходит проверку, а затем используется как беззнаковое при копировании буфера — путь к переполнению. В псевдокоде Ghidra тип переменной виден в объявлении; если сомневаетесь — проверьте через Retype Variable.
Ограничения Ghidra и когда статического анализа недостаточно
Статический анализ в Ghidra — подход с чёткими границами. Понимание этих границ отличает практика от новичка, который пытается решить декомпилятором задачу, требующую отладчика.
Упакованные бинари. VMProtect, Themida, даже UPX — Ghidra декомпилирует обёртку пакера, а не реальный код. Для UPX достаточно upx -d target_app. Для коммерческих протекторов потребуется динамический дампинг через GDB или x64dbg с точкой останова на OEP (Original Entry Point — адрес, с которого начинается реальный код после распаковки).
Динамическая загрузка. Если бинарь подгружает модули через dlopen/LoadLibrary или вычисляет адреса функций в рантайме — Ghidra не увидит эти вызовы. Тут нужен ltrace (трассировка вызовов динамических библиотек) или strace (трассировка системных вызовов).
Сложная обфускация строк. Когда секреты зашифрованы AES с ключом, который собирается в рантайме из нескольких источников, статический анализ покажет алгоритм, но не результат расшифровки. Поможет GDB с перехватом данных после вызова функции дешифрования.
Go, Rust, Swift. Бинари на Go содержат специфические структуры (pclntab), которые Ghidra «из коробки» разбирает хуже, чем C/C++. По данным исследования CUJO AI, для Go-бинарей существуют дополнительные Ghidra-скрипты (go_func.py), восстанавливающие имена функций даже в stripped-варианте через структуру .gopclntab. Для Rust ситуация аналогична: стандартная библиотека генерирует тысячи служебных функций, и без плагинов навигация превращается в кошмар.
Ghidra анализ бинарных файлов строится на двух вещах: понимание того, что именно искать, и умение навигировать по безымянному коду через строки и перекрёстные ссылки. Stripped-бинарь пугает в первые минуты — тысячи FUN_ без подсказок. Но секреты и логические ошибки не исчезают при удалении символов. Они остаются в секциях данных и в структуре условий, а декомпилятор делает их видимыми.
Основная ошибка начинающих — попытка разобрать весь бинарь целиком, функция за функцией. В stripped ELF на десять тысяч функций это путь в никуда. На практике я открываю Defined Strings, фильтрую по паттернам (key, secret, pass, AKIA), смотрю xrefs — и через 10–15 минут нахожусь в нужной функции. Строки, перекрёстные ссылки, контекст в псевдокоде — эта тройка закрывает 80% задач по поиску хардкодных секретов. Остальные 20% — обфусцированные строки и динамически собираемые ключи — требуют комбинации статики с динамическим анализом, и здесь одной Ghidra уже мало. Компании, которые считают компиляцию защитой своих секретов, ошибаются системно. А пентестер, не умеющий открыть бинарь в декомпиляторе, оставляет целый класс находок нетронутым. Если реверс пока выглядит далёким горизонтом и хочется сначала выстроить фундамент от основ ИБ до первых практических задач — IB Basics на codeby.school берёт с любого старта, без предварительных требований к Linux или программированию.
Эту тему и смежные навыки разбирают на практике в курсе «Профессия Реверс-инженер» Codeby Academy.