
BianryNinja 플러그인: 디컴파일된 바이너리에서 취약점을 식별하며 프로그래매틱 스캔과 LLM 지원을 모두 제공합니다.
LLM 기반 취약점 연구 도구 for Binary Ninja.
VulnFanatic-NG는 사이드바 패널을 추가하여 현재 바이너리를 스캔하고 LLM(기본값은 로컬 호스팅 OpenAI 호환 모델, 또는 Anthropic Claude, Google Gemini, Azure OpenAI — LLM 백엔드 참조)에게 의심스러운 코드가 실제로 취약한지 판단하도록 요청합니다. 주로 Binary Ninja의 디컴파일러 출력(HLIL) 을 사용하며, 필요시 어셈블리로 폴백하고, 확인된 문제만 코드로의 클릭 가능한 참조와 함께 보고합니다.
스캔은 최대 3단계로 진행됩니다(3단계는 옵트인이며 온라인 전용).
rules/phase1_rules.json에 정의된 위험한 함수의 호출 지점을 찾습니다 — strcpy, memcpy, sprintf/포맷 문자열, system, alloca, scanf, 명령어/실행 API, 취약한 RNG, 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) 및 Annex-K _s 변형도 포함됩니다. 제한된 포맷 출력 함수(snprintf 및 변형)는 자체 기본 안전 규칙을 가지므로 올바른 크기 인수가 오버플로로 보고되지 않습니다. 호출 지점은 세 가지 방식으로 찾습니다: 명명된 심볼에 대한 직접 호출; 포워딩 thunk / PLT 스텁을 통한 호출(실제 호출자가 복구되므로 스텁을 통해서만 도달하는 임포트도 놓치지 않음); 그리고 vulnfanatic.scanIndirectCalls가 꺼져 있지 않은 한 — Binary Ninja가 위험한 함수로 해석한 함수 포인터 또는 vtable을 통해 디스패치되는 간접 호출. 각 호출 지점에 대해 프로시저 간, 디컴파일러 중심의 컨텍스트를 구축하며, 토큰 제한(기본값 100k) 이내로 예산이 할당됩니다:
__*_chk 및 경계 검사 *_s 변형은 추가 선행 인수를 취하여 포맷/크기/대상 위치를 변경함,s->buf와 같은 구조체 필드는 s의 포인터 크기가 아닌 필드의 실제 배열 크기로 해석됨; 타입 섹션의 구조체 정의도 필드별 바이트 크기를 전달함,0x40으로 증명되거나 [0, 0xff]로 제한됨), 모델이 크기를 버퍼 용량과 비교할 때 추측 대신 실제 기준으로 사용함,vulnfanatic.includeStackLayout),if/루프/switch 조건),해당 컨텍스트와 규칙별 프롬프트가 모델로 전송되며, 모델은 구조화된 판정을 반환합니다. 문제가 아닌 것은 제외됩니다. 프롬프트는 강력한 로컬 코드 모델(예: Qwen2.5-Coder)에 맞게 조정되었으며, 전체 흐름을 분석하고 JSON만 출력하도록 지시합니다.
모델은 재현율을 선호하도록 지시됩니다 — 그럴듯하고 보안 관련 문제를 보고하고, 완전히 증명할 수 없는 것은 버리지 않고 신뢰도(Confidence) 를 통해 불확실성을 표현합니다. 모델은 스크래치패드에 작업 과정을 보여주며, 이는 의존한 코드 조각(입력 소스, 각 가드, 크기/길이, 관련 타입, 싱크)을 그대로 인용하며, 이는 발견 항목에 저장되어 추론을 감사할 수 있습니다.
각 발견 항목은 신뢰도(높음/중간/낮음)를 전달합니다: 높음 = 전체 체인이 컨텍스트에 표시됨; 중간 = 가능성 있음, 하나 또는 두 개의 링크가 추론됨; 낮음 = 수동 검토가 필요한 단서. 이것이 주요 지표입니다(모델의 심각도 추정은 보조 필드). vulnfanatic.minConfidence를 설정하여 임계값 미만의 항목을 제외할 수 있습니다.
기본적으로 VulnFanatic-NG는 재현율(실제 문제 발견)을 선호합니다. 너무 많은 오탐이 발생하면 다음 중 하나로 조정할 수 있습니다:
vulnfanatic.validationPass (기본값 꺼짐) — 두 번째 LLM 패스를 실행하여 각 플래그된 문제를 동일한 컨텍스트에 대해 이중 검증(스크래치패드 조각 확인 및 흐름 재추적)하며, 판정이나 신뢰도를 수정할 수 있습니다. 플래그된 후보에 대해 LLM 호출이 두 배가 됩니다.
vulnfanatic.validatorModel(및 validatorProvider / validatorBaseUrl / validatorApiKey)을 설정하여 두 번째 패스를 다른 모델에서 실행합니다. 독립적인 모델의 두 번째 의견이 훨씬 더 유용합니다 — 블라인드 스팟을 덜 공유하고 첫 번째 판정을 쉽게 도장 찍지 않을 가능성이 높습니다(모델은 자신의 답변을 선호하는 경향이 있음). 좋은 패턴은 캐스케이드: 빠른 모델을 분석자(넓은 재현율)로, 가장 강력한 모델을 검증자로 사용하며, 검증자는 플래그된 후보에 대해서만 실행됩니다. 검증자 모델을 비워두면 분석자 모델로 검증합니다. 검증자는 분석자보다 최소한 동등한 능력을 가져야 합니다 — 더 약한 모델은 주로 오탐만 추가합니다. 공급자/기본 URL/키/모델을 제외한 모든 것은 분석자 연결 설정에서 상속됩니다; 빈 검증자 키는 분석자 키를 재사용합니다; 검증자 엔드포인트에 연결할 수 없으면 첫 번째 판정이 유지됩니다(검증자 중단으로 발견 항목이 손실되지 않음).vulnfanatic.minConfidence (기본값 low) — medium/high로 높이면 더 강력한 발견 항목만 보고합니다.vulnfanatic.skipConstantArgCalls (기본값 ) — 인수가 모두 컴파일 타임 상수인 오버플로 클래스 호출 지점을 건너뜁니다.속도. 대부분의 호출당 지연 시간은 작성된 추론에 있으므로, vulnfanatic.verdictReasoning 은 모델이 작성하는 양을 제어합니다:
concise (기본값) — 간결한 1~3문장 근거, 코드 인용 없음. full보다 훨씬 빠르며 정확도 손실이 거의 없음; vulnfanatic.maxResponseTokens를 낮출 수도 있음.full — 인용된 조각이 포함된 상세 스크래치패드(가장 감사 가능, 가장 느림).none — 판정만. 가장 빠름; 추론 가능한 백엔드(vulnfanatic.reasoningEffort)와 함께 사용하여 모델의 내부 사고가 작업을 수행하도록 함. 일반 로컬 모델에서 none은 정확도를 잃음(체인 오브 thought 전혀 없음).항상 켜져 있는 정밀도 지원 기능(모델에 정보를 제공하지만 발견 항목을 억제하지 않음):
_s(Annex K) 및 _chk(FORTIFY) 변형과 길이 제한 API를 크기 인수 자체가 잘못되지 않는 한 안전한 것으로 처리합니다.Scan Offline 버튼은 모델 없이 1단계를 실행합니다 — phase1_rules.json의 각 규칙에 있는 offline 블록에 선언된 순수 프로그램적 휴리스틱입니다. 위험한 호출 지점을 플래그하고 명백히 안전한 것은 제거하며, 휴리스틱 신뢰도를 할당합니다:
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, 경로 처리, 취약한 RNG, 취약한 숫자 파싱, 권한 변경, 할당 크기 등)가 있습니다. 진정으로 의미 분석이 필요한 두 가지 범주만 오프라인에서 건너뛰고 LLM에 맡깁니다: free/delete 계열(use-after-free / double-free, 포인터 수명 추적 필요) 및 TLS 검증(버그는 SSL_VERIFY_NONE과 같은 특정 상수 값). 오프라인 요약은 플래그/제거/건너뜀(LLM 필요)/실패된 사이트 수를 보고하여 합계가 맞춰집니다. 이는 빠른 트라이지입니다; 실제 판단 — 및 건너뛴 범주에 대해서는 — 전체 LLM 스캔을 실행하십시오.
오프라인 발견 항목은 온라인 스캔이 보낼 동일한 전체 프로시저 간 컨텍스트(플래그된 사이트에 대해서만)를 구축하고 저장하므로, 트라이지 후 온라인 발견 항목과 마찬가지로 파인튜닝 데이터로 내보낼 수 있습니다. 최대 오프라인 속도를 원하면 vulnfanatic.offlineBuildContext로 비활성화하십시오.
바이너리에 실제 심볼/변수 이름이 있는 것으로 보일 때만 실행됩니다. rules/phase2_rules.json에 정의된 보안에 민감한 함수를 찾습니다 — 인증, 암호화(약한 알고리즘 포함), 서명/인증서 검증, 세션/토큰 처리, 접근 제어, 비밀/키 처리, 입력 검증, 비상수 시간 비밀 비교, 안전하지 않은 역직렬화 — 함수 이름 및 참조된 문자열로 일치시킨 후 모델이 감사합니다.
펌웨어 강화 감사: 오류 주입(전압/클록/EM 글리칭) 및 부채널(타이밍/전력) 공격에 대한 것으로, 하드웨어 공격 완화 지침에 기반합니다. 1~2단계(버그를 찾음)와 달리, 3단계는 보안에 중요한 함수에서 누락되거나 위반된 강화 제어를 보고합니다. 예: 기본 실패 분기, 이중 확인된 보안 결정, 루프 후 카운터 검증, 높은 해밍 거리 상태 상수(단순 0/1 대신), 상수 시간 전체 길이 비밀 비교, 무작위 오프셋 비밀 접근/지우기, 암호화 후 검증(anti-DFA), 제어 흐름 무결성 카운터, 사용자 영역 암호화 회피, 원시 키 자료 직접 처리 회피 (rules/phase3_rules.json).
컴파일러 최적화는 소스 수준 보호를 제거할 수 있으므로, 이러한 제어는 컴파일된 바이너리에서 가장 잘 확인됩니다 — 정확히 이것이 확인하는 것입니다. 3단계는 LLM 전용(온라인), 심볼 게이트, 기본적으로 비활성화됨; 새 스캔 탭의 Phase 3 체크박스로 스캔당 활성화할 수 있습니다(오프라인 모드에서는 절대 실행되지 않음).
발견 항목은 표(상태, 신뢰도, 단계, CWE, 함수, 주소, 제목)에 나열되며, 설명, 분석 스크래치패드, 검증 노트를 보여주는 세부 정보 창이 있습니다. 행을 더블 클릭하면 바이너리 뷰가 해당 코드로 이동합니다.
모든 발견 항목은 Untriaged(미분류) 로 시작합니다. 행을 마우스 오른쪽 버튼으로 클릭하여 상태를 설정합니다 — Real Issue로 표시, False Positive로 표시, 또는 Untriaged로 표시. 각 상태 변경 시 "Provide reason:" 텍스트 상자가 나타납니다(이유는 발견 항목과 함께 저장됨). 표는 상태를 명확히 보여줍니다: Real Issue는 녹색/굵게 표시되어 맨 위로 정렬되고, False Positive는 회색/취소선으로 맨 아래로 정렬되며, Untriaged는 그 사이에 신뢰도 색상으로 표시됩니다. 요약 줄에 카운트가 표시됩니다.
각 결과 탭에는 Export triaged (fine-tuning)… 버튼이 있어 분류된 발견 항목(Real Issue + False Positive)만 OpenAI 채팅 형식 JSONL로 내보내 파인튜닝에 사용합니다: 각 예제는 원래 시스템+사용자 프롬프트를 인간이 수정한 판정과 어시스턴트 대상으로 쌍을 이룹니다(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와 같이 하이픈이 포함된 이름은 로드되지 않음).
(선택 사항) Binary Ninja의 Python에 정확한 토큰 계산 설치: ``` 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 / vulnfanatic.callPathMaxPaths,
(호출 경로를 따라 함수의 디컴파일된 본문 포함; 기본값 켜짐) / (상한, 기본값 12),
(경로를 따라 호출된 다른 함수도 포함, 경계/유효성 검사를 보유할 수 있음; 기본값 켜짐) /
(상한, 기본값 12),
(struct/union/enum 정의 포함; 기본값 켜짐) /
(상한, 기본값 24),
(호출 인수를 생산자/소비자를 통해 역추적하고 해당 본문 포함; 기본값 켜짐) /
(상한, 기본값 8),
(호출 함수에 고정 크기 버퍼가 있을 때 스택 변수 레이아웃 포함; 기본값 켜짐),
(해석된 함수 포인터/vtable을 통해 디스패치된 위험한 호출도 매칭; 기본값 켜짐 — 매우 큰 바이너리에서 더 빠른 스캔을 위해 끄기),
(두 번째 재확인 패스 실행; 기본값 꺼짐) /
/ /
/ (별도의 독립적인 모델에서 유효성 검사 패스 실행 — 빈 칸 = 분석가와 동일한 모델) /
(//; 이 미만의 결과는 폐기; 기본값
), (모델이 점수를 매길 수 없는 사이트를 신뢰도의 "Unscored" 리드로 보고, 폐기하지 않음; 기본값 켜짐),
(모든 상수 오버플로 호출 사이트 건너뛰기;
기본값 꺼짐), (//; 모델이 판정당 얼마나 많은 추론을 작성하는지 — 주요 속도 조절 수단; 기본값 ),
/
/ (각 단계 활성화; Phase 3은 온라인 전용이며 일반적으로 여기보다는 New Scan 체크박스를 통해 스캔별로 전환),
/ ,
(토큰 추정을 위한 tiktoken 인코딩; tiktoken이 설치되지 않은 경우 문자 휴리스틱으로 대체),
(오프라인 결과를 위한 전체 컨텍스트를 구축하여 미세 조정용으로 내보낼 수 있도록 함; 기본값 켜짐),
(콘솔에 상세 파이프라인 추적 출력; 기본값 꺼짐) /
(바이너리 식별 정보를 모두 삭제하여 로그를 공유할 수 있도록 함 — 아래 참조),
, (HTTPS 인증서 확인; 기본값 켜짐) / (HTTPS용 CA 번들 — 가 발생하면 문제 해결 참조), 및
/ /
(감지 및 프롬프트를 사용자 정의하기 위해 자체 규칙 파일을 가리킴).
보안 참고: API 키는 Binary Ninja 설정에 일반 텍스트로 저장됩니다. 민감한 키에는 환경 변수 재정의를 사용하는 것이 좋습니다.
vulnfanatic.apiBaseUrl을 리터럴 값 TEST 로 설정하여 LLM 없이 실행합니다:
/tmp/vulnfanatic_ng/<binary>-<timestamp>/ 아래 자체 파일에 기록됩니다.이것을 사용하여 VulnFanatic-NG가 모델에 보낼 내용을 검사 및 검증하고, 모델 시간을 소모하지 않고 규칙 프롬프트/컨텍스트를 반복할 수 있습니다.
vulnfanatic.debugLogging 을 켜면 스캔 파이프라인(온라인 및 오프라인 모두)의 상세한 단계별 추적을 Binary Ninja 로그/콘솔에 출력합니다: 각 호출 사이트, 모든 건너뛰기/제거 결정, 컨텍스트 빌드(크기만), 각 LLM 요청(공급자/모델/엔드포인트, 재시도, 폴백), 모든 판정, 및 각 보고된 결과. API 키는 절대 기록되지 않습니다.
디버그 로깅이 켜져 있는 동안 온라인 스캔은 확인된 이슈가 되지 않은 후보를 결과 테이블에서 유지하며, 각각 디버그 전용 상태(희미하게 표시, 하단 정렬)가 태그됩니다:
따라서 디버그 스캔은 /N 총계에서 후보당 하나의 행을 표시하며, 요약은 이슈 vs. rejected/skipped/error 카운트를 별도로 보고합니다. 이러한 행 중 하나를 마우스 오른쪽 버튼으로 클릭하여 Real Issue 또는 False Positive로 재분류할 수 있습니다(미세 조정 내보내기 대상이 됨). (오프라인 스캔은 영향을 받지 않습니다 — LLM을 호출하지 않습니다.)
디버그 모드와 무관하게, 모델이 구문 분석 불가능한 응답을 반환하는 경우 — Gemma의 <unused…> 같은 튀는 토큰, JSON 대신 산문, 또는 빈 메시지(오직 role만 있고 content 없음) — 클라이언트는 한 번의 수정 재시도를 수행하며, 구조화된 출력 형식을 비활성화한 상태로 JSON만 다시 요청합니다. 성공하면 스캔의 나머지 부분에 대해 형식이 꺼진 상태로 유지됩니다. 클라이언트는 또한 content가 비어 있을 때 추론 채널(reasoning_content / reasoning)을 읽으므로, 답변을 거기에 넣는 추론 모델도 작동합니다.
빈 메시지 사례는 OpenAI 호환 API(예: mlx-community/gpt-oss-20b)를 통해 제공되는 GPT-OSS / o1과 같은 추론 모델에서 흔합니다: response_format=json_object가 설정되면 하모니 "최종" 답변 채널이 종종 억제되고 서버가 콘텐츠 없이 {"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를 복사본을 가리키도록 설정하세요. Phase 1 규칙은 functions(정확히 일치) 및 name_regex로 매칭되고, Phase 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 저장소 ID)을 인수로 받습니다. 다른 매개변수는 선택 사항입니다: `--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` 파일을 재귀적으로 병합하고, 채팅 예제를 검증 및 **중복 제거**한 후, MLX가 예상하는 `train.jsonl`/`valid.jsonl` 분할을 만든 다음 `python -m mlx_lm lora`를 실행합니다 (`--fuse`를 사용하면 `mlx_lm 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가 구동 중이어야 합니다.
argv[1]을 고정된 스택 버퍼에 strcpy하고 입력에 대해 system()을 호출하는 프로그램). 심볼을 포함하여 컴파일하면 Phase 2도 테스트할 수 있습니다.vulnfanatic.apiBaseUrl, vulnfanatic.apiKey, vulnfanatic.model을 설정하세요.SSL: CERTIFICATE_VERIFY_FAILED ... unable to get local issuer certificate —
HTTPS 엔드포인트의 인증서는 정상이지만, Binary Ninja에 번들된 Python에는 인증서를 검증할 CA 번들이 없습니다 (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/completions 엔드포인트가 메시지를 포맷할 수 없습니다. VulnFanatic-NG는 이 오류가 발생하면 나머지 스캔에 대해 자동으로 /completions 엔드포인트로 **대체(fallback)**하므로 스캔이 계속됩니다. 첫 번째 실패한 요청을 완전히 피하려면 vulnfanatic.apiMode를 completions로 설정하세요. 또는 서버 측에서 채팅 템플릿이 포함된 모델을 제공하거나 서버에 템플릿을 전달하여 해결할 수 있습니다 (예: vLLM의 경우 --chat-template <template.jinja> 또는 -Instruct/-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를 끄세요. 심볼 게이트는 휴리스틱입니다.response_format=json_object를 무시하거나 거부합니다. 클라이언트는 이를 허용하고 여전히 JSON을 추출합니다. 서버가 이 매개변수를 완전히 거부하는 경우 vulnfanatic.sendJsonResponseFormat을 비활성화하세요.Apache-2.0 (© Martin Petran) — plugin.json 참조.
MAIN→ABCD→strcpy의 경우 MAIN 및 ABCD가 다른 곳에서 호출하는 함수도 포함) — 위험한 값을 제어하는 경계/검증 검사를 포함할 수 있으므로(vulnfanatic.includeCallPathSiblings, 예산이 허용하는 동안 채움), 및recv/read/getenv와 같은 입력 함수).| 설정 | 의미 |
|---|
vulnfanatic.apiProvider | 호출할 LLM 백엔드: openai(기본값), anthropic, google, 또는 azure. 아래 LLM 백엔드 참조. 모든 공급자는 Python 표준 라이브러리를 통해 접근됩니다 — pip install이 필요하지 않습니다. |
vulnfanatic.apiBaseUrl | 선택한 공급자의 엔드포인트 베이스(아래 표 참조). 기본값 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(단일 평면 프롬프트 — 채팅 템플릿 없이 제공되는 기본/인스트럭트 모델용). |
vulnfanatic.azureApiVersion | azure 전용: api-version 쿼리 매개변수(기본값 2024-10-21). |
| 공급자 | apiBaseUrl | 인증 | 참고 |
|---|
openai | 사용자 서버, 예: http://localhost:8080/v1 | Authorization: Bearer | OpenAI 호환 Chat/Completions: 로컬 llama.cpp / ollama / vLLM, OpenAI, AWS Bedrock의 OpenAI 호환 엔드포인트. |
anthropic | 빈 칸 → https://api.anthropic.com | x-api-key + anthropic-version | Claude Messages API (POST <base>/v1/messages). temperature는 전송되지 않습니다(현재 Claude 모델이 거부함). |
google | 빈 칸 → https://generativelanguage.googleapis.com | URL에 API 키 | Gemini generateContent (<base>/v1beta/models/<model>:generateContent). |
azure | https://<resource>.openai.azure.com | api-key 헤더 | Azure OpenAI; model을 배포 이름으로 설정하고 azureApiVersion을 API 버전으로 설정합니다. |
vulnfanatic.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