Yen Wang

0x20Writing

Demangling the Symbol in Rust Binary: <alloc::string::FromUtf8Error as …>

Demangling <alloc::string::FromUtf8Error as core::fmt::Debug>::fmt::<hash>, a symbol found while reversing Akira's Rust build.

Published 15 May 2026 Read 5 min Tags rust, reverse-engineering

Originally published on The Dark Grimoire (Medium). Read the original ↗

This is the string discovered from the previous article: Reversing Akira’s Rust Experiment: A Breakdown Part 1

Welcome, Low Level Wizard 🧙‍♂️

A good time to learn the binary magic spells…

A good time to learn the binary magic spells…

Intro

The original article has been way too long, my goal for for my blog is to offer as many details as I could, so I won’t try to make it professional, neat and brief (I believe you can find many good threat reports without going through the messay process).

This is my journey of reverse engineering, I enjoy sharing both acdemic insights and the learning strugglings. As a beginner, I found it hard to learn assembly without practicing and guidance when I tried to reverse the samples, whether it’s for testing or at production level.

By all means, it’s imperfect and might have some mistakes, feel free to leave comments down below, I will update the content. Meanwhile, hope you enjoy the interesting things I found.

Mangling Scheme

I didn’t use any demangler in this analysis (in Binary Ninja), so it helps me to discover the native binary landscape (and it looks very scary too).

First, we can see the raw symbol is using the legacy Rust v0 mangling scheme (pre-v0, actually, the $ encoding). Demangled, it reads:

<alloc::string::FromUtf8Error as core::fmt::Debug>::fmt::h510500198db9042f

Breaking it apart:

Component Meaning alloc::string::FromUtf8Error The type this impl is for as core::fmt::Debug The trait being implemented ::fmt The specific trait method h510500198db9042f rustc hash (disambiguator for monomorphisation / codegen unit)

This is a trait method symbol, not a free function. The angle-bracket form ::method is the standard Rust way to name a trait impl's method.

Why Does debug Appear in a Release Build?

This is the key misconception to correct: fmt::Debug has nothing to do with debug vs release compilation mode. The word "debug" here refers to the std::fmt::Debug formatting trait, which controls how a type prints when you use the {:?} format specifier. It is entirely orthogonal to rustc's optimisation profile.

The trait is defined in core::fmt:

pub trait Debug {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result;
}

alloc::string::FromUtf8Error derives or implements this trait so it can be pretty-printed with {:?}. The stdlib implementation lives in library/alloc/src/string.rs.

The derived impl for FromUtf8Error looks roughly like this (simplified):

#[derive(Debug)]
pub struct FromUtf8Error {
    bytes: Vec<u8>,
    error: Utf8Error,
}

#[derive(Debug)] causes rustc to auto-generate a fmt method. That generated method is what this symbol represents.

Why Is This Symbol Present in a Stripped Release Binary?

This is worth understanding carefully for RE purposes.

In a release build with strip = true, named symbols are removed from the symbol table, but the code still exists if it is reachable. The presence of this string suggests one of:

  1. The binary is not fully stripped (common with Rust: strip = "symbols" removes .symtab but may leave strings in .rodata or panic metadata).
  2. This is a panic string / type name, not a symbol table entry. Rust embeds type names as string literals for panic formatting. If the code path does unwrap() or expect() on a Result<_, FromUtf8Error>, the type name can be embedded in the binary as part of the panic payload even in release mode.
  3. It survived as a function name in**.dynstr** if the binary is dynamically linked (unlikely for Rust malware but possible).

The $LT$ / $GT$ / $u20$ encoding is the legacy mangling scheme (used before the v0 scheme introduced in Rust 1.37). If you are seeing this exact encoding rather than the newer _R prefix scheme, the binary was compiled with an older toolchain or with symbol-mangling-version = "legacy" in Cargo config.

What Does This Tell You About the Binary?

From a malware RE perspective:

  • String::from_utf8 is being used somewhere in the code. The Debug impl for FromUtf8Error is only monomorphised and retained if the error type is actually used, which means either it is returned as part of a Result, or it is displayed/printed via {:?}.
  • The error path is reachable. If the compiler dead-code-eliminated the fmt call entirely, this symbol would not appear even as a string.
  • Possible use patterns: parsing raw bytes into strings (network data, file content, C interop buffers) and either propagating or logging the error. This is common in malware doing C2 protocol parsing, config decryption output handling, or filename/path reconstruction.

Quick Reference: Source Location

The actual Debug impl is in the Rust stdlib:

library/alloc/src/string.rs

Look for:

impl fmt::Debug for FromUtf8Error { ... }

Or, in older versions, it is derived via #[derive(Debug)] on the struct definition itself.

References

Klabnik, S., Nichols, C. and The Rust Project Developers (n.d.) FromUtf8Error in std::string. The Rust Programming Language. Available at: https://doc.rust-lang.org/std/string/struct.FromUtf8Error.html

Klabnik, S., Nichols, C. and The Rust Project Developers(n.d.) Debug in core::fmt. The Rust Programming Language. Available at: https://doc.rust-lang.org/core/fmt/trait.Debug.html

rust-lang (2017) Non well-formed symbol mangling and bad symbol tracking issue, GitHub issue #46552. Available at: https://github.com/rust-lang/rust/issues/46552