Ghidra MCP — 253 инструмента для разбора чужих программ через ИИ

· 9 мин чтения
mcp reverse-engineering security binary-analysis ai-agents
📂 Исходный код на GitHub

MCP-сервер для Ghidra: 253 инструмента для разбора бинарных файлов, которые ИИ-ассистент вызывает как обычные функции. Плагин для окна Ghidra и отдельный сервер без интерфейса, пакетные операции, проверка соглашений об именах, интеграция с Ghidra Server.

Ghidra MCP — 253 инструмента для разбора чужих программ через ИИ

Ghidra MCP — разбор чужих программ вместе с ИИ-ассистентом

Ghidra — бесплатный дизассемблер от Агентства национальной безопасности США. Программа умеет превращать машинный код обратно в читаемый вид, строить граф вызовов и показывать, что делает бинарный файл. Но управлять ею вручную неудобно: каждое действие — это клик в интерфейсе или запуск скрипта на Java.

Ghidra MCP решает ровно эту проблему. Это сервер протокола Model Context Protocol, который переводит возможности Ghidra в обычные инструменты для ИИ-ассистента. Ассистент получает 253 инструмента: попросить декомпилировать функцию, найти, кто её вызывает, переименовать символ, создать структуру данных, запустить код по шагам.

Проект написан на Java и Python, распространяется под лицензией Apache-2.0 и на момент публикации собрал около 4,8 тысяч звёзд.

Что именно умеет сервер

Разбор бинарных файлов — основная работа проекта.

  • Декомпиляция функций. Тело функции переводится в читаемый псевдокод C-подобного вида. Можно забрать сразу несколько функций одним вызовом.
  • Граф вызовов и перекрёстные ссылки. Кто вызывает функцию, кого вызывает она, какие адреса на неё ссылаются.
  • Поиск строк. Поиск по регулярному выражению с фильтром мусора. Строки — самый дешёвый способ понять, о чём вообще программа.
  • Структуры данных. Создание структур, объединений и перечислений с разбором полей и подсказками по именам.
  • Потоки данных на уровне P-code. P-code — это низкоуровневый псевдокод, который Ghidra строит при разборе. Через граф P-code можно проследить, куда уходит значение переменной или регистра, вперёд или назад.
  • Импорт и экспорт. Таблицы символов, внешние адреса, разрешение импортов по порядковому номеру.

Живой запуск — вторая половина проекта. Появился в версии 5.4.0.

  • Эмуляция P-code. Функцию можно выполнить отдельно, в отрыве от всей программы. Так неизвестные вызовы API определяются перебором хешей за миллисекунды вместо долгого анализа.
  • Подключение к отладчику. 17 Java-точек и 22 инструмента-моста поверх TraceRmi в Ghidra: присоединиться, сделать шаг, поставить точку останова, прочитать регистры и память. Инструменты-мосты — это прямые вызовы к отдельному серверу отладчика. Адреса из статического разбора переводятся в динамические с учётом ASLR.

Отдельный сервер отладчика с 11 августа 2026 года живёт в другом репозитории — d2-game-exe, потому что слой с соглашениями о вызовами D2 заточили под конкретную игру. В этом репозитории остались только прокси-инструменты. Они появляются в списке только если задана переменная GHIDRA_DEBUGGER_URL, иначе их просто нет.

Проверка соглашений внутри инструментов

Самая интересная идея проекта лежит не в количестве инструментов, а в том, что часть правил перенесена из головы разработчика в код сервера.

Обычная картина в большом проекте: через полгода в одном файле живут ProcessItem, process_items, handleItem и ItemProc. Четыре функции делают одно и то же, но названы четырьмя разными людьми или сессиями ИИ. Приводить их к общему виду дольше, чем писать новую функцию, и через год всё повторяется.

Версия 5.0 переносит соглашения в слой инструментов. Там три уровня реакции:

Уровень Что происходит Пример
Поправить самому Изменение применяется молча поле count у uint32 при сохранении само получает префикс dwCount
Предупредить Изменение проходит, но возвращается предупреждение processData → «имя должно быть в PascalCase с глаголом: ProcessData»
Отклонить Изменение блокируется с объяснением смена типа undefined на undefined отклоняется как пустая операция

Что это даёт:

  • ИИ-агенту. Одинаковый результат в каждой сессии, с каждой моделью, при каждом запуске. Стиль-гайд не надо вставлять в каждый промпт: правила знает инструмент, модели остаётся только его вызвать.
  • Команде. Пропадает целый класс замечаний на ревью в духе «у нас так не называют». Спор об именах переносится из code review в инструмент.
  • Один разработчик в большом объёме. Инструмент analyze_function_completeness даёт функции оценку от 0 до 100 процентов. Артефакты, которые нельзя исправить, в итоговую оценку не входят. Одна плохая категория не топит остальные.

Инструменты подгружаются по требованию

253 инструмента — это много. Если показать их все сразу, Gemini API откажется работать: он превращает описания функций в конечный автомат с ограниченным числом состояний и отвечает 400 INVALID_ARGUMENT ещё до первого вызова.

Поэтому по умолчанию при подключении загружаются только группы listing,function,program — 84 метода плюс 8 статических инструментов. Остальное модель добирает сама:

  • search_tools("rename function") — поиск по всему каталогу, включая ещё не загруженные группы. В ответе сразу видно, доступен инструмент сейчас или нет, и какой вызов его включит.
  • list_tool_groups() — список всех категорий и их состояние.
  • load_tool_group("datatype") и unload_tool_group("datatype") — подключить и отключить категорию во время работы.
  • check_tools("rename_symbol,batch_set_comments") — проверить, доступны ли конкретные инструменты.

Отключить это поведение можно флагом --no-lazy или переменной GHIDRA_MCP_LAZY=0. Так придётся делать клиентам, которые игнорируют уведомление tools/list_changed. Gemini API такой режим принимает наотрез.

Отдельная настройка GHIDRA_MCP_REQUIRE_PROGRAM_SELECTORS=1 запрещает вызовы без указания программы. Без неё запрос без program= уходит в ту программу, которая сейчас активна. Для одного открытого файла это нормально, а вот когда файлов открыто несколько, такой вызов молча читает и правит не тот бинарный файл.

Установка

Требования: Java 21 LTS, Apache Maven 3.9+ или Gradle, Ghidra 12.1.3 и Python 3.10+ с uv.

Один и тот же путь работает на всех системах: скрипт python -m tools.setup проверяет окружение, ставит JAR-файлы Ghidra в локальное хранилище Maven, собирает расширение и кладёт его в профиль Ghidra.

git clone https://github.com/bethington/ghidra-mcp.git
cd ghidra-mcp

python -m tools.setup preflight --ghidra-path /path/to/ghidra_12.1.3_PUBLIC
python -m tools.setup ensure-prereqs --ghidra-path /path/to/ghidra_12.1.3_PUBLIC
python -m tools.setup build
python -m tools.setup deploy --ghidra-path /path/to/ghidra_12.1.3_PUBLIC

Шаг deploy при необходимости закрывает уже запущенный Ghidra подходящей версии, ставит расширение, запускает программу, ждёт готовности сервера и прогоняет проверки схемы.

На Arch Linux есть готовые пакеты AUR от сообщества: ghidra-mcp следит за помеченными релизами, ghidra-mcp-git — за веткой main.

Подключение к ассистенту

Основной способ — через stdio. Сервер запускается как дочерний процесс клиента:

uv run bridge-mcp-ghidra

Конфигурация клиента:

{
  "mcpServers": {
    "ghidra-mcp": {
      "command": "/home/<you>/.local/bin/uv",
      "args": ["run", "--directory", "/path/to/ghidra-mcp", "bridge-mcp-ghidra", "--transport", "stdio"],
      "env": { "GHIDRA_MCP_URL": "http://127.0.0.1:8089" }
    }
  }
}

Здесь важен полный путь к uv. Клиент ищет команду по своему собственному PATH, а не по вашему. Приложение, запущенное из меню или из дока macOS, наследует PATH от launchd и не видит ~/.local/bin. Ошибка появляется ещё до старта процесса — spawn uv ENOENT — и в логах Ghidra или самого сервера её нет, потому что процесс просто не создался. Своё значение выводит python -m tools.setup preflight.

Второй способ — HTTP для веб-клиентов и браузерных инструментов:

uv run bridge-mcp-ghidra --transport streamable-http --mcp-host 127.0.0.1 --mcp-port 8081
{
  "mcpServers": {
    "ghidra-mcp-http": {
      "url": "http://127.0.0.1:8081/mcp"
    }
  }
}

Транспорт SSE объявлен устаревшим.

Проверить, что всё живо, можно обычным запросом:

curl http://127.0.0.1:8089/check_connection

Ответом будет строка вида Connected: GhidraMCP plugin running with program '<name>'.

Если клиент разрешает только часть инструментов

Некоторые клиенты пускают ИИ-агента через белый список разрешённых инструментов. Список должен быть коротким, но самодостаточным: без возможности найти точку входа агент не сможет начать, и тогда он идёт в обход и обращается к HTTP-API напрямую через curl. А это уже рушит всю идею единого протокола.

Минимальный набор из четырёх инструментов закрывает задачу целиком:

Инструмент Что даёт
get_metadata Какой бинарный файл загружен: имя, архитектура, базовый адрес, число функций
list_methods Перечисление имён функций постранично. Главный инструмент для ориентации
get_entry_points Откуда начинается выполнение
decompile_function Само тело функции. Принимает адрес или список имён через functions=

Набор работает сам по себе: точки входа и список функций дают адреса, декомпиляция тела называет вызываемые функции, и те снова идут в decompile_function. Дальше по порядку полезности идут get_function_callers, get_function_callees, get_xrefs_to, list_strings, search_functions, list_imports и list_exports — все они только читают данные.

Безопасность

По умолчанию сервер слушает только 127.0.0.1 и не требует пароля. Для одного разработчика за своим рабочим компьютером это нормально.

Если нужно выставить сервер в сеть, сначала задайте три переменные окружения. Без токена сервер откажется стартовать на любом адресе, кроме 127.0.0.1:

Переменная Что делает
GHIDRA_MCP_AUTH_TOKEN Каждый запрос должен нести Authorization: Bearer <токен>. Сравнение идёт за постоянное время
GHIDRA_MCP_ALLOW_SCRIPTS Включает методы запуска скриптов. Они исполняют произвольный Java-код внутри процесса Ghidra, поэтому с версии 5.4.1 выключены по умолчанию
GHIDRA_MCP_FILE_ROOT Ограничивает все операции с файлами каталогом. Не даёт выйти за его пределы через ../

Отдельно про настройки имён. По умолчанию rename_function и другие методы записи отклоняют имена, которые не проходят встроенные проверки, а полям структур добавляют префикс по типу. Слой можно отключить в Edit > Tool Options > GhidraMCP HTTP Server > Strict Naming Enforcement. Предупреждения при этом всё равно возвращаются.

Что ещё есть

Пакетные операции сокращают число вызовов API на 93 процента. Это удобно, когда нужно переименовать или описать сотни функций. Транзакции атомарные: применяется всё изменение или ничего.

Отдельный сервер без окна Ghidra умеет создавать проекты, импортировать и выгружать программы, вести версии в общем Ghidra Server. Он запускается как java -jar GhidraMCPHeadless.jar --bind 0.0.0.0 --port 8089 и подходит для Docker и CI/CD, где графической оболочки нет вообще. Плагин в окне Ghidra отдаёт 239 методов, сервер без интерфейса — 226, а 212 есть в обоих.

Для ИИ предусмотрен готовый процесс документирования функций из семи шагов: венгерская нотация (префикс в имени, который показывает тип), проверка типов и автоматическая оценка полноты. Есть также пакетное документирование, где несколько ИИ-агентов работают над функциями одновременно, поиск забытых функций в промежутках между известными и перенос документации между версиями бинарного файла по совпадению SHA-256 хешей функций.

Подробности по промптам и сценариям — в руководстве по использованию инструментов, полный список методов генерируется из tests/endpoints.json, а лицензия лежит в LICENSE.

Источник: https://github.com/bethington/ghidra-mcp