A small ELF packer/crypter for x86-64 ET_DYN and ET_EXEC binaries.
This is a fun project for learning more about the ELF format and code protection. It's not intended for real world use.
The project has two parts:
- Stub — a statically linked
nostdlibexecutable that decrypts the packed executable in memory and jumps to it, mimickingexecvebased on ul_exec. - Packer — encrypts the target executable with RC4 and injects the encrypted data into the stub's
PT_NOTEsegment.
The stub uses custom syscall wrappers to avoid libc and keep the binary small.
The stub is loaded at 0x70000000 instead of the usual 0x40000000 base address for static x86-64 executables, helping avoid conflicts with packed static executables.
The encryption key consists of a random 16-byte key combined with the stub's FNV-1a hash, making simple patching of the stub a little more inconvenient.
From the project root: make or make DEBUG=1 to enable debugging and logging for the stub
Example: ./bin/packer -i /usr/bin/ls -o ./testing/ls_packed
Before being packed:
$ readelf -h /usr/bin/ls
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: DYN (Position-Independent Executable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x6a60
Start of program headers: 64 (bytes into file)
Start of section headers: 164872 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 14
Size of section headers: 64 (bytes)
Number of section headers: 30
Section header string table index: 29
$ readelf -l /usr/bin/ls
Elf file type is DYN (Position-Independent Executable file)
Entry point 0x6a60
There are 14 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
PHDR 0x0000000000000040 0x0000000000000040 0x0000000000000040
0x0000000000000310 0x0000000000000310 R 0x8
INTERP 0x0000000000000374 0x0000000000000374 0x0000000000000374
0x000000000000001c 0x000000000000001c R 0x1
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
LOAD 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000003f50 0x0000000000003f50 R 0x1000
LOAD 0x0000000000004000 0x0000000000004000 0x0000000000004000
0x0000000000018f79 0x0000000000018f79 R E 0x1000
LOAD 0x000000000001d000 0x000000000001d000 0x000000000001d000
0x0000000000009578 0x0000000000009578 R 0x1000
LOAD 0x0000000000026cd0 0x0000000000027cd0 0x0000000000027cd0
0x0000000000001590 0x00000000000028a8 RW 0x1000
DYNAMIC 0x0000000000027a18 0x0000000000028a18 0x0000000000028a18
0x0000000000000200 0x0000000000000200 RW 0x8
NOTE 0x0000000000000350 0x0000000000000350 0x0000000000000350
0x0000000000000024 0x0000000000000024 R 0x4
NOTE 0x0000000000026538 0x0000000000026538 0x0000000000026538
0x0000000000000020 0x0000000000000020 R 0x8
NOTE 0x0000000000026558 0x0000000000026558 0x0000000000026558
0x0000000000000020 0x0000000000000020 R 0x4
GNU_PROPERTY 0x0000000000026538 0x0000000000026538 0x0000000000026538
0x0000000000000020 0x0000000000000020 R 0x8
GNU_EH_FRAME 0x00000000000224a8 0x00000000000224a8 0x00000000000224a8
0x0000000000000ab4 0x0000000000000ab4 R 0x4
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RW 0x10
GNU_RELRO 0x0000000000026cd0 0x0000000000027cd0 0x0000000000027cd0
0x0000000000001330 0x0000000000001330 R 0x1
after being packed:
$ readelf -h ./testing/ls_packed
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x70001810
Start of program headers: 64 (bytes into file)
Start of section headers: 8976 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 5
Size of section headers: 64 (bytes)
Number of section headers: 7
Section header string table index: 6
$ readelf -l ./testing/ls_packed
Elf file type is EXEC (Executable file)
Entry point 0x70001810
There are 5 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
LOAD 0x0000000000000000 0x0000000070000000 0x0000000070000000
0x000000000000017c 0x000000000000017c R 0x1000
LOAD 0x0000000000001000 0x0000000070001000 0x0000000070001000
0x0000000000000a9e 0x0000000000000a9e R E 0x1000
LOAD 0x0000000000002000 0x0000000070002000 0x0000000070002000
0x00000000000002ac 0x00000000000002ac R 0x1000
LOAD 0x00000000000024d0 0x00000000700034d0 0x00000000700034d0
0x0000000000028ba0 0x0000000000028ba0 RWE 0x1000
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RW 0x10