Overview
FLOSS (FLARE Obfuscated String Solver) is an open-source tool developed by Mandiant’s FLARE team that automatically extracts obfuscated strings from malware samples. Malware authors routinely encode, encrypt, or dynamically construct strings to evade static analysis and signature-based detection. FLOSS goes beyond simple strings extraction by using static analysis heuristics and CPU emulation to identify and decode strings that are deobfuscated at runtime. It can recover strings hidden by XOR encoding, stack strings (constructed character-by-character on the stack), and tight strings (built through compact loops).
FLOSS combines three extraction methods: static string extraction (like the strings utility), stack string extraction (identifying sequences of character-by-character assignments to stack variables), and decoded string extraction (emulating functions identified as likely string decoders). The tool supports PE, ELF, and .NET executables and outputs results in plain text, JSON, or as IDA Pro/Ghidra scripts for annotation. FLOSS is an essential triage tool in malware analysis workflows — it can reveal C2 server addresses, registry keys, filenames, API function names, and other indicators that would otherwise require manual reverse engineering to uncover.
Installation
Via pip
# Install FLOSS
pip install flare-floss
# Verify installation
floss --version
Pre-built Binary
# Linux
wget https://github.com/mandiant/flare-floss/releases/latest/download/floss-v3.1.0-linux.zip
unzip floss-v3.1.0-linux.zip
chmod +x floss
sudo mv floss /usr/local/bin/
# Windows
# Download floss-v3.1.0-windows.zip from GitHub releases
# macOS
wget https://github.com/mandiant/flare-floss/releases/latest/download/floss-v3.1.0-macos.zip
unzip floss-v3.1.0-macos.zip
chmod +x floss
sudo mv floss /usr/local/bin/
From Source
git clone https://github.com/mandiant/flare-floss.git
cd flare-floss
pip install -e ".[dev]"
Core Commands
| Command | Description |
|---|
floss <file> | Run all extraction methods on a file |
floss --only static <file> | Extract only static strings |
floss --only stack <file> | Extract only stack strings |
floss --only decoded <file> | Extract only decoded strings |
floss --only tight <file> | Extract only tight strings |
floss -j <file> | Output as JSON |
floss -n <min_length> <file> | Set minimum string length |
floss --functions <addr> <file> | Analyze specific function(s) |
# Full analysis (all extraction methods)
floss malware.exe
# JSON output for automation
floss -j malware.exe > strings.json
# Only decoded (deobfuscated) strings
floss --only decoded malware.exe
# Only stack strings
floss --only stack malware.exe
# Set minimum string length
floss -n 6 malware.exe
# Analyze specific functions
floss --functions 0x401000 0x402500 malware.exe
# Verbose output showing function details
floss -v malware.exe
# Very verbose with debug information
floss -vv malware.exe
# Analyze .NET assembly
floss dotnet_malware.exe
# Analyze ELF binary
floss linux_malware.elf
# Analyze shellcode (specify base address)
floss --format sc64 shellcode.bin
Understanding Output
String Types
| Type | Description | Example |
|---|
| Static | Plain ASCII/Unicode strings in the binary | "kernel32.dll" |
| Stack | Characters pushed one at a time to the stack | "cmd.exe /c" (from mov [esp], 'c'; mov [esp+1], 'm'...) |
| Tight | Strings decoded via compact loops | "http://evil.com" (from XOR loop) |
| Decoded | Strings decoded by identified decoder functions | "HKLM\Software\Microsoft" (from decryption routine) |
# Example output structure
# FLOSS static strings
# ────────────────────
# kernel32.dll
# VirtualAlloc
# GetProcAddress
#
# FLOSS decoded strings
# ─────────────────────
# http://c2server.example.com/beacon
# HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
# cmd.exe /c del %s
#
# FLOSS stack strings
# ───────────────────
# powershell.exe
# -ExecutionPolicy Bypass
JSON Output Structure
# Parse JSON output with jq
# Get all decoded strings
floss -j malware.exe | jq '.strings.decoded_strings[].string'
# Get strings with addresses
floss -j malware.exe | jq '.strings.decoded_strings[] | {string, decoded_at, decoding_routine}'
# Get stack strings
floss -j malware.exe | jq '.strings.stack_strings[].string'
# Count strings by type
floss -j malware.exe | jq '{
static: (.strings.static_strings | length),
decoded: (.strings.decoded_strings | length),
stack: (.strings.stack_strings | length),
tight: (.strings.tight_strings | length)
}'
Configuration
Analysis Options
# Limit analysis time per function (seconds)
floss --max-function-time 30 malware.exe
# Limit total analysis time
floss --max-total-time 300 malware.exe
# Set number of address space limits for emulation
floss --max-address-revisits 800 malware.exe
# Disable specific analysis methods
floss --only static,decoded malware.exe # Skip stack and tight
Output Filtering
# Filter by minimum string length
floss -n 8 malware.exe
# Extract only strings matching a pattern
floss malware.exe | grep -E "(http|ftp|https|\.exe|\.dll|\.bat)"
# Extract URLs
floss -j malware.exe | jq -r '.. | .string? // empty' | grep -oP 'https?://[^\s"]+' | sort -u
# Extract IP addresses
floss -j malware.exe | jq -r '.. | .string? // empty' | grep -oP '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}' | sort -u
# Extract registry keys
floss -j malware.exe | jq -r '.. | .string? // empty' | grep -iP '^(HKLM|HKCU|HKCR)' | sort -u
Advanced Usage
Batch Processing
# Process all files in a directory
for f in /malware/samples/*; do
echo "=== $(basename "$f") ===" >> all_strings.txt
floss --only decoded,stack "$f" >> all_strings.txt 2>/dev/null
echo "" >> all_strings.txt
done
# JSON batch processing
find /malware/samples -type f | while read f; do
floss -j "$f" 2>/dev/null | jq -c "{
file: \"$(basename "$f")\",
decoded: [.strings.decoded_strings[].string],
stack: [.strings.stack_strings[].string]
}"
done > batch_strings.jsonl
# Extract IOCs from batch results
cat batch_strings.jsonl | jq -r '.decoded[], .stack[]' | \
grep -oP '(https?://[^\s"]+|\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' | \
sort -u > iocs.txt
IDA Pro Integration
# Generate IDA Python script with string annotations
floss --ida malware.exe > annotate_strings.py
# In IDA Pro: File > Script file > annotate_strings.py
# This adds comments at the locations where decoded strings are used
Ghidra Integration
# Generate Ghidra script
floss --ghidra malware.exe > annotate_strings_ghidra.py
# In Ghidra: Script Manager > Run Script > annotate_strings_ghidra.py
# Traditional strings vs FLOSS
strings -n 6 malware.exe > static_strings.txt
floss --only decoded,stack malware.exe > floss_strings.txt
# Find strings only FLOSS found
comm -13 <(sort static_strings.txt) <(sort floss_strings.txt)
# Compare with YARA string extraction
floss -j malware.exe | jq -r '.strings.decoded_strings[].string' | \
while read s; do
echo " \$s_$(echo "$s" | md5sum | cut -c1-8) = \"$s\""
done
Integration with Malware Analysis Pipeline
import subprocess
import json
def extract_floss_strings(filepath):
"""Extract obfuscated strings using FLOSS."""
result = subprocess.run(
["floss", "-j", filepath],
capture_output=True, text=True, timeout=300
)
if result.returncode == 0:
data = json.loads(result.stdout)
return {
"decoded": [s["string"] for s in data["strings"]["decoded_strings"]],
"stack": [s["string"] for s in data["strings"]["stack_strings"]],
"tight": [s["string"] for s in data["strings"]["tight_strings"]],
}
return None
# Usage
strings = extract_floss_strings("/malware/sample.exe")
if strings:
print(f"Decoded strings: {len(strings['decoded'])}")
for s in strings["decoded"]:
print(f" {s}")
Troubleshooting
| Issue | Solution |
|---|
| No decoded strings found | Sample may use custom encoding; try manual analysis in IDA/Ghidra |
| Analysis timeout | Increase --max-function-time and --max-total-time values |
| Memory error on large files | Limit scope with --functions to specific addresses |
vivisect import error | Reinstall: pip install flare-floss --force-reinstall |
| Packed samples yield few results | Unpack the sample first (UPX, custom packer), then run FLOSS |
| False positive strings | Filter by minimum length (-n 8) and validate against known IOCs |
| .NET analysis fails | Ensure .NET runtime libraries are accessible; try --format dotnet |
| Slow emulation | Reduce --max-address-revisits or target specific functions |