
Плагин BianryNinja для выявления уязвимостей в декомпилированных бинарных файлах, сочетающий программные проверки и поддержку LLM.
LLM-assisted vulnerability research for Binary Ninja.
VulnFanatic-NG добавляет боковую панель, которая сканирует текущий бинарный файл и спрашивает LLM — по умолчанию локально размещённую модель, совместимую с OpenAI, или Anthropic Claude, Google Gemini, либо Azure OpenAI (см. Бэкенды LLM) — является ли подозрительный код действительно уязвимым. Она работает в основном с выходом декомпилятора (HLIL) Binary Ninja, переходя к ассемблеру при необходимости, и сообщает только о подтверждённых проблемах с кликабельными ссылками на код.
Сканирование выполняется максимум в три фазы (фаза 3 — опциональная и только онлайн):
Находит места вызовов опасных функций, определённых в
rules/phase1_rules.json: strcpy,
memcpy, sprintf/строки формата, system, alloca, scanf, API команд/exec,
слабый ГПСЧ, семейство free/delete (use-after-free / double-free),
чтение недоверенных входных данных в буферы фиксированного размера (recv/read/fread/ReadFile),
SQL-инъекции (sqlite3_exec/mysql_query/PQexec), отключённую проверку сертификатов TLS (SSL_CTX_set_verify/curl), SSRF и некорректное управление привилегиями (setuid/setresgid), семейство memset/bzero и
сравнения с длиной, контролируемой атакующим (memcmp/strncmp →
обход аутентификации) для C/C++, Win32 и (в лучшем случае) Rust FFI. Покрытие
включает укреплённые варианты _chk (FORTIFY) and Annex-K _s variants. Ограниченные
функции форматированного вывода (snprintf и варианты) имеют собственное правило
безопасности по умолчанию, так что корректный аргумент размера не сообщается как переполнение. Места вызовов находятся тремя способами: прямые вызовы именованных символов; вызовы через пересылающие заглушки / PLT-стабы (реальные вызывающие восстанавливаются, поэтому импорт, доступный только через стаб, не пропускается); и — если
vulnfanatic.scanIndirectCalls не выключен — косвенные вызовы через
указатель на функцию или vtable, которые Binary Ninja сопоставил с опасной функцией.
Для каждого места вызова он строит межпроцедурный, ориентированный на декомпилятор контекст,
в пределах лимита токенов (по умолчанию 100k):
__*_chk и проверяющие границы *_s принимают дополнительные ведущие
аргументы, сдвигая позицию формата/размера/назначения,s->buf,
разрешается в реальный размер массива поля, а не в размер указателя s;
определения структур в разделе типов также содержат размеры полей в байтах,0x40
или ограниченная [0, 0xff]), которые модель использует как эталон при сравнении
размера с ёмкостью буфера вместо догадок,vulnfanatic.includeStackLayout),if/циклов/switch, защищающие вызов),Этот контекст вместе со специальным для правила запросом отправляется модели, которая возвращает структурированный вердикт. Не-проблемы отбрасываются. Запросы настроены на сильную локальную модель кода (например, Qwen2.5-Coder) и предписывают ей проанализировать весь поток и выдать только JSON.
Модели предписано отдавать предпочтение полноте (recall) — сообщать о правдоподобных, значимых для безопасности проблемах и выражать неуверенность через Confidence, а не отбрасывать то, что она не может полностью доказать. Она показывает свою работу в черновике (scratchpad), который цитирует дословные фрагменты кода, на которые она опиралась (исходный источник, каждую защиту, размер/длину, соответствующий тип и приёмник), и который сохраняется в находке, чтобы вы могли проверить рассуждения.
Каждая находка несёт Confidence (high/medium/low): high = вся цепочка показана в
контексте; medium = вероятно, с одной-двумя предполагаемыми связями; low = зацепка, заслуживающая
ручной проверки. Это главный показатель (оценка серьёзности модели — вторичное поле).
Установите vulnfanatic.minConfidence, чтобы отбрасывать всё ниже порога.
По умолчанию VulnFanatic-NG отдаёт предпочтение полноте (выявлению реальных проблем). Если ложных срабатываний слишком много, ужесточите настройки любым из способов:
vulnfanatic.validationPass (по умолчанию выкл) — запускает второй проход LLM, который
перепроверяет каждую помеченную проблему на том же контексте (сверяя фрагменты из
черновика и повторно прослеживая поток) и может исправить вердикт или
уверенность. Удваивает вызовы LLM для помеченных кандидатов.
vulnfanatic.validatorModel (и validatorProvider / validatorBaseUrl /
validatorApiKey), чтобы запустить второй проход на другой модели. Второе
мнение гораздо полезнее от независимой модели — у неё меньше общих слепых зон и
гораздо меньше вероятность бездумно одобрить первый вердикт (модели склонны
предпочитать собственные ответы). Хороший паттерн — каскад: быстрая модель в роли
аналитика (широкая полнота) и ваша самая сильная модель в роли валидатора, который запускается только
на помеченных кандидатах. Оставьте модель валидатора пустой, чтобы проверять моделью
аналитика. Валидатор должен быть по крайней мере не слабее аналитика —
более слабый в основном добавляет ложные отклонения. Всё, кроме провайдера/базового URL/ключа/
модели, наследуется из настроек подключения аналитика; пустой ключ валидатора
повторно использует ключ аналитика; а если конечная точка валидатора недоступна, сохраняется первый
вердикт (находка никогда не теряется из-за сбоя валидатора).vulnfanatic.minConfidence (по умолчанию low) — поднимите до medium/, чтобы сообщать
только о более сильных находках.Скорость. Основная задержка на вызов приходится на записываемые рассуждения, поэтому
vulnfanatic.verdictReasoning управляет тем, сколько модель пишет:
concise (по умолчанию) — краткое обоснование на 1–3 предложения, без дословного кода. Намного
быстрее full с небольшой потерей точности; можно также снизить
vulnfanatic.maxResponseTokens.full — подробный черновик с цитируемыми фрагментами (наиболее проверяемый, самый медленный).none — только вердикт. Самый быстрый; сочетайте его с бэкендом, поддерживающим рассуждения
(vulnfanatic.reasoningEffort), чтобы внутреннее мышление модели делало работу.
На простой локальной модели none теряет точность (вообще без цепочки рассуждений).Вспомогательные функции точности, которые всегда включены (они информируют модель, не подавляя находки):
_s (Annex K) и
_chk (FORTIFY), а также API с ограничением длины как безопасные, если только сам аргумент
размера не неверен.Кнопка Scan Offline запускает фазу 1 без модели — чисто программные эвристики,
объявленные в блоке offline каждого правила в phase1_rules.json. Она помечает опасные
места вызовов и исключает заведомо безопасные, присваивая эвристический Confidence:
memcpy/memmove с константной длиной, strcpy
из константной строки, printf с константным форматом, system с константной
командой и т. д. — вызовы, чей управляющий аргумент является константой времени
компиляции и поэтому не может контролироваться атакующим. «Константа» включает значения,
которые анализ множества значений Binary Ninja зафиксировал выше по потоку, а не только
буквальные аргументы.strlen/размера, if (len < …)) — в том числе в функциях, вызываемых по пути, —
так что он, возможно, уже обработан. (Ветвь, которая лишь упоминает переменную без
сравнения, больше не учитывается, что устраняет источник ложных понижений.)Эвристики используют небольшой декларативный словарь в правилах
(constant_safe_args, eliminate_if_all_args_constant, format_arg_lookup,
length_guard_vars, base_confidence, skip), вычисляемый предикатами Python —
без встроенного кода для exec. У большинства правил есть офлайн-определение (переполнение,
форматная строка, выполнение команд, scanf, обработка путей, слабый ГПСЧ, слабый числовой разбор,
изменение привилегий, размер выделения, …). Только две категории, которым действительно нужен
семантический анализ, пропускаются в офлайне и оставляются LLM: семейство free/delete
(use-after-free / double-free, требующее отслеживания времени жизни указателей) и
проверка TLS (ошибка заключается в конкретном константном значении, например
SSL_VERIFY_NONE). Офлайн-сводка сообщает, сколько мест было помечено / исключено / пропущено
(нужна LLM) / не удалось, так что суммы сходятся. Это быстрая сортировка; для настоящего суждения —
и для пропущенных категорий — запустите полное сканирование LLM.
Офлайн-находки по-прежнему строят тот же полный межпроцедурный контекст, который отправило бы
онлайн-сканирование (только для помеченных мест), и сохраняют его, так что после сортировки их
можно экспортировать как данные для тонкой настройки, как и онлайн-находки. Отключите через
vulnfanatic.offlineBuildContext, если нужна максимальная офлайн-скорость.
Запускается только тогда, когда в бинарном файле, судя по всему, есть реальные символы / имена
переменных. Находит чувствительные к безопасности функции, определённые в
rules/phase2_rules.json, —
аутентификация, криптография (вкл. слабые алгоритмы), проверка подписей/сертификатов,
обработка сессий/токенов, контроль доступа, обработка секретов/ключей, валидация ввода,
непостоянное по времени сравнение секретов и небезопасная десериализация, — сопоставляя
по имени функции и строкам, на которые есть ссылки, а затем анализирует модель.
Аудит укрепления прошивки против атак с внесением сбоев (glitching по
напряжению/тактовой частоте/ЭМИ) и побочных каналов (время/потребление), основанный на
рекомендациях по смягчению аппаратных атак. В отличие от фаз 1–2 (которые находят ошибки),
фаза 3 сообщает об отсутствующем или нарушенном контроле укрепления в функции, критичной
для безопасности, — например: ветви с отказом по умолчанию, дважды проверенные решения
безопасности, проверка счётчика после цикла, константы состояния с большим расстоянием Хэмминга
(вместо простых 0/1), постоянное по времени сравнение секрета полной длины, доступ/очистка
секрета со случайным смещением, шифрование-затем-проверка (анти-DFA), счётчики целостности
потока управления, отказ от криптографии в пользовательском пространстве и отсутствие прямой
работы с сырым ключевым материалом (rules/phase3_rules.json).
Поскольку оптимизации компилятора могут удалять защиту на уровне исходного кода, эти контроли лучше всего проверять на скомпилированном бинарном файле — именно это и делается. Фаза 3 — только LLM (онлайн), зависит от символов и отключена по умолчанию; включайте её для каждого сканирования флажком Phase 3 на вкладке New Scan (в офлайн-режиме она не запускается).
Находки перечислены в таблице (status, confidence, phase, CWE, function, address, title) с панелью деталей, показывающей объяснение, черновик анализа и заметки валидации. Двойной щелчок по строке перемещает представление бинарного файла к коду.
Каждая находка начинается со статуса Untriaged. Щёлкните правой кнопкой по строке, чтобы задать статус — Mark as Real Issue, Mark as False Positive или Mark as Untriaged. При каждом изменении статуса появляется текстовое поле "Provide reason:" (причина сохраняется вместе с находкой). Таблица делает статус наглядным: Real Issues — зелёные/жирные и сортируются вверх, False Positives — серые/зачёркнутые и сортируются вниз, Untriaged находятся между ними со своим цветом уверенности. Сводная строка показывает количество.
На каждой вкладке результатов есть кнопка Export triaged (fine-tuning)…, которая экспортирует
только отсортированные находки (Real Issue + False Positive) как JSONL в формате чата OpenAI
для тонкой настройки: каждый пример объединяет исходный системный+пользовательский запрос
с исправленным человеком вердиктом в качестве целевого ответа ассистента (False Positive учит
is_vulnerable=false с вашей причиной; Real Issue закрепляет is_vulnerable=true), так что вы
можете итеративно повышать точность модели на ваших бинарных файлах.
Контекст по каждой находке, показываемый на панели деталей (и используемый для восстановления
запросов тонкой настройки), по умолчанию сохраняется полностью — этим управляет
vulnfanatic.storedContextChars (0 = без ограничений; установите положительный предел, например
4000, чтобы ограничить рост BNDB ценой точности контекста).
Панель работает с вкладками. Первая вкладка — всегда New Scan, где вы задаёте:
<timestamp> <mode>, например
2026-06-15 14:03:50 offline),затем нажмите Start Scan или Scan Offline. Каждый запуск открывает собственную вкладку результатов, и находки поступают в неё в реальном времени. Все сканирования хранятся в BNDB, так что вы можете, например, сохранить офлайн-сканирование, а позже добавить онлайн-сканирование или сравнить запуски с разными наборами правил бок о бок — они снова появляются как вкладки при повторном открытии базы данных. Закрытие вкладки навсегда удаляет это сканирование из BNDB — во избежание случайностей появляется подтверждение, требующее отметить "I confirm that I will lose the results from forever." перед активацией кнопки Delete results forever. Export current scan… записывает выбранную вкладку в Markdown/JSON.
У каждого открытого бинарного файла своё независимое состояние панели — свои вкладки сканирований и выполняющееся сканирование. Запуск сканирования в одном бинарном файле и переключение на другой показывает результаты второго (и позволяет сканировать его отдельно); сканирование первого продолжает работать в фоне и остаётся нетронутым при переключении обратно.
Папка пакета этого плагина называется vulnfanatic_ng (допустимый идентификатор Python —
Binary Ninja импортирует имя папки плагина как модуль, поэтому имя с дефисом, например
VulnFanatic-NG, не загрузилось бы).
(Необязательно) Установите точный подсчёт токенов в Python Binary Ninja: ``` pip install tiktoken
Создайте символическую ссылку или скопируйте папку vulnfanatic_ng в каталог пользовательских
плагинов Binary Ninja:
~/Library/Application Support/Binary Ninja/plugins/~/.binaryninja/plugins/%APPDATA%\Binary Ninja\plugins\Например, на macOS: ``` ln -s "$(pwd)/vulnfanatic_ng" "$HOME/Library/Application Support/Binary Ninja/plugins/vulnfanatic_ng"
Перезапустите Binary Ninja (или выполните Reload Plugins). В правой боковой панели появится значок VF.
Откройте Настройки (шестерёнка / Edit ▸ Preferences ▸ Settings) и найдите
vulnfanatic. Установите как минимум:
vulnfanatic.apiProvider определяет, как формируются и аутентифицируются запросы. Контракт вердикта (и все промпты правил) одинаков для всех провайдеров.
AWS Bedrock можно использовать через провайдера
openaiс его OpenAI-совместимой конечной точкой, поэтому отдельный бэкенд не нужен.
Другие полезные настройки: vulnfanatic.maxContextTokens (по умолчанию 100000),
vulnfanatic.maxResponseTokens, vulnfanatic.temperature,
vulnfanatic.reasoningEffort (off/low/medium/high; по умолчанию high — просит
модель подумать перед ответом, где это поддерживается, с сопоставлением по провайдерам:
openai/azure reasoning_effort, anthropic адаптивное мышление + output_config.effort,
google динамический thinkingConfig; автоматически удаляется и повторяется, если модель его отвергает),
vulnfanatic.requestTimeoutSec,
vulnfanatic.callPathMaxDepth / ,
(включать декомпилированные тела функций вдоль
пути вызовов; по умолчанию вкл.) / (предел, по умолчанию 12),
(также включать другие функции, вызываемые вдоль
пути, которые могут содержать проверки границ/валидации; по умолчанию вкл.) /
(предел, по умолчанию 12),
(включать определения struct/union/enum; по умолчанию вкл.) /
(предел, по умолчанию 24),
(прослеживать аргументы вызовов до их производителей
/потребителей и включать их тела; по умолчанию вкл.) /
(предел, по умолчанию 8),
(включать раскладку стековых переменных вызывающей функции,
если в ней есть буфер фиксированного размера; по умолчанию вкл.),
(также сопоставлять опасные вызовы, отправляемые через разрешённый
указатель на функцию/vtable; по умолчанию вкл. — отключите для более быстрого сканирования очень больших бинарных файлов),
(выполнять второй проверочный проход; по умолчанию выкл.) /
/ /
/ (выполнять проверочный проход на
отдельной независимой модели — пусто = та же модель, что у аналитика) /
(//; отбрасывать находки ниже этого уровня; по умолчанию
), (сообщать о местах, которые модель не смогла оценить, как
лиды с уверенностью ("Unscored") вместо их отбрасывания; по умолчанию вкл.),
(пропускать места вызовов переполнения с полностью константными аргументами;
по умолчанию выкл.), (//; объём
рассуждений, которые модель пишет для каждого вердикта, — главный рычаг скорости; по умолчанию ),
/
/ (включать каждый этап; этап 3 —
только для онлайн-сканирования и обычно переключается при каждом сканировании через флажок New Scan, а не здесь),
/ ,
(кодировка tiktoken для оценки токенов; при отсутствии tiktoken используется
эвристика по символам, если tiktoken не установлен),
(строить полный контекст для офлайн-находок, чтобы их можно было
экспортировать для дообучения; по умолчанию вкл.),
(подробный трассировочный вывод конвейера в консоль; по умолчанию выкл.) /
(редактировать все детали, идентифицирующие бинарный файл, чтобы лог можно было
передавать другим — см. ниже),
, (проверять HTTPS
сертификаты; по умолчанию вкл.) / (набор CA для HTTPS — см.
раздел Troubleshooting, если вы столкнулись с ), и
/ /
(укажите эти параметры на свои файлы правил, чтобы настроить
обнаружения и промпты).
Замечание по безопасности: API-ключ хранится в настройках Binary Ninja в открытом виде. Для чувствительных ключей предпочтительнее переопределение через переменную окружения.
Установите vulnfanatic.apiBaseUrl в буквальное значение TEST, чтобы запустить без LLM:
/tmp/vulnfanatic_ng/<binary>-<timestamp>/.Используйте это, чтобы проверить и убедиться, что именно VulnFanatic-NG отправил бы модели, и чтобы итерировать промпты/контекст правил, не тратя время модели.
Включите vulnfanatic.debugLogging, чтобы выводить подробную пошаговую трассировку
конвейера сканирования (и онлайн, и офлайн) в журнал/консоль Binary Ninja: каждое место
вызова, каждое решение о пропуске/исключении, сбор контекста (только размер), каждый
LLM-запрос (провайдер/модель/конечная точка, повторы, fallback'и), каждый вердикт и каждую
найденную находку. API-ключи никогда не записываются в журнал.
Пока включено отладочное журналирование, онлайн-сканирование сохраняет каждого кандидата в таблице результатов, вместо того чтобы отбрасывать тех, кто не стал подтверждённой проблемой; каждый помечен статусом, доступным только в режиме отладки (затемнён, отсортирован вниз):
Таким образом, отладочное сканирование показывает по одной строке на каждого кандидата в общем
количестве /N, а сводка отдельно сообщает количество проблем и отклонённых/пропущенных/ошибочных.
Вы можете щёлкнуть правой кнопкой мыши по любой из этих строк, чтобы переклассифицировать её как
Real Issue или False Positive (что делает её пригодной для экспорта на дообучение). (Офлайн-сканирования
не затрагиваются — они никогда не вызывают LLM.)
Независимо от режима отладки, когда модель возвращает неразбираемый ответ — случайный токен вроде
<unused…> у Gemma, прозу вместо JSON или пустое сообщение (только role, без content) — клиент
делает одну корректирующую повторную попытку, снова запрашивая JSON только с отключённым форматом
структурированного вывода; если это удаётся, он оставляет формат выключенным до конца сканирования. Клиент
также читает канал рассуждений (reasoning_content / reasoning), когда content пуст, поэтому
reasoning-модели, помещающие ответ туда, тоже работают.
Случай пустого сообщения часто встречается у reasoning-моделей, таких как GPT-OSS / o1, обслуживаемых
через OpenAI-совместимый API (например, mlx-community/gpt-oss-20b): при установленном
response_format=json_object канал "final"-ответа harmony часто подавляется, и сервер возвращает
{"role": "assistant"} без содержимого. Эти модели также могут израсходовать весь свой бюджет вывода на
канал рассуждений и быть обрезанными на середине мысли, возвращая прозу вообще без JSON. Автоповтор
исправляет случаи, связанные с форматом; если это продолжается, отключите vulnfanatic.sendJsonResponseFormat,
уменьшите vulnfanatic.reasoningEffort (чтобы на размышления уходило меньше бюджета) и/или увеличьте
vulnfanatic.maxResponseTokens. Устойчивый ответ <unused…>/мусор обычно означает, что промпт превышает
окно контекста модели (задайте vulnfanatic.modelContextWindow и/или увеличьте длину контекста на сервере),
или что модель плохо подходит для строгого JSON-вывода (кодовая модель вроде Qwen2.5-Coder ведёт себя здесь
гораздо лучше, чем Gemma).
Фолбэк, сохраняющий полноту. Когда кандидата по-прежнему не удаётся оценить после повторной попытки,
vulnfanatic.flagUnparseableResponses (по умолчанию вкл.) всё равно сообщает о нём как о находке
"Unscored" с уверенностью UNKNOWN — значением, отличным от low (модель никогда не выносила
вердикт, так что это не низкоуверенное суждение), которое сортируется вниз, — сохраняя частичный вывод
модели в качестве объяснения; таким образом, вы не теряете место, а просто просматриваете его вручную.
Отключите эту опцию, чтобы вместо этого отбрасывать такие места (тогда они появляются только как ошибки
анализа или строки ERROR в отладочном режиме).
Также включите vulnfanatic.debugAnonymous, чтобы сделать лог безопасным для передачи: он
редактирует всё, что может идентифицировать анализируемый файл — имена символов/переменных и адреса
становятся хешами с солью для каждого запуска (при этом консистентны в рамках запуска, чтобы поток был
прослеживаем), имя файла скрывается, текст находок заменяется на <redacted>, хост LLM-эндпоинта
хешируется, а декомпилированный код / промпты / контекст логируются только как размеры (не содержимое).
Поэтому вы можете отправить отладочный лог для сообщения о проблеме, не раскрывая ничего о вашем бинарном
файле.
Находки — включая их статус ложного срабатывания — хранятся в базе данных Binary Ninja.
Они записываются в .bndb при сохранении базы данных (и немедленно сбрасываются, если
.bndb уже существует), поэтому они переживают повторное открытие.
Сканирование анализирует каждое подходящее место вызова (без ограничения), что уместно для локальных моделей. Для размещённого/платного эндпоинта учитывайте объём на больших бинарных файлах.
Оба файла правил используют общую обёртку с общим system_prompt и
output_schema, а также список rules. Скопируйте входящий в комплект файл, отредактируйте
функции/ключевые слова/промпты и укажите vulnfanatic.rulesPhase1Path /
vulnfanatic.rulesPhase2Path на свою копию. Правила этапа 1 сопоставляются по functions (точно)
и name_regex; правила этапа 2 — по name_keywords, name_regex и
string_keywords. В prompt каждого правила можно использовать плейсхолдер {function}.
Экспорт после триажа предназначен для прямой подачи обратно в модель. После
триажа находок по нескольким бинарным файлам и нажатия Export triaged
(fine-tuning)… на каждом (сбор файлов .jsonl в одну папку),
scripts/finetune_mlx.py выполняет на них MLX LoRA-дообучение.```bash
pip install mlx-lm # Apple Silicon / macOS
python scripts/finetune_mlx.py ./exports
--model mlx-community/Qwen2.5-Coder-7B-Instruct-4bit
--adapter-path ./vf-adapters --iters 800
python scripts/finetune_mlx.py ./exports --model
--fuse --fused-path ./vf-qwen-coder-vuln
Скрипт принимает **папку training-data** в качестве позиционного аргумента и
базовую **`--model`** (локальный путь или идентификатор репозитория MLX/HF); остальные параметры необязательны:
`--adapter-path`, `--valid-split` (0.1), `--iters`, `--batch-size` (автоматически ограничивается до
соответствия небольшому разбиению), `--num-layers`, `--learning-rate`, `--max-seq-length`
(`0` = **автоподбор** по самому длинному примеру, с ограничением до 16384; укажите положительное значение, чтобы
принудительно задать его), `--fine-tune-type` (`lora`/`dora`/`full`), `--seed`, `--fuse`/`--fused-path`,
и `--dry-run` (подготовить данные + вывести команду без обучения). Всё, что указано после
литерального `--`, передаётся дословно в `mlx_lm lora`. Он рекурсивно объединяет все
файлы `*.jsonl` в папке, проверяет и **дедуплицирует** чат-примеры, создаёт
разбиение `train.jsonl`/`valid.jsonl`, которое ожидает MLX, затем запускает `python -m mlx_lm lora`
(и `mlx_lm fuse` с параметром `--fuse`).
Опубликуйте результат с помощью OpenAI-совместимого сервера (`mlx_lm.server --model <path>`)
и укажите `vulnfanatic.apiBaseUrl` на него, чтобы сканировать с вашей дообученной моделью.
> Контексты VulnFanatic-NG велики, поэтому по умолчанию скрипт **автоподбирает**
> `--max-seq-length` под ваш самый длинный пример (с округлением вверх, с ограничением в **16384 токена**).
> Длинные последовательности занимают основную часть памяти при обучении, поэтому большая модель вблизи этого предела может вызвать
> нехватку памяти на Mac поменьше. Если ваши примеры превышают предел, они усекаются — передайте
> большее `--max-seq-length` (больше памяти) или уменьшите `vulnfanatic.storedContextChars`
> перед экспортом. Если обучение прерывается сигналом (например, `exit -10` / SIGBUS), это
> сбой из-за нехватки памяти: уменьшите `--max-seq-length`, добавьте `-- --grad-checkpoint` или используйте
> модель поменьше.
---
## Разработка и тестирование
У плагина нет обязательных сторонних зависимостей. Чистые модули
(`rules`, `tokens`, `llm`, `findings`, `settings`, `prototypes`) покрыты
автономным набором тестов, которому не нужны ни Binary Ninja, ни сеть. Набор `tests/`
находится в исходном репозитории проекта (он не поставляется внутри
публикуемого плагина); запускайте его оттуда. Из каталога пакета вы по-прежнему можете
проверить синтаксис каждого модуля:```
python3 -m py_compile *.py ui/*.py
python3 -m unittest discover -s tests # from the source repository
Модули, ориентированные на Binary Ninja (context_builder, phase1, phase2), импортируются
без Binary Ninja без проблем (их доступ к API защищён), но для работы требуют запущенного
Binary Ninja.
strcpy из argv[1] в
фиксированный стековый буфер и вызывает system() для входных данных). Скомпилируйте с символами,
чтобы также задействовать фазу 2.vulnfanatic.apiBaseUrl,
vulnfanatic.apiKey и vulnfanatic.model.SSL: CERTIFICATE_VERIFY_FAILED ... unable to get local issuer certificate —
сертификат HTTPS-эндпоинта в порядке, но в комплектном Python из Binary Ninja нет
набора корневых сертификатов (CA bundle) для его проверки (часто встречается на macOS и во встроенных Python; вы увидите
это у хостинг-эндпоинтов вроде AWS Bedrock, Anthropic, Google, Azure). Исправляется одним
из следующих способов, в порядке предпочтения:
pip install certifi.
VulnFanatic-NG подхватит его автоматически.vulnfanatic.caBundlePath как путь к файлу пакета (или
каталогу) — например, путь, выводимый python3 -m certifi, или /etc/ssl/cert.pem.vulnfanatic.tlsVerify (только для доверенного/внутреннего
эндпоинта или локального сервера с самоподписанным сертификатом — это отключает проверку сертификатов).HTTP 400 ... tokenizer.chat_template is not set — у обслуживаемой вами модели
нет chat-шаблона, поэтому эндпоинт /chat/completions не может форматировать
сообщения. VulnFanatic-NG автоматически переключается на эндпоинт /completions для
остальной части сканирования, когда видит эту ошибку, поэтому сканирование продолжается. Чтобы полностью
избежать первого неудачного запроса, установите vulnfanatic.apiMode в completions. Альтернативно,
исправьте это на стороне сервера, обслуживая модель с chat-шаблоном, или передайте его
вашему серверу — например, для vLLM: --chat-template <template.jinja> (или используйте
вариант модели -Instruct/-Chat). Специализированный chat-шаблон обычно даёт
лучшие результаты, чем плоский промпт completions.
No JSON object found ... response looks truncated — ответ модели был обрезан
до завершения JSON. Две причины:
vulnfanatic.maxResponseTokens.maxResponseTokens. Локальные серверы часто имеют небольшое окно (ollama по умолчанию
использует num_ctx=2048!). Исправьте это, установив vulnfanatic.modelContextWindow в значение
окна вашего сервера (например, ollama num_ctx, llama.cpp -c, vLLM --max-model-len) —
VulnFanatic-NG затем автоматически ограничивает отправляемый контекст, чтобы промпт + ответ помещались.
Также держите vulnfanatic.maxResponseTokens разумным (≈8192, а не 65535) и/или увеличьте
окно сервера. Крошечные окна (≤8k) не могут вместить полный межпроцедурный контекст;
используйте модель/сервер, настроенные на 32k+.IncompleteRead / Could not complete request ... after N attempt(s) —
сервер принял запрос, но закрыл соединение до отправки полного
ответа. Это почти всегда означает, что сервер модели завершился или завис в процессе генерации:
нехватка памяти (большой контекст + длинный вывод), внутренний/рабочий тайм-аут или прокси,
сбрасывающий соединение. VulnFanatic-NG автоматически повторяет попытку один раз, а затем пропускает этот
сайт. Проверьте собственные журналы сервера модели, чтобы найти настоящую причину; уменьшение
vulnfanatic.maxContextTokens и/или vulnfanatic.maxResponseTokens или выделение серверу больше
памяти / большего контекстного окна обычно решает проблему.
vulnfanatic.phase2ForceEnable, чтобы также проверять сопоставления по именам, или
vulnfanatic.phase2RequireSymbols=off. Символьный фильтр — эвристика.response_format=json_object; клиент
терпимо относится к этому и всё равно извлекает JSON. Отключите vulnfanatic.sendJsonResponseFormat,
если ваш сервер полностью отклоняет этот параметр.Apache-2.0 (© Martin Petran) — см. plugin.json.
MAIN→ABCD→strcpy также функции, которые MAIN и ABCD вызывают в других местах),
поскольку в них могут находиться проверки границ/валидации, управляющие опасным значением
(vulnfanatic.includeCallPathSiblings, заполняется, пока позволяет бюджет), иrecv/read/getenv, вызываемые в той же функции).highvulnfanatic.skipConstantArgCalls (по умолчанию выкл) — пропускать места вызовов класса
переполнения, все аргументы которых являются константами времени компиляции.| Setting | Meaning |
|---|
vulnfanatic.apiProvider | Какой LLM-бэкенд вызывать: openai (по умолчанию), anthropic, google или azure. См. LLM backends ниже. Все провайдеры доступны через стандартную библиотеку Python — ничего pip install не требуется. |
vulnfanatic.apiBaseUrl | Базовый URL конечной точки для выбранного провайдера (см. таблицу ниже). По умолчанию http://localhost:8080/v1. Установите буквальное значение TEST, чтобы включить тестовый режим (см. ниже). |
vulnfanatic.apiKey | API-ключ / bearer-токен. Может быть пустым для локальных серверов. Переопределяется переменными окружения VULNFANATIC_API_KEY или OPENAI_API_KEY. |
vulnfanatic.model | Обязательно (кроме тестового режима). Идентификатор модели (для azure — имя развёртывания). |
vulnfanatic.apiMode | Только для openai: chat (по умолчанию, /chat/completions) или completions (один плоский промпт — для базовых/instruct-моделей, обслуживаемых без чат-шаблона). |
vulnfanatic.azureApiVersion | Только для azure: параметр запроса api-version (по умолчанию 2024-10-21). |
| Provider | apiBaseUrl | Аутентификация | Примечания |
|---|
openai | ваш сервер, напр. http://localhost:8080/v1 | Authorization: Bearer | OpenAI-совместимые Chat/Completions: локальные llama.cpp / ollama / vLLM, OpenAI и OpenAI-совместимая конечная точка AWS Bedrock. |
anthropic | пусто → https://api.anthropic.com | x-api-key + anthropic-version | Claude Messages API (POST <base>/v1/messages). temperature не отправляется (текущие модели Claude отвергают его). |
google | пусто → https://generativelanguage.googleapis.com | API-ключ в URL | Gemini generateContent (<base>/v1beta/models/<model>:generateContent). |
azure | https://<resource>.openai.azure.com | заголовок api-key | Azure OpenAI; задайте model как имя развёртывания, а azureApiVersion — как вашу версию API. |
vulnfanatic.callPathMaxPathsvulnfanatic.callPathIncludeBodiesvulnfanatic.callPathMaxBodiesvulnfanatic.includeCallPathSiblingsvulnfanatic.callPathSiblingMaxBodiesvulnfanatic.includeDataTypesvulnfanatic.maxTypeDefsvulnfanatic.includeVariableDataflowvulnfanatic.dataflowMaxFunctionsvulnfanatic.includeStackLayoutvulnfanatic.scanIndirectCallsvulnfanatic.validationPassvulnfanatic.validatorModelvulnfanatic.validatorProvidervulnfanatic.validatorBaseUrlvulnfanatic.validatorApiKeyvulnfanatic.minConfidencelowmediumhighlowvulnfanatic.flagUnparseableResponsesUNKNOWNvulnfanatic.skipConstantArgCallsvulnfanatic.verdictReasoningconcisefullnoneconcisevulnfanatic.runPhase1vulnfanatic.runPhase2vulnfanatic.runPhase3vulnfanatic.phase2RequireSymbolsvulnfanatic.phase2ForceEnablevulnfanatic.tokenizerEncodingvulnfanatic.offlineBuildContextvulnfanatic.debugLoggingvulnfanatic.debugAnonymousvulnfanatic.sendJsonResponseFormatvulnfanatic.tlsVerifyvulnfanatic.caBundlePathCERTIFICATE_VERIFY_FAILEDvulnfanatic.rulesPhase1Pathvulnfanatic.rulesPhase2Pathvulnfanatic.rulesPhase3Path