Stack Strings
Malware builds sensitive strings character-by-character on the stack at runtime so they never appear as static literals in the binary, defeating simple string-search analysis.
A naive way to hide a string from strings(1) or IDA's string window is to build it one character at a time on the stack. Because the bytes are never contiguous in the binary's .data or .rdata section, automated string extraction tools see nothing; the string only materialises in memory during execution.
Compilers can produce stack strings accidentally (for small constant strings under optimisation), but malware authors generate them intentionally — often through a code-generation script or LLVM obfuscation pass — for API names, registry keys, URLs, and mutex names.
How it works
// Instead of: const char *url = "http://evil.example/c2";
// Malware writes:
void BuildC2Url(char *buf)
{
buf[0] = 'h';
buf[1] = 't';
buf[2] = 't';
buf[3] = 'p';
buf[4] = ':';
buf[5] = '/';
buf[6] = '/';
buf[7] = 'e';
buf[8] = 'v';
buf[9] = 'i';
buf[10] = 'l';
// ... etc.
buf[22] = '\0';
}In optimised assembly this compiles to a sequence of immediate-byte MOV instructions with no contiguous string in the code section:
; x86-64 — building "http" on the stack
mov byte [rsp+00h], 68h ; 'h'
mov byte [rsp+01h], 74h ; 't'
mov byte [rsp+02h], 74h ; 't'
mov byte [rsp+03h], 70h ; 'p'A faster variant stores the string as a series of 4- or 8-byte integer constants moved into stack slots:
mov dword [rsp+00h], 70747468h ; "http" (little-endian)
mov dword [rsp+04h], 2F2F3A68h ; "h://"This form is harder to spot visually but equally hidden from static string extraction.
Detection & analysis
Static analysis:
- FLOSS (FLARE Obfuscated String Solver) from Mandiant emulates short function sequences to extract stack strings automatically; it is the standard tool for this technique.
- IDA/Ghidra: look for long sequences of
MOV byte [rbp/rsp+N], imm8targeting adjacent stack offsets — a characteristic pattern. - Entropy analysis is not useful here (stack strings don't increase section entropy).
Dynamic analysis:
- Set a breakpoint immediately after the build function returns and inspect the stack or heap buffer — the string is fully assembled there.
- Frida: hook the first downstream API call (e.g.,
URLDownloadToFile) that consumes the string; log the argument.
Detection rule hint:
Flag functions containing 8 or more single-byte immediate stack writes targeting sequential offsets within a 64-byte window — this pattern is almost never produced by legitimate, unobfuscated code.