Arborist is a fully vibecoded Binary Ninja plugin and script for analyzing control-flow-flattened functions. It identifies likely state variables, resolves values written to the state slot, finds dispatcher regions, builds a basic-block/state map, and recovers a higher-level CFG that can also be previewed in the Binary Ninja UI. Only flattened functions that use a jump-table (switch-case) are currently supported.
Warning
This plugin has only been tested against flattened functions generated by a specific, unknown
commercial obfuscator used by some iOS applications. Your mileage may vary when used on different families of obfuscators. You can use the provided yara rule at SPT_antihook_macho.yar to verify if you are dealing with the same obfuscator this plugin targets.
The repository exposes the same core analysis in three ways:
- Binary Ninja plugin commands such as
Arborist\Run Verbose AnalysisandArborist\Show Recovered CFG - Direct execution of
arborist.pyinside Binary Ninja's Python environment - A
bnCLI bridge viapython3 -m tools.bn_arborist
I had to reverse engineer multiple iOS applications that used the same obfuscator to implement CFF, among other obfuscation mechanisms, and I eventually got tired of having to go through hundreds of basic blocks just to start understanding what a function does.
- Binary Ninja
>= 3164 - Python 3
- This repository cloned or symlinked into your Binary Ninja plugins directory for plugin-installed use
cobra-cliinPATHif you want MBA expression normalization during state-value resolutionbn(Optional)
- Clone this repository.
- Clone or symlink it into your Binary Ninja plugins directory.
- Restart Binary Ninja.
- Open a target binary or
.bndb. - Run
Arborist\Run Verbose Analysison the current function. - Optionally run
Arborist\Show Recovered CFGto open the recovered CFG pane.
To run the bn bridge against an already open Binary Ninja target:
bn target list
python3 -m tools.bn_arborist --target <selector> --address 0x401000To run the test suite:
python3 -m unittest tests.test_arborist tests.test_bn_arborist- Menu navigation:
- CFG Recovery
Run the bn bridge and get JSON output. Bear in mind that although the generated report will contain state transition information, the CFG recovery functionality is only available in GUI mode:
python3 -m tools.bn_arborist --target obfuscated.bndb --address 0x10066ddf8Output:
{
"analysis": {
"bb_state_map": {
"block_to_states": [
{
"block_range": {
"end": "0x10066df08",
"start": "0x10066df00"
},
"block_start": "0x10066df00",
"classification": "case-entry",
"dispatcher_component": null,
"dispatcher_internal": false,
"state_values": [
14
]
},
{
"block_range": {
"end": "0x10066df40",
"start": "0x10066df24"
},
"block_start": "0x10066df24",
"classification": "case-entry",
"dispatcher_component": null,
"dispatcher_internal": false,
"state_values": [
0
]
},
...
"state_transitions": [
{
"source_state_value": 0,
"transitions": [
{
"expression": null,
"kind": "constant",
"shared_source": false,
"source_block_classifications": [
"likely-original-logic"
],
"source_block_ranges": [
{
"end": "0x10066df40",
"start": "0x10066df24"
}
],
"source_state_value": 0,
"target_block_range": {
"end": "0x10066e01c",
"start": "0x10066e008"
},
"target_block_start": "0x10066e008",
"target_state_value": 1,
"write_addresses": [
"0x10066df34"
]
},
...
