Packer/Protector สำหรับ X86-64 ELF Binaries บน Linux Kiteshield ห่อไบนารีเอลฟ์ที่มีการเข้ารหัสหลายเลเยอร์และฉีดด้วยรหัสโหลดที่ถอดรหัสแผนที่และดำเนินการไบนารีที่บรรจุทั้งหมดใน Userspace เครื่องยนต์รันไทม์ที่ใช้ PTRACE ช่วยให้มั่นใจได้ว่าฟังก์ชั่นเฉพาะในสแต็กการโทรปัจจุบันจะถูกถอดรหัสในเวลาใดก็ตามและใช้เทคนิคการต่อต้านการเบ็ดที่หลากหลายเพื่อให้ไบนารีที่บรรจุยาก รองรับทั้งสองไบนารีเดี่ยวและแบบมัลติเธรด
ดูส่วนของสถาปัตยกรรมและ codebase ด้านล่างสำหรับมุมมองของนกในการทำงานของวิธีการทำงานของ Kiteshield
Kiteshield มีจุดประสงค์เพื่อการออกกำลังกายเชิงวิชาการที่สนุกสนานในการทำให้งงงวยแบบไบนารีมากกว่าสิ่งที่สามารถใช้ในโลกแห่งความเป็นจริงได้ตามซอร์สโค้ดและวิธีการทำงานเป็นสาธารณะ
ชื่อสำหรับโล่ที่ชาวนอร์มันต้องการในศตวรรษที่ 11 (อีกวิธีหนึ่ง: Kiteshields ที่แพร่หลายใน Runescape ของโรงเรียนเก่า)
Kiteshield ต้องการไลบรารี Disassembler Bitdefender เพื่อถอดรหัสคำแนะนำใน Packer มันรวมอยู่ใน submodule ที่ packer/bddisasm ในการสร้างจากโคลนสดให้เรียกใช้สิ่งต่อไปนี้ (หมายเหตุคุณจะต้องติดตั้ง cmake):
git submodule update --init
cd packer/bddisasm
mkdir build
cd build
cmake ..
make
ตอนนี้คุณสามารถสร้าง Kiteshield ในโหมดรีลีสได้โดยเรียกใช้ make จากไดเรกทอรีระดับบนสุด หรือคุณสามารถสร้างบิลด์ดีบั๊กด้วย make debug การดีบักสร้าง Kiteshield ปิดการใช้งานคุณสมบัติต่อต้านการเบ็ดทั้งหมดและเปิดการบันทึกการดีบัก verbose ของตัวโหลด
ในการดีบั๊กฟังก์ชั่นต่อต้าน debugging ที่แท้จริงคุณสามารถสร้าง kiteshield ในโหมดการดีบักด้วยฟังก์ชั่นต่อต้าน debugging เปิด ใช้งาน โดยใช้ make debug-antidebug
packed.ks ต้องการแพ็ค program ไบนารีที่เรียก
./packer/kiteshield program packed.ks
packed.ks สามารถเรียกใช้และควรใช้งานได้กับ program แต่เข้ารหัสและยากที่จะย้อนกลับวิศวกร โปรดทราบว่าสำหรับการเข้ารหัสเลเยอร์ 2 ที่จะนำไปใช้ไบนารีอินพุต จะต้องไม่ ถูกถอดออกเป็น kiteshield ขึ้นอยู่กับตารางสัญลักษณ์ที่มีอยู่ ใน linux distros ส่วนใหญ่ยูทิลิตี้ระบบมาตรฐาน (เช่น /bin/ls ) จะถูกถอดออกโดยทั่วไป
อย่างไรก็ตามคุณยังสามารถแพ็คไบนารีที่ถอดออกได้โดยไม่ต้องเข้ารหัสเลเยอร์ 2 โดยใช้ธง -n :
./packer/kiteshield -n program packed.ks
สิ่งนี้จะสร้างไบนารีเอาท์พุทที่เต็มไปด้วยการเข้ารหัสเลเยอร์ 1 เท่านั้นและเครื่องยนต์รันไทม์ถูกละเว้น
Kiteshield ประกอบด้วยสองส่วนแยกกัน Packer เป็นแอปพลิเคชัน C ปกติที่อ่านเครื่องมือและเข้ารหัสไบนารีอินพุต ตัวโหลดเป็นแอปพลิเคชัน C อิสระที่รับผิดชอบการถอดรหัสฟังก์ชั่นแบบไดนามิกและฟังก์ชั่นต่อต้าน debugging ที่ถูกฉีดเข้าไปในไบนารีอินพุตโดย Packer ได้รับการควบคุมเริ่มต้นจากเคอร์เนลแมปเซ็กเมนต์ที่เหมาะสมทั้งหมดของไบนารีลงในหน่วยความจำ (รวมถึงตัวเชื่อมโยงแบบไดนามิกถ้ามี) และควบคุมการควบคุมแอปพลิเคชัน โหลดเดอร์ยังมีเอ็นจิ้นรันไทม์ซึ่งถอดรหัสฟังก์ชั่นและเข้ารหัสแบบไดนามิกตามที่พวกเขาป้อนและออกเมื่อรันไทม์
เนื่องจากตัวโหลดได้รับการควบคุมเริ่มต้นจากเคอร์เนล (เช่นก่อนที่ไลบรารีที่ใช้ร่วมกันจะถูกแมปโดยตัวเชื่อมโยงแบบไดนามิก) จึงไม่สามารถเข้าถึง LIBC ได้
Packer และรหัสโหลดสามารถพบได้ใน packer/ และ loader/ Directory ตามลำดับ รหัสที่พบได้ทั่วไปทั้งคู่สามารถพบได้ในไดเรกทอรี common/ ไดเรกทอรี ภาพรวมระดับสูงของส่วนสำคัญของ codebase มีดังนี้:
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 เช่นไบนารีบนดิสก์นั้นค่อนข้างงงงวย เลเยอร์เหล่านี้ถูกถอดออกเมื่อรันไทม์โดยรถตัก
เลเยอร์แรกของการเข้ารหัส (อ้างถึงใน codebase เป็น "เลเยอร์ด้านนอก") ประกอบด้วย RC4 ครั้งเดียวผ่านไบนารีอินพุตทั้งหมด สิ่งนี้ได้รับการออกแบบมาเพื่อต่อสู้กับการวิเคราะห์แบบคงที่ เนื่องจากวิธีการที่คีย์เป็น deobfuscated (ซึ่งขึ้นอยู่กับรหัสโหลด) เลเยอร์แรกของการเข้ารหัสยังตรวจสอบรหัสโหลดตัวโหลดได้อย่างมีประสิทธิภาพก่อนที่จะดำเนินการไบนารีที่บรรจุทำให้คิทชิลล์ทนต่อการแก้ไขรหัส
เลเยอร์ที่สองของการเข้ารหัส (อ้างถึงใน codebase เป็น "ชั้นใน") ประกอบด้วยการเข้ารหัสแต่ละรายการของเกือบทุกฟังก์ชั่นในไบนารีอินพุต (ระบุผ่านตารางสัญลักษณ์ในเวลาแพ็ค) เอ็นจิ้นรันไทม์ที่ใช้ PTRACE จะถูกเรียกใช้ในทุกฟังก์ชั่นและออกจากการแทนที่คำสั่งการป้อนข้อมูลของฟังก์ชั่นแต่ละรายการและคำแนะนำการส่งคืนทั้งหมดด้วยคำแนะนำ int3 (ซึ่งส่ง SIGTRAP เมื่อดำเนินการ) เมื่อได้รับกับดักเครื่องยนต์รันไทม์จะค้นหาฟังก์ชั่นปัจจุบันและเข้ารหัสหรือถอดรหัสตามต้องการเช่นเดียวกับฟังก์ชั่นภายในสแต็กการโทรปัจจุบันจะถูกถอดรหัส ณ เวลาใดก็ได้
หลังจากปิดเลเยอร์ 1 Kiteshield จะเปิดใช้งาน exec SYSCALL ใน USSSPACE อีกครั้ง (ดู loader/loader.c mprotect นี้มักจะถูกเรียกใน mmap เป็น "ผู้ใช้งานผู้ใช้งาน" หรือ "ผู้บริหาร") เพื่อทำแผนที่ ใช้ ptrace)
นอกเหนือจากการเข้ารหัสแล้วรหัสโหลดเดอร์ของ Kiteshield ยังมีคุณสมบัติต่อต้านการลดจำนวนจำนวนมากที่ออกแบบมาเพื่อให้ยากที่สุดเท่าที่จะเป็นไปได้ในการวิเคราะห์ไบนารีที่ทำงานอยู่ (ดู loader/anti_debug.c และ loader/include/anti_debug.h )
เพื่อให้ตัวอย่างคอนกรีตของ Kiteshield ในการดำเนินการพิจารณาโปรแกรม Hello World ต่อไปนี้ซึ่งเราจะแพ็คกับ Kiteshield ในโหมด Debug
#include <stdio.h>
int main ()
{
puts ( "Hello World!" );
return 0 ;
}เมื่อบรรจุในโหมดดีบักรหัสโหลดในไบนารีที่บรรจุจะบันทึกข้อมูลการดีบัก verbose มาก ต่อไปนี้เป็นบันทึกจากไบนารีที่สอดคล้องกับโปรแกรมด้านบน มันได้รับการใส่คำอธิบายประกอบ (และเพิ่มใหม่เพื่อความชัดเจน) เพื่อให้ตัวอย่างคอนกรีตของ Kiteshield ในการดำเนินการ:
$ ./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