
أداة إزالة تشويش ثابتة لشفرة JavaScript البايتية المُجمَّعة في محرك V8، مع التركيز على حمولات JSCeal. توفر عوامل تصفية قائمة على الأنماط، وإعادة تسطيح تدفق التحكم، وإعادة بناء السلاسل النصية، وإعادة تسمية اختيارية للدوال بمساعدة LLM لأغراض التحليل.
هذه الأداة مخصصة لإزالة التعتيم (Deobfuscation) بشكل ثابت من البايت كود المُجمَّع لـ V8 JavaScript والذي تمت حمايته باستخدام javascript-obfuscator.
تعمل الأداة على الكود الزائف (Pseudocode) الناتج عن View8، وليس على كود JavaScript الأصلي. تم تطوير المشروع واختباره على حمولات JSCeal.
المرشحات (Filters) تعتمد على الأنماط (Pattern-driven) وهي مخصصة في المقام الأول لتكون مجموعة أدوات بحثية وتنفيذًا مرجعيًا. الأداة ليست أداة إزالة تعتيم عامة لـ JavaScript، ولا تعيد بناء الكود المصدري الأصلي، ولا تنتج كود JavaScript قابلًا للتشغيل. يبقى ناتجها كودًا زائفًا من View8 مخصصًا للفحص الثابت والبحث والمقارنة وتصدير شجرة الدوال.
pickle الخاص بـ Python. تحميل ملف .pkl خبيث أو غير موثوق يمكن أن ينفذ كودًا. قم بتحميل الملفات المسلسلة التي قمت بإنشائها محليًا باستخدام View8 فقط.requirements.txt؛brotli لسير عمل فك الضغط الجماعي على Linux؛أنشئ بيئة Python معزولة:
python3 -m venv .venv
source .venv/bin/activate
python3 -m pip install --upgrade pip
python3 -m pip install -r requirements.txt
الخلفية (Backend) الخاصة بـ OpenAI في deobf_ai.py تتطلب أيضًا حزمة OpenAI الخاصة بـ Python:
python3 -m pip install openai
خلفية Anthropic تستخدم HTTP API عبر requests. خلفية Ollama تتوقع خادم Ollama يمكن الوصول إليه.
حمولة JSCeal الأصلية app.jsc مضغوطة بـ Brotli. على Linux، يمكن فك ضغطها باستخدام أداة brotli:
brotli -d app.jsc -o app.decompressed.jsc
سير العمل الجماعي تحت scripts/ يقوم بهذه الخطوة باستخدام scripts/unpack_all.sh.
على Windows، أو عندما تكون أداة سطر الأوامر brotli غير متوفرة، يمكن استخدام مساعد Node.js المرفق كبديل. يقوم فقط بفك ضغط الإدخال ولا ينفذه:
node Utils/decompress-jsc.js app.jsc
يكتب:
app.jsc.decompressed.jsc
V8 code cache خاص بإصدار محدد. استخدم مفككًا مبنيًا لنفس إصدار V8 المستخدم في الحمولة.
عينات JSCeal المستخدمة أثناء التطوير كانت مبنية على V8 10.2.154.26. المفككات الافتراضية من بناء V8 غير مرتبط لن تعمل بشكل صحيح.
شجرة المصدر تحتوي على كود المفكك وتصحيحات V8 المطلوبة تحت:
Utils/disasm/v8dasm.cpp
Utils/disasm/patches/
يتم توزيع ثنائي Linux مُجمَّع مسبقًا مع إصدار المشروع، بينما تحتوي شجرة المصدر على الكود المصدري والتصحيحات اللازمة لإعادة بنائه. الوصف التفصيلي متاح على ويكي المشروع. بعد الحصول على أو بناء v8dasm المطابق، قم بتشغيل:
/path/to/v8dasm app.decompressed.jsc > app.jsc.disasm.txt
قم بتغذية الملف المفكك إلى view8.py وأنتج كلاً من المخرجات المسلسلة لمزيد من المعالجة والكود الزائف القابل للقراءة البشرية:
mkdir -p decompiled
python3 View8/view8.py \
--input_format disassembled \
--inp app.jsc.disasm.txt \
--normalize \
--out decompiled/app.dec.txt \
--export_format decompiled serialized
هذا ينتج:
decompiled/app.dec.txt
decompiled/app.dec.pkl
خيار --normalize يجعل معرفات الدوال المولدة قابلة للتكرار عبر عمليات التفكيك وفك الترجمة المتكررة.
هناك مرشحات منفصلة لطبقات التعتيم الفردية. يمكن تطبيقها معًا على مخرجات View8 المسلسلة باستخدام deobf_all.py:
mkdir -p deobfuscated
python3 deobf_all.py \
--inp decompiled/app.dec.pkl \
--out deobfuscated/app.deobf.txt \
--export_format decompiled serialized
مرشح السلاسل النصية الافتراضي هو النمط 2، المستخدم في غالبية حمولات JSCeal التي تم تحليلها. لتحديد مخطط السلاسل الأبسط بشكل صريح، أضف:
--str_deobf 1
المخرجات النموذجية هي:
deobfuscated/app.deobf.txt
deobfuscated/app.deobf.pkl
deobfuscated/app.deobf.txt.strings.txt
decompiled/app.dec.resolved_funcs.csv
ملف CSV للدوال المُحلَّلة هو ذاكرة تخزين مؤقت خاصة بالعينة. عندما يكون غائبًا، تستعيد مرحلة السلاسل النصية تكوين وحدة فك الترميز المطلوبة، وتكتب CSV، وتستمر في إزالة تعتيم السلاسل في نفس التشغيل. التشغيلات اللاحقة تعيد استخدام الذاكرة المؤقتة وتكون عادةً أسرع.
لا تعيد استخدام CSV للدوال المُحلَّلة مع حمولة مفككة مختلفة.
بعد تطبيق جميع مرشحات إزالة التعتيم الهيكلية، يمكن لـ deobf_ai.py اقتراح أسماء تصف سلوك الدوال. يدعم خلفيات Anthropic وOpenAI وOllama.
مرر النموذج بشكل صريح حتى تبقى عمليات التشغيل قابلة للتكرار.
export ANTHROPIC_API_KEY='...'
python3 deobf_ai.py \
--inp deobfuscated/app.deobf.pkl \
--out deobfuscated/app.renamed.txt \
--llm_backend anthropic \
--model '<model-id>' \
--export_format decompiled serialized
export OPENAI_API_KEY='...'
python3 deobf_ai.py \
--inp deobfuscated/app.deobf.pkl \
--out deobfuscated/app.renamed.txt \
--llm_backend openai \
--model '<model-id>' \
--export_format decompiled serialized
python3 deobf_ai.py \
--inp deobfuscated/app.deobf.pkl \
--out deobfuscated/app.renamed.txt \
--llm_backend ollama \
--model '<local-model>' \
--ollama_url http://localhost:11434 \
--export_format decompiled serialized
في الوضع الافتراضي، يبني مُعيد التسمية شجرة استدعاءات مباشرة بدءًا من الدالة المدخلة ويعيد تسمية الدوال التي يتم الوصول إليها عبر الاستدعاءات فقط. أضف --greedy لتضمين جميع مراجع الدوال المرئية، بما في ذلك الاستدعاءات الخلفية والمعالجات المعينة.
ملف CSV ثنائي الأعمدة المُنشأ يعمل كذاكرة تخزين مؤقت ويسمح لاستمرار تشغيل متقطع. حدد ذاكرة تخزين مؤقت موجودة بشكل صريح باستخدام --csv:
python3 deobf_ai.py \
--inp deobfuscated/app.deobf.pkl \
--out deobfuscated/app.renamed.txt \
--csv deobfuscated/app.deobf.renamed_funcs.greedy.example-model.csv \
--llm_backend anthropic \
--model '<model-id>' \
--greedy \
--export_format decompiled serialized
في الوضع العادي، يتم التعامل مع CSV كذاكرة تخزين مؤقت جزئية محتملة. يتم تطبيق الأسماء المخزنة أولاً، وتتم إزالة الدوال المغطاة بالفعل بواسطة الذاكرة المؤقتة من شجرة الاستدعاءات أو المراجع المحددة، ويتم استدعاء LLM فقط للدوال التي تبقى غير محلولة. إذا كانت CSV تغطي تلك الشجرة بالكامل، فلا حاجة لمفتاح API أو اتصال LLM. إذا كانت تغطي جزءًا فقط من الشجرة، تتم تهيئة الخلفية المحددة وتُضاف التعيينات المُنشأة حديثًا إلى نفس CSV.
استخدم نفس وضع الشجرة الذي استُخدم عند إنشاء CSV. CSV الناتج من تشغيل --greedy يحتاج عادةً إلى --greedy مرة أخرى إذا كان الهدف هو مواصلة ذلك التشغيل بدلاً من إعادة استخدام مجموعة الاستدعاءات المباشرة فقط.
استخدم --apply-csv-only عندما تحتوي CSV بالفعل على التسميات التي تريد تطبيقها، بما في ذلك التعيينات المراجعة أو المحررة أو المستوردة أو المعاد ترسيخها:
python3 deobf_ai.py \
--inp deobfuscated/app.deobf.pkl \
--out deobfuscated/app.renamed.txt \
--csv renamed_functions.normalized.csv \
--apply-csv-only \
--export_format decompiled serialized
هذا الوضع:
--csv صريحًا؛--func.يتم تجاهل الصفوف التي لا يوجد معرف الدالة الأصلي الخاص بها في الإدخال. يفشل الأمر عندما تحتوي CSV على تعيينات غير قابلة للتطبيق على الملف المحمّل.
استخدم --func مع معرف الدالة الكامل الدقيق لطلب تحليل دلالي مركّز لدالة واحدة بعد إزالة التعتيم: