- BinaryExprKind enum (8 kinds): HardcodedString, CallSite, VtableEntry... - 8 BinaryFindingKind values for binary-specific vulnerabilities - Detector pipeline mirrors source architecture (standalone functions) - Phase plan: 4 phases, target 3.7% → 40%+ detection
3.1 KiB
3.1 KiB
fold Binary Backend Architecture v2 — BinaryIR + BinaryDetector Pipeline
Status: Design (May 2026) Scope: IR, finding taxonomy, detector pipeline for binary/hybrid scan modes
Problem
CTF evaluation showed 3.7% binary detection vs 66.7% source. The binary backend lacks:
- Structured IR between r2 data and findings (source has ir::Expr trees)
- Detector pipeline (source has 20+ detectors with observer hooks)
- Type-aware findings (binary findings are opaque strings)
BinaryIR Design
Mirrors the source IR architecture (include/fold/ir/expr.hpp) but for binary constructs:
enum class BinaryExprKind : uint8_t {
// Data discovery
HardcodedString, // "password", "http://", key patterns
ImportedSymbol, // dlsym/GetProcAddress targets
SectionData, // .rodata, .data, .text section references
// Control flow
BasicBlock, // Disassembled basic block
CallSite, // Call instruction with target
IndirectCall, // Call through register/memory
// Data flow
StringXref, // Code referencing a string
DataXref, // Data referencing data
CodeXref, // Code referencing code
// Structure
ExportEntry, // Exported function
VtableEntry, // Virtual table slot
SwitchTable, // Jump table
};
BinaryFindingKind
New finding kinds for binary-specific vulnerabilities:
| Finding | What it detects | Confidence |
|---|---|---|
| HardcodedUrl | HTTP/HTTPS URLs in .rodata | Syntactic |
| HardcodedPassword | "password", "passwd" patterns | Heuristic |
| StackString | String built on stack (obfuscation) | Heuristic |
| SuspiciousImport | system(), exec(), popen() imports | Syntactic |
| PackedSection | UPX/ASPack detection | Syntactic |
| MissingStackCookie | No __stack_chk_fail import | Heuristic |
| WritableXSegment | RWX memory regions | Syntactic |
| UnresolvedIndirectCall | Call through register without known target | Heuristic |
BinaryDetector Pipeline
Mirrors source detector architecture:
Binary (Mach-O/ELF) → R2Backend → BinaryIR tree → BinaryDetector → Finding
↓
BinaryExpr nodes flow through
detector pipeline like source
ir::Expr flows through ASTVisitor
Each detector is a standalone function:
std::vector<Finding> detectHardcodedStrings(const BinaryIRTree& tree);
std::vector<Finding> detectSuspiciousImports(const BinaryIRTree& tree);
std::vector<Finding> detectPackedSections(const BinaryIRTree& tree);
Implementation Plan
| Phase | What | Effort |
|---|---|---|
| 1 | BinaryExprKind enum + BinaryIRTree | S |
| 2 | HardcodedString + SuspiciousImport detectors | S |
| 3 | PackedSection + WritableXSegment detectors | S |
| 4 | Wire into scan_router + CLI | S |
| 5 | Test against 10 CTF binaries, measure improvement | S |
Target: 3.7% → 40%+ detection rate (Phase 2 alone adds ~10 string+suspicious-import findings).