reverse-skills-max: initial public release (restored, redacted, hardened)
This commit is contained in:
@@ -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
|
||||
@@ -0,0 +1,89 @@
|
||||
---
|
||||
name: reverse-engineering-binaries-with-binary-ninja
|
||||
description: 'Reverse engineers binaries with Binary Ninja using its analysis stack and Python API
|
||||
to enumerate functions, navigate IL levels (LLIL/MLIL/HLIL), and automate annotation and
|
||||
extraction. Activates for requests to reverse a binary with Binary Ninja, script the Binary Ninja
|
||||
API, or work with its intermediate languages.'
|
||||
domain: cybersecurity
|
||||
subdomain: reverse-engineering
|
||||
tags:
|
||||
- reverse-engineering
|
||||
- binary-ninja
|
||||
- il
|
||||
- automation
|
||||
- static-analysis
|
||||
version: 1.0.0
|
||||
author: analyst-ai-pack
|
||||
license: Apache-2.0
|
||||
mitre_attack:
|
||||
- T1027
|
||||
- T1059
|
||||
- T1587.001
|
||||
d3fend:
|
||||
- D3-DA
|
||||
- D3-SDA
|
||||
references:
|
||||
- 'Binary Ninja Python API documentation — https://api.binary.ninja/'
|
||||
- 'Binary Ninja IL (LLIL/MLIL/HLIL) guide — https://docs.binary.ninja/dev/bnil-llil.html'
|
||||
---
|
||||
|
||||
# Reverse Engineering Binaries With Binary Ninja
|
||||
|
||||
## When to Use
|
||||
|
||||
- You want to reverse a binary with Binary Ninja and automate analysis via its Python API
|
||||
(function enumeration, IL traversal, annotation, extraction).
|
||||
- You need to leverage MLIL/HLIL for cleaner analysis of obfuscated code.
|
||||
|
||||
**Do not use** the headless API to execute the sample — Binary Ninja performs static analysis. Run
|
||||
in an isolated environment and treat inputs as malicious.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Binary Ninja with the `binaryninja` Python API available (the script degrades gracefully and
|
||||
generates a script skeleton if the API is not importable).
|
||||
|
||||
## Safety & Handling
|
||||
|
||||
- Static analysis does not execute the sample; keep inputs isolated.
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 1: Generate an analysis script skeleton
|
||||
|
||||
```bash
|
||||
python scripts/analyst.py skeleton --emit functions,strings --out bn_extract.py
|
||||
```
|
||||
|
||||
Emits a Binary Ninja Python script that opens a view, iterates functions, and exports
|
||||
functions/strings to JSON using the real API (`open_view`, `bv.functions`, `bv.get_strings`).
|
||||
|
||||
### Step 2: Choose the IL level
|
||||
|
||||
Use LLIL for close-to-assembly, MLIL for variable/SSA reasoning, and HLIL for readable
|
||||
pseudo-code; traverse instructions and operands programmatically.
|
||||
|
||||
### Step 3: Automate annotation
|
||||
|
||||
Rename symbols (`func.name`), add comments (`bv.set_comment_at`), and create tags for findings.
|
||||
|
||||
### Step 4: Run and aggregate
|
||||
|
||||
Execute the script (headless or in the UI console) and aggregate the JSON output.
|
||||
|
||||
## Validation
|
||||
|
||||
- The skeleton uses real API calls (`binaryninja.open_view`, `bv.functions`).
|
||||
- The chosen IL level matches the analysis goal.
|
||||
- Exported JSON contains plausible functions/strings.
|
||||
|
||||
## Pitfalls
|
||||
|
||||
- Headless licensing differences (Commercial vs Personal) affecting `open_view` availability.
|
||||
- Confusing IL levels and operand structures across LLIL/MLIL/HLIL.
|
||||
- Long analysis times on large binaries — scope function ranges.
|
||||
|
||||
## References
|
||||
|
||||
- See [`references/api-reference.md`](references/api-reference.md) for the skeleton generator.
|
||||
- Binary Ninja API and IL docs (linked in frontmatter).
|
||||
@@ -0,0 +1,41 @@
|
||||
# API Reference: Reverse Engineering Binaries With Binary Ninja
|
||||
|
||||
## Overview
|
||||
|
||||
`scripts/analyst.py` generates Binary Ninja Python API analysis scripts that open a view, iterate
|
||||
functions, and export functions/strings to JSON. `check` reports whether the `binaryninja` API is
|
||||
importable. It only generates text and does not run Binary Ninja or a sample.
|
||||
|
||||
## Dependencies
|
||||
|
||||
| Package | Version | Purpose |
|
||||
|---------|---------|---------|
|
||||
| binaryninja | licensed | the analysis API (optional for generation) |
|
||||
| (stdlib) | — | JSON, file IO |
|
||||
|
||||
## Core functions
|
||||
|
||||
### `check()`
|
||||
Reports `binaryninja` API availability.
|
||||
|
||||
### `skeleton(out, emit)`
|
||||
Writes a script using `binaryninja.open_view`, `bv.functions`, and `bv.get_strings`.
|
||||
|
||||
## IL levels
|
||||
|
||||
- LLIL: close to assembly.
|
||||
- MLIL: variables/SSA reasoning.
|
||||
- HLIL: readable pseudo-code.
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
python scripts/analyst.py check
|
||||
python scripts/analyst.py skeleton --emit functions,strings --out bn_extract.py
|
||||
```
|
||||
|
||||
## Sources
|
||||
|
||||
- Binary Ninja Python API — https://api.binary.ninja/
|
||||
- Binary Ninja IL (LLIL/MLIL/HLIL) — https://docs.binary.ninja/dev/bnil-llil.html
|
||||
- `open_view`/`bv.functions`/`get_strings` usage from official API documentation
|
||||
@@ -0,0 +1,83 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Generate Binary Ninja Python API analysis scripts (and report API availability).
|
||||
|
||||
`check` reports whether the binaryninja API is importable. `skeleton` writes a Binary Ninja script
|
||||
that opens a view, iterates functions, and exports functions/strings to JSON using the real API.
|
||||
This tool only generates text — it does not run Binary Ninja or any sample.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
try:
|
||||
import binaryninja # type: ignore # noqa: F401
|
||||
HAVE_BN = True
|
||||
except ImportError:
|
||||
HAVE_BN = False
|
||||
|
||||
FUNCTIONS_SNIPPET = '''
|
||||
for func in bv.functions:
|
||||
result["functions"].append({
|
||||
"name": func.name,
|
||||
"start": hex(func.start),
|
||||
"basic_blocks": len(list(func.basic_blocks)),
|
||||
})
|
||||
'''
|
||||
|
||||
STRINGS_SNIPPET = '''
|
||||
for s in bv.get_strings():
|
||||
result["strings"].append({"value": s.value, "start": hex(s.start)})
|
||||
'''
|
||||
|
||||
|
||||
def check() -> dict:
|
||||
return {"binaryninja_api_available": HAVE_BN}
|
||||
|
||||
|
||||
def skeleton(out: str, emit: list[str]) -> dict:
|
||||
keys = []
|
||||
body = []
|
||||
if "functions" in emit:
|
||||
keys.append('"functions": []')
|
||||
body.append(FUNCTIONS_SNIPPET)
|
||||
if "strings" in emit:
|
||||
keys.append('"strings": []')
|
||||
body.append(STRINGS_SNIPPET)
|
||||
script = (
|
||||
"#!/usr/bin/env python3\n"
|
||||
"# Binary Ninja headless analysis script (generated skeleton).\n"
|
||||
"import json\n"
|
||||
"import sys\n"
|
||||
"import binaryninja\n\n"
|
||||
"def analyze(path):\n"
|
||||
" bv = binaryninja.open_view(path)\n"
|
||||
" result = {%s}\n%s"
|
||||
" return result\n\n"
|
||||
"if __name__ == '__main__':\n"
|
||||
" print(json.dumps(analyze(sys.argv[1]), indent=2))\n"
|
||||
) % (", ".join(keys), "".join(body))
|
||||
Path(out).write_text(script, encoding="utf-8")
|
||||
return {"output": out, "emits": emit, "binaryninja_api_available": HAVE_BN}
|
||||
|
||||
|
||||
def main(argv: list[str] | None = None) -> int:
|
||||
parser = argparse.ArgumentParser(description="Binary Ninja script generator")
|
||||
sub = parser.add_subparsers(dest="cmd", required=True)
|
||||
sub.add_parser("check")
|
||||
ps = sub.add_parser("skeleton")
|
||||
ps.add_argument("--emit", default="functions,strings")
|
||||
ps.add_argument("--out", required=True)
|
||||
args = parser.parse_args(argv)
|
||||
if args.cmd == "check":
|
||||
print(json.dumps(check(), indent=2))
|
||||
else:
|
||||
print(json.dumps(skeleton(args.out, [e.strip() for e in args.emit.split(",")]),
|
||||
indent=2))
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user