Packer/pelindung untuk binari X86-64 ELF di Linux. Kiteshield membungkus binari elf dengan beberapa lapisan enkripsi dan menyuntikkannya dengan kode loader yang mendekripsi, memetakan, dan mengeksekusi biner yang dikemas sepenuhnya di ruang pengguna. Mesin runtime berbasis PTRACE memastikan bahwa hanya fungsi dalam tumpukan panggilan saat ini yang didekripsi pada waktu tertentu dan juga mengimplementasikan berbagai teknik anti-debugging untuk membuat binari yang dikemas sekeras mungkin. Binari tunggal dan multithreaded didukung.
Lihat bagian arsitektur dan tata letak basis kode di bawah ini untuk pandangan mata burung tentang cara kerja Kiteshield.
Kiteshield dimaksudkan untuk menjadi latihan akademik yang menyenangkan dalam kebingungan biner daripada sesuatu yang dapat digunakan di dunia nyata mengingat kode sumber, dan dengan demikian cara kerjanya, adalah publik.
Dinamai untuk perisai yang disukai oleh Normandia pada abad ke -11 (sebagai alternatif: Kiteshields yang begitu lazim di runescape sekolah lama).
Kiteshield mengharuskan perpustakaan Bitdefender Disassembler untuk mendekode instruksi di Packer. Ini termasuk sebagai submodule di packer/bddisasm . Untuk membangunnya dari klon baru, jalankan berikut ini (Catatan Anda harus menginstal CMake):
git submodule update --init
cd packer/bddisasm
mkdir build
cd build
cmake ..
make
Anda sekarang dapat membangun Kiteshield dalam mode rilis dengan menjalankan make dari Direktori Top Level. Atau Anda dapat membuat debug build dengan make debug . Debug Builds dari Kiteshield menonaktifkan semua fitur anti-debugging dan mengaktifkan logging debug yang sangat verbose loader.
Untuk men-debug fungsionalitas anti-debugging yang sebenarnya, Anda dapat membangun Kiteshield dalam mode debug dengan fungsionalitas anti-debugging yang dihidupkan menggunakan make debug-antidebug .
Untuk mengemas program yang dipanggil biner dan output biner yang dikemas untuk packed.ks , jalankan:
./packer/kiteshield program packed.ks
packed.ks Sekarang dapat dijalankan dan harus setara secara fungsional dengan program , tetapi dienkripsi dan sulit untuk direverse engineer. Perhatikan bahwa untuk enkripsi Layer 2 diterapkan, biner input tidak boleh dilucuti karena Kiteshield bergantung pada tabel simbol yang hadir. Pada sebagian besar distro Linux, utilitas sistem standar (mis. /bin/ls ) umumnya dilucuti.
Namun Anda masih bisa mengemas binari yang dilucuti tanpa enkripsi Layer 2 menggunakan bendera -n :
./packer/kiteshield -n program packed.ks
Ini akan menghasilkan biner output yang dikemas hanya dengan enkripsi lapisan 1 dan mesin runtime dihilangkan.
Kiteshield terdiri dari dua bagian terpisah. Packer adalah aplikasi C biasa yang membaca, instrumen, dan mengenkripsi biner input. Loader adalah aplikasi C berdiri bebas yang bertanggung jawab untuk dekripsi fungsi dinamis dan fungsionalitas anti-debugging yang disuntikkan ke dalam biner input oleh pengepak. Ia menerima kontrol awal dari kernel, memetakan semua segmen biner yang tepat ke dalam memori (termasuk tautan dinamis jika berlaku), dan menyerahkan kontrol ke aplikasi. Loader juga berisi mesin runtime, yang secara dinamis mendekripsi dan mengenkripsi fungsi saat dimasukkan dan keluar saat runtime.
Karena loader menerima kontrol awal dari kernel (yaitu. Sebelum perpustakaan bersama biasanya akan dipetakan oleh penghubung dinamis), ia tidak memiliki akses ke LIBC dan dengan demikian semua fungsionalitas yang dibutuhkan yang disediakan oleh LIBC diimplementasikan kembali dalam kode loader.
Kode Packer dan Loader dapat ditemukan di masing -masing packer/ dan loader/ Direktori. Kode yang umum untuk keduanya dapat ditemukan di Direktori common/ . Tinjauan tingkat tinggi dari bagian-bagian penting dari basis kode adalah sebagai berikut:
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 membungkus input biner elf menjadi dua (atau satu, jika menggunakan end -n ) lapisan enkripsi RC4 sedemikian rupa sehingga biner pada disk cukup dikaburkan. Lapisan -lapisan ini dilucuti saat runtime oleh loader.
Lapisan enkripsi pertama (disebut dalam basis kode sebagai "lapisan luar") terdiri dari satu RC4 yang melewati seluruh biner input. Ini dirancang terutama untuk melawan analisis statis. Karena cara kunci deobfuscated (yang tergantung pada kode loader), lapisan enkripsi pertama juga secara efektif memeriksa kode loader sebelum menjalankan biner yang dikemas, membuat kiteshielf tahan terhadap penambalan kode.
Lapisan enkripsi kedua (disebut dalam basis kode sebagai "lapisan dalam") terdiri dari enkripsi individu dari hampir setiap fungsi dalam biner input (diidentifikasi melalui tabel simbol pada waktu paket). Mesin runtime berbasis ptrace dipicu pada setiap entri fungsi dan keluar melalui penggantian instruksi entri masing-masing fungsi dan semua instruksi pengembaliannya dengan instruksi int3 (yang memberikan SIGTRAP saat dieksekusi). Setelah menerima perangkap, mesin runtime mencari fungsi saat ini dan mengenkripsi atau mendekripsi sesuai kebutuhan sehingga hanya fungsi dalam tumpukan panggilan saat ini yang didekripsi kapan saja.
After stripping off layer 1, Kiteshield effectively re-implements the exec syscall in userspace (See loader/loader.c . This technique is commonly referred to in literature as a "userspace exec" or "userland exec".) to map the packed binary into memory via a series of mmap / mprotect calls before forking and handing control off to the packed binary in the child and the runtime engine in the parent (which attaches to anak menggunakan ptrace).
Selain enkripsi, kode loader Kiteshield juga berisi sejumlah fitur anti-debugging yang dirancang untuk membuatnya sesulit mungkin untuk menganalisis biner yang dikemas (lihat loader/anti_debug.c dan loader/include/anti_debug.h ).
Untuk memberikan contoh konkret Kiteshield dalam aksi, pertimbangkan program Hello World berikut, yang akan kami kemas dengan Kiteshield dalam mode debug.
#include <stdio.h>
int main ()
{
puts ( "Hello World!" );
return 0 ;
}Saat dikemas dalam mode debug, kode loader di binari yang dikemas akan mencatat informasi debug yang sangat bertele -tele. Berikut ini adalah log dari biner yang dikemas sesuai dengan program di atas. Telah dianotasi (dan Newline tambahan ditambahkan untuk kejelasan) untuk memberikan contoh konkret dari Kiteshield dalam tindakan:
$ ./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 memiliki serangkaian tes integrasi yang luas untuk memverifikasi kebenaran di beberapa platform yang berbeda. Lihat testing/README.md untuk detailnya.
Kiteshield ditulis dengan kebingungan dalam pikiran, bukan kecepatan. Perangkap ke runtime Kiteshield di setiap pintu masuk fungsi dan keluar sangat mahal. Program yang dikemas dengan enkripsi Layer 2 harus mengharapkan hit kinerja yang serius.
MIT © Rhys Rustad-Elliott