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
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-gcmamong the crates is what decrypts Chromium'sv10/v20saved 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
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¶
- The rustc book: the Rust compiler and its target toolchains.

