ToC
PhD Research on Rust Binary Analysis and Malware Detection
View on GitHubToC
- [Overview of Tools]
- [Binary Ninja]
- [IDA Pro]
- [Ghidra]
- [Radare2]
- Detailed Breakdown
Overview of Tools
Rust Binary Analysis Challenges
Rust binaries present unique challenges for reverse engineers:
- Heavy use of generics and monomorphization creates code bloat
- Name mangling makes symbols difficult to read
- LLVM optimizations produce complex control flow
- Panic handling adds boilerplate code throughout
- Zero-cost abstractions compile to efficient but harder-to-read assembly
- Trait implementations and vtables can be confusing
Binary Ninja
Binary Ninja has been making steady improvements for Rust analysis:
Strengths:
- Rust symbol demangling built-in (both legacy and v0 mangling schemes)
- Clean decompilation with the HLIL (High-Level IL) often producing readable pseudo-code
- Type recovery works reasonably well for Rust structures
- Plugin ecosystem includes Rust-specific analysis tools
- Fast analysis compared to competitors
- Good handling of panic infrastructure - can identify and simplify panic-related code
Workflow tips:
- Use the symbol list to find meaningful functions (filter by demangled names)
- Look for
mainor::mainto find the actual entry point - The type system can be manually improved with struct definitions
- HLIL is generally more useful than decompilation for Rust
IDA Pro
IDA remains the industry standard with strong Rust support:
Strengths:
- Excellent decompiler (Hex-Rays) handles Rust fairly well
- Robust symbol demangling for Rust (supports both formats)
- FLIRT signatures can identify standard library functions
- Mature plugin ecosystem with Rust-specific tools available
- Superior debugging integration for dynamic analysis
- Strong pattern recognition for identifying Rust idioms
Limitations:
- Expensive licensing
- Can struggle with heavily optimized LLVM output
- Type recovery requires manual work for complex Rust types
Plugins worth noting:
rust-rttiplugins for recovering type information- Various scripts for identifying common Rust patterns
Ghidra
Ghidra (NSA’s free tool) has decent Rust support:
Strengths:
- Free and open-source
- Rust demangling built-in
- P-Code intermediate representation useful for understanding optimized code
- Collaborative features for team analysis
- Scriptable in Python/Java for custom Rust analysis
Weaknesses:
- Decompiler output can be messier than IDA’s for Rust
- Slower analysis on large Rust binaries
- Type recovery less sophisticated than commercial tools
- Can struggle with panic handling code
Tips:
- Use the “Demangler” analyzer (should run automatically)
- Look for
rust_panicandrust_begin_unwindto understand error paths - The Function Call Trees are useful for navigating monomorphized functions
Radare2/Rizin
Radare2 and its fork Rizin offer command-line focused analysis:
Strengths:
- Free and open-source
- Scriptable with r2pipe
- Rust demangling supported
- Cutter GUI (for Rizin) provides visual interface
- Good for automation and scripting analysis workflows
Weaknesses:
- Steeper learning curve (command-line focused)
- Decompiler (Ghidra integration or r2dec) less polished than competitors
- Type system less sophisticated for Rust-specific constructs
- Documentation can be fragmented
Useful commands:
aaa- analyze allafl- list functionspdf @ sym.function- disassemble functionafn newname @ addr- rename function
General Rust Reverse Engineering Tips
Regardless of tool:
- Find the real main: Look for
<crate_name>::mainnot the entry point wrapper - Identify the standard library: Functions like
std::io::*,std::collections::*are building blocks - Look for string references: Rust programs often have many error strings that reveal functionality
- Understand Result/Option: Many functions return these enums, affecting control flow
- Use dynamic analysis: Running under a debugger can clarify what static analysis obscures
- Demangle everything: All tools support this, make sure it’s enabled
- Focus on high-level flow first: Don’t get lost in monomorphized helper functions
General Recommendation
- For professional/commercial work: IDA Pro (best overall decompilation and tooling)
- For best Rust experience: Binary Ninja (modern architecture, good Rust support, reasonable price)
- For free/open-source: Ghidra (most mature free option)
- For scripting/automation: Radare2/Rizin (best for custom workflows)
Detailed Breakdown
Let me give you a detailed breakdown of Radare2’s Rust support:
Rust Demangling in Radare2
Built-in Support:
- Radare2 has native Rust demangling built into the core
- Supports both legacy mangling and v0 mangling schemes
- Automatic demangling when loading Rust binaries
Commands:
# Automatic demangling (usually enabled by default)
e bin.demangle=true
e bin.demangler=rust
# Manual demangling of a symbol
iD <mangled_symbol>
# List all symbols (demangled)
is
# List functions (demangled)
afl
# Show demangled name in disassembly
pdf @ sym._ZN...
Rust Binary Analysis Capabilities
1. Symbol Analysis
# List all Rust symbols
is ~rust
# Find main function
afl ~main
# Search for specific Rust stdlib functions
afl ~std::
# Find panic handlers
afl ~panic
2. String Analysis
Rust strings are particularly important for analysis:
# List all strings
iz
# Search strings with context
izz ~error
izz ~"unwrap"
# Find string cross-references
axt @ str.some_string
3. Function Analysis
# Analyze all functions
aaa
# Show function info
afi @ <function>
# Show function arguments (limited for Rust)
afv
# Generate call graph
agc
# Function call tree
aftl
4. Disassembly & Decompilation
r2dec (Radare2’s decompiler):
# Install r2dec
r2pm -ci r2dec
# Decompile function
pdc @ sym.function_name
r2ghidra (Ghidra decompiler integration):
# Install r2ghidra
r2pm -ci r2ghidra
# Decompile with Ghidra engine
pdg @ sym.function_name
5. Type Information (DWARF)
If the binary has debug symbols:
# Load DWARF info
id
# Show type information
it
# Show structure definitions
its
6. Cross-References
# Show xrefs to address
axt @ <address>
# Show xrefs from address
axf @ <address>
# Show all xrefs
ax
Practical Rust Analysis Workflow
Here’s a typical workflow:
# 1. Open binary
r2 rust_binary
# 2. Analyze
aaa
# 3. Find main
afl ~main
# Look for something like: sym.myapp::main
# 4. Seek to main and disassemble
s sym.myapp::main
pdf
# 5. Look at strings to understand functionality
izz ~!std # Filter out std library strings
# 6. Find interesting functions
afl | grep -v "std::" | grep -v "core::"
# 7. Decompile interesting functions
pdg @ sym.interesting_function
# 8. Trace calls
aftl @ sym.interesting_function
# 9. Analyze panic paths
afl ~panic
afl ~unwrap
Limitations for Rust
What Radare2 struggles with:
- Type Recovery: Limited ability to reconstruct Rust structs, enums, traits
- Trait Objects: No automatic vtable reconstruction
- Panic Metadata: Manual analysis required
- Monomorphization: Hard to track which generic instantiations exist
- Decompilation Quality: Less readable than IDA/Binary Ninja for complex Rust
- Async State Machines: No special handling
Strengths for Rust
- Scriptability: Great for automating Rust analysis
- Fast: Quick analysis on large binaries
- Pattern Matching: Can script detection of Rust patterns
- DWARF Support: Good if debug symbols present
- Free: No licensing costs
- Hex Editing: Can patch Rust binaries easily
Useful r2 Scripts for Rust
Finding main:
r2 -q -c 'aaa; afl ~main; q' binary
Extract all non-std functions:
r2 -q -c 'aaa; afl | grep -v "std::" | grep -v "core::"; q' binary
Find panic strings:
r2 -q -c 'izz ~panic ~unwrap; q' binary
Cutter (GUI for Radare2/Rizin)
If you prefer a GUI, Cutter provides:
- Visual function graphs
- Integrated decompiler view
- Better navigation for Rust binaries
- Side-by-side assembly/decompilation
- Built on Rizin (r2 fork)
# Install Cutter
# Download from: https://cutter.re
# Or use package manager
Rizin vs Radare2
Rizin (r2 fork) has some improvements for Rust:
- Better maintained demangler
- Cleaner API
- Cutter integration
- More consistent behavior
Both have similar Rust support, but Rizin may have newer fixes.
Comparison with Other Tools
When to use Radare2 for Rust:
- ✅ Automated analysis/scripting
- ✅ Quick triage of binaries
- ✅ Command-line workflows
- ✅ Budget constraints
- ✅ Integration with other tools
When to use alternatives:
- ❌ Need best decompilation quality → IDA Pro
- ❌ Need interactive Rust-specific features → Binary Ninja
- ❌ Want free + GUI + better decompiler → Ghidra
- ❌ Deep type recovery needed → Binary Ninja/IDA
Recommended Setup
For serious Rust analysis with Radare2:
# Install r2
git clone https://github.com/radareorg/radare2
cd radare2
sys/install.sh
# Install plugins
r2pm -ci r2ghidra # Better decompiler
r2pm -ci r2dec # Alternative decompiler
r2pm -ci r2frida # For dynamic analysis
# Configure
echo 'e bin.demangle=true' >> ~/.radare2rc
echo 'e asm.demangle=true' >> ~/.radare2rc
echo 'e bin.demangler=rust' >> ~/.radare2rc
Based on my research, I need to provide you with a more nuanced picture of Radare2’s Rust demangling support. Here are the resources and evidence:
Evidence for Rust Demangling Support
1. Built-in Support in Code
Radare2’s source code includes Rust demangling definitions in its demangle.h header file, which defines DMGL_RUST and rust_demangling as part of the demangling styles enumeration.
2. Historical Implementation
Radare2 version 0.10.0 (released January 2016) officially added “demangling for Rust binaries” as a new feature.
In December 2016, there was a GitHub issue suggesting integration of a Rust demangler from the Linux kernel’s perf tool (demangle-rust.c).
3. libiberty Integration
Radare2 uses libiberty (from GCC/binutils), which includes rust-demangle.c - a demangler written by David Tolnay and rewritten by Eduard-Mihai Burtescu for v0 support. The rust-demangle.c code explicitly mentions it handles “Rust mangling version, with legacy mangling being -1” for the legacy scheme and modern v0 mangling.
Important Clarifications
However, I need to correct my earlier statement about “automatic demangling when loading Rust binaries”:
-
Not Always Automatic: Historical issues show that demangling wasn’t enabled by default and required configuration via
e bin.demangle=trueande asm.demangle=truein the radare2rc file. -
Version-Dependent: The quality and automation of Rust demangling has evolved over Radare2 versions, and older versions required manual configuration.
Accurate Summary
What is proven:
- ✅ Radare2 has native Rust demangling built into the core (via libiberty)
- ✅ Supports both legacy and v0 mangling schemes (in the code)
- ⚠️ May require manual configuration - not always automatic
Corrected statement: Radare2 has native Rust demangling support built into the core through libiberty integration, which supports both legacy and v0 mangling schemes. However, users may need to enable it manually using:
e bin.demangle=true
e asm.demangle=true
e bin.demangler=rust
The “automatic demangling when loading Rust binaries” depends on the Radare2 version and user configuration - it’s not guaranteed to work out-of-the-box on all installations.
Comparison Table
Enhanced Rust Binary Analysis Tool Comparison
Existing Rows (from original table)
| Rust Features | Binary Ninja | Ghidra | IDA Pro | Radare 2 |
|---|---|---|---|---|
| Version | v5.1.8104 Personal | v11.4.2 | v9.2 | v6.0.0 |
| Native Rust Demangler | Yes (LLVM demangler built-in) | Yes (v11.0+, v0 mangling) | Yes (configurable) | Yes (libiberty-based, requires config) |
| String Analysis | Rust String Slicer plugin | Yes (RustStringAnalyzer) | Yes (plugin) | Basic (iz/izz commands) |
| Library Recognition | Signature Kit + custom plugins | FunctionID/FIDB databases | RIFT (FLIRT + binary diffing) | Zignatures + FLIRT |
| Trait Object Analysis | Better vtable support | Limited | Limited | Limited |
| Type Recovery Quality | Good HLIL foundation | Basic-Fair (general: 36.1-38.6% precise on stripped binaries per research) | Better with RIFT | Basic |
| Panic Metadata Analysis | Plugin extractable metadata | Basic | Manual analysis possible | Manual |
| DWARF Support | Good | Good | Good | Good |
| Custom Calling Conventions | Standard | Standard only | Custom __usercall syntax | Limited |
| Decompilation Quality | Clean HLIL output | Readable but loses semantics | Excellent (gold standard) | Basic (r2dec/r2ghidra) |
| Plugin/API Languages | Python, C++, Rust (unique) | Java, Python, JavaScript | Python (IDAython), IDC | Python (r2pipe), C, JavaScript |
NEW ROWS - Enhanced Analysis Features
Cross-References Quality
How well each tool handles Rust’s heavy cross-referencing
| Binary Ninja | Ghidra | IDA Pro | Radare 2 |
|---|---|---|---|
| Excellent - Fast xref computation, pinned UI panel with tabs, handles monomorphized functions well, works great with Rust’s heavy xref patterns | Good - Built-in xref support, handles cross-references adequately but can be slower on very large Rust binaries | Excellent - Industry standard for xrefs, reliable even on complex Rust binaries, mature implementation | Fair - Basic xref support (axt/axf commands), can struggle with large monomorphized codebases, may miss some references |
Notes:
- Rust binaries generate heavy cross-reference graphs due to monomorphization and trait implementations
- Binary Ninja and IDA Pro handle this best, with fast navigation between related monomorphized functions
- Radare2 xrefs work but may require manual analysis for complex cases
Async/Await Analysis
Support for analyzing Rust’s async state machines
| Binary Ninja | Ghidra | IDA Pro | Radare 2 |
|---|---|---|---|
| Manual with MLIL/HLIL aid - No automatic async recognition, but MLIL/HLIL makes state machine analysis tractable. Can manually identify Future trait implementations and poll methods | Manual - No specialized async support. Decompiler output helps but requires manual interpretation of state machine enums and match statements | Manual - No automatic async detection. Hex-Rays decompilation aids understanding but async patterns must be identified manually | Minimal - No async-specific support. Requires extensive manual work to identify and trace state machines |
Notes:
- Async/await in Rust compiles to state machine enums implementing the Future trait
- None of the tools automatically identify or annotate async state machines
- Analysis requires understanding of Rust’s async lowering (see Tyler Mandry’s blog series)
- Look for: enum with variants for suspension points, poll() methods, switchInt patterns in MIR/assembly
Macro Expansion Visibility
Whether you can see what macros generated
| Binary Ninja | Ghidra | IDA Pro | Radare 2 |
|---|---|---|---|
| None - Macros are expanded at compile time. No visibility into original macro source. DWARF info may help if available | None - Cannot see macro expansions. Only compiled result is visible. DWARF debug info can provide hints about source locations | None - Macros expanded before compilation. No direct visibility. DWARF info can help correlate to source | None - No macro expansion visibility. Only final compiled code is analyzable |
Notes:
- Rust macros are expanded during compilation, before any binary is generated
- No reverse engineering tool can recover macro expansions from compiled binaries
- With debug symbols (DWARF), you may see source line numbers that reference macro definitions
- Best approach: Keep source code alongside if macro understanding is critical
- Common Rust macro patterns (println!, vec!, etc.) can be recognized by their expanded patterns
Result/Option Enum Recognition
Automatic identification of common Rust patterns
| Binary Ninja | Ghidra | IDA Pro | Radare 2 |
|---|---|---|---|
| Limited - No automatic pattern detection. Can use rust_type_layout_helper_bn plugin to import type layout info. Manual type application helps | Limited - No automatic Result/Option recognition. Decompiler may show generic enum patterns. Manual type annotation required | Limited - No built-in pattern recognition. Manual identification of Ok/Err and Some/None branches needed. RTTI plugins may help with debug builds | Minimal - No automatic detection. Requires manual pattern recognition and annotation |
Notes:
- Result<T, E> and Option
compile to discriminated unions (tagged enums) - Common patterns: match statements become switch/if chains on discriminant values
- Look for discriminant checks (typically at offset 0 or in specific byte)
- Without debug info, distinguishing Result from Option or other enums is challenging
- Helper: Use
-Zprint-type-sizeswhen compiling to understand memory layouts
Ownership/Lifetime Hints
Any reconstruction of Rust’s memory safety features
| Binary Ninja | Ghidra | IDA Pro | Radare 2 |
|---|---|---|---|
| None - Ownership/lifetimes are compile-time only. No runtime representation. Cannot be reconstructed from binary | None - Lifetimes are compile-time concepts only. Not present in compiled code | None - Ownership model enforced at compile-time. No trace in binary analysis | None - Cannot recover Rust’s ownership/borrowing information from binaries |
Notes:
- Ownership and lifetimes are zero-cost abstractions - they exist only at compile time
- The borrow checker validates code before compilation; no runtime overhead
- By the time code is compiled, ownership information is erased
- What you CAN see: Drop implementations (destructors), reference counting (Arc/Rc), and explicit checks
- LLVM IR and MIR (mid-level compiler representations) contain lifetime info, but not final binaries
Cargo/Crate Identification
Can it identify which crates were used?
| Binary Ninja | Ghidra | IDA Pro | Radare 2 |
|---|---|---|---|
Manual via symbols - No automatic crate detection. Demangled symbols reveal crate names (e.g., tokio::runtime::...). String analysis finds crate names in panic messages |
Manual via symbols - Parse demangled symbols for crate names. Strings may contain crate references. No automatic crate catalog | Manual via symbols - Demangled symbols show crate namespace. Can script symbol extraction. No built-in crate identification | Manual via symbols - Symbol listing (is/afl) shows demangled crate names. No automatic identification |
Notes:
- Crate names appear in demangled symbol paths:
std::,tokio::,serde::, etc. - Panic strings often include crate names and file paths
- Debug builds retain more crate information than release builds
- Common crates to look for:
tokio::- Async runtimeserde::- Serialization frameworkclap::- CLI argument parsingreqwest::,hyper::- HTTP clients/serversdiesel::,sqlx::- Database ORMs
- Strategy: Search for
::in demangled symbols to find crate boundaries
Performance on Large Binaries
Rust binaries can be huge due to monomorphization
| Binary Ninja | Ghidra | IDA Pro | Radare 2 |
|---|---|---|---|
| Good - Fast analysis engine, handles large Rust binaries (10-50MB+) well. HLIL/MLIL generation is efficient. Multi-threading helps | Fair to Good - Can handle large files but initial analysis may be slow (10-30 mins for 50MB+). Memory intensive. Java-based, so GC impacts performance | Good - Mature analysis handles large binaries well. Initial analysis can be lengthy but generally faster than Ghidra. Stable on huge files | Fair - Can struggle with very large Rust binaries. Analysis may be slow or incomplete. Works better with smaller targets (<20MB) |
Notes:
- Rust release builds with full optimization can be 50-200MB+ due to:
- Generic monomorphization (separate copy of code for each type)
- Aggressive inlining
- LLVM optimizations
- Standard library statically linked by default
- Size reduction tips:
stripbinary to remove symbols- Use
--releasewith LTO (Link-Time Optimization) - Consider
wasmor embedded targets for smaller footprints cargo-bloattool to analyze binary size
- Performance comparison for 50MB Rust binary (rough estimates):
- Binary Ninja: 5-15 minutes initial analysis
- Ghidra: 15-30 minutes initial analysis
- IDA Pro: 10-20 minutes initial analysis
- Radare2: Varies greatly, may timeout or require manual guidance
Additional Recommendations
Best Practices for Rust Binary Analysis
- Enable Debug Symbols if possible (cargo build with
--debugor DWARF info) - Keep source code when analyzing your own Rust binaries
- Use multiple tools - combine Binary Ninja/IDA’s UI with Ghidra’s decompiler
- Learn Rust patterns - understanding monomorphization, vtables, and panic handling is crucial
- Script symbol extraction - automate crate/module identification via demangled symbols
- Focus on HLIL/decompiled output rather than raw assembly for Rust
- Use compiler explorer (godbolt.org) to understand how Rust patterns compile
Tool Selection Guide for Rust
- Professional work + Budget: IDA Pro (best overall, mature)
- Modern + Clean UX + Good Rust support: Binary Ninja (fast, excellent API)
- Free + Powerful: Ghidra (best free option, good decompiler)
- Automation + Scripting: Radare2 or Binary Ninja (both have good APIs)
- Async-heavy analysis: Binary Ninja or IDA (better HLIL/decompiler for state machines)
- Very large binaries (100MB+): IDA Pro or Binary Ninja (better performance)
Community Resources
- Binary Ninja Rust plugins: Rust String Slicer, Rust Type Layout Helper
- Ghidra Rust tools: Community scripts for Rust analysis (check GitHub)
- Understanding Rust compilation: Rust Compiler Development Guide
- Async internals: Tyler Mandry’s blog series on async optimization
Summary Score (Additional Features)
Scoring: 1.0 (Full support), 0.5 (Partial), 0.0 (None/Manual)
| Feature | Binary Ninja | Ghidra | IDA Pro | Radare 2 |
|---|---|---|---|---|
| Cross-References Quality | 1.0 | 0.75 | 1.0 | 0.5 |
| Async/Await Analysis | 0.3 | 0.25 | 0.3 | 0.1 |
| Macro Expansion | 0.0 | 0.0 | 0.0 | 0.0 |
| Result/Option Recognition | 0.25 | 0.25 | 0.25 | 0.1 |
| Ownership/Lifetime Hints | 0.0 | 0.0 | 0.0 | 0.0 |
| Crate Identification | 0.4 | 0.4 | 0.4 | 0.3 |
| Large Binary Performance | 0.9 | 0.7 | 0.9 | 0.6 |
| TOTAL | 3.85/7 | 3.35/7 | 3.85/7 | 2.6/7 |
Last Updated: November 2025 Tools evolve rapidly - verify current capabilities before making decisions
Important Clarifications & Corrections
Binary Ninja Rust Demangler
Correction: Binary Ninja has built-in Rust demangling via LLVM demangler (supports msvc/itanium/rust/dlang). The FAQ states: “We currently demangle both GNU3 and MSVC symbols including C++11 using our own cross-platform library” and the API docs show demangle_llvm() function that handles Rust symbols natively. While there are community Rust demangler plugins available, native support exists in the core.
Ghidra Type Recovery Precision
Clarification: The 36.1-38.6% precision figure comes from a research paper titled “A Framework for Assessing Decompiler Inference Accuracy” (2023). This metric is for general stripped binaries (not Rust-specific) and represents “precisely infers” vs “partially infers” (which achieves 97.2-99.3%). With debug symbols, precision jumps to 99.7%. These are general benchmarks, not Rust-specific measurements.
Radare2 Rust Demangler Configuration
Important Note: Radare2’s Rust demangling via libiberty requires manual configuration and may not work automatically on all installations. Users need to:
e bin.demangle=true
e asm.demangle=true
e bin.demangler=rust
This is version-dependent and not guaranteed out-of-the-box.
Additional Verification Notes
- All version numbers should be verified as tools update frequently
- Plugin availability changes over time - check current repositories
- Performance metrics are rough estimates based on community reports
- Rust-specific features remain limited across all tools as of November 2025