Linux上のX86-64 ELFバイナリのパッカー/プロテクター。 Kiteshieldは、エルフのバイナリを複数の暗号化で包み、ユーザースペースで完全に詰め込まれたバイナリを復号化、マップ、および実行するローダーコードを注入します。 PTRACEベースのランタイムエンジンは、現在のコールスタック内の機能がいつでも復号化されるようにし、さらに、パックされたバイナリを可能な限り逆転させるのが難しいようにするために、さまざまな反抗技術をさらに実装します。シングルバイナリとマルチスレッドバイナリの両方がサポートされています。
Kiteshieldの仕組みの鳥瞰図については、以下のアーキテクチャとコードベースのレイアウトセクションを参照してください。
Kiteshieldは、ソースコードを考慮して現実世界で使用できるものではなく、バイナリ観測における楽しいアカデミックエクササイズになることを目的としています。
11世紀にノルマン人が好む盾にちなんで名付けられました(代わりに、古い学校のルーンスケープで非常に一般的なキテシールド)。
Kiteshieldでは、BitDefender Resassemblerライブラリがパッカーの命令をデコードする必要があります。これは、 packer/bddisasmのサブモジュールとして含まれています。新鮮なクローンからそれを構築するには、以下を実行します(cmakeをインストールする必要があることに注意してください):
git submodule update --init
cd packer/bddisasm
mkdir build
cd build
cmake ..
make
これで、トップレベルのディレクトリからmake実行することにより、リリースモードでKiteshieldを構築できるようになりました。または、 make debugを使用してデバッグビルドを作成することもできます。 Kiteshieldのデバッグビルドでは、すべての不自由な機能を無効にし、ローダーの非常に冗長なデバッグロギングをオンにします。
実際のアンチボッグ機能をデバッグするために、 make debug-antidebugを使用して、不開発機能をオンにしてデバッグモードでKiteshieldを構築できます。
programと呼ばれるバイナリをパックし、梱包されたバイナリをpacked.ksれた.ksに出力するには、実行します。
./packer/kiteshield program packed.ks
packed.ks実行できるようになり、 programと機能的に同等である必要がありますが、暗号化され、リバースエンジニアリングが難しくなります。レイヤー2暗号化を適用するには、Kiteshieldが存在するシンボルテーブルに依存しているため、入力バイナリを剥がすべきではないことに注意してください。ほとんどのLinuxディストリビューションでは、標準のシステムユーティリティ( /bin/lsなど)が一般的に剥がされます。
ただし、 -nフラグを使用してレイヤー2暗号化なしで剥がれたバイナリを梱包できます。
./packer/kiteshield -n program packed.ks
これにより、レイヤー1暗号化とランタイムエンジンのみが省略された出力バイナリが詰め込まれます。
Kiteshieldは、2つの別々の部品で構成されています。パッカーは、入力バイナリを読み取り、楽器、暗号化する定期的な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は、RC4暗号化の2つのレイヤー(または-nフラグを使用する場合)で入力ELFバイナリをラップし、ディスク上のバイナリがかなりよく難読化されます。これらのレイヤーは、実行時にローダーによって剥奪されます。
暗号化の最初の層(コードベースで「外層」と呼ばれる)は、入力バイナリ全体の単一のRC4パスで構成されています。これは、主に静的分析と戦うために設計されています。キーの脱ブスケート(ローダーコードに依存する)のために、暗号化の最初のレイヤーは、パックされたバイナリを実行する前にローダーコードを効果的にチェックサムし、キテシールドがコードパッチングに抵抗するようにします。
暗号化の2番目の層(コードベースで「内側の層」と呼ばれる)は、入力バイナリ内のほぼすべての関数の個々の暗号化(パック時にシンボルテーブルを介して識別)で構成されています。 PTRACEベースのランタイムエンジンは、すべての関数エントリでトリガーされ、各関数のエントリ命令を交換し、すべてのリターン命令をint3命令(実行時にSIGTRAPを提供します)を交換します。トラップを受信すると、ランタイムエンジンは現在の関数を検索し、必要に応じて暗号化または復号化し、現在のコールスタック内の機能のみがいつでも復号化されます。
レイヤー1を除去した後、Kiteshieldはユーザースペースでexec Syscallを効果的に再インプレクトします( mmap loader/loader.c mprotect参照してください。この手法は、一般に文献では「ユーザースペースexec」または「ユーザーランドエグゼクティブ」と呼ばれています。)。 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