Architecture
sol-azy is a modular static analysis toolkit designed to work on Solana programs compiled to eBPF.
It is capable of disassembling, analyzing control flow, decoding embedded .rodata
strings, and performing pattern-based syntactic analysis through rule-based AST matching.
High-Level Design
sol-azy is structured around three main engines, supported by auxiliary modules:
Core Engines
-
Reverse Engine Handles binary-level disassembly, control flow graph generation, and
.rodata
analysis. → Triggered via thereverse
CLI command. -
SAST Engine Performs static source-level analysis using Starlark-based rule evaluation on Rust ASTs. → Triggered via the
sast
CLI command. -
Build Engine Detects the project type (
Anchor
,SBF
) and compiles the bytecode accordingly. → Triggered via thebuild
CLI command.
Supporting Modules
-
Dotting Module Allows users to manually reintroduce function clusters into reduced CFGs by editing
.dot
files post-generation. → Useful for large programs or targeted function exploration. -
Fetcher Module Retrieves deployed program bytecode directly from on-chain Solana accounts via RPC. → Enables reverse analysis even without access to local source code.
Each component is designed to be composable and scriptable, making sol-azy flexible for both auditing and program analysis workflows.
Component Overview
1. reverse/
Handles all operations on compiled .so
eBPF files:
disass.rs
: Disassembler with inline.rodata
resolutioncfg.rs
: Generates DOT graphs from the control flowimmediate_tracker.rs
: Tracks data regions used byLD_DW_IMM
utils.rs
: String formatting and decoding
It produces:
disassembly.out
immediate_data_table.out
cfg.dot
→ See Reverse Overview
2. parsers/
+ state/sast_state.rs
Used in source-level static analysis.
- Parses all
.rs
files into [syn::File
] ASTs - Builds
AstPositions
with span references - Applies Starlark-based rules to nodes and attributes
- Aggregates findings into a
SastState
→ See SAST Overview
3. engines/starlark_engine.rs
Embeds a Starlark interpreter to run user-defined rules against Rust ASTs.
- Prepares the AST (JSON + span tracking)
- Loads
.star
files fromrules/
- Invokes
syn_ast_rule(...)
with context - Collects
matches
and metadata as JSON
→ See Writing Rules
4. commands/
Command routing layer:
build_command.rs
: Uses Anchor/Cargo to compile.so
filesreverse_command.rs
: Dispatches disass + cfg generationsast_command.rs
: Launches Starlark rule scanning
Used by AppState::run_cli()
to manage flow.
5. helpers/
Utilities to:
- Detect project type (
Anchor.toml
,Cargo.toml
) - Check external dependencies (
cargo
,anchor
) - Run subprocesses with environment overrides
6. dotting/
Post-processing module for .dot
control flow graphs:
- Allows restoring function subgraphs in reduced or entrypoint-only graphs
- Takes as input a list of function IDs (clusters) to reinject
- Outputs an
updated_*.dot
file with the requested functions and edges
This module is especially useful when a full CFG is too large or noisy, letting analysts rebuild targeted graphs incrementally.
→ See Dotting
7. fetcher/
Bytecode retrieval module for on-chain programs:
- Connects to Solana RPC endpoints
- Downloads the deployed
.so
bytecode of a program ID - Saves the ELF file locally for reverse analysis
This feature is useful for audits where source code is unavailable or unverifiable.
→ See Fetcher
Output Flow
+----------------+
| .so Bytecode | ← built via cargo / anchor
+----------------+
|
[reverse_command]
↓
+-----------------------+
| Analysis (sbpf-solana)
| + immediate tracker
+-----------------------+
↓ ↓ ↓
disass immediate cfg.dot
.out _data.out
--------------------------------------
+----------------+
| Rust Source | ← e.g. Anchor project
+----------------+
|
[sast_command]
↓
+----------------------+
| syn::File + spans |
| + rule evaluation |
+----------------------+
↓
Findings
(printed / JSON)
External Dependencies
sbpf-solana (anza-xyz)
: Disassembly / Analysis coresyn
: Source AST parsingstarlark-rust
: Rule evaluation engine
Extensibility
The architecture is modular and designed for extension:
- Add new output formats by extending the
ReverseOutputMode
- Plug in new analysis passes (e.g., MIR or LLVM IR) in
engines/
- Write new rules without modifying Rust code (
.star
files) - Integrate into CI pipelines via CLI interface