reverse-skills-max: initial public release (restored, redacted, hardened)

This commit is contained in:
baradok609hecl1pq6qi
2026-10-20 02:17:15 +03:00
commit da24c2bd20
2227 changed files with 443931 additions and 0 deletions

View File

@@ -0,0 +1,9 @@
Apache License 2.0 — see the repository root LICENSE file for the full text.
Copyright the AnalystAIPack contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0

View File

@@ -0,0 +1,85 @@
---
name: defeating-control-flow-flattening
description: 'Defeats control-flow-flattening obfuscation by identifying the dispatcher/state-
variable structure and reconstructing the original control flow so the logic becomes readable.
Activates for requests to defeat control-flow flattening, deobfuscate an OLLVM-flattened function,
or recover original control flow from a dispatcher loop.'
domain: cybersecurity
subdomain: reverse-engineering
tags:
- reverse-engineering
- obfuscation
- control-flow-flattening
- ollvm
- deobfuscation
version: 1.0.0
author: analyst-ai-pack
license: Apache-2.0
mitre_attack:
- T1027
- T1027.013
- T1140
d3fend:
- D3-DA
- D3-SDA
references:
- 'OLLVM control-flow flattening (Obfuscator-LLVM) — https://github.com/obfuscator-llvm/obfuscator'
- 'MITRE ATT&CK T1027 Obfuscated Files or Information — https://attack.mitre.org/techniques/T1027/'
---
# Defeating Control-Flow Flattening
## When to Use
- A function is flattened (a dispatcher loop switching on a state variable, with original blocks as
switch cases) and you need to recover the original control flow.
- You are reversing OLLVM-style or similar flattening.
**Do not use** this on non-flattened code — confirm the dispatcher/state-variable pattern first.
This skill analyzes disassembly/CFG data statically and executes nothing.
## Prerequisites
- A disassembled function's basic-block/edge data (e.g., exported from Ghidra/IDA/Binary Ninja as
JSON).
## Workflow
### Step 1: Detect the flattening structure
```bash
python scripts/analyst.py detect cfg.json
```
Identifies a dispatcher block (high in-degree, switch/compare on a state variable) and the relay/
case blocks that all branch back to it.
### Step 2: Recover state transitions
Track the constant assigned to the state variable in each case to determine the successor block,
rebuilding the true edges.
### Step 3: Reconstruct the original CFG
Emit the deflattened successor mapping (case → next case) for re-annotation in the disassembler.
### Step 4: Verify
Confirm the recovered flow has a single entry, sane successors, and no orphan blocks.
## Validation
- The dispatcher is identified by in-degree and state-variable comparison.
- Each case's next-state constant maps to a real successor block.
- The reconstructed CFG covers all original (non-relay) blocks.
## Pitfalls
- State variable computed (not a constant) — requires emulation/symbolic execution.
- Multiple dispatchers or nested flattening.
- Opaque predicates and bogus blocks inflating the case set.
## References
- See [`references/api-reference.md`](references/api-reference.md) for the deflattener.
- OLLVM and ATT&CK T1027 references (linked in frontmatter).

View File

@@ -0,0 +1,49 @@
# API Reference: Defeating Control-Flow Flattening
## Overview
`scripts/analyst.py` consumes a function CFG (basic blocks with successors, in-degree, state-compare
flag, and next-state constants) and reconstructs the original control flow by identifying the
dispatcher and mapping each case's next-state to its successor. It parses JSON only and executes
nothing.
## Dependencies
| Package | Version | Purpose |
|---------|---------|---------|
| (stdlib) | — | JSON, argparse, pathlib |
## Input format
```json
{
"state_var": "eax",
"entry": "A",
"blocks": [
{"id": "D", "succ": ["B","C"], "in_degree": 5, "state_compare": true},
{"id": "B", "succ": ["D"], "in_degree": 1, "next_state": "C"}
]
}
```
## Core functions
### `detect(path)`
Returns the dispatcher, case count, deflattened transitions, and unresolved blocks.
## Method
Dispatcher = highest in-degree block that compares the state variable; case blocks branch back to
it; each case's `next_state` constant gives the true successor.
## Usage
```bash
python scripts/analyst.py detect cfg.json
```
## Sources
- Obfuscator-LLVM control-flow flattening — https://github.com/obfuscator-llvm/obfuscator
- MITRE ATT&CK T1027 Obfuscated Files or Information — https://attack.mitre.org/techniques/T1027/
- Dispatcher/state-variable deflattening method from public deobfuscation research

View File

@@ -0,0 +1,67 @@
#!/usr/bin/env python3
"""Detect control-flow flattening and reconstruct original control flow from CFG JSON.
Input JSON describes a function's basic blocks:
{
"state_var": "eax",
"blocks": [
{"id": "A", "succ": ["D"], "in_degree": 1, "state_compare": false,
"next_state": null},
{"id": "D", "succ": ["B","C","E"], "in_degree": 5, "state_compare": true},
{"id": "B", "succ": ["D"], "in_degree": 1, "next_state": "C_const"} ...
]
}
Identifies the dispatcher (high in-degree + state_compare) and rebuilds case->next mappings using
each case's next_state. Parses JSON only; executes nothing.
"""
from __future__ import annotations
import argparse
import json
import sys
from pathlib import Path
def detect(path: str) -> dict:
data = json.loads(Path(path).read_text(encoding="utf-8-sig"))
blocks = {b["id"]: b for b in data.get("blocks", [])}
# Dispatcher: a block that compares the state variable and has the highest in-degree.
candidates = [b for b in blocks.values() if b.get("state_compare")]
if not candidates:
candidates = list(blocks.values())
dispatcher = max(candidates, key=lambda b: b.get("in_degree", 0), default=None)
if not dispatcher:
return {"flattening_detected": False}
disp_id = dispatcher["id"]
# Case/relay blocks branch back to the dispatcher.
cases = [b for b in blocks.values()
if disp_id in b.get("succ", []) and b["id"] != disp_id]
deflattened = {}
for case in cases:
nxt = case.get("next_state")
deflattened[case["id"]] = nxt
covered = set(deflattened) | {disp_id}
orphans = [bid for bid in blocks if bid not in covered
and bid not in (data.get("entry"),)]
return {
"flattening_detected": len(cases) >= 3,
"dispatcher": disp_id,
"state_var": data.get("state_var"),
"case_count": len(cases),
"deflattened_transitions": deflattened,
"unresolved_blocks": orphans,
}
def main(argv: list[str] | None = None) -> int:
parser = argparse.ArgumentParser(description="Defeat control-flow flattening")
sub = parser.add_subparsers(dest="cmd", required=True)
p = sub.add_parser("detect")
p.add_argument("cfg")
args = parser.parse_args(argv)
print(json.dumps(detect(args.cfg), indent=2))
return 0
if __name__ == "__main__":
sys.exit(main())