باكر/واقي لثنائيات X86-64 ELF على Linux. يلف Kiteshield ثنائيات Elf بطبقات متعددة من التشفير وضخها برمز اللودر الذي يفكّر ويخطط وتنفيذ الثنائي المعبأ بالكامل في مساحة المستخدمين. يضمن محرك وقت التشغيل المستند إلى PTRACE أن يتم فك تشفير الوظائف فقط في مكدس الاتصال الحالي في أي وقت معين ، ويقوم بالإضافة إلى ذلك بتنفيذ مجموعة متنوعة من تقنيات مكافحة الأداء من أجل جعل الثنائيات المعبأة من الصعب على عكس الهندسة العكسية. يتم دعم كل من الثنائيات الفردية والمتعددة مؤشرات الترابط.
راجع أقسام تخطيط الهندسة المعمارية و CodeBase أدناه للحصول على عرض الطيور حول كيفية عمل Kiteshield.
يهدف Kiteshield إلى أن تكون تمرينًا أكاديميًا ممتعًا في التشويش الثنائي بدلاً من شيء يمكن استخدامه في العالم الحقيقي بالنظر إلى رمز المصدر ، وبالتالي كيف يعمل ، هو عام.
سميت باسم الدروع التي يفضلها النورمان في القرن الحادي عشر (بدلاً من ذلك: The Kiteshields السائدة في المدارس القديمة Runescape).
يتطلب Kiteshield مكتبة Bitdefender Disassembler لفك تشفير التعليمات في Packer. يتم تضمينه كوحدة فرعية في packer/bddisasm . لبناءه من استنساخ جديد ، قم بتشغيل ما يلي (لاحظ أنك ستحتاج إلى تثبيت CMake):
git submodule update --init
cd packer/bddisasm
mkdir build
cd build
cmake ..
make
يمكنك الآن إنشاء Kiteshield في وضع الإصدار عن طريق make من الدليل العليا. بدلاً من ذلك ، يمكنك إنشاء بناء تصحيح مع make debug . تصاعد Debug من Kiteshield تعطيل جميع ميزات مكافحة الأداء وتشغيل تسجيل تصحيح الأخطاء المطوّل للغاية.
من أجل تصحيح وظائف مكافحة الأداء الفعلية ، يمكنك بناء Kiteshield في وضع التصحيح مع وظائف مكافحة الأداء التي تم تشغيلها باستخدام make debug-antidebug .
لحزم برنامج ثنائي يسمى program وإخراج الثنائي المعبأ إلى packed.ks ، تشغيل:
./packer/kiteshield program packed.ks
يمكن الآن تشغيل packed.ks . ويجب أن تكون مكافئة وظيفيًا program ، ولكن تم تشفيرها وصعوبة في عكس الهندسة. لاحظ أنه بالنسبة للطبقة 2 التي سيتم تطبيق تشفيرها ، يجب ألا يتم تجريد المدخلات الثنائية عندما يعتمد Kiteshield على جدول الرموز. في معظم توزيعات Linux ، يتم تجريد مرافق النظام القياسية (على سبيل المثال /bin/ls ) بشكل عام.
ومع ذلك ، لا يزال بإمكانك حزمة ثنائيات مجردة بدون تشفير الطبقة 2 باستخدام علامة -n :
./packer/kiteshield -n program packed.ks
سيؤدي ذلك إلى إنتاج إخراج ثنائي معبأة مع تشفير الطبقة 1 فقط وحذف محرك وقت التشغيل.
يتكون Kiteshield من جزأين منفصلين. Packer هو تطبيق C العادي الذي يقرأ ، والأدوات ، وترميز ثنائيات الإدخال. يعد المحمل تطبيقًا قائمًا بذاته مسؤول عن فك تشفير الوظائف الديناميكية ووظائف مكافحة الأعمدة التي يتم حقنها في ثنائيات الإدخال بواسطة Packer. يتلقى التحكم الأولي من النواة ، ويخطط جميع الأجزاء المناسبة من الثنائي إلى الذاكرة (بما في ذلك الرابط الديناميكي إن أمكن) ، وتسليم التحكم في التطبيق. يحتوي المحمل أيضًا على محرك وقت التشغيل ، والذي يقوم بفك تشفير وظائف وتشفير ديناميكيًا عند إدخالها وخرج منها في وقت التشغيل.
نظرًا لأن المحمل يتلقى التحكم الأولي من kernel (أي قبل أن يتم تعيين أي مكتبات مشتركة عادةً بواسطة الرابط الديناميكي) ، فإنه لا يمكنه الوصول إلى LIBC ، وبالتالي يتم إعادة تشكيل جميع الوظائف المطلوبة من قبل LIBC في رمز المحمل.
يمكن العثور على رمز Packer و Loader في packer/ و loader/ الدلائل على التوالي. يمكن العثور على الكود الشائع لكليهما في الدليل common/ . نظرة عامة رفيعة المستوى على الأجزاء المهمة من قاعدة كود هي كما يلي:
kiteshield
├── common # Code common to packer/loader
│ ├── include
│ │ ├── defs.h
│ │ ├── obfuscation.h
│ │ └── rc4.h
│ ├── obfuscation.c # Obfuscation utilities
│ └── rc4.c # RC4 stream cipher implementation
├── LICENSE
├── loader # Loader code
│ ├── anti_debug.c # Anti-debugging functionality
│ ├── bin_to_header.py # Script to "headerize" a compiled loader
│ ├── entry.S # Loader entry point code
│ ├── include
│ │ ├── anti_debug.h
│ │ ├── debug.h
│ │ ├── elf_auxv.h
│ │ ├── errno.h
│ │ ├── malloc.h
│ │ ├── obfuscated_strings.h # Generated file produced by string_obfuscation.py
│ │ ├── signal.h
│ │ ├── string.h
│ │ ├── syscalls.h
│ │ └── types.h
│ ├── link.lds # Custom linker script for building loader
│ ├── loader.c # Binary loading/mapping code (userspace exec)
│ ├── Makefile
│ ├── malloc.c # Freestanding malloc/free implementation
│ ├── runtime.c # Main body of runtime engine code
│ ├── string.c # String processing utilities (eg. strncat)
│ ├── string_obfuscation.py # String obfuscation helper script
│ ├── syscalls.c # System call implementations in inline assembly
│ └── test # Loader unit tests
│ ├── attounit.h
│ ├── Makefile
│ ├── test_main.c
│ ├── test_malloc.c
│ └── test_rc4.c
├── Makefile
├── packer # Packer code
│ ├── bddisasm # Bitdefender x86-64 disassembler library (submodule)
│ ├── elfutils.c # ELF binary reading/writing utilities
│ ├── include
│ │ └── elfutils.h
│ ├── kiteshield.c # Main body of packer code
│ └── Makefile
├── README.md
└── testing # Integration tests (see testing/README.md)
يلف Kiteshield ثنائيات elf المدخلات في طبقتين (أو واحد ، إذا استخدمت العلم -n ) من تشفير RC4 بحيث يكون الثنائي على القرص مملوءة بشكل جيد إلى حد ما. يتم تجريد هذه الطبقات في وقت التشغيل بواسطة المحمل.
تتكون الطبقة الأولى من التشفير (المشار إليها في قاعدة كود باسم "الطبقة الخارجية") من تمريرة RC4 واحدة على مدخلات مدخل بالكامل. تم تصميم هذا في المقام الأول لمحاربة التحليل الثابت. نظرًا للطريقة التي يتم بها تفكيك المفتاح (الذي يعتمد على رمز المحمل) ، تحقق الطبقة الأولى من التشفير بشكل فعال رمز المحمل قبل تنفيذ الثنائي المعبأ ، مما يجعل مقاومة Kiteshield مقاومة للترويح.
تتكون الطبقة الثانية من التشفير (المشار إليها في قاعدة البيانات باسم "الطبقة الداخلية") من التشفير الفردي لكل وظيفة تقريبًا في المدخلات الثنائية (التي تم تحديدها عبر جدول الرموز في وقت الحزمة). يتم تشغيل محرك وقت التشغيل المستند إلى PTRACE على كل إدخال وظائف والخروج عن طريق استبدال تعليمات إدخال كل وظيفة وجميع تعليمات الإرجاع الخاصة به مع تعليمات int3 (التي تقدم SIGTRAP عند تنفيذها). عند تلقي فخ ، يبحث محرك وقت التشغيل عن الوظيفة الحالية ويشفر أو فك تشفيره حسب الحاجة بحيث يتم فك تشفير الوظائف فقط داخل مكدس الاتصال الحالي في أي وقت من الأوقات.
بعد تجريد الطبقة 1 ، يعيد Kiteshield بشكل فعال أن يعيد تنفيذ syscall exec في مساحة المستخدمين (انظر mmap loader/loader.c mprotect باستخدام Ptrace).
بالإضافة إلى التشفير ، يحتوي رمز Loader الخاص بـ Kiteshield أيضًا على عدد من ميزات مضادات الأداء المصممة لجعل من الصعب تحليل ثنائي معبأ تشغيله (انظر loader/anti_debug.c و loader/include/anti_debug.h ).
لإعطاء مثال ملموس على Kiteshield في العمل ، فكر في برنامج Hello World التالي ، والذي سنحزمه مع Kiteshield في وضع التصحيح.
#include <stdio.h>
int main ()
{
puts ( "Hello World!" );
return 0 ;
}عند تعبئتها في وضع التصحيح ، سوف يقوم رمز المحمل في الثنائيات المعبأة بتسجيل معلومات تصحيح الأخطاء. ما يلي هو السجل من ثنائي معبأ يتوافق مع البرنامج أعلاه. تم شرحه (وتم إضافة خطوط جديدة إضافية من أجل الوضوح)
$ ./packed.ks
# Runtime startup
[kiteshield] starting ptrace runtime
[kiteshield] number of trap points: 5
[kiteshield] number of encrypted functions: 3
# List of points in memory that have been instrumented with an int3 instruction
[kiteshield] list of trap points:
[kiteshield] 8000011ac value: c3, type: ret, function: __libc_csu_init (#0)
[kiteshield] 800001150 value: 41, type: ent, function: __libc_csu_init (#0)
[kiteshield] 800001050 value: 31, type: ent, function: _start (#1)
[kiteshield] 80000114b value: c3, type: ret, function: main (#2)
[kiteshield] 800001135 value: 55, type: ent, function: main (#2)
# Runtime has started and is waiting on the packed app, begin mapping binary
# Stripping layer one encryption
[kiteshield] RC4 decrypting binary with key 85e19ad41fb8cc13e87e3cd1589a45fb
[kiteshield] decrypted 12336 bytes
# Mapping segments from packed binary program header table
[kiteshield] mapping LOAD section from packed binary at 800000000
[kiteshield] mapping LOAD section from packed binary at 800001000
[kiteshield] mapping LOAD section from packed binary at 800002000
[kiteshield] mapping LOAD section from packed binary at 800003000
# Mapping dynamic linker specified in INTERP header of packed binary
[kiteshield] mapping INTERP ELF at path /lib64/ld-linux-x86-64.so.2
[kiteshield] mapped LOAD section from fd at b00000000
[kiteshield] interpreter base address is b00000000
[kiteshield] mapped LOAD section from fd at b00001000
[kiteshield] mapped LOAD section from fd at b0001f000
[kiteshield] mapped extra space for static data (.bss) at b00029000 len 400
[kiteshield] mapped LOAD section from fd at b00027000
[kiteshield] binary base address is 800000000
# Modifying ELF auxiliary vector as needed for program execution
[kiteshield] taking 7ffff2997c60 as auxv start
[kiteshield] replaced auxv entry 9 with value 34359742544 (0x800001050)
[kiteshield] replaced auxv entry 3 with value 34359738432 (0x800000040)
[kiteshield] replaced auxv entry 7 with value 47244640256 (0xb00000000)
[kiteshield] replaced auxv entry 5 with value 11 (0xb)
[kiteshield] finished mapping binary into memory
[kiteshield] control will be passed to packed app at b00001090
# Mapping done
# Runtime attaches to the packed application with ptrace
[kiteshield] child is traced, handing control to packed binary
# Program is executing, functions are logged on entry/exit
[kiteshield] tid 13508: entering encrypted function _start decrypting with key 74c974f9d097e5a8c60049c3842c6110
[kiteshield] tid 13508: entering encrypted function __libc_csu_init decrypting with key 9124511baa87daa76c09b2426355dfca
[kiteshield] tid 13508: leaving function __libc_csu_init for address 7fa9a821d02a (no function record) via ret at 8000011ac
[kiteshield] tid 13508: entering encrypted function main decrypting with key 2f1c20e77ff3617b0b89a579669aba48
# Actual program output
Hello World!
# Packed application returns from main() and exits
[kiteshield] tid 13508: leaving function main for address 7fa9a821d09b (no function record) via ret at 80000114b
[kiteshield] tid 13508: exited with status 0
[kiteshield] all threads exited, exiting
لدى Kiteshield مجموعة واسعة من اختبارات التكامل للتحقق من الصواب عبر عدة منصات مختلفة. انظر testing/README.md للحصول على التفاصيل.
تم كتابة Kiteshield مع مراعاة التشويش ، وليس السرعة. يعد محاصرة وقت تشغيل Kiteshield على كل مدخل وظيفة والخروج مكلفًا للغاية. يجب أن تتوقع البرامج المليئة بتشفير الطبقة 2 الحصول على أداء خطير.
MIT © RHYS RUSTAD-ELLIOTT