Skip to content

Rust Binaries

Rust malware (ransomware, loaders, stealers) is growing because the compiler produces fast, stripped-looking native code with no runtime to fingerprint. But Rust leaves panic-location records: every unwrap(), array index and assert! that can panic embeds the source file path and line number it came from. Those paths are a detailed map of the project, and often of the machine that built it.

How PPEE detects Rust

PPEE looks for the rustc standard-library source paths (library\core\src\…, library\std\src\…) that panic records reference, and reads the panic-location structures around them. The Detected line names the first evidence found, for example rustc standard-library path at offset 0x9CBB78.

Views

View Columns Use it to
Summary compiler, build environment, source, dependencies, layout clues The report below
Project files File · Panic sites · Lines List every source file that has a panic site, with the line range and a link to the record's bytes
Crates third-party crates Crates named in the panic paths (shown only when any are found)

What the Summary tells you

Section Facts
Compiler The rustc commit (and whether it's a stable release, or a nightly/beta/custom build), and the target toolchain: MSVC or GNU (MinGW)
Build environment Project folders: the workspace root(s) the code was built from
Source Number of panic-site records, number of distinct source files, and the project-file list
Dependencies Third-party crates, or No third-party crate paths
Layout clues Overlay, sections with no file data, writable + executable sections

Windows screenshot: Rust Summary of an infostealer: rustc version, MSVC toolchain, PDB name, 12 project files and 68 crates

Rust Summary of an infostealer: rustc version, MSVC toolchain, PDB name, 12 project files and 68 crates

The Summary of the infostealer below. Every blue value is a link: the rustc version to its bytes, kuinabot.pdb to the debug directory, and the counts to the Project files and Crates views. The build machine's user name is redacted in this screenshot.

Walkthrough: a Rust infostealer, read from its panic paths

42c6a1581f9ac7134dcd392b13d3c7fad3c75fef3473ee68ffc6ae8d2e086fcb.exe

$ ppee-cli --analysis 42c6a158….exe
Rust > Summary  (built from panic-location records, the debug directory and the file layout)
Compiler
  rustc: 1.94.1 (2026-03-25, commit e408947bf) [offset 0x3CAA88]
  Target toolchain: MSVC, linked by Microsoft's link.exe (Rich header present)
Build environment
  User name: …
  Build host paths: Windows-style (C:\...)
  Registry: crates.io  (index.crates.io-1949cf8c6b5b557f), the name cargo 1.85+ uses
  PDB path: kuinabot.pdb [DIR Entry Debug]
Source
  Panic sites: 2510 records naming 391 source files
  Project files: 12 files [Analysis > Rust > Project files]
  src\autofill.rs, src\cookie.rs, src\credit_cards.rs, src\crypto.rs, src\discord.rs, src\history.rs, src\main.rs,
  src\password.rs, src\search_history.rs, src\system.rs, src\telegram_sender.rs, src\wifi.rs
Dependencies
  Crates: 68 crates with panic sites [Analysis > Rust > Crates]
  aead 0.5.2, aes 0.8.4, aes-gcm 0.10.3, …, chacha20poly1305 0.10.1, …

No disassembly needed:

  • The project files are the feature list: browser autofill, cookies, credit cards, passwords, history, Discord tokens, Wi-Fi keys, and telegram_sender.rs, the exfiltration channel.
  • aes-gcm among the crates is what decrypts Chromium's v10/v20 saved values.
  • The PDB name (kuinabot) and the user name of the build machine (shown by PPEE, left out here) are attribution leads.
  • A stable rustc release (1.94.1) and MSVC with a Rich header: built natively on Windows.

Another RustyStealer sample, 4156bba1….exe (injector.pdb), has project files injector\src\injector\module_stomping.rs and injector\src\c2.rs: a module-stomping injector with a C2 module, again named by its own source tree.

Windows screenshot: Rust Project files view: twelve source files of the stealer with their panic-site counts and line ranges

Rust Project files view: twelve source files of the stealer with their panic-site counts and line ranges

Project files for the same sample: one row per source file, with the number of panic sites and the line range they span. cookie.rs (24 sites) and system.rs (16) have the most panic sites, and main.rs reaches line 1498.

The toolchain line (MSVC, or GNU (MinGW) for programs cross-compiled from Linux) tells you which platform's conventions to expect. Project folders give the module structure without any symbols. A benign file for comparison: cargo-clippy.exe reports a nightly rustc commit, MinGW, and 719 project files under src\tools\clippy.

Reading a Rust build like an analyst

Observation What it suggests
Project folders like C:\Users\<name>\Desktop\<project>\src Attribution: the builder's user name and directory naming habits, unless the build remapped paths (--remap-path-prefix, trim-paths)
Registry paths (.cargo\registry\src\…\<crate>-<version>\) Which crates and versions were used, e.g. chacha20, reqwest, windows-sys. A file-encryption crate plus directory-walking crate is a strong ransomware signal
A project-file list with names like encrypt.rs, persist.rs, c2.rs The module layout is self-describing
Nightly, beta or custom rustc commit Not a distribution build: a developer's own toolchain. Same commit across samples is a good cluster key
Target toolchain MSVC vs GNU Cross-compiled from Linux (GNU/MinGW) or built natively on Windows (MSVC): a hint at the operator's environment
Reproducible build noted Deterministic build: the timestamps are hashes (see the overview)
Few or no panic sites A very small program, or built with panic=abort and paths remapped, so this evidence is thin

Combine it with the debug directory (a Rust PDB path also names the project) and the TLS directory, since Rust runtimes register their own callbacks.

CLI and JSON

ppee-cli --analysis f.exe
# Source files with the most panic sites first
ppee-cli --json --analysis f.exe | jq -r '.analysis.runtimes[] | select(.key == "rust") | .views[] | select(.key == "analysis.rust.sources")
  | .table.rows | sort_by(-(.cells[1] | tonumber)) | .[0:10][] | .cells | @tsv'

# rustc commit and toolchain, for clustering a sample set
for f in samples/*.exe; do
  ppee-cli --no-similarity --json --analysis "$f" 2>/dev/null | jq -r --arg f "$f" '.analysis.runtimes[] | select(.key == "rust")
    | .views[0].blocks[] | select(.kind == "fact" and (.label == "rustc" or .label == "Target toolchain")) | "\($f)\t\(.label)\t\([.spans[].text] | join(""))"'
done

Related: Analysis overview · --analysis · Debug directory (PDB paths)

References