Упаковщик/защитник для бинарных файлов x86-64 эльфов на Linux. Kiteshield завершает бинарные файлы эльфов с несколькими уровнями шифрования и вводит их в код загрузчика, который расширяет, карты и полностью выполняет упакованный бинар в пользовательском пространстве. Двигатель времени выполнения на основе PTRACE гарантирует, что только функции в текущем стеке вызовов дешифрованы в любой момент времени и дополнительно реализуют различные методы против де-дебаггирования, чтобы сделать упакованные двоичные файлы как можно более трудно. Поддерживаются как одиночные, так и многопоточные двоичные файлы.
См. Разделы макета архитектуры и кодовой базы ниже для вида птичьего полета о том, как работает Kiteshield.
Kiteshield предназначен для того, чтобы быть веселым академическим упражнением в бинарном запутывании, а не чем -то, что можно использовать в реальном мире, учитывая исходный код, и, следовательно, то, как он работает, является публичным.
Назван в честь щитов, предпочитаемых норманнами в 11 веке (в качестве альтернативы: Kiteshields, которые так распространены в старой школе Runescape).
Kikeshield требует, чтобы библиотека Disassassembler Bitdefender для декодирования инструкций в упаковке. Он включен в качестве подмодуля в packer/bddisasm . Чтобы построить его из свежего клона, запустите следующее (обратите внимание, вам нужно будет установить Cmake):
git submodule update --init
cd packer/bddisasm
mkdir build
cd build
cmake ..
make
Теперь вы можете построить Kiteshield в режиме выпуска, выполняя make из каталога верхнего уровня. В качестве альтернативы вы можете создать сборку отладки с помощью make debug . Debug Builds of 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 состоит из двух отдельных частей. Упаковка - это обычное приложение C, которое читает, инструменты и шифрование входных двоичных файлов. Погрузчик-это отдельно стоящее приложение C, ответственное за динамическую расшифровку функции и функциональность против де-дебаггирования, которое вводится в входные двоичные файлы упаковщиком. Он получает начальное управление от ядра, отображает все соответствующие сегменты бинарного в памяти (включая динамический линкер, если применимо) и передает управление приложению. Погрузчик также содержит двигатель времени выполнения, который динамически расшифровывает функции и шифрования, когда они вводятся и выходят во время выполнения.
Поскольку погрузчик получает начальное управление от ядра (т. Е. Прежде чем любые общие библиотеки обычно будут отображаться динамическим линкером), он не имеет доступа к LIBC, и, следовательно, все необходимые функциональные возможности, предоставляемые LIBC, повторно внедряется в коде загрузчика.
Упаковщик и код загрузчика можно найти в 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 завершает бинарные файлы входных эльфов в два (или один, при использовании флага -n ) слоев шифрования RC4, так что бинарный на диске довольно хорошо запутался. Эти слои разряжаются во время выполнения погрузчиком.
Первый слой шифрования (называемый в кодовой базе как «внешний слой») состоит из одного прохода RC4 по всему бинарному вводу. Это разработано в первую очередь для борьбы с статическим анализом. Из -за того, как ключ деобусновен (что зависит от кода загрузчика), первый слой шифрования также эффективно контролирует код загрузчика перед выполнением упакованного двоичного файла, что делает Kiteshield устойчивым к исправлению кода.
Второй слой шифрования (называемый в кодовой базе как «внутренний слой») состоит из индивидуального шифрования практически каждой функции в бинарном входном двоичном языке (идентифицированном через таблицу символов во время пакета). Двигатель выполнения на основе PTRACE запускается при каждой записи функции и выходит за счет замены инструкции каждой функции и всех его инструкций по возвращению с помощью инструкций int3 (которые доставляют SIGTRAP при выполнении). Получив ловушку, двигатель времени выполнения просматривает текущую функцию и шифрует или расшифровывает ее по мере необходимости, так что только функции в текущем стеке вызовов дешифрованы в любой момент времени.
После снятия слоя 1, Kiteshield эффективно повторно внедряет Syscall exec в mmap пространстве (см. loader/loader.c mprotect Использование PTRACE).
В дополнение к шифрованию, код загрузчика KiteShield также содержит ряд анти-дебаггирующих функций, предназначенных для того, чтобы сделать это как можно более трудным для анализа заполненного упакованного двоичного файла (см. loader/anti_debug.c и loader/include/anti_debug.h ).
Чтобы привести конкретный пример Kiteshield в действии, рассмотрите следующую программу Hello World, которую мы будем упаковать с Kiteshield в режиме отладки.
#include <stdio.h>
int main ()
{
puts ( "Hello World!" );
return 0 ;
}При упаковке в режиме отладки код загрузчика в упакованных двоичных файлах будет регистрировать очень многословную информацию отладки. Ниже приведено журнал из упакованного двоичного файла, соответствующего вышеуказанной программе. Он был аннотирован (и дополнительные новеньши, добавленные для ясности), чтобы дать конкретный пример 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 на каждом входе и выходе функции очень дорого. Программы, заполненные шифрованием уровня 2, должны ожидать серьезного успеха.
MIT © Rhys Rustad-Elliott