daisvke/woody-woodpacker
GitHub: daisvke/woody-woodpacker
Stars: 0 | Forks: 0
# **woody-woodpacker**
## **Table of Contents**
* [Overview](#overview)
* [Execution Flow](#execution-flow)
* [Runtime Behavior](#runtime-behavior)
* [ELF 64-bit File Structure](#elf-64-bit-file-structure)
* [Injection Mechanism](#injection-mechanism)
* [Stub Patch System](#stub-patch-system)
* [Entry Point Redirection](#entry-point-redirection)
* [Encryption System](#encryption-system)
* [Commands](#commands)
* [Debug Tools](#debug-tools)
# **Overview**
This project implements a **64-bit ELF packer with runtime unpacking capabilities**.
It transforms an ELF binary into a new executable (`woody`) that embeds:
* an encrypted copy of the original executable segment
* a custom unpacking stub injected into the binary
At runtime, the stub reconstructs the original program in memory and transfers execution back to it, preserving identical behavior while modifying only the binary representation.
# **Execution Flow**
Original ELF
→ Parse ELF headers & program headers
→ Locate executable PT_LOAD segment
→ Extract segment (includes .text region)
→ Encrypt payload (XOR + additive cipher)
→ Inject stub into executable segment region
(padding or shifting mode)
→ Patch stub with metadata (offsets, sizes, key)
→ Modify ELF entry point (e_entry → stub)
→ Generate "woody"
Runtime:
→ Kernel loads ELF
→ Execution starts in stub
→ Stub decrypts payload in memory
→ Restores original code
→ Prints: ....WOODY.....
→ Jumps to original entry point
→ Original program executes
# **Runtime Behavior**
At execution time, a packed `/bin/whoami` behaves as follows:
....WOODY.....
username
Except for the printed string, the final behavior remains strictly identical to the original binary.
# **ELF 64-bit File Structure**
+----------------------------------------------------+
| ELF Header |
| (64 bytes, ELF64_Ehdr structure) |
+----------------------------------------------------+
| Program Header Table |
| (Variable size, ELF64_Phdr entries) |
| describes memory-mapped segments |
+----------------------------------------------------+
| Text Section |
| (Executable code inside PT_LOAD segment) |
+----------------------------------------------------+
| Data Section |
| (Initialized data inside PT_LOAD segment) |
+----------------------------------------------------+
| Symbol Table Section |
| (ELF64_Sym entries) |
+----------------------------------------------------+
| String Table Section |
| ("name1\0name2\0...") |
+----------------------------------------------------+
| Section Header Table (optional) |
| (ELF64_Shdr entries) |
+----------------------------------------------------+
# **Injection Mechanism**
The stub is injected into the **executable PT_LOAD segment**, which typically contains:
* `.text`
* executable data pages
* padding between segments
It is not restricted to `.text` only, but placed inside the **executable memory-mapped region**.
## **1. Padding Injection (preferred mode)**
Used when sufficient space exists inside the executable segment.
Condition:
sizeof_stub ≤ padding_size
Where:
padding_size = next_segment.p_offset - injection_offset
Behavior:
* stub is written directly into existing padding
* no ELF relocation required
* no structural modification of headers
[ PT_LOAD (code + .text) | padding | STUB ]
## **2. Shifting Injection (fallback mode)**
Used when padding is insufficient or explicitly required.
### Step 1 — Extend segment size
p_filesz += sizeof_stub;
p_memsz += sizeof_stub;
### Step 2 — Relocate ELF structures
All headers after injection are updated:
* program headers offsets shifted
* section headers offsets shifted
* ELF section header table offset updated
### Step 3 — Rebuild binary layout
[ original ELF ]
[ STUB inserted ]
[ shifted ELF data ]
# **Stub Patch System**
The injected stub is patched with runtime metadata:
ww_t_patch patch;
This includes:
* offset from stub to original entry point
* `.text` section offset relative to stub
* `.text` size
* segment relocation offsets
Layout inside binary:
[ STUB ........ PATCH ........ KEY ]
# **Entry Point Redirection**
The ELF entry point is modified:
e_entry = injection_addr;
Result:
Before: entry → main()
After: entry → stub → main()
# **Encryption System**
## XOR Cipher
* symmetric encryption
* same function used for encryption and decryption
## Additive Layer
Applied before XOR:
byte → +offset → XOR → encrypted
encrypted → XOR → -offset → original
# **Commands**
## Basic usage
make # Build project
./woody_woodpacker [OPTIONS]
# Make and run the packer with the default options, then run the packed binary, all with valgrind
make run
# Example: run the packer with verbose mode, padding injection mode, then run the binary
./woody_woodpacker /bin/ls -i=p -v && ./woody
## Options
### Verbose mode
Displays detailed information about:
* ELF parsing
* injection offsets
* padding analysis
* relocation operations
* stub patch values
-v
--verbose
### Injection mode: padding
Attempts to inject stub into existing executable segment padding.
-i=p
--injection-type=padding
* safest mode
* no ELF restructuring
* requires enough free space
### Injection mode: shift
Forces structural modification of ELF when padding is insufficient or explicitly selected.
-i=s
--injection-type=shift
* rewrites ELF layout
* shifts headers and segments
* guarantees injection success
# **Debug tools**
readelf -l [filename] # Check program headers of the file
readelf -S [filename] # Check section headers
hexdump -C [filename] # Check the file in hex format
vimdiff [filename 1] [filename 2] # Check the difference between two files
# Extract the .text section from code.o
objcopy --dump-section .text=code-raw code.o
# Print the loaded file content in hex format at address 0x401040
gdb ./woody
run (or r)
x/16xw 0x401040
# Add breakpoint at relative address 11ad if base address is 0x4011ad
b *0x4011ad
# Produce a trace trap that stops the execution at the position (useful when debugging)
int3
# **Bonus ideas**
标签:客户端加密