
إضافة BianryNinja لتحديد الثغرات الأمنية في الملفات الثنائية المفكّكة، مع دعم كلٍّ من الفحوصات البرمجية ونماذج LLM.
بحث الثغرات بمساعدة LLM لـ Binary Ninja.
يضيف VulnFanatic-NG لوحة جانبية تفحص الثنائي الحالي وتطلب من LLM — نموذج مستضاف محليًا متوافق مع OpenAI افتراضيًا، أو Anthropic Claude أو Google Gemini أو Azure OpenAI (انظر محركات LLM الخلفية) — لتقرير ما إذا كان الكود المشبوه ضعيفًا فعلًا. يعمل بشكل أساسي على مخرجات المُفكِّك (HLIL)، ويعود إلى لغة التجميع عند الحاجة، ويبلغ فقط بالمشكلات المؤكدة مع مراجع قابلة للنقر تعيد إلى الكود.
تعمل عملية الفحص في مراحل يصل عددها إلى ثلاث (المرحلة 3 اختيارية وتعتمد على الإنترنت حصريًا):
يجد مواقع استدعاء الدوال الخطرة المعرّفة في
rules/phase1_rules.json — strcpy،
memcpy، sprintf/سلاسل التنسيق، system، alloca، scanf، واجهات برمجة الأوامر/التنفيذ،
خوارزميات RNG ضعيفة، عائلة free/delete (استخدام بعد التحرير / تحرير مزدوج)،
قراءات مدخلات غير موثوقة في مخازن ثابتة (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 وما يشابهها) لها قاعدة افتراضية آمنة خاصة بها
حتى لا يُبلَّغ عن وسيط حجم صحيح على أنه تجاوز. تُكتشف مواقع الاستدعاء
بثلاث طرق: استدعاءات مباشرة للرموز المسماة؛ استدعاءات تُوجَّه عبر
thunks مُمرِّرة / PLT stubs (يُستعاد المستدعون الحقيقيون، لذا لا يُفوَّت استيراد
لا يُوصَل إليه إلا عبر stub)؛ و— ما لم يكن
vulnfanatic.scanIndirectCalls معطّلًا — استدعاءات غير مباشرة تُرسَل عبر
مؤشر دالة أو vtable حُلّت بواسطة Binary Ninja إلى دالة خطيرة.
لكل موقع استدعاء، يبني سياقًا بين الإجراءات متمحورًا حول المُفكِّك،
محدودًا بحد أقصى للتوكنات (افتراضيًا 100k):
__*_chk والمتغيرات ذات التحقق من الحدود *_s تأخذ وسائط
إضافية في البداية، مما يغيّر موضع التنسيق/الحجم/الوجهة،s->buf
إلى الحجم الحقيقي لمصفوفة الحقل بدلًا من حجم مؤشر s؛
تعريفات البنيات في قسم الأنواع تحمل أيضًا أحجامًا بالبايت لكل حقل،0x40
أو محصور في [0, 0xff])، ويستخدمه النموذج كحقيقة قاطعة عند مقارنة
الحجم بسعة المخزن بدلًا من التخمين،vulnfanatic.includeStackLayout)،if/الحلقة/switch التي تحرس الاستدعاء)،يُرسل هذا السياق مع موجه خاص بالقاعدة إلى النموذج، الذي يعيد حكمًا منظمًا. يتم تجاهل غير المشكلات. وقد ضُبطت الموجّهات لنموذج كود محلي قوي (مثل Qwen2.5-Coder) وتطلب منه تحليل التدفق بالكامل وإخراج JSON فقط.
يُطلب من النموذج تفضيل الاسترجاع — الإبلاغ عن المشكلات المحتملة وذات الصلة بالأمان والتعبير عن عدم اليقين عبر Confidence بدلًا من تجاهل أي شيء لا يستطيع إثباته تمامًا. يعرض عمله في مسودة تقتبس حرفيًا مقتطفات الكود التي اعتمد عليها (مصدر الإدخال، كل حارس، الحجم/الطول، النوع ذي الصلة، والمغسلة)، ويُخزَّن ذلك في النتيجة حتى يمكنك مراجعة الاستدلال.
تحمل كل نتيجة Confidence (عالية/متوسطة/منخفضة): عالية = السلسلة كاملة
ظاهرة في السياق؛ متوسطة = محتملة، مع استنتاج رابط أو رابطين؛ منخفضة = خيط
يستحق مراجعة يدوية. هذا هو المقياس الرئيسي (تقدير النموذج لشدة الخطورة هو
حقل ثانوي). اضبط vulnfanatic.minConfidence لتجاهل أي شيء يقل عن حد معيّن.
افتراضيًا يفضّل VulnFanatic-NG الاسترجاع (اكتشاف المشكلات الحقيقية). إذا حصلت على عدد كبير جدًا من النتائج الإيجابية الخاطئة، فشدّد باستخدام أيٍّ من:
vulnfanatic.validationPass (افتراضيًا معطّل) — يشغّل تمريرة LLM ثانية
تتحقق مرة أخرى من كل مشكلة تم الإبلاغ عنها مقابل نفس السياق (التحقق من
مقتطفات المسودة وإعادة تتبع التدفق) ويمكنها تصحيح الحكم أو
الثقة. يضاعف استدعاءات LLM للمرشحين المبلَّغ عنهم.
vulnfanatic.validatorModel (بالإضافة إلى validatorProvider / validatorBaseUrl /
validatorApiKey) لتشغيل التمريرة الثانية على نموذج مختلف. الرأي الثاني
أكثر فائدة بكثير من نموذج مستقل — فهو يشارك نقاطًا عمياء أقل
ومن غير المرجح كثيرًا أن يصدّق الحكم الأول تلقائيًا (تميل النماذج إلى
تفضيل إجاباتها الخاصة). النمط الجيد هو تسلسل متتالٍ: نموذج سريع بصفته
المحلل (استرجاع واسع) وأقوى نموذج لديك بصفته المدقّق، الذي يعمل فقط
على المرشحين المبلَّغ عنهم. اترك نموذج المدقّق فارغًا للتحقق باستخدام
نموذج المحلل. يجب أن يكون المدقّق بقدرة المحلل على الأقل — فالنموذج
الأضعف يضيف في الغالب رفضًا خاطئًا. كل شيء ما عدا المزوّد/عنوان URL الأساسي/المفتاح/
النموذج موروث من إعدادات اتصال المحلل؛ والمفتاح الفارغ للمدقّق
يعيد استخدام مفتاح المحلل؛ وإذا كانت نقطة نهاية المدقّق غير قابلة للوصول، يُحتفظ بالحكم
الأول (لا تُفقد النتيجة أبدًا بسبب انقطاع المدقّق).vulnfanatic.minConfidence (افتراضيًا low) — ارفعه إلى medium/high للإبلاغ
فقط عن النتائج الأقوى.السرعة. معظم زمن الانتظار لكل استدعاء هو الاستدلال المكتوب، لذا
يتحكم vulnfanatic.verdictReasoning في مقدار ما يكتبه النموذج:
concise (افتراضيًا) — مبرر موجز من 1–3 جمل، دون اقتباس كود. أسرع
بكثير من full مع خسارة قليلة في الدقة؛ يمكنك أيضًا خفض
vulnfanatic.maxResponseTokens.full — المسودة المفصلة مع المقتطفات المقتبسة (الأكثر قابلية للتدقيق، والأبطأ).none — الحكم فقط. الأسرع؛ اقرنه بنهاية خلفية تدعم الاستدلال
(vulnfanatic.reasoningEffort) حتى يقوم تفكير النموذج الداخلي بالعمل.
على نموذج محلي عادي، يفقد none الدقة (لا يوجد سلسلة أفكار على الإطلاق).ميزات دعم الدقة التي تعمل دائمًا (تُعلم النموذج دون إخفاء النتائج):
_s (ملحق K)
و_chk (FORTIFY) وواجهات البرمجة المحدودة الطول على أنها آمنة ما لم يكن وسيط
الحجم نفسه خاطئًا.يزر 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، معالجة المسارات، RNG ضعيفة، تحليل رقمي ضعيف،
تغييرات الامتيازات، حجم التخصيص، …). فقط الفئتان اللتان تحتاجان فعلًا إلى
تحليل دلالي يتم تخطيهما دون اتصال وتركهما لـ LLM: عائلة free/delete
(استخدام بعد التحرير / التحرير المزدوج، التي تحتاج إلى تتبع عمر المؤشر) والتحقق من TLS
(الخطأ هو قيمة ثابتة محددة مثل SSL_VERIFY_NONE). ويوضح
الملخص دون اتصال عدد المواقع التي تم الإبلاغ عنها / حذفها / تخطيها (تحتاج
إلى LLM) / فشلت، بحيث تُجمع الأعداد. هذا فرز سريع؛ للحكم الحقيقي — و
للفئات المتخطاة — شغّل فحص LLM الكامل.
لا تزال نتائج الفحص دون اتصال تبني نفس السياق الكامل بين الإجراءات الذي سيرسله
الفحص عبر الإنترنت (فقط للمواقع المبلَّغ عنها) وتخزنه، لذا بمجرد فرزها
يمكن تصديرها كبيانات ضبط دقيق تمامًا مثل نتائج الفحص عبر الإنترنت. عطِّل هذا عبر
vulnfanatic.offlineBuildContext إذا أردت أقصى سرعة دون اتصال.
يعمل فقط عندما يبدو أن الثنائي يحتوي على رموز/أسماء متغيرات حقيقية. يحدد
الدوال الحساسة أمنيًا المعرّفة في
rules/phase2_rules.json —
المصادقة، التشفير (بما في ذلك الخوارزميات الضعيفة)، التحقق من التوقيع/الشهادة،
معالجة الجلسات/الرموز، التحكم في الوصول، معالجة الأسرار/المفاتيح،
التحقق من صحة الإدخال، مقارنة الأسرار غير ثابتة الزمن، وعدم أمان
إلغاء التسلسل — مطابقةً حسب اسم الدالة والسلاسل المُشار إليها، ثم مراجعتها
بواسطة النموذج.
تدقيق تحصين البرمجيات الثابتة ضد هجمات حقن الأعطال (وميض الجهد/الساعة/الكهرومغناطيسية)
وهجمات القنوات الجانبية (التوقيت/الاستهلاك)، استنادًا إلى إرشادات تخفيف هجمات الأجهزة.
على عكس المرحلتين 1–2 (اللتين تكتشفان الأخطاء)، تُبلِّغ المرحلة 3 عن تحصين مفقود أو
مُنتهَك في دالة حرجة أمنيًا — على سبيل المثال:
فروع تفشل افتراضيًا، قرارات أمنية مزدوجة الفحص، تحقق من العداد بعد الحلقة،
ثوابت حالة ذات مسافة هامينغ عالية (بدلًا من 0/1 العادي)، مقارنة سرية ثابتة الزمن
بطول كامل، وصول/مسح سري بإزاحات عشوائية،
تشفير ثم تحقق (مضاد DFA)، عدادات سلامة تدفق التحكم، تجنب تشفير
مساحة المستخدم، وعدم معالجة مواد المفاتيح الخام مباشرة
(rules/phase3_rules.json).
لأن تحسينات المترجم يمكن أن تزيل حمايات مستوى المصدر، فمن الأفضل التحقق من هذه الضوابط على الثنائي المترجم — وهذا بالضبط ما يفحصه هذا. المرحلة 3 هي LLM فقط (عبر الإنترنت)، مرتبطة بالرموز، ومعطلة افتراضيًا؛ فعِّلها لكل فحص بخانة اختيار Phase 3 في تبويب New Scan (لا تعمل أبدًا في وضع عدم الاتصال).
تُعرض النتائج في جدول (الحالة، الثقة، المرحلة، CWE، الدالة، العنوان، الاسم) مع لوحة تفاصيل تعرض الشرح، ومسودة التحليل، وملاحظات التحقق. انقر نقرًا مزدوجًا على صف للتنقل في عرض الثنائي إلى الكود.
تبدأ كل نتيجة بحالة Untriaged (غير مُفرَزة). انقر بزر الماوس الأيمن على صف لتعيين حالته — Mark as Real Issue (وضع علامة كمشكلة حقيقية)، أو Mark as False Positive (وضع علامة كنتيجة إيجابية خاطئة)، أو Mark as Untriaged (وضع علامة كغير مُفرَز). عند كل تغيير للحالة تظهر نافذة منبثقة بها مربع نص "Provide reason:" (السبب يُخزَّن مع النتيجة). يوضح الجدول الحالة بوضوح: المشكلات الحقيقية خضراء/غامقة وتُرتَّب في الأعلى، والنتائج الإيجابية الخاطئة رمادية/مشطوبة وتُرتَّب في الأسفل، وغير المُفرَزة تقع بينهما بلون ثقتها. ويظهر سطر ملخص بالعدادات.
يحتوي كل تبويب نتائج على زر Export triaged (fine-tuning)… الذي يصدّر فقط
النتائج المُفرَزة (مشكلة حقيقية + نتيجة إيجابية خاطئة) بصيغة OpenAI chat-format JSONL
من أجل الضبط الدقيق: كل مثال يقترن بالموجه الأصلي للنظام+المستخدم مع
الحكم المصحح بشريًا كهدف للمساعد (النتيجة الإيجابية الخاطئة تعلّم
is_vulnerable=false مع سببك؛ والمشكلة الحقيقية تعزز 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 — ولمنع الحوادث، تظهر نافذة تأكيد تتطلب تحديد "أؤكد أنني سأفقد نتائج إلى الأبد." قبل تفعيل زر 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 في الشريط الجانبي الأيمن.
افتح Settings (الترس / 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 مثبتًا)،
(بناء سياق كامل للنتائج غير المتصلة بحيث يمكن
تصديرها لضبط النموذج؛ الافتراضي مفعّل)،
(تتبع مطوّل لخط الأنابيب إلى وحدة التحكم؛ الافتراضي معطّل) /
(إخفاء كل التفاصيل التي تحدّد الملف الثنائي بحيث يمكن مشاركة
السجل — انظر أدناه)،
، (التحقق من شهادات HTTPS؛
الافتراضي مفعّل) / (حزمة CA لـ HTTPS — راجع
Troubleshooting إذا واجهت )، و
/ /
(وجّه هذه إلى ملفات القواعد الخاصة بك لتخصيص
الاكتشافات والموجهات).
ملاحظة أمنية: يتم تخزين مفتاح API في إعدادات Binary Ninja كنص عادي. فضّل تجاوز متغير البيئة للمفاتيح الحساسة.
عيّن vulnfanatic.apiBaseUrl إلى القيمة الحرفية TEST للتشغيل بدون أي LLM:
/tmp/vulnfanatic_ng/<binary>-<timestamp>/.استخدم هذا لفحص والتحقق بالضبط مما سيرسله VulnFanatic-NG إلى النموذج، وللتكرار على موجهات القواعد/السياق دون استهلاك وقت النموذج.
فعّل vulnfanatic.debugLogging لطباعة تتبع مطوّل خطوة بخطوة لخط
أنابيب الفحص (عبر الإنترنت وغير المتصل) إلى سجل/وحدة تحكم Binary Ninja: كل موقع
استدعاء، وكل قرار تجاوز/استبعاد، وبناء السياق (الحجم فقط)، وكل طلب LLM
(المزوّد/النموذج/نقطة النهاية، وإعادة المحاولات، والتراجع)، وكل حكم، وكل نتيجة
مبلّغ عنها. لا يتم تسجيل مفاتيح API أبدًا.
أثناء تفعيل تسجيل التصحيح، يُبقي الفحص عبر الإنترنت على كل مرشح في جدول النتائج بدلًا من إسقاط المرشحات التي لا تتحول إلى مشكلات مؤكدة، ويُوسم كل منها بحالة خاصة بالتصحيح (معتمة، مرتبة في الأسفل):
لذلك يُظهر فحص التصحيح صفًا واحدًا لكل مرشح من إجمالي /N، ويُبلغ الملخص
المشكلات مقابل أعداد المرفوضين/المتجاوزين/الأخطاء بشكل منفصل. يمكنك النقر بزر الماوس الأيمن على أي
من هذه الصفوف لإعادة تصنيفه كمشكلة حقيقية أو إيجابية كاذبة (ما يجعله مؤهلًا
لتصدير ضبط النموذج). (الفحوصات غير المتصلة غير متأثرة — فهي لا تستدعي LLM أبدًا.)
بشكل مستقل عن وضع التصحيح، عندما يُرجع النموذج استجابة غير قابلة للتحليل — رمزًا
شاردًا مثل <unused…> الخاص بـ Gemma، أو نثرًا بدلًا من JSON، أو رسالة فارغة (تحتوي فقط على
role، دون content) — يقوم العميل بـإعادة محاولة تصحيحية واحدة، معيدًا طلب JSON
فقط مع تعطيل تنسيق المخرجات المنظم؛ وإذا نجحت تُبقي التنسيق معطّلًا
لبقية الفحص. كما يقرأ العميل قناة الاستدلال
(reasoning_content / reasoning) عندما يكون content فارغًا، لذا فإن نماذج الاستدلال التي تضع
إجابتها هناك ما تزال تعمل.
حالة الرسالة الفارغة شائعة مع نماذج الاستدلال مثل GPT-OSS / o1 المُقدَّمة
عبر واجهة متوافقة مع OpenAI (مثل mlx-community/gpt-oss-20b): مع
تعيين response_format=json_object، غالبًا ما يتم كبت قناة الإجابة "النهائية" 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. يمكن لموجه كل قاعدة استخدام العنصر النائب {function}.
صُممت التصديرات المصنّفة لتُغذّى مباشرة مرة أخرى إلى النموذج. بعد
تصنيف النتائج عبر عدة ملفات ثنائية والنقر على Export triaged
(fine-tuning)… لكل منها (جمع ملفات .jsonl في مجلد واحد)،
يشغّل scripts/finetune_mlx.py ضبط LoRA باستخدام MLX
عليها.```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 قيد
التشغيل لاختبارها.
argv[1] عبر strcpy إلى
مخزن مؤقت ثابت الحجم على المكدس ويستدعي system() على المدخلات). قم بتجميعه
مع الرموز لاختبار Phase 2 أيضًا.vulnfanatic.apiBaseUrl،
وvulnfanatic.apiKey، وvulnfanatic.model.SSL: CERTIFICATE_VERIFY_FAILED ... unable to get local issuer certificate —
شهادة نقطة نهاية HTTPS سليمة، لكن Python المضمنة في Binary Ninja لا تملك حزمة
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 template)، لذا لا يمكن لنقطة النهاية
/chat/completions تنسيق الرسائل. عندما يرى VulnFanatic-NG هذا الخطأ،
يتراجع تلقائيًا إلى نقطة النهاية /completions لبقية الفحص، لذلك يستمر
الفحص. لتجنّب أول طلب فاشل تمامًا، اضبط vulnfanatic.apiMode على completions.
بدلًا من ذلك، أصلحه من جهة الخادم بتقديم نموذج يتضمن قالب محادثة، أو مرّر
واحدًا إلى خادمك — مثلًا لـ vLLM: --chat-template <template.jinja> (أو استخدم
نسخة نموذج -Instruct/-Chat). عادةً ما يعطي قالب المحادثة المخصص نتائج أفضل
من مطالبة الإكمال المسطحة.
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.maxContextTokens و/أو vulnfanatic.maxResponseTokens، أو منح
الخادم ذاكرة أكبر / نافذة سياق أوسع.vulnfanatic.phase2ForceEnable لتدقيق المطابقات
القائمة على الأسماء أيضًا، أو اجعل vulnfanatic.phase2RequireSymbols=off.
بوابة الرموز أسلوب استدلالي (heuristic).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.skipConstantArgCalls (افتراضيًا معطّل) — يتخطى مواقع استدعاءات
فئة التجاوز التي تكون جميع وسائطها ثوابت وقت الترجمة.| الإعداد | المعنى |
|---|
vulnfanatic.apiProvider | أي خلفية LLM سيتم الاتصال بها: openai (الافتراضي)، anthropic، google، أو azure. انظر خلفيات LLM أدناه. جميع المزوّدين يُستدعَون عبر مكتبة Python القياسية — لا حاجة إلى pip install. |
vulnfanatic.apiBaseUrl | نقطة الأساس لنقطة النهاية للمزوّد المحدد (انظر الجدول أدناه). الافتراضي http://localhost:8080/v1. عيّنها إلى القيمة الحرفية TEST لتفعيل وضع الاختبار (انظر أدناه). |
vulnfanatic.apiKey | مفتاح API / رمز الحامل. يمكن أن يكون فارغًا للخوادم المحلية. يتم تجاوزه بواسطة متغيري البيئة 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 | Chat/Completions متوافق مع OpenAI: llama.cpp / ollama / vLLM محليًا، وOpenAI، ونقطة نهاية AWS Bedrock المتوافقة مع OpenAI. |
anthropic | فارغ ← https://api.anthropic.com | x-api-key + anthropic-version | واجهة Messages API الخاصة بـ Claude (POST <base>/v1/messages). لا يتم إرسال temperature (نماذج Claude الحالية ترفضه). |
google | فارغ ← https://generativelanguage.googleapis.com | مفتاح API في عنوان URL | generateContent الخاص بـ Gemini (<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