Open-source project
mandiant/flare-floss avatar
mandiant/flare-floss

FLOSS: extracting obfuscated strings from malware binaries

FLARE Obfuscated String Solver - Automatically extract obfuscated strings from malware.

4,165 stars539 forksPythonApache-2.0

At a glance

What is it?
FLOSS is Mandiant's static analysis tool for pulling static, stack, tight and decoded strings out of Windows, Go and Rust binaries. It is a drop-in upgrade to strings.exe for triage, with a JSON schema and an HTML report you can hand to someone else.
Who is it for?
Use FLOSS when you are doing first-pass static triage of an unknown Windows, Go or Rust binary and need strings that the plain strings.exe pass missed. Skip it when you only need ASCII and UTF-16LE output at maximum speed, or when the sample is packed and the deobfuscation emulator has nothing to follow.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 8 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The gap FLOSS fills in basic static analysis

Malware authors rarely pack an entire executable. More often they obfuscate only the parts that matter: the domain, the file path, the registry key, the mutex name. Those artifacts never appear as plaintext in strings.exe output, so a first-pass analyst sees a binary with almost no readable configuration and moves on. FLOSS is built for exactly that situation. It targets the strings that are constructed or decoded at run time rather than stored as literals, and it does so statically, without executing the sample. The README frames the tool as something you can use "just like strings.exe to enhance the basic static analysis of unknown binaries", which is the right mental model: it sits in the same triage slot, not in a sandbox or a debugger session. Its audience is the analyst who already runs strings and PE inspection on a sample and wants a second pass that costs seconds rather than a full reverse engineering session.

Four string types and the passes that produce them

The README lists the string categories FLOSS extracts: static strings (ASCII and UTF-16LE), stack strings built on the stack at run time, tight strings (a special form of stack strings decoded on the stack), and decoded strings produced inside a decoding function. The first category is the classic strings.exe territory. The other three come from static analysis of the code that builds them, which is why the tool depends on a disassembly and emulation stack rather than a byte scanner. The repository requirements list vivisect and viv-utils alongside dncil and dnfile, so the analysis covers both native and .NET binaries, and python-flirt is present for library identification. The README points to doc/theory.md for the algorithm itself; anyone evaluating whether FLOSS will work on a given family should read that document before trusting the output on a packed sample.

Layout-aware static strings and the tag databases

Version 2 changed the default output. Static strings are now enriched with file structure context and tags, and the README describes several specific behaviours: strings are shown with right-aligned colored context including tags and file offset, rendered within PE section range delimiters, annotated when they come from known PE structures such as the import table, and suppressed when they overlap with instructions. Three embedded databases do filtering work: one mutes strings known to be globally prevalent, one mutes strings from popular open source libraries, and one highlights strings matching expert rules. That is a meaningful design choice. It trades completeness for signal, and the trade is deliberate: a default run will not show you every byte sequence that looks like a string, and an analyst who wants the raw set has to turn the filtering off. The databases are tracked with Git LFS, so cloning the repository without Git LFS leaves those files missing. Maintenance of the tag databases is documented under scripts/tags/README.md.

Installing FLOSS and running a first sample

The README gives two routes. The recommended one is a standalone executable from the releases page, which avoids managing a Python environment at all. The other is the Python package, named flare-floss on PyPI, which requires Python 3.10 or newer according to pyproject.toml. The README does not give a pip install line, so the command below follows the package name declared in pyproject.toml rather than a documented example.

bash
pip install flare-floss

After installation, floss should be on your PATH. Running it against a binary with no arguments produces the default report: layout-aware static strings first, then stack, tight and decoded strings when deobfuscation is enabled.

bash
floss sample.exe

The README shows the JSON flag and the HTML report flag as separate invocations. The first writes the machine-readable results document, the second writes a standalone report you can open in a browser.

bash
floss sample.exe -j
floss --html malware.exe > report.html

If you only want the deobfuscation passes, restrict the string types. The README shows the flag taking one or more values followed by a double dash before the sample path.

bash
floss --string-type stack tight -- suspicious.exe
floss --no-string-type static -- backdoor.exe

Shell completion is available through shtab, invoked as floss --print-completion with bash, zsh or fish as the argument.

Where FLOSS is the wrong tool

The deobfuscation passes are heuristic. Stack, tight and decoded strings are recovered by analyzing code paths that construct or decode data, and a sample that is packed, virtualized or that resolves its strings through a mechanism the emulator does not model will produce nothing useful from those passes. In that case FLOSS degrades to a strings replacement with better formatting, which may still be worth running but is not the reason you adopted it. There is a second, quieter limitation: the default output is filtered. Globally prevalent strings and strings from popular open source libraries are muted by embedded databases, so a default run is not a complete inventory. If your workflow depends on seeing every candidate string, including the ones that look like compiler runtime noise, you need to understand what the muting is hiding. Finally, the tool is static only. It will not tell you which of the extracted strings is actually used at run time, and it will not resolve strings that are fetched from a remote server.

How FLOSS compares with a plain strings pass

The obvious alternative is strings.exe or the GNU strings utility, and the difference is not cosmetic. A byte scanner finds contiguous printable sequences and nothing else; it has no concept of a string being assembled one character at a time on the stack, and no concept of a decode routine. FLOSS adds a disassembly and emulation layer on top of the byte scan, which is what lets it report stack, tight and decoded strings. The cost is runtime and dependency weight: a strings pass completes in milliseconds on almost any binary, while FLOSS loads the sample into an analysis engine and walks code. For a batch of thousands of samples where you only need literal strings, strings is still the correct tool. FLOSS earns its place on the smaller set of samples where the literal strings are uninformative and you suspect the configuration is being built at run time. The second alternative is a full disassembler session in IDA Pro or Binary Ninja. The repository ships scripts under scripts/ that load FLOSS output into both, which is the intended workflow: FLOSS for the fast pass, the disassembler for the strings that need context.

Licence, maintenance and the cost of upgrading

FLOSS is Apache-2.0, with the licence file at LICENSE.txt and the same identifier declared in pyproject.toml. That permits commercial and internal use, modification and redistribution provided the licence and notices are preserved, but the usual caveat applies: if you embed it in a product, review the transitive dependency licences yourself rather than assuming the top-level Apache grant covers everything. The dependency list is large and pinned to exact versions in requirements.txt, which means upgrades are not automatic and a version bump in vivisect or pefile can change analysis behaviour. The repository is not archived and the last push was on 2026-09-22, one day before this writing. The most recent release listed is quantumstrand-beta3 from 2026-04-22, and the two before it are also betas, so the current release line carries beta labelling even though pyproject.toml declares the project Production/Stable. Treat release notes as required reading before upgrading in a pipeline, and pin the version you install.

Editorial conclusion

Use FLOSS when you are doing first-pass static triage of an unknown Windows, Go or Rust binary and need strings that the plain strings.exe pass missed. Skip it when you only need ASCII and UTF-16LE output at maximum speed, or when the sample is packed and the deobfuscation emulator has nothing to follow. Before you rely on it in a pipeline, pin the release you install, run floss --html on one sample you already understand and check the JSON schema version against doc/results_document.md, because the results format is versioned and the deobfuscation passes are heuristic.

Frequently asked questions

What does the abbreviation FLOSS stand for in the context of flare-floss?

It stands for FLARE Obfuscated String Solver. The README notes the tool was formerly called FireEye Labs Obfuscated String Solver.

What is flare floss?

It is Mandiant's static analysis tool that extracts and deobfuscates strings from malware binaries, covering static, stack, tight and decoded strings. The README describes using it like strings.exe to enhance basic static analysis of unknown binaries.

How do I install FLOSS?

The README recommends downloading a standalone executable from the releases page. Alternatively, the Python package is named flare-floss on PyPI and requires Python 3.10 or newer, and doc/installation.md documents all the installation methods.

Can FLOSS extract strings from Go and Rust binaries?

Yes. The README states that FLOSS identifies and extracts strings from programs compiled from Go and Rust, because not all compilers use string formats the classic strings.exe algorithm supports, and it points to doc/language_specific_strings.md for details.

How do I get FLOSS output as JSON or HTML?

Run floss with -j to emit JSON, or with --html to write a standalone HTML report. The README also mentions a hosted web viewer where you can upload floss -j output and filter strings.

Why are some strings missing from the default FLOSS output?

By default FLOSS mutes strings known to be globally prevalent and strings from popular open source libraries, using embedded databases. It also suppresses junk strings that overlap with instructions, so the default listing is filtered rather than complete.

Official sources

  1. Issues
  2. License: Apache-2.0
  3. mandiant/flare-floss on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/mandiant-flare-floss.svg)](https://hysenlabs.com/projects/mandiant-flare-floss)