
مُشفر ثنائي متعدد الأشكال لحمولات الأمن الهجومية. يقوم بتشفير شيلكود باستخدام حلقة تغذية راجعة قائمة على LFSR، وحقن تعليمات غير مرغوب فيها، وتعتيم متعدد التكرارات لتفادي الكشف الثابت.
SGN هو مشفر ثنائي متعدد الأشكال لأغراض الأمن الهجومي، مثل إنشاء حمولات ثنائية لا يمكن اكتشافها بشكل ثابت. يستخدم حلقة تغذية راجعة إضافية لتشفير التعليمات الثنائية المعطاة، على غرار LFSR. هذا المشروع هو إعادة تنفيذ لـ Shikata ga nai الأصلية بلغة go مع العديد من التحسينات.
[!WARNING]
تم نقل المشروع مؤخرًا إلى Rust. يحافظ هذا النقل على التصميم والسلوك الأصليين ولكنه يستبدل keystone (مجمّع النصوص) بـiced-x86(مجمّع Rust خالص)، لذلك لا توجد تبعيات للمكتبات الأصلية — يتم بناؤه باستخدامcargo buildعادي. اطلع على فرع sgn-go للحصول على الإصدار القديم بلغة Go.
بالنسبة لمجتمع الأمن الهجومي، يعتبر التطبيق الأصلي لمشفر shikata ga nai أفضل مشفر للشيلكود (حتى الآن). ولكن على مر السنين، وجد الباحثون في مجال الأمن عدة ثغرات للكشف الثابت عن دالة فك التشفير (عمل ذو صلة مقالة FireEye). الدافع الرئيسي لهذا المشروع هو إنشاء مشفر أفضل يقوم بتشفير الملف الثنائي المعطى إلى درجة تصبح فيها البيانات متطابقة تمامًا مع البيانات العشوائية الكاملة ولا يمكن اكتشاف وجود أداة فك التشفير.
أخيرًا شيلكودات x64 مشفرة بشكل صحيح!تم تقليل مفتاح LFSR إلى 1 بايتكما يتم تشفير دالة فك التشفير بنظام عشوائي زائفتقوم الدالة بفك تشفير نفسها دون استخدام أي شروط حلقة !!تمت إضافة مولد تعليمات غير مرغوب فيها (garbage) عشوائي باستخدام keystoneلا يتم تدمير أي من السجلات (مقدمة اختيارية، قد تقلل من تعدد الأشكال)كل مرحلة تشفير:
--plain، يتم تشفير الدالة نفسها باستخدام تشفير مخطط عشوائي لكل تشغيل (XOR/ADD/SUB/ROL/ROR/NOT على DWORDs) وإضافة دالة فك تشفير المخطط ذاتية التحديد، بحيث تبدو حتى أداة فك التشفير كبيانات عشوائية؛--enc مرات مع قيم أولية جديدة؛cargo install sgn
كما يمكنك الحصول على الملفات الثنائية المجمّعة مسبقًا هنا.
الاستخدام
-h واضح جدًا، استخدم -v إذا كنت تريد رؤية ما يحدث خلف الكواليس ( ͡° ͜ʖ ͡°)_/¯
__ _ __ __ _
___ / / (_) /_____ _/ /____ _ ___ ____ _ ___ ___ _(_)
(_-</ _ \/ / '_/ _ `/ __/ _ `/ / _ `/ _ `/ / _ \/ _ `/ /
/___/_//_/_/_/\_\\_,_/\__/\_,_/ \_, /\_,_/ /_//_/\_,_/_/
========[Author:-Ege-Balcı-]====/___/=======v2.0.2=========
┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ (ノ ゜Д゜)ノ ︵ 仕方がない
sgn [OPTIONS]
Options:
-i, --input <INPUT> مسار الملف الثنائي المدخل
-o, --out <OUT> اسم الملف الثنائي المشفر الناتج (الافتراضي: <input>.sgn)
-a, --arch <ARCH> بنية الملف الثنائي (32/64) [الافتراضي: 64]
-c, --enc <ENC> عدد مرات تشفير الملف الثنائي [الافتراضي: 1]
-M, --max <MAX> الحد الأقصى للبايتات لكل كتلة تعليمات غير مرغوب فيها [الافتراضي: 50]
--plain لا تقم بتشفير دالة فك التشفير
--ascii إنشاء حمولة قابلة للطباعة باستخدام ASCII بالكامل (بطيء)
-S, --safe الحفاظ على جميع قيم السجلات (لا تدمير)
--badchars <BADCHARS> تجنب هذه البايتات، بصيغة سداسية عشرية (مثال: \x00\x0a)
-v, --verbose وضع المفصل
-h, --help طباعة المساعدة
-V, --version طباعة الإصدار
مثال:
sgn -i shellcode.bin -o encoded.bin -a 64 --badchars '\x00\x0a\x0d'
الصورة التالية هي مخطط سير عمل أساسي للمشفر. لكن ضع في اعتبارك أن الأحجام والمواقع والترتيبات ستتغير للتعليمات غير المرغوب فيها ووظائف فك التشفير ووظائف فك تشفير المخطط في كل تكرار.
LFSR نفسه قوي جدًا من حيث مساحة الاحتمالات. لمزيد من تعدد الأشكال، يتم إلحاق تعليمات غير مرغوب فيها في بداية الحمولة الخام غير المشفرة. الصورة أدناه تُظهر المصفوفة المرافقة لكثيرات الحدود المميزة لـ LFSR، مع الإشارة إلى القيمة الأولية كمتجه عمودي، وحالة المسجل في تكوين Fibonacci بعد k خطوة.
use sgn::Encoder;
let shellcode = std::fs::read("payload.bin")?;
let mut encoder = sgn::Encoder::new(64)?;
let encoded = encoder.encode(&shellcode)?;
println!("encoded {} bytes", encoded.len());
انظر examples/encode_binary.rs.
cargo test
تتضمن المجموعة اختبارات وحدة ذهابًا وإيابًا للتشفير بالإضافة إلى اختبارات تنفيذ حقيقية:
يتم تعيين الشيلكود المشفر لـ x64 كذاكرة قابلة للتنفيذ وتنفيذه داخل العملية، ويتم تنفيذ شيلكود x86 عبر وسيط مساعد cc -m32 (يتم تخطيه تلقائيًا إذا لم تكن مجموعة أدوات 32 بت موجودة). يتم اختبار كلتا البنيتين عبر أوضاع التشفير العادي والمخطط والمتعدد الطبقات والآمن، بما في ذلك حلقة ضغط عشوائية.
iced-x86 بدلاً من نص keystone؛ تم إعادة بناء دوال فك التشفير حول العنونة النسبية لـ RIP (x64) ومخطط call/pop ثنائي المراحل (x86).random_byte يغطي الآن النطاق الكامل 0..=255، ويتم تطبيق ميزانية حجم التعليمات غير المرغوب فيها (--max) بشكل ثابت كحد أقصى لكل كتلة.