Unveiling RIFT: Advanced Pattern Matching for Rust Libraries
Andreas Klopsch (Malware Reverse Engineer · Microsoft MSTIC)
REcon 2025 · Day 2 · Main Track · Reverse Engineering
Overview
Rust has become a favored language for malware authors. Its memory safety guarantees, performance characteristics, and single-binary output make it attractive for everything from ransomware to nation-

Key moments
- 0:02 Introduction: the pain of reverse engineering Rust — 10,000+ unannotated functions
- 5:49 Rust ecosystem: rustup, cargo, and statically-linked crate dependencies
- 10:04 RIFT architecture: static analyzer, generator, and diff applier plugins
- 12:44 RIFT generator: four-phase pipeline — compile, collect, sign, diff
- 19:04 Case study: FLIRT signatures applied to RyoRd ransomware
- 24:17 Binary diffing on Star Blizzard's Speaker backdoor — 0.97 similarity
- 25:43 RIFT open-source release announcement and future roadmap
Unveiling RIFT: Advanced Pattern Matching for Rust Libraries
Speakers: Andreas Klopsch, Malware Reverse Engineer, Microsoft MSTIC
Conference: REcon 2025
YouTube: https://www.youtube.com/watch?v=_JiuYkFzVgg
Overview
Rust has become a favored language for malware authors. Its memory safety guarantees, performance characteristics, and single-binary output make it attractive for everything from ransomware to nation-state backdoors. But for reverse engineers, Rust binaries are a nightmare: statically linked libraries bloat a simple program to nearly 10,000 functions, decompiler output is frequently incomprehensible, and existing FLIRT signatures cover only a fraction of the Rust ecosystem. In this REcon 2025 talk, Andreas Klopsch of Microsoft MSTIC's MIRAGE team introduces RIFT (Rust Identification Framework Tool), an open-source IDA Pro toolset that tackles the core problem: automatically identifying and annotating Rust library code in malware binaries so analysts can focus on what the threat actor actually wrote.
Background
▶ Watch: Introduction: the pain of reverse engineering Rust — 10,000+ unannotated func... (0:02)
The Rust Reverse Engineering Problem
To illustrate the scale of the problem, Klopsch described a simple experiment: two PE files were compiled that do exactly the same thing—download a file from a URL provided on the command line and save it as sample_data.txt. The C++ version was linked dynamically and contained 80 functions when loaded into IDA Pro, most of which were annotated via existing signatures. The Rust version, compiled with cargo build --release and no debug symbols, contained nearly 10,000 functions, with almost none annotated.
That 125× explosion in function count is entirely due to statically embedded library code. Every use declaration in a Rust project pulls in code that gets compiled into the final binary. The decompiled output is correspondingly cluttered: abstraction layers, monomorphized generic code, and Rust's ownership model all produce patterns that modern decompilers—IDA, Binary Ninja, Ghidra—struggle to represent cleanly, partly because these tools were designed for languages that do not have multiple return values or Rust's ownership constructs.
The root cause is that, unlike typical Windows PE files linked against system DLLs, Rust binaries embed their dependencies directly. The crates ecosystem (hosted on crates.io) means every Rust project can have a unique set of libraries at specific versions. There is no single stable ABI to match against—every library version is its own target.
The Rust Toolchain: A Developer Perspective
Understanding how Rust is built is essential to RIFT's approach. The toolchain has three components:
- rustup: The version manager, analogous to
nvmorpyenv. - rustc: The compiler itself.
- cargo: The package manager that handles dependencies defined in
Cargo.toml.
When a project is compiled with cargo build --release, all dependencies are pulled from crates.io, compiled into COFF object files (.o), and stored in .rlib (AR archive) files. These archives live in platform-specific paths—on Windows, typically under a path containing rustup with the compiler triple (e.g., x86_64-pc-windows-msvc). The object files inside these archives are then linked into the final PE binary.
This architecture gives RIFT its foothold: by knowing which Rust compiler and which crate versions were used to build a binary, the tool can re-compile the exact same dependencies and generate reference signatures for them.
The Rust team hosts pre-compiled compiler toolchains in an AWS S3 bucket at static.rustlang.org. Crucially, each pre-compiled compiler is accompanied by a TOML metadata file that maps a git commit hash to a human-readable Rust compiler version. This commit hash is often embedded verbatim in the compiled binary (visible in strings alongside a rustc prefix), which RIFT's static analyzer uses to pinpoint the exact compiler version used.
Key Findings
▶ Watch: RIFT architecture: static analyzer, generator, and diff applier plugins (10:04)
RIFT demonstrates that the information needed to reconstruct reference signatures is almost always present in the binary itself:
- The Rust compiler commit hash is embedded in binary strings (visible as
rustc-<hash>). This maps to an exactrustcversion via the AWS S3 TOML metadata files. - The crate dependency list is also frequently extractable from binary strings—crate names and versions appear as metadata embedded at compile time.
- The target triple (e.g.,
x86_64-pc-windows-msvc) provides the architecture and OS context needed to pull the correct pre-compiled toolchain.
With these three data points, RIFT can fully reconstruct the compilation environment and generate either FLIRT signatures or binary diff databases for the specific library versions present in the target malware—something no general-purpose signature set can do reliably.
Technical Deep Dive
▶ Watch: RIFT generator: four-phase pipeline — compile, collect, sign, diff (12:44)
RIFT Architecture
RIFT consists of three components:
- RIFT Static Analyzer (IDA Pro plugin): Extracts static information—crate dependencies, compiler commit hash, target triple—from a loaded binary and writes it to a JSON output file.
- RIFT Generator (Python command-line tool): Consumes the static analyzer JSON, orchestrates compilation of the identified crates, and produces FLIRT signatures or binary diff databases.
- RIFT Diff Applier (IDA Pro plugin): Consumes the diff results JSON produced by RIFT Generator and presents them interactively within IDA.
The generator wraps several existing tools:
- rustup / cargo: For initiating Rust projects, downloading dependencies, and compiling them.
- Hex-Rays pcf / sigmake (zsigmake): For generating FLIRT
.sigfiles from the compiled COFF object files. - IDAT (IDA Pro text-mode binary): For generating IDA databases from COFF files without spawning a GUI.
- Diaphora: For performing binary diffing between the target malware's IDB and the reference IDB files generated from the libraries.
Two Analysis Approaches
RIFT supports two workflows, each with distinct trade-offs:
Approach 1: FLIRT Signature Generation
The generator initializes a Cargo project, adds the identified dependencies, compiles them, extracts the COFF object files from the resulting .rlib archives, and runs them through pcf followed by sigmake/zsigmake to produce .pat and then .sig files. One .sig file is generated per dependency and one for the Rust compiler itself—avoiding an unmanageable proliferation of signature files.
These FLIRT signatures can then be loaded directly into IDA (or other compatible tools) using standard mechanisms.
Strengths: High accuracy and low false positive rate; strict matching; faster to generate than diffing.
Weaknesses: Requires accurate extraction of the compiler version and dependency list. If the binary is packed (e.g., VMProtect), string extraction may fail, making the compiler version unobtainable. Also does not help if the exact crate version cannot be determined.
Approach 2: Batch Binary Diffing
For cases where FLIRT signatures are insufficient or static information is incomplete, RIFT uses Diaphora's binary diffing capability at scale. The workflow:
- Use IDAT to generate IDA databases (IDBs) for each COFF object file extracted from the crate archives.
- Run Diaphora on each IDB to produce SQLite files containing function feature vectors.
- Run Diaphora comparing the target malware's SQLite file against each library's SQLite file (a 1-to-N diff).
- Collect all N resulting SQLite diff result files and merge them into a single
results.jsonlookup database, where each function has a list of candidate matches with similarity scores.
This JSON database is then loaded into the RIFT Diff Applier IDA plugin, which provides an interactive interface to browse top-matching functions and apply renamings with a configurable similarity threshold. The plugin supports both automated bulk-renaming (e.g., "rename everything above 0.97 similarity") and interactive per-function review.
Strengths: Can recover library identification even without exact compiler version information; similarity-based approach can handle minor version differences.
Weaknesses: More prone to false positives than FLIRT; requires manual validation; currently very slow because it requires running IDAT and Diaphora on potentially dozens of COFF files.
Real-World Application
Klopsch applied RIFT to two malware samples:
RLord ransomware: A Rust-based ransomware. Used primarily for the FLIRT signature workflow. After applying the generated signatures, common Rust library functions—rust_cd_demangle, fill_bytes, unwrap_failed, and similar boilerplate—were correctly identified and labeled, allowing the analyst to focus on the encryption logic itself.
SPICA backdoor: A Rust-based backdoor attributed by Google to Star Blizzard, a Russian nation-state threat actor. SPICA is far more complex than RLord—it has full C2 capabilities, cookie stealing, and information-gathering functionality. Used primarily for the binary diffing workflow (FLIRT signatures did not perform as well on this target). With a similarity threshold set to 0.97, the diff applier correctly identified many library functions that the FLIRT approach missed, including a stats::windows_fs_stat function with a 0.97 similarity score, and significantly reduced the total unannotated function count.
De-mangling
Rust uses name mangling for internal symbols. RIFT Diff Applier integrates the rustc-demangle open-source library to translate mangled names (e.g., _ZN4core3ptr13drop_in_place17h...) into human-readable forms before displaying or applying them in IDA.
Demo / Proof of Concept
▶ Watch: Binary diffing on Star Blizzard's Speaker backdoor — 0.97 similarity (24:17)
Klopsch demonstrated the RIFT Static Analyzer IDA plugin live, showing the GUI (self-deprecatingly described as the product of a six-month front-end development phase) extracting a JSON file containing:
git_commit_hash: The rustc commit embedded in the binary.target_triple: e.g.,x86_64-pc-windows-msvc.architecture:x86_64.crates: List of detected dependency crates with versions (e.g.,base64 0.21.2extracted from the RLord binary).
The RIFT Generator was then shown being invoked from the command line with a config file pointing to the locations of pcf, sigmake, idat, and diaphora, with a flag selecting either --flirt or --diff mode.
For RLord, the set of generated FLIRT signatures was shown, with one .sig file per crate and one for the Rust compiler 1.84.1. Applied in IDA, the right-hand function list showed previously unlabeled sub_ functions renamed to proper library function names.
For SPICA, the Diff Applier was shown in interactive mode: selecting a previously unannotated function from the IDA function list and right-clicking to invoke "RIFT: Display Top Matching Functions" populated a ranked list with stats::windows_fs_stat at 0.97 similarity.
Defensive Implications
▶ Watch: RIFT open-source release announcement and future roadmap (25:43)
RIFT's open sourcing has direct relevance for defensive operations:
- SOC and incident response workflows: When a Rust binary is pulled from an incident, RIFT can immediately reduce the analysis burden from ~10,000 unknown functions to a tractable set of authored functions, accelerating triage and capability extraction.
- Threat intelligence: Identifying the exact Rust compiler version and crate set used by a threat actor can serve as a fingerprint across campaigns. Detecting a re-use of
base64 0.21.2combined with a specific rustc commit hash is a weak but potentially useful clustering signal. - Configuration and C2 extraction: The faster analysts can strip away library boilerplate, the sooner they can identify decryption routines, C2 protocol implementations, and embedded configuration structures—directly reducing attacker dwell time.
- Limitation: packed binaries: If a Rust binary has been additionally protected with a commercial packer (e.g., VMProtect), the embedded string metadata that RIFT relies on may be absent or encrypted. In those cases, the binary diffing approach with approximate version guessing is the fallback.
Key Takeaways
- Rust malware is a growing and poorly served problem: a simple Rust binary can contain 10,000 functions versus 80 for a comparable C++ binary.
- The key insight RIFT exploits is that Rust embeds its compiler version (as a git commit hash) and crate dependency metadata directly in compiled binaries, enabling exact re-compilation and reference signature generation.
- RIFT provides two complementary workflows: FLIRT signature generation (fast, accurate, strict) and batch binary diffing via Diaphora (more flexible, handles incomplete metadata, more prone to false positives).
- The tool was validated on real-world malware: RLord ransomware (FLIRT path) and the SPICA backdoor attributed to Russian nation-state actor Star Blizzard (diffing path).
- RIFT is open source and available at github.com/microsoft/rift.
- Current limitations include Windows-only testing, IDA Pro as the only supported disassembler, and slow binary diffing performance—all items on the development roadmap.
- The roadmap includes support for additional architectures, other disassemblers (Binary Ninja, Ghidra), performance improvements to the diffing pipeline, and potential AI-assisted library code stripping.
About the Speaker
Andreas Klopsch is a malware reverse engineer at Microsoft's MSTIC (Microsoft Threat Intelligence Center), where he is a member of the MIRAGE (Malware Intelligence Research and Analysis Global Expert) team. His research focuses on nation-state malware and threats used by nation-state actors. He is also the maintainer of malware.com, where he publishes reverse engineering guides and analysis. RIFT represents his contribution to the ongoing community effort to make Rust reverse engineering tractable.
Reviews
Dr. Zero (Offensive Security Researcher) — SOLID
RIFT solves a real and growing problem — Rust malware reversing — with a clean insight about exploiting compiler metadata embedded in the binary itself, but it's a defensive tooling talk at REcon, and the execution has enough gaps to keep it out of the top tier.
Heather Calloway (CISO) — PASS
Essential tooling for anyone analyzing Rust malware — RIFT solves a genuine analyst bottleneck in a technically elegant way, and Zero should review it properly, because the governance and enterprise implications are thin here.