| English | 中文 |
Control Flow Deflattening
D810G recovers original control flow from obfuscated functions by detecting and reversing the state machine transformation applied by OLLVM and Tigress.
Supported Patterns
OLLVM Switch-Dispatch
OLLVM converts the function’s basic blocks into cases of a giant switch(state) statement. Each original block updates the state variable and jumps back to the dispatcher.
Original: After OLLVM CFF:
┌───────┐ ┌──────────────┐
│ entry │ │ dispatcher │◄────┐
└───┬───┘ │ switch(state) │ │
│ └┬──┬──┬──┬────┘ │
┌───▼───┐ ┌──▼┐┌▼─┐┌─▼┐┌──▼──┐ │
│ if() │ │0xA││0xB││0xC││ ret │ │
└─┬───┬─┘ │s= ││s= ││s= │└─────┘ │
│ │ │0xB││0xC││0xD│ │
▼ ▼ └─┬─┘└─┬─┘└─┬─┘ │
return └────┴────┴──────────────┘
D810G’s approach:
- Detect the dispatcher block (high in-degree + high out-degree)
- Use Unicorn to emulate each case block and trace state variable writes
- Build a state transition map: state_value → next_block
- Use Keystone to assemble direct
jmpinstructions replacing the state update + dispatcher jump - NOP out dead code
Tigress Indirect Jump Table
Tigress uses jmp [table + state * 8] instead of a switch statement. D810G detects the jump table in .rodata and resolves each entry.
Tigress If-Chain
Tigress may also use sequential if/else comparisons instead of a switch. D810G detects chains of 3+ comparison blocks.
Architecture Support
| Arch | Emulation | Patching |
|---|---|---|
| x86_64 | Unicorn UC_ARCH_X86 | jmp rel32 |
| ARM64 | Unicorn UC_ARCH_ARM64 | b offset |
| ARM32 | Unicorn UC_ARCH_ARM | b offset |
API
# JSON-RPC
{"method": "deflat.run", "params": {"blocks": [...], "binary_hex": "...", "arch": "x86_64"}}
{"method": "deflat.tigress", "params": {"blocks": [...], "binary_hex": "..."}}