Skip to content

Project 0xA11C deoxidizing the Rust malware ecosystem

Nicole FishbeinJuan Andrés Guerro-Saade

MalwareVirus Bulletin33 minOpen on YouTube ↗

Discusses project 0xA11C deoxidizing the Rust malware ecosystem and evaluates key implications for security practitioners.

Summary

### Overview In this talk, security researchers introduce Project 0xA11C (Project Oxalic), an effort aimed at addressing the steep challenges of reverse engineering Rust malware. Drawing inspiration from earlier work on reversing Go binaries (such as the AlphaGolang project), the speakers analyze why Rust binaries pose significant obstacles for decompilers and reverse engineers, and present methodologies, data structures, and automation tooling designed to ease the analysis process.

### Key Topics - **Evolution of Binary Reversing**: Transitioning from historical reversing challenges (Delphi, C++) to modern languages that produce massive, statically linked binaries with non-standard structures (Go, Rust). - **Lessons from AlphaGolang**: How extracting metadata like the `pclntab`, repairing non-null-terminated strings, and filtering library code dramatically reduced analysis overhead in Go binaries, and how a similar methodology applies to Rust. - **Rust's Growing Adoption in Threat Landscapes**: The increasing prevalence of Rust in targeted attacks and ransomware (citing examples such as Wild Card, Luna, and Hive), driven by strict compiler guarantees, lack of garbage collection, speed, cross-compilation support, and inherent difficulty in reverse engineering. - **Decompilation and Tooling Bottlenecks**: Limitations in current disassemblers/decompilers (IDA Pro, Ghidra, Binary Ninja) when interpreting Rust abstractions, calling conventions, stack variable lifecycles, and IDA Python script compatibility issues.

### Technical Details - **Compiler & Dependency Extraction**: Rust binaries retain compiler-generated strings including `rustc` versions tied to exact GitHub commit IDs, as well as Cargo metadata revealing third-party dependencies and precise version information. - **String & Slice Structures**: Rust strings and string slices (`&str`) do not use standard null-terminated representations. Slices consist of a pointer/content and length (frequently placed in sections like `.rdata`), while owned strings include capacity, content, and length. In IDA Pro, these patterns frequently cause decompilation anomalies such as reversed strings stored in XMM registers. Creating and applying custom string structures in IDA cleans up pseudocode readability. - **Unwind Metadata & Exceptions**: When binaries crash, runtime exception handling relies on unwind metadata detailing prologue sizes, stack frames, and non-volatile registers. While parsing this metadata provides insights into function boundaries and frame layouts, resolving exact calling conventions still requires additional type reconstruction. - **Panic Information & Debug Structures**: Expansion of standard library macros (e.g., during panics) leaves structured debug metadata embedded in the binary. By defining a custom `debuginfo` structure, analysts can recover original source file paths, line numbers, column numbers, and commit hashes, linking them back to structured exception handling routines. - **By-Reference Stack Variables**: Rust functions heavily utilize by-reference stack pointers (potentially tied to closures or internal compiler optimizations), causing scope-violating variable updates that decompilers fail to accurately track, generating dead variables and ghost representations. - **FLIRT Signatures & Tooling Pipeline**: The speakers discuss using parsed Cargo dependencies to pull matching crate versions, compile them, and generate FLIRT signatures (leveraging upcoming IDA Pro 9 features like the FLIRT signature manager). Additionally, they introduced "feature_proof," a middleware abstraction library intended to shield IDA Python scripts from breaking across IDA API releases.

### Takeaways While major decompilers still lack native, complete handling for Rust semantics, reverse engineers can surface significant structural and contextual information prior to manual analysis. By parsing embedded Cargo metadata, reconstructing string and slice structures, leveraging panic debug info, and generating targeted FLIRT signatures for common crates, analysts can systematically reduce the attack surface of complex Rust malware.

Related talks