pybingraph
pybingraph is a binary-inspection service and library built on
angr. It reads function symbols from a binary and renders
per-function control-flow graphs (CFGs) as SVG or DOT.
Supported binary formats include ELF executables, shared libraries and relocatable objects, and Windows PE executables and DLLs. The corpus covers x86/x86-64, ARM/Thumb/AArch64, MIPS, PowerPC, RISC-V and s390x. Instruction decoding and indirect-transfer proofs depend on the architecture and binary; not every format/architecture combination has the same analysis coverage.
The default custom strategy constructs a function-bounded CFG directly from
Capstone decoding and VEX control-flow proofs, without a CFGFast seed graph.
It resolves proven indirect transfers, recovers ELF exception paths, and keeps
unresolved targets and additionally discovered code explicit.
CFG Examples
These are real custom-mode CFGs from the playground binaries. Comments are disabled for compact previews, matching the golden-test configuration; they will be shown in the browser as block annotations. Click a thumbnail to inspect the full-size SVG.
TODOs for this library are:
- Render call graph (CG) of all functions in a binary.
- Render data dependency graph (DDG) for instructions in a basic block.
- Graph coloring from execution counts, after adding support for profile information.
Requirements
For the container option below, only Docker is required on the host. A native Python installation requires:
- Python 3.12 or later
- uv
- The Graphviz
dotexecutable for rendered image formats
On macOS:
brew install graphviz
Setup
Run with Docker
Release images are published to GitHub Container Registry for Linux AMD64 and ARM64. Docker chooses the appropriate platform automatically. They include Python, runtime dependencies and Graphviz, but no playground binaries.
docker run --rm --name bingraph \
-p 127.0.0.1:9000:8000 \
--mount type=bind,src=/absolute/path/to/binaries,dst=/binaries,readonly \
ghcr.io/manelfx/pybingraph:latest
Replace the host directory with your binary directory and 9000 with the local
port you want. Open http://127.0.0.1:9000/docs for interactive API documentation,
or /symtab?filepath=your-binary for the symbol table. Paths remain relative to
the mounted directory. The image runs as a non-root user; mounted files and their
parent directories must be readable/searchable by that user.
Use a numeric release tag instead of latest to select a specific version.
docker run --rm ghcr.io/manelfx/pybingraph:latest --version reports its version.
Configure global settings with environment flags such as
-e BINGRAPH_DEMANGLE=true or -e BINGRAPH_COMMENTS=false before the image name.
The server listens on 0.0.0.0:8000 inside the container; the example publishes
it only on the host's loopback interface. It has no authentication and should not
be exposed directly to an untrusted network.
Install a release
Published releases can be installed from PyPI with their Python dependencies:
uv venv --python 3.12
uv pip install pybingraph
On macOS/Linux, activate that environment and run the installed command:
source .venv/bin/activate
bingraph --version
bingraph --root /path/to/your/binaries server
No repository checkout is required. Install the Graphviz dot executable
separately; wheels do not bundle system tools or the optional playground corpus.
Alternatively, download a wheel (.whl) from a GitHub release and install it
with uv pip install ./pybingraph-*.whl in the environment above.
Work from a checkout
Install the runtime dependencies:
uv sync
For development tools such as pytest, Ruff, and Ty:
uv sync --extra dev
Playground binaries
The optional playground corpus is used by unit tests, golden CFG tests and the examples below. Fetch it with:
./scripts/fetch_playground.sh
It is cloned into ./angr-binaries/; the binaries themselves live under
./angr-binaries/tests/. The helper also fetches pinned example fixtures from
angr-utils into
tests/samples/ within that corpus. Existing samples are verified, not overwritten.
Run Bingraph
All binary paths are relative to --root and are constrained to remain below
that directory.
Check the version from the CLI or Python:
uv run bingraph --version
uv run python -c 'import bingraph; print(bingraph.__version__, bingraph.__commit__)'
Server
Start the local web server:
uv run bingraph --root ./angr-binaries/tests server
Then open a symbol table or CFG in a browser:
http://127.0.0.1:8000/symtab?filepath=samples/ais3_crackme
http://127.0.0.1:8000/cfg?filepath=samples/ais3_crackme&function=0x40043c
Useful server options include --port, --debug, --no-comments, and
--cfg-mode none|custom. Run uv run bingraph --help for the full CLI.
Use the global --demangle option (or BINGRAPH_DEMANGLE=true) to display
demangled C++ and Rust names in symbol tables, CFG headers, and comments.
It defaults to false. CFG names are shortened after demangling, keeping
block offsets; symbol-table names remain full. Addresses, assembly operands,
and analysis metadata are unchanged. Unsupported names are kept as-is.
Client
The client subcommand makes an in-process request, so it is useful for
scripting and does not require a separately running server:
uv run bingraph --no-comments --root ./angr-binaries/tests \
client --endpoint /cfg --filepath samples/ais3_crackme \
--function 0x40043c --format raw
HTTP API
The HTML routes are intended for browser use, while /api/... routes return
JSON.
| Route | Result |
|---|---|
GET /symtab?filepath=<path> |
HTML table of function symbols |
GET /api/symtab?filepath=<path> |
{"items": [...]} function-symbol response |
GET /cfg?filepath=<path>&function=<addr> |
SVG CFG |
GET /api/cfg?filepath=<path>&function=<addr>&format=dot |
{"graph": "..."} CFG response |
function accepts either decimal or 0x-prefixed hexadecimal addresses. CFG
JSON responses support format=svg|dot|raw|xdot; raw is unprocessed DOT,
dot runs Graphviz's DOT output backend, and xdot includes drawing metadata.
Binary formats such as PNG/PDF are not supported by the string-returning API.
CFG routes also accept optional mode=none|custom, comments=true|false,
dfs=true|false, and exits=never|jump|always query
parameters. A request value overrides the corresponding
application setting for that render only.
Both symbol-table and CFG routes also accept demangle=true|false, overriding
the global setting for that request. Symbol-table links retain this override.
Configuration
Settings are Pydantic settings: they can be supplied as CLI options,
BINGRAPH_-prefixed environment variables, or values in .bingraphenv.
For example:
BINGRAPH_ROOT=./angr-binaries/tests \
BINGRAPH_CFG_MODE=custom \
BINGRAPH_COMMENTS=false \
uv run bingraph server
CFG modes:
custom(default): independently decode and prove bounded control flow, then recover eligible disconnected code without treating it as proven entry-reachable code.none: return the boundedCFGFastgraph without custom construction; useful for comparison and diagnostics.
Disconnected-code recovery is part of custom mode.
It scans only eligible explicitly sized functions with
unresolved jumps, rejects padding and known data, and shows selected rejoining
or validated return/trap/non-returning-exit regions behind dashed-orange
UnresolvableEntrySource edges. These are discovery hints, not proven jump targets.
Custom summaries separate discovered, entry-connected, and disconnected
instruction counts.
Development
The Makefile wraps the standard development commands:
make # fast unit tests
make format # rewrite source and tests with Ruff formatting
make check # formatting, linting, type checking, and unit tests
The commands behind make check are also available independently:
make format-check
make lint
make typecheck
make units
make coverage
make coverage runs both unit tests and curated golden checkpoints, prints a
terminal summary, and writes a browsable report to htmlcov/index.html.
License
pybingraph's original code is licensed under the BSD 2-Clause License. Copied or adapted code retains the upstream copyright and license notices in NOTICE. Dependencies, playground binaries and their disassembly examples remain subject to their respective upstream terms.
Troubleshooting
Optional Unicorn warning on macOS
If startup reports:
angr.state_plugins.unicorn_engine | failed loading "unicornlib.dylib"
Unicorn is an optional angr acceleration dependency. The bounded CFGFast and
custom CFG workflows used by Bingraph still work without it. Install a
compatible Unicorn build only if you specifically need Unicorn-backed symbolic
execution.
Metadata
Release files for pybingraph 0.2.5
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pybingraph-0.2.5.tar.gz | 162.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pybingraph-0.2.5-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 356.1 kB
Release files / pybingraph-0.2.5.tar.gz
| Download URL | pybingraph-0.2.5.tar.gz |
|---|---|
| Size | 162.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d31ed1b3981588ee5d9ffd86aed1246472bf4cf87a2ca0a7d591735b85f9ddf4
|
|
BLAKE2b-256 checksum How to use checksums |
302779637bd565e299f1d274e8bfc8329d92e033640bd5aefe5c435237f47876
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 17, 2026.
Transparency logRelease files / pybingraph-0.2.5-py3-none-any.whl
| Download URL | pybingraph-0.2.5-py3-none-any.whl |
|---|---|
| Size | 193.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
d72d2c0484c207a401269251b10ae9d4e385fc1f736117090eba4c26d42ff13a
|
|
BLAKE2b-256 checksum How to use checksums |
b63aaa35210b8fbf465af802c01fc008e85bcea1317d12ffc85c320a9eca2f8d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 17, 2026.
Transparency log