Перейти к содержимому

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

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

На внутреннем аудите 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 как первый аргумент. Вот как через неё найти главную функцию:

  1. В Symbol Tree раскройте раздел Functions и найдите entry (точку входа ELF). Двойной клик откроет её в окне Decompiler — панели справа, показывающей псевдокод на языке, похожем на C.
  2. В псевдокоде entry найдите вызов __libc_start_main. Первый аргумент — адрес main.
  3. Кликните по адресу (выглядит как FUN_004010xx) — Ghidra перейдёт в тело этой функции.
  4. Переименуйте: правый клик → 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_1user_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.