flare-floss Documentation

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

4,199 stars Python Python 15 files ยท ~16,730 tokens #deobfuscation#flare#gsoc-2026#malware#malware-analysis#strings
RAW Doc

Technical Documentation: mandiant/flare-floss

โ„น๏ธ Provenance: Multi-Tier Ingestion ยท CodeWiki Reference

Overview (`README.md`)




FLARE Obfuscated String Solver

The FLARE Obfuscated String Solver (FLOSS, formerly FireEye Labs Obfuscated String Solver) uses advanced
static analysis techniques to automatically extract and deobfuscate all strings from
malware binaries. You can use it just like strings.exe to enhance the
basic static analysis of unknown binaries.

Obfuscated Strings

Rather than heavily protecting backdoors with hardcore packers, many
malware authors evade heuristic detections by obfuscating only key
portions of an executable. Often, these portions are strings and resources
used to configure domains, files, and other artifacts of an infection.
These key features will not show up as plaintext in the output of the strings.exe utility
that we commonly use during basic static analysis.

FLOSS extracts all the following string types:

  1. static strings: "regular" ASCII and UTF-16LE strings
  2. stack strings: strings constructed on the stack at run-time
  3. tight strings: a special form of stack strings, decoded on the stack
  4. decoded strings: strings decoded in a function

Please review the theory behind FLOSS here.

Our blog post talks more about the motivation behind FLOSS and details how the tool works.

FLOSS version 2.0 updates are detailed in this blog post.

Language-specific Strings

Not all compilers use string formats that the classic strings.exe algorithm supports. For example, if strings are UTF-8 encoded or stored without a NULL-terminator. FLOSS can identify and extract strings from programs compiled from the following languages:

  1. Go
  2. Rust

The strings FLOSS extracts specific to a compiler are much easier to inspect by humans.

Please consult the documentation to learn more about the language-specific string extraction.

Layout-aware static strings

FLOSS enriches static strings by default with
file structure context and tags (global prevalence, open-source libraries,
expert rules, and more). Stack, tight, and decoded strings still appear after
the layout-aware static listing when deobfuscation is enabled.

console
$ floss sample.exe
$ floss sample.exe -j

Features:

  • extract ASCII and UTF-16LE strings
  • show strings next to right-aligned, colored context, including tags and file offset
  • render strings within PE section range delimiters
  • annotate strings from known PE structures, like the import table
  • don't show junk strings that overlap with instructions
  • mute strings known to be globally prevalent, via an embedded database
  • mute strings from popular open source libraries, via embedded databases
  • highlight strings that match expert rules, via embedded databases

Tag databases and FLIRT signature files are tracked with Git LFS; contributors
cloning the repo may need Git LFS installed to fetch those files. Maintenance of
tag databases is documented in scripts/tags/README.md
and the per-database notes under floss/tags/data/.

Installation

To use FLOSS, download a standalone executable file from the releases page:
https://github.com/mandiant/flare-floss/releases

See the installation documentation for a detailed description of all methods to install FLOSS.

Usage Examples

Extract obfuscated strings from a malware binary:

text
$ floss malware.exe

Only extract stack and tight strings:

text
$ floss --string-type stack tight -- suspicious.exe

Do not extract static strings:

text
$ floss --no-string-type static -- backdoor.exe

Display the help/usage screens:

text
$ floss -h  # show all supported arguments

Enable tab completion for flags, choice values, and file paths with floss --print-completion bash
(also zsh, fish); installation instructions are in doc/usage.md.

For a detailed description of using FLOSS, review the documentation
here.

Scripts

FLOSS also contains additional Python scripts in the scripts directory
which can be used to load its output into other tools such as Binary Ninja or IDA Pro.
For detailed description of these scripts review the documentation here.

Graphical viewer

Explore floss -j output in the hosted web viewer:
upload the JSON, filter strings by search term, minimum length, tags, or
structures, and copy what you keep.

Emit a standalone HTML report directly and open it in a browser:

text
floss --html malware.exe > report.html

You can also build the viewer yourself into a single, self-contained offline HTML
file, see viewer/README.md.

Documentation

Mailing List

Subscribe to the FLARE mailing list for community announcements by sending an email with the subject "subscribe" to [email protected].


Overview (`scripts/README.md`)

FLOSS Scripts

Auxiliary scripts live under scripts/, grouped by purpose:

Directory Purpose
disassemblers/ Convert classic FLOSS JSON output into import scripts for Binary Ninja, Ghidra, IDA Pro, Radare2, and x64dbg; includes the IDA plugin
tags/ Build and maintain FLOSS tag databases (global prevalence, OSS libraries, VT feeds)
analysis/ Batch analysis helpers

disassemblers/

Turn FLOSS JSON (floss -j sample.exe > results.json) into tool-specific artifacts.

  1. Run a render script, redirecting stdout to a file.
  2. Import or run the generated artifact in the target tool.

Example (Ghidra):

console
$ python render-ghidra-import-script.py results.json > apply_floss.py

See disassemblers/ for per-tool scripts and the IDA plugin (File โ†’ Script fileโ€ฆ in IDA Pro).

Install FLOSS from source first; see installation.

tags/

Scripts that extract strings, build tag databases, and query them. See tags/README.md for the full pipeline.

analysis/

  • bulk_analyze.py โ€” run floss over every binary in a directory and write JSON results.

Language-specific data maintenance (for example regenerating the Rust version hash database) lives alongside the implementation under floss/language/.


Overview (`viewer/README.md`)

FLOSS Graphical Viewer

This is a web-based viewer for analyzing the output of the floss tool. It allows for interactive filtering and exploration of extracted strings, tags, and structures from a binary file.

Features

  • Upload and parse floss JSON output.
  • Filter strings by search term, minimum length, tags, and structures.
  • Toggle display of columns (tags, encoding, offset/structure).
  • Copy filtered strings to the clipboard.
  • Download the viewer itself as a standalone HTML file for offline use (download icon in the header). The saved file is fully self-contained and can be opened directly in a browser without an internet connection. The file is named after the viewer version, the commit date, and the git commit it was built from (e.g. floss-viewer-4.0.0a2-26-08-24-abc1234.html).
  • Preload results from window.flossResults. FLOSS --html fills this from the built dist/index.html template so the report opens with results already loaded. Leave it null for the hosted viewer and the Download-viewer copy.

Development

To set up the development environment, first install the dependencies:

bash
npm install

Then, run the development server:

bash
npm run dev

This will start a local server, and you can view the application in your browser. The server supports Hot Module Replacement (HMR), so changes to the source code will be reflected live without a full page reload.

Building

To check your changes and build for production, run:

bash
npm run lint
npm run build

This will create a single, self-contained HTML file in the dist directory and copy it to floss/render/templates/index.html. That copy is what floss --html reads for source checkouts, pip, and the standalone executable. Do not commit it.


Overview (`floss/sigs/README.md`)

FLOSS signatures

This directory contains FLIRT signatures that FLOSS uses to identify library functions.
Typically, FLOSS will ignore library functions, which reduces false positives and improves runtime.

These FLIRT signatures were generated by Mandiant using the Hex-Rays FLAIR tools such as pcf and sigmake.
Mandiant generated the signatures from source data that they collected; these signatures are not derived from the FLIRT signatures distributed with IDA Pro.

The signatures in this directory have the same license as FLOSS: Apache 2.0.


Overview (`scripts/tags/README.md`)

Tag database maintenance

Scripts for building and inspecting the tag databases shipped under floss/tags/data/.

Pipeline overview

text
extract_strings.py  โ†’  generate_gp_db.py  โ†’  gp.jsonl.gz
                              โ†‘
                    (raw PE string JSON)

build_oss_db.py  โ†’  <library>.jsonl.gz   (OSS tag databases)

fetch_vt_hashes.py  โ†’  hash list          (VT feed sampling)

query_string.py     โ†’  lookup GP tags     (debug / inspection)

Global prevalence (GP)

  1. Extract raw strings from PEs:

    console
    $ python scripts/tags/extract_strings.py C:\Windows outdir
  2. Generate the global-prevalence database from extracted JSON:

    console
    $ python scripts/tags/generate_gp_db.py outdir gp.jsonl.gz --type native
  3. Install the result at floss/tags/data/gp/gp.jsonl.gz (and related hash files).

  4. Query a string against the installed database:

    console
    $ python scripts/tags/query_string.py "kernel32.dll"

Open-source library (OSS) databases

build_oss_db.py automates the vcpkg & jh technique: install static libraries, extract features with jh, emit gzip-compressed JSONL, and merge with any existing databases in the output directory.

console
$ python scripts/tags/build_oss_db.py --libraries zlib curl --output-dir floss/tags/data/oss

VirusTotal feed sampling

fetch_vt_hashes.py downloads hashes for relevant file types from the VT feed over a time range (requires virustotal3 and API credentials).

console
$ python scripts/tags/fetch_vt_hashes.py 202305010000 202305020000

Overview (`floss/tags/data/expert/readme.md`)

Expert String Database

This directory contains databases of strings manually curated by experts.

The format of the database is a JSONL file (one JSON document per line).
Each document looks like:

json
{
    "type":"string",
    "value":"This program cannot be run in DOS mode.",
    "tag":"#capa",
    "action":"highlight",
    "note":"contain an embedded PE file",
    "description":"",
    "authors":["[email protected]"],
    "references":[]
}

Regex rules store the bare pattern in value. Flags go into the optional modifiers
field (default ""); currently only i (case-insensitive) is used.

The expert databases are:

  • capa.jsonl: strings extracted from capa rules.
    Do not edit it by hand; regenerate it with the importer from a checkout of the capa
    rules repository:

    text
    python floss/tags/data/expert/import_from_capa.py ~/code/capa/rules/ > floss/tags/data/expert/capa.jsonl

    The importer needs Python 3.10+ with capa 7 or newer, msgspec and FLOSS importable
    (for example PYTHONPATH=. from the repository root). Rules are visited sorted by
    rule name; a string that occurs in several rules is emitted once, attributed to the
    first rule. The output depends only on the rules checkout, not on the capa version.

    The committed file was generated from
    capa-rules master at 805f9eac
    (2026-09-08, "rule: graduate .NET time delay rule (#1196)") using capa 9.4.0.
    When regenerating, update this paragraph and put the same link in the commit message
    so the database can be diffed against the rules it came from:
    https://github.com/mandiant/capa-rules/compare/<old>...<new>.

  • capa_blocklist.json: a list of noisy capa strings that the importer leaves out of
    capa.jsonl to prevent false positives. Each entry has type, value and an
    optional modifiers key (missing means ""). A rule is skipped only if its
    type, value and modifiers are all equal to an entry; an entry without
    modifiers therefore does not match a rule with modifiers: "i".
    The importer resolves the blocklist relative to its own location, not the current
    working directory.


Overview (`floss/tags/data/gp/readme.md`)

Globally Prevalent Strings

This directory contains databases of strings that are globally prevalent.
In other words, they are seen widely, and may be difficult to attribute to a specific library.

There are two types of databases here:

  • jsonl.gz files that contain strings and metadata
  • hash databases that contain hashes of strings

JSONL files

These databases are gzip-compressed JSONL files (one JSON document per line).
The first line contains metadata about the database, such as:

json
{
    "type":"metadata",
    "version":"1.0",
    "timestamp":"2023-05-11T12:49:35.328896",
    "note":null
}

The subsequent lines look like:

json
{
    "string":"!This program cannot be run in DOS mode.",
    "encoding":"ascii",
    "global_count":424466,
    "location":null
}

JSONL databases:

  • gp.jsonl.gz: a proof-of-concept GP database derived from an internal string database. All strings were seen at least 100,000 times across millions of files. This database doesn't provide much value.
  • cwindb-dotnet.jsonl.gz: strings seen in .NET modules found on a Windows 10 system during May 2023.
  • cwindb-native.jsonl.gz: strings seen in native PE files found on a Windows 10 system during May 2023.
  • junk-code.jsonl.gz: junk strings from .text section of native PE files found on a Windows 10 system during May 2023. These strings are likely instruction sequences and we use them to supplement our code analysis recovery solution.

Hash databases

When collecting strings from a large number of files, we encounter a huge number of strings. For example, 100,000 files results in more than 3 million strings seen more than 100 times (and almost 600 million distinct strings).

The hash database format is a sorted list of eight byte truncated MD5 hashes of strings found in a large corpus like this. FLOSS can quickly check if a string is in the database by computing the hash of the string and performing a binary search in the database; however, it can't recover any additional metadata about the string.

Hash databases:

  • xaa-hashes.bin: strings seen more than 100 times in 100,000 files uploaded to VirusTotal on May 1, 2023. There's probably a substantial bias in this collection. See issue #722 for the history.
  • yaa-hashes.bin: strings seen more than 100 times in 100,000 files uploaded to VirusTotal between May 18 and 24, 2023. The samples are randomly selected from more than 3 million total candidates in this time range. There's probably less bias in this collection (I hope). Also see issue #722 for the history.
  • gp-2026-hashes.bin: Refined global prevalence database (82,269 hashes). Compiled from a 153k sample corpus (Sep 2023 - Jun 2026) to filter out common string noise.
  • gp-go-specific.bin: Go-specific runtime noise (41,585 hashes). Contains Go-specific runtime and type descriptor strings.
  • gp-rust-specific.bin: Rust-specific runtime noise (3,953 hashes). Contains Rust panic-handling and standard library strings.
  • gp-pyinstaller-specific.bin: PyInstaller-specific noise (13,702 hashes). Contains PyInstaller bootloader and standard library Python bytecode strings.

Source Data (CSVs)

For transparency and future reference, the raw string lists (with counts and locations) used to generate the 2026 databases are included as compressed CSV files in the raw/ directory:

  • raw/gp-2026-hashes.csv.gz: Raw strings and metadata for gp-2026-hashes.bin.
  • raw/gp-go-specific.csv.gz: Raw strings and metadata for gp-go-specific.bin.
  • raw/gp-rust-specific.csv.gz: Raw strings and metadata for gp-rust-specific.bin.
  • raw/gp-pyinstaller-specific.csv.gz: Raw strings and metadata for gp-pyinstaller-specific.bin.

2026 Database Generation

The 2026 prevalence databases were generated from a temporally balanced corpus to represent the modern threat landscape while filtering out campaign-specific noise.

1. Corpus Selection & Extraction

  • Source: 247,485 unique PE binaries collected from VirusTotal (balanced at ~250/day over 1,000 days from Sep 2023 to Jun 2026).
  • Clustering: Clustered by Vhash and TLSH to select at most 3 representatives per cluster, resulting in 153,913 representative samples used for string extraction.

2. Global Database (`gp-2026-hashes.bin`)

To filter out general PE noise while avoiding malware campaign flooding:

  • Imphash Grouping: Grouped the 153k files into 54,996 unique imphash groups (counting only 1 file per group) to normalize the weight of malware families.
  • Section Filtering: Restricted the database to strings from 14 standard PE sections (e.g., .text, .rdata), removing packer and overlay noise.
  • Campaign Pruning: Removed low-frequency campaign noise by requiring strings to appear in >= 11 groups (or >= 1,000 raw samples).
  • Result: 82,269 unique hashes (a clean, high-confidence global noise database).

3. Specialized Sub-Databases (Go, Rust, PyInstaller)

Statically linked runtimes share identical IATs and collapse into single imphash groups, hiding their runtime strings. To capture this noise:

  • Classification: Identified Go (1,574 samples), Rust (1,038 samples), and PyInstaller (1,229 samples) subsets using metadata.
  • Raw Samples Approach: Compiled strings using raw sample counts (no grouping) at a 5% threshold (10% for PyInstaller) to capture the runtime.
  • Global Subtraction: Subtracted the Global DB from each subset to remove redundant common APIs and keep the sub-databases lightweight.
  • Results:
    • gp-go-specific.bin (41,585 hashes)
    • gp-rust-specific.bin (3,953 hashes)
    • gp-pyinstaller-specific.bin (13,702 hashes)

Overview (`floss/tags/data/oss/readme.md`)

Strings from Open Source libraries

This directory contains databases of strings extracted from open soure software. FLOSS uses these databases to show the user when a string is likely from a library.

There is one file for each database. Each database is a gzip-compressed, JSONL (one JSON document per line) file.
The JSON document looks like this:

text
string: "1.0.8, 13-Jul-2019"
library_name: "bzip2"
library_version: "1.0.8#3"
file_path: "CMakeFiles/bz2.dir/bzlib.c.obj"
function_name: "BZ2_bzlibVersion"
line_number: null

The following databases were extracted via the vkpkg & jh technique:

  • brotli 1.0.9#5
  • bzip2 1.0.8#3
  • cryptopp 8.7.0
  • curl 7.86.0#1
  • detours 4.0.1#7
  • jemalloc 5.3.0#1
  • jsoncpp 1.9.5
  • kcp 1.7
  • liblzma 5.2.5#6
  • libsodium 1.0.18#8
  • libpcap 1.10.1#3
  • mbedtls 2.28.1
  • openssl 3.0.7#1
  • sqlite3 3.40.0#1
  • tomcrypt 1.18.2#2
  • wolfssl 5.5.0
  • zlib 1.2.13

The vkpkg & jh technique

Major steps:

  1. build static libraries via vcpkg
  2. extract features via jh
  3. convert to JSONL format with jh_to_oss.py
  4. compress with gzip

Build static libraries via vcpkg

vcpkg is a free C/C++ package manager for acquiring and managing libraries.
We use it to easily build common open source libraries, like zlib.
Use the triplet x64-windows-static to build static archives (.lib files that are AR archives containing COFF object files):

console
PS > C:\vcpkg\vcpkg.exe install --triplet x64-windows-static zlib

Why these build parameters

We use triplet=x64-windows-static, compiler=msvc143, profile=release to match FLOSS's primary target (PE binaries on Windows). MSVC v143 was the current Visual Studio toolchain at the time the databases were first generated; switching to a newer toolchain would be expected to shift extracted string counts only marginally, since most strings come from source-level literals and symbol names.

A cross-platform check (macOS arm64 vs. MinGW x86_64) showed total counts stay similar but per-string overlap is low: most non-overlap is random printable byte runs in compiled code (which differ per ISA), section/segment names (.rdata vs. __TEXT,__cstring), and symbol conventions (Mach-O prefixes C symbols with _, COFF does not). We keep the databases Windows-only since FLOSS targets PE.

Extract features via jh

jh
is a lancelot-based utility that parses AR archives containing COFF object files,
reconstructs their control flow, finds functions, and extracts features.
jh extracts numbers, API calls, and strings; we are only interested in the string features.

For each feature, jh emits a CSV line with the fields

  • target triplet
  • compiler
  • library
  • version
  • build profile
  • path
  • function
  • feature type
  • feature value

For example:

csv
x64-windows-static,msvc143,bzip2,1.0.8#3,release,CMakeFiles/bz2.dir/bzlib.c.obj,BZ2_bzBuffToBuffCompress,number,0x00000100

For example, to invoke jh:

console
$ ~/lancelot/target/release/jh x64-windows-static msvc143 zlib 1.2.13 release /mnt/c/vcpkg/installed/x64-windows-static/lib/zlib.lib > ~/flare-floss/floss/tags/data/oss/zlib.csv

Convert to OSS database format

We use the script jh_to_oss.py to convert these CSV lines into JSONL file prepared for FLOSS:

console
$ python3 jh_to_oss.py zlib.csv > zlib.jsonl

These files are then gzip'd:

console
$  gzip -c zlib.jsonl > zlib.jsonl.gz

The scripts/tags/build_oss_db.py script automates the steps above and merges into
any .jsonl.gz already present in the output directory rather than
replacing them. For each library being rebuilt, the newly-extracted
entries are combined with the existing entries (new entries win on
string collisions, which is the right behavior when the library version
changes).


Doc Installation (`doc/installation.md`)

FLARE Obfuscated String Solver

Installation

You can install FLOSS in a few different ways.
First, if you simply want to use FLOSS to extract strings, just download
the standalone binaries.
However, if you want to use FLOSS as a Python library,
you can install the package directly from GitHub using pip.
Finally, if you'd like to contribute patches or features to FLOSS,
you'll need to work with a local copy of the source code.

Method 1: Using FLOSS standalone

If you simply want to use FLOSS to extract strings,
use the standalone binaries we host on GitHub:
https://github.com/mandiant/flare-floss/releases.
These binary executable files contain all the source code,
Python interpreter, and associated resources needed to make FLOSS run.
This means you can run it without any installation!
Just invoke the file using your terminal shell to see the help documentation.

We use PyInstaller to create these packages.

MacOS Standalone installation

By default, on macOS Catalina or greater, Gatekeeper will block execution of the standalone binary. To resolve this, simply try to execute it once on the command-line and then go to System Settings / Privacy & Security and approve the application. Alternatively, remove the quarantine attribute (enabled by default for downloaded files) from the binary before running it:

text
xattr -d com.apple.quarantine ./floss

Method 2: Using FLOSS as a Python library

If you'd like to use FLOSS as part of an automated analysis system,
you might want to invoke it as a Python library.
We designed FLOSS to be as easy to use from a client program as from
the command line.

:warning: FLOSS requires Python >= 3.12.

Step 1: Install FLOSS module

Use pip (Python >= 3.12) to install the flare-floss module to your local
Python environment.
This fetches the library code to your computer, but does not keep
editable source files around for you to hack on.
If you'd like to edit the source files, see Method 3.

  • Install FLOSS:

    $ pip install flare-floss

Step 2: Use FLOSS from a Python script

You can now import the floss module from a Python script. The supported
programmatic entry points are:

  • floss.main.main(argv) โ€” run the same analysis the CLI does and return the
    process exit code. Pass a list of arguments (for example
    ["sample.exe", "--json"]) in place of sys.argv[1:].
  • floss.pipeline.analyze(options) โ€” run the full analysis pipeline and return a
    floss.results.ResultDocument. You must build a floss.pipeline.Options
    object (sample path, min_length, an Analysis config, and so on).
  • floss.results.ResultDocument โ€” load and validate an existing results JSON
    document (ResultDocument.parse_file(path)), or construct one in memory to
    render with the modules under floss.render.

Example, driving the pipeline directly:

text
#!/usr/bin/env python
from pathlib import Path
from floss.pipeline import Options, analyze
from floss.results import Analysis

options = Options(
    sample=Path("malware.exe"),
    min_length=4,
    analysis=Analysis(),
)
doc = analyze(options)
print(len(doc.strings.stack_strings), "stack strings")

These are the current programmatic interfaces. The CLI (floss ...) remains the
stable, documented interface โ€” the Python API can change between releases, so
pin the flare-floss version if you rely on it.

:warning: Importing floss does not itself register any convenience functions;
dir(floss) is not a useful listing. Use the entry points above instead.

Method 3: Inspecting the FLOSS source code

If you'd like to review and modify the FLOSS source code,
you'll need to check it out from GitHub and install it locally.
By following these instructions, you'll maintain a local directory
of source code that you can modify and run easily.

Step 1: Check out source code

  • Clone the FLOSS git repository:

    $ git clone https://github.com/mandiant/flare-floss /local/path/to/src

Several large data files (tag databases under floss/tags/data/ and FLIRT
signatures under floss/sigs/) are tracked with Git LFS.
Ensure Git LFS is installed (git lfs install) and that the clone has the
filters enabled, then fetch the large objects with:

text
`$ git lfs pull`

Without these files the tag and signature features will be silently missing or
empty.

Step 2: Install the local source code

Next, use pip to install the source code in "editable" mode.
This means that Python will load the FLOSS module from this local
directory rather than copying it to site-packages or dist-packages.
This is good, because it is easy for us to modify files and see the
effects reflected immediately.
But be careful not to remove this directory unless uninstalling FLOSS!
If you encounter the error ERROR: Project has a 'pyproject.toml' and its build backend is missing the 'build_editable' hook.,
please ensure that you have upgraded to the latest versions of pip and setuptools.

  • Install FLOSS:

    $ pip install -e /local/path/to/src

You'll find that the floss.exe (Windows) or floss (Linux, macOS) executables
in your path now invoke the FLOSS binary from this directory.

Step 3: Install development and testing dependencies

When developing FLOSS, please use the pinned dependencies found in requirements.txt.
This ensures that everyone has the exact same, reproducible environment.
Please install these dependencies before install FLOSS (from source or from PyPI):

$ pip install -r requirements.txt

To install all testing and development dependencies, run:

$ pip install -e /local/path/to/src[dev]

We use a git submodule to separate code and test data.
To clone everything use the --recurse-submodules option:

  • $ git clone --recurse-submodules https://github.com/mandiant/flare-floss.git /local/path/to/src (HTTPS)
  • $ git clone --recurse-submodules [email protected]:mandiant/flare-floss.git /local/path/to/src (SSH)

Or use the manual option:

  • clone repository
    • $ git clone https://github.com/mandiant/flare-floss.git /local/path/to/src (HTTPS)
    • $ git clone [email protected]:mandiant/flare-floss.git /local/path/to/src (SSH)
  • $ cd /local/path/to/src
  • $ git submodule update --init tests/data

We use the following tools to ensure consistent code style and formatting:

We use pre-commit so that its trivial to run the same linters & configuration locally as in CI.

Run all linters liks:

text
โฏ pre-commit run --all-files
isort....................................................................Passed
black....................................................................Passed
mypy.....................................................................Passed

Or run a single linter like:

text
โฏ pre-commit run --all-files isort
isort....................................................................Passed

Importantly, you can configure pre-commit to run automatically before every commit by running:

text
โฏ pre-commit install --hook-type pre-commit
pre-commit installed at .git/hooks/pre-commit

โฏ pre-commit install --hook-type pre-push
pre-commit installed at .git/hooks/pre-push

This way you can ensure that you don't commit code style or formatting offenses.
You can always temporarily skip the checks by using the -n/--no-verify git option.

The test suite is not part of these hooks because it is slow. Run it with pytest tests/ or pre-commit run pytest --hook-stage manual.

The linters and tests run in CI must all pass before a pull request is merged.

Step 4: Building standalone executables

Once you're happy with your contribution to FLOSS, you can package and
distribute a standalone executable for your friends using PyInstaller.
This combines the source code, Python interpreter, and required resources
into a single file that can be run without installation.

  • Install pyinstaller:

    $ pip install pyinstaller

  • Build standalone executable:

    $ pyinstaller .github/pyinstaller/floss.spec

  • Distribute standalone executable:

    $ cp ./dist/floss.exe /the/internet


Doc Language Specific Strings (`doc/language_specific_strings.md`)

Go String Extraction

Programs compiled by the Go compiler use a string representation that is difficult to interpret by humans. Although they are UTF-8 encoded, and therefore show up in the output of strings.exe, program strings are not NULL-terminated. This means separate strings within the binary may appear as a large chunk of indistinguishable string data.

FLOSS implements an algorithm to handle the unusual characteristics of strings in Go binaries. This approach analyzes instances of the struct String type to identify candidate strings and reasons about the length-sorted order to avoid false positives. Crucially, FLOSS automatically handles the complexities of Go strings and displays strings as written in the program's source code.

It's important to mention that there are other types of strings, such as runtime strings, which are not derived from the program strings.

Algorithm:

  1. Analyze the string instances within the binary.
    • In Go, strings are encoded as structs (see source code links below) containing two fields: a pointer to the string's underlying data and the length of the string.
    • By examining these instances, we can identify the strings and their locations within the binary.
  2. Identify the longest continuous sequence of monotonically increasing string lengths to find the string blob.
  3. Use the byte sequence 00 00 00 00 as a delimiter to accurately mark the boundaries of the string blob.
  4. Extract the string blob located between the identified boundaries.
  5. Split the identified string blob, based on the cross-references available in the binary to separate the individual strings.

Please note that while FLOSS handles many scenarios effectively, there are certain optimizations, such as inlined constants, that may not be fully supported yet.
For more information on Go strings, you can refer to the Go project's documentation and the source code of the struct String layout.

Learn more:

text
Go Project: [Go Project](https://github.com/golang/go)
Blog post: [Unveiling Go Strings: A Google Summer of Code Journey](https://medium.com/p/92f6d9fee97c)
Source code: 
- https://github.com/golang/go/blob/36ea4f9680f8296f1c7d0cf7dbb1b3a9d572754a/src/builtin/builtin.go#L70-L73
- https://github.com/golang/go/blob/38e2376f35907ebbb98419f1f4b8f28125bf6aaf/src/go/types/builtins.go#L824-L825

Rust String Extraction

Similar to Go, Rust binaries may contain strings that are not NULL terminated. Separate strings within the binary may appear as larger chunks of indistinguishable string data.

FLOSS analyzes the data and code in Rust binaries to identify individual candidate strings.

Algorithm:

  1. Extract all UTF-8 encoded strings
  2. Analyze data and code references to identify substring boundaries
  3. Split strings from step 1 into individual parts as found in step 2

For more information on Rust strings, you can refer to the Rust project's documentation and the source code of the Rust String layout.

Learn more:

text
Rust Project: [Rust Project](https://github.com/rust-lang/rust)
Source code: 
- https://github.com/rust-lang/rust/blob/3911a63b7777e19dad4043542f908018e70c0bdd/library/alloc/src/string.rs

Doc Results Document (`doc/results_document.md`)

FLOSS results document

floss -j sample.exe emits the full analysis result as a single, versioned JSON
object. This is the interchange format for all of the tools under
scripts/ and the web viewer. The
model is defined in floss/results.py.

Loading

The format is self-describing: run

text
floss sample.exe -j > sample.json

and pass it back to FLOSS to re-render it (as text, summary, or JSON) without
re-running the analysis:

text
floss sample.json
floss sample.json --summary

Scripts can load and validate a document programmatically:

python
from floss.results import ResultDocument
doc = ResultDocument.parse_file(path)

layout, analysis, and strings are always present (possibly empty); the
metadata block is always first so a document is recognizable from its leading
bytes. Loading via the CLI mutates a copy of the document: --analyze-functions
and -n/--minimum-length are re-applied on load, and a -n looser than the one
used to build the document is an error, because those shorter strings were
already dropped at extraction time.

An empty file still produces a document and exit code 0: the hashes, the
layout tree without strings, and empty string lists. There is no program to
deobfuscate, so FLOSS records enable_stack_strings, enable_tight_strings,
and enable_decoded_strings as false, as it does for .NET binaries. Earlier
versions printed nothing. Errors, such as an unsupported file format, still exit
non-zero and report the error on stderr.

Top-level structure

jsonc
{
  "metadata": { "...": "..." },
  "analysis": { "...": "..." },
  "strings": { "...": "..." },
  "layout":  { "...": "..." }
}
Key Type Description
metadata object Sample metadata: file path, hashes, tool version, runtime, thresholds
analysis object Which string types were enabled and function analysis counts
strings object The recovered strings, grouped by type
layout object | null Layout-aware static string context tree

metadata carry the sample identity and the settings used for extraction:

  • file_path, md5, sha1, sha256
  • version โ€” the FLOSS version that produced the document (cached documents are
    keyed on this)
  • imagebase โ€” the base address (0 for non-PE/ELF inputs such as shellcode)
  • min_length โ€” the extraction minimum string length
  • language, language_version, language_selected โ€” Go/Rust identification
  • runtime โ€” per-stage elapsed time, e.g. static_strings, layout, tags

analysis records the extraction configuration and supporting counts:

  • enable_static_strings, enable_stack_strings, enable_tight_strings,
    enable_decoded_strings, enable_language_strings, enable_layout,
    enable_tags
  • functions โ€” discovered, library, and per-stage counts such as
    analyzed_decoded_strings and decoding_function_scores

strings groups the results by extraction technique:

  • static_strings โ€” plain ASCII/UTF-16LE strings
  • stack_strings โ€” strings constructed on the stack at run time
  • tight_strings โ€” a special form of stack strings decoded in a tight loop
  • decoded_strings โ€” strings decoded in a function
  • language_strings / language_strings_missed โ€” language-specific strings
    (Go/Rust) and candidates that were not recovered

Each element carries the string value, its address/offset, and its encoding
(ASCII, UTF-16LE, UTF-8). Decoded/stack strings additionally record the
decoding function (decoding_routine, decoded_at) or stack frame details.

Layout

When layout and static string extraction are enabled, layout is a tree whose
nodes describe the binary structure. Inputs that are not PE, ELF, or Mach-O
files (or whose headers fail to parse) get a single root node named binary
with no children that spans the whole file. layout is null only when layout
analysis is disabled. A node is:

jsonc
{
  "name": ".rdata",
  "offset": 1890752,
  "length": 1476336,
  "strings": [
    {
      "string": "open",
      "offset": 1906840,
      "size": 4,
      "encoding": "ASCII",
      "tags": ["#winapi"],
      "structure": "import table"
    }
  ],
  "children": [ { "...": "..." } ]
}
  • name is the file format, section, or segment name (e.g. pe, .text,
    .rdata, header, overlay). Structures such as the import table are not
    nodes; they are reported in each string's structure field.
  • offset/length give the node's byte range; each string records its offset,
    size, encoding, tag list, and the structure it lives in.
  • structure is the name of the file format structure that contains the string,
    such as import table (which includes delay-load imports), export table,
    section header, or string table. It is the empty string "", never
    null, when the string is not part of a known structure.

Stability

The document carries metadata.version. While FLOSS is under active
development, the schema is allowed to change between releases: the top-level
keys and their meaning are intended to be stable, but new fields may be added and
the presence of a field is not a guarantee between minor versions. Tools that
consume the document should treat unknown keys as ignorable and should pin the
flare-floss version that produced it. The scripts/ import tools
and the viewer are kept in sync with the current schema.


Doc Tags (`doc/tags.md`)

FLOSS tags

When layout-aware static string extraction is enabled, FLOSS annotates strings
with tags. Tags come from embedded databases and expert rules, and let you
filter the listing down to the strings that matter using --tag, --no-tag, and
--interesting (see usage.md).

When the input is not a PE, ELF, or Mach-O file (or its layout cannot be parsed),
FLOSS places all static strings in a single layout node named binary that
covers the whole file. Tags, filters, the summary, and the viewer work the same
as for structured inputs; only the layout-derived tags (#code, #reloc,
#decoded) and the section and structure context are unavailable.

This document covers tag consumption: which tags exist and how to filter with
them. Rebuilding and installing the databases is maintenance, documented in
scripts/tags/README.md. Per-database notes sit next
to the data under floss/tags/data/.

Tag families

A family name matches any tag in that family, so --tag oss matches every
open-source library tag, and --no-tag oss drops all of them at once.

The multi-tag families are:

Family Tags
gp #common, #code-junk
oss one tag per library, e.g. #openssl, #zlib, #curl

The oss family derives each library tag from the file name in
floss/tags/data/oss/ (for example openssl.jsonl.gz โ†’ #openssl).

The remaining tags are single tags, not families, and can be filtered directly:

Tag Source
#winapi Windows API usage database (floss/tags/data/winapi/)
#msvc Microsoft C runtime library (floss/tags/data/crt/)
#capa Expert / capa rules (floss/tags/data/expert/)

A library tag (oss family or #msvc) is dropped from a file's strings when
fewer than 5 strings in the file carry it. A handful of hits are usually generic
strings such as System, signal, or kernel32.dll that also appear in the
library, not evidence that the library is linked in.

Match behavior

Tag matching is normalized: a leading # is stripped and the tag is lowercased,
so winapi, #WinAPI, and #winapi all match the stored tag #winapi. Values
that do not name a family are compared directly. A string matches a --tag filter
if any of its tags matches any of the requested tags/families.

Default rendering

Without --tag or --interesting, the text view hides strings tagged #code,
#reloc, or #code-junk (known instruction-byte sequences such as D$0H, which
supplement code range recovery), mutes #common, #duplicate, and other tags,
and highlights #capa. The HTML viewer deselects the same three tags by default.
JSON output is not affected. To see hidden strings in the text view, select them
explicitly, e.g. --tag code-junk.

Noisy tags and `--interesting`

Some tags mark strings that are rarely interesting during analysis โ€” prevalent
strings, duplicates, or strings that overlap code or relocations:

text
#common  #duplicate  #code  #reloc  #code-junk

--interesting drops any string carrying a noisy tag, unless the string also
carries a highlight tag (such as #capa from the expert rules), which is
preserved. This is a fast way to hide boilerplate and focus on distinctive
strings.

Where tags come from

Tagging is implemented in floss/tags/:

  • gp.py โ€” global-prevalence (#common, #code-junk) and hashes
  • oss.py โ€” open-source library membership
  • winapi.py โ€” Windows API usage
  • expert.py โ€” expert/capa rules (#capa), plus an optional #decoded marker

The databases are tracked with Git LFS and loaded from floss/tags/data/. If they
are missing (for example, after a plain clone without Git LFS), tag extraction is
skipped; see installation.md.


Doc Test (`doc/test.md`)

FLARE Obfuscated String Solver

Testing

We use pytest to test FLOSS and ensure that it adheres to our specifications. You can run test cases using the following steps to confirm that FLOSS behaves as expected on your platform.

First, make sure that pytest is installed:

text
pip install pytest

Running the unit test suite

FLOSS ships a unit-test suite covering the renderers, layout, tagging, caching,
and the CLI. Install the dev dependencies (see
installation.md),
then run:

text
pytest tests/

Add -k <name> to select specific tests or -x to stop at the first failure.

Set FLOSS_SAVE_WORKSPACE=1 FLOSS_LOAD_VIV_WORKSPACE=1 to cache the vivisect workspaces of the binary test cases as <sample>.viv and skip re-analysis on later runs (CI sets both).

Continuous integration

The tests.yml workflow runs on every push and
pull request. It checks code style and runs the unit test suite across the
supported Python versions and operating systems. See the workflow file for the
current matrix. All checks must pass before a pull request is merged.

Binary Test Cases

We test FLOSS using a collection of binary files that implement various decoding routines. You can find the C source code for these tests under the directory tests/data/src/.

We store all test-related files in the flare-floss-testfiles repository.

Building Binary Test Cases

You can easily build the binary test cases on both Linux (and OSX) and Windows systems because the source code is C99 source code. Under Linux, we provide Makefiles that invoke the build commands to compile all the tests in one go. On Windows, you may need to script calls to cl.exe using a batch script.

If you install wclang,
you can cross-compile 32-bit and 64-bit Windows executables from your Linux environment.
You can use the following steps to configure your environment for building the binary test cases:

text
sudo apt-get install clang mingw-w64 cmake make
git clone https://github.com/tpoechtrager/wclang.git /home/user/src/wclang
cd /home/user/src/wclang
cmake -DCMAKE_INSTALL_PREFIX=/usr/local
make
sudo make install

You can now run make all from the directory tests/data/src to build all the test cases in ELF, PE32, and PE64 formats.

Adding a new Binary Test Case

  • Decide on a name for your test. Pick something like decode-rot-13. Follow the examples and stick to this name throughout the test case.
  • Copy the directory tests/data/src/template to tests/data/src/decode-rot-13.
  • Update the test.yml document to describe the purpose of the test.
  • Update the Makefile in tests/data/src/decode-rot-13/Makefile. You should only need to update the test name in the first line. Change it to test-decode-rot-13.
  • Move the file template.c to decode-rot-13.c and provide your implementation.
  • Update the Makefile in tests/data/src/Makefile. Add a new line in the first section with the name of your test.
  • Ensure you have the build environment configured, as described in the section "Building Binary Test Cases."
  • cd to tests/data/src/decode-rot-13 and run make all. Confirm the binary runs as expected.
  • Create a new branch named feature/test-decode-rot-13, add and commit the Readme, Makefiles, .c source file, compiled binaries, and submit a PR to the flare-floss-testfiles repository.

Doc Theory (`doc/theory.md`)

FLARE Obfuscated String Solver

Theory

Malware authors pack their software to resist reverse engineering and
enable their operations to survive longer.
However, many features of packing are easy to automatically identify
during static or dynamic analysis.
Therefore, some authors obfuscate only the most sensitive resources used by
malware in an attempt to blend in.
We call this "string obfuscation".
String obfuscation maintains some difficulty around extracting host or network based
signatures (such as filenames, registry keys, or domain names), while
structuring the executable file like legitimate programs.
This is a technique that balances moderate anti-reverse
engineering tricks with a moderate level of stealth.

As a reverse engineer, it takes significant effort to extract obfuscated
strings from a malware sample.
This is because there are a huge number of possible encoding functions,
configurations, and control flows.
For example, some malware uses a single-byte XOR operation with a static
key for all obfuscated strings, while other malware uses RC4 encryption
with a unique key per string.
Its often difficult to figure out how encoded data is protected without
opening IDA Pro or reviewing a debugger trace.

Manual extraction of obfuscated strings commonly involves thoroughly
studying a decryption routine and reimplementing it in a scripting language.
This is a tedious and error-prone process that is fun at first, and
mind-numbing after a few iterations.
Alternatively, an analyst may instrument a debugger to hop around
hundreds of locations in hopes of forcing the malware to decode itself.
This is also complex, tedious, and error-prone.

FLOSS combines and automates the best manual reverse engineering
techniques for string decoding.
First, it uses heuristics to identify decoding routines in a sample.
Then FLOSS extracts cross references and arguments to decoders
using control flow analysis.
Next FLOSS emulates decoder functions using extracted arguments.
Finally, FLOSS diffs the emulator memory states from before and
after decoder emulation and extracts human readable strings.

Algorithm

  1. Analyze control flow of malware to identify functions, basic blocks, etc.
  2. Use heuristics to find potential decoding routines
  3. Brute force emulate all code paths among basic blocks and functions
  4. Snapshot emulator state (registers, memory) at appropriate points
  5. Extract arguments to decoder functions from emulator snapshots
  6. Emulate decoder functions using extracted arguments and emulator state
  7. Diff memory state from before and after decoder emulation
  8. Extract human-readable strings from memory state difference

This document covers only the deobfuscation algorithm above. FLOSS also enriches
static strings with layout-aware context and semantic tags by default, and
extracts language-specific strings from Go and Rust binaries. See the
language-specific string extraction doc, the
tags doc, and the layout-aware static strings feature list in the
README.


Doc Usage (`doc/usage.md`)

FLARE Obfuscated String Solver

Usage

You can use FLOSS just like you'd use strings.exe
to extract human-readable strings from binary data.
The enhancement that FLOSS provides is that it statically
analyzes executable files and decodes obfuscated strings.
These include:

  • strings encrypted in global memory or deobfuscated onto the heap
  • strings manually created on the stack (stackstrings)
  • strings created on the stack and then further modified (tight strings)

Since FLOSS also extracts static strings (like strings.exe),
you should consider replacing strings.exe with FLOSS
within your analysis workflow.

Here's a summary of the command line flags and options you
can provide to FLOSS to modify its behavior.

See floss -h for all supported arguments and usage examples.

For a first look at a new sample, start with floss --summary malware.exe. It
prints metadata, per-type string counts, a tag histogram, and the most
interesting strings, which is usually enough to decide where to dig next.

Extract static, obfuscated, and stack strings (default mode)

text
floss.exe malware.exe

The default mode for FLOSS is to extract the following string types from an executable file:

  • static ASCII and UTF-16LE strings
  • stack strings
  • tight strings
  • obfuscated strings

See the section on Shellcode analysis below on how to analyze raw binary files
containing shellcode.

By default, FLOSS uses a minimum string length of four (4).

Language-specific strings

FLOSS can identify programs compiled from selected programming languages and extract strings that are easier to inspect by humans.

By default, this process is automatic. However, you can use the --language argument to manually select or disable this feature.

Disable string type extraction (`--no-string-type {static,stack,tight,decoded,language,all}`)

When FLOSS searches for static strings, it looks for
human-readable ASCII and UTF-16 strings across the
entire binary contents of the file.
This means you may be able to replace strings.exe with
FLOSS in your analysis workflow. However, you may disable
the extraction of static strings via the --no-string-type static switch.

text
floss.exe --no-string-type static -- malware.exe

Since --no-string-type supports multiple arguments, end the command options with a double dash --.

Analogous, you can disable the extraction of obfuscated strings, stackstrings or any combination.

text
floss.exe --no-string-type decoded -- malware.exe
floss.exe --no-string-type stack tight -- malware.exe

Enable string type extraction (`--string-type {static,stack,tight,decoded,language,all}`)

Sometimes it's easier to specify only the string type(s) you want to extract.
Use the --string-type option for that.

text
floss.exe --string-type decoded -- malware.exe

Please note that --string-type and --no-string-type cannot be used at the same time.

Filtering arguments

These options let you drill into the layout-aware static string listing by
binary section, structure, semantic tag, or content. They are the primary
controls for the layout-aware output that FLOSS enables by default (see the
Tags section and layout-aware static strings
in the README).

Filtering by binary section:

text
floss.exe --section .rdata -- malware.exe
floss.exe --no-section .text -- malware.exe

--section keeps only static strings whose containing section is in the given
list; --no-section drops them. Both accept multiple names and repeat.

Filtering by binary structure (PE/ELF/Mach-O structures such as the import
table, section headers, etc.):

text
floss.exe --structure import-table -- malware.exe
floss.exe --no-structure symbol-table -- malware.exe

Structure names are slugs and match regardless of separators, so import-table,
import_table, and import table are equivalent. In PE files, import-table
covers both the regular and the delay-load import directory. Run --summary to
see the structures present in a specific sample.

Filtering by semantic tag:

text
floss.exe --tag winapi openssl -- malware.exe
floss.exe --no-tag crt -- malware.exe

--tag keeps strings that carry any of the given tags (or tag families, see the
Tags section); --no-tag drops them. Run --summary to see the tags
present in a specific sample.

Convenience shortcuts:

text
floss.exe --interesting -- malware.exe
floss.exe --query "http://" -- malware.exe
floss.exe --max-strings 50 -- malware.exe
  • --interesting drops strings that carry a "noisy" tag (prevalent, duplicated,
    code, or relocation-related strings, e.g. #common, #duplicate, #code),
    unless they also carry a highlight tag (such as #capa).
  • --query REGEX keeps only strings matching the given regular expression(s).
    Repeatable; patterns are ORed.
  • --max-strings N caps the emitted strings per section to the top N by
    relevance (highlighted first, then untagged, then tagged, ascending by offset).

--interesting is a shorthand for the noisy-tag exclusion; the section,
structure, and tag filters can all be combined with each other and with
--query.

Output options

Not all renderers produce the full layout-aware listing. These options select
alternative views:

text
floss.exe --plain malware.exe
floss.exe --summary malware.exe
floss.exe --columns tags offset structure -- malware.exe
  • --plain renders a flat list of strings, one per line, without layout context
    or tags. Use it when piping output into line-oriented tools like grep.
  • --summary emits a concise summary (sample metadata, per-type string counts,
    section counts, a tag histogram, and high-value strings). It is static-only by
    default unless string types are explicitly selected. This is the quickest way
    to see which sections, structures, and tags a sample contains.
  • --columns {tags,offset,structure,encoding} selects which columns appear in
    the layout view. Valid values are tags, offset, structure, encoding;
    the default is tags and offset.

Advanced options

text
floss.exe -L malware.exe
floss.exe --signatures /path/to/lib.sig malware.exe
floss.exe -dd malware.exe
floss.exe --color never malware.exe
  • -L/--large-file allows processing files larger than the default 64 MB
    limit. Files above this limit abort deobfuscation with an error unless this
    flag is set, because stack/tight/decoded string extraction is expensive.
  • --signatures PATH specifies a .sig/.pat file (or directory) used to
    identify library functions for deobfuscation. FLOSS uses its embedded FLIRT
    signatures by default. Signature databases are tracked with Git LFS; see the
    README for the LFS note.
  • -d/--debug enables debugging output on STDERR. Specify it multiple times
    to increase verbosity: -d (debug), -dd (TRACE), -ddd (SUPERTRACE). These
    levels are most useful to FLOSS developers and when reporting bugs.
  • --color {auto,always,never} controls ANSI color codes in the results.
    auto (the default) colors only during an interactive session.

Tags

FLOSS tags static strings with semantic context from embedded databases: Windows
API usage, C runtime, global prevalence, open-source libraries, and expert rules.
Filter with --tag, --no-tag, and --interesting as shown above. See
tags.md for every family and tag, and where each database comes from.

Environment variables

FLOSS reads the following environment variables:

Variable Effect
FLOSS_CACHE_DIR directory for the analysis result cache (default: the platform cache directory)
FLOSS_CACHE_ENABLE set to 0 to disable result caching (enabled by default)
FLOSS_CACHE_REFRESH set to 1 to ignore the cached result and overwrite the entry (disabled by default)
FLOSS_SAVE_WORKSPACE set to 1 (or true/yes/on) to save the vivisect workspace next to the sample as <sample>.viv during deobfuscation (disabled by default)
FLOSS_LOAD_VIV_WORKSPACE set to 1 to load an existing <sample>.viv workspace instead of re-analyzing the sample (disabled by default). Workspaces are deserialized with pickle, so only enable this for .viv files you trust. Workspaces saved with a different format, vivisect version, or FLIRT signatures are discarded after loading and the sample is re-analyzed

Result caching is enabled by default. The full result document is cached on
first run and reused on later runs, so repeated analyses of the same sample are
fast. Because a cache hit may serve a document written by an earlier run, disable
it with FLOSS_CACHE_ENABLE=0 (or point FLOSS_CACHE_DIR at a scratch
directory) when reproducing or diffing output across code changes.

Write output as JSON (`-j/--json`)

Write FLOSS results to stdout structured in JSON to make it easy to ingest by a script.

text
floss.exe -j malware.exe > malware_strings.json

The easiest way to explore this output is the hosted
web viewer: upload the JSON file, then
filter by tag, structure, or search term, and copy the strings you keep. See
results_document.md for the schema itself.

An empty file yields a document with empty string lists and exit code 0. A file
without static strings is analyzed like any other, so shellcode can still yield
stack strings. Errors, such as an unsupported file format, exit non-zero with
the error on stderr, whether or not the file contains strings; earlier versions
exited 0 silently for a string-less file.

Write a standalone HTML report (`--html`)

Write a self-contained HTML file that opens in a browser with the results already
loaded.

text
floss.exe --html malware.exe > malware_strings.html

The report is a copy of the web viewer
with the result document embedded. Interactive exploration of the data happens in the browser, the same
way it does when you upload JSON to the hosted viewer. The pip package and
standalone executable include the viewer. From a source checkout, build it first
with cd viewer && npm install && npm run build.

--html also works on a saved results document:

text
floss.exe --html malware_strings.json > malware_strings.html

Load FLOSS results (automatic)

Loading a saved FLOSS results JSON document is automatic and detected from the file
content, so you can explore results without re-running the analysis.

text
floss.exe malware_floss_results.json

Verbose results (`-v`)

Enable verbose results output, e.g. including function offsets and string encoding.
This does not affect the JSON output.

text
floss.exe -v malware.exe

Quiet mode (`-q/--quiet`)

You can suppress the formatting of FLOSS output by providing
the flags -q or --quiet.
These flags are appropriate if you will pipe the results of FLOSS
into a filtering or searching program such as grep, and
want to avoid matches on the section headers.
In quiet mode, each recovered string is printed on its
own line.
The "type" of the string (static, decoded, stackstring, tightstring)
is not included.

text
floss.exe -q malware.exe

Minimum string length (`-n/--minimum-length`)

By default, FLOSS searches for human-readable strings
with a length of at least four characters.
You can use the -n or --minimum-length options to
specific a different minimum length.
Supplying a larger minimum length reduces the chances
of identifying random data that appears to be ASCII;
however, FLOSS may then pass over short legitimate
human-readable strings

text
floss.exe -n 10 malware.exe

Decoding function specification (`--analyze-functions`)

You can instruct FLOSS to decode the strings provided
to specific functions by using the --analyze-functions
option.
By default, FLOSS uses heuristics to identify decoding
routines in malware.
This mode circumvents the identification phase and skips
directly to the decoding phase.
If you've previously done analysis on an executable program
and manually identified the decoding routines, use
this mode.
This can improve performance as FLOSS by perhaps one-third
(on the order of seconds, so it is usually not worth it
to always manually identify decoding routines).
Specify functions by using their hex-encoded virtual address.
Since --analyze-functions accepts multiple arguments, end the command options with a double dash --.

text
floss.exe --analyze-functions 0x401000 0x402000 -- malware.exe

Install/Uninstall right click menu option for Windows (`--install-right-click-menu/--uninstall-right-click-menu`)

You can use the --install-right-click-menu and --uninstall-right-click-menu
options to install/remove the Open with FLOSS option from the right-click menu
of the Windows file explorer.

After this option is installed, you can right-click on any file and select Open with FLOSS
to quickly open the target file with FLOSS for analysis.

Shell completions (`--print-completion {bash,zsh,tcsh,fish,powershell}`)

FLOSS can print a tab-completion script for your shell. The script is generated
from FLOSS's argument definitions, so flags, choice values (such as
--string-type static), and sample file paths all complete as you type.

text
floss --print-completion bash

Install the output for your shell:

bash:

text
mkdir -p ~/.local/share/bash_completion
floss --print-completion bash > ~/.local/share/bash_completion/floss
echo 'source ~/.local/share/bash_completion/floss' >> ~/.bashrc

zsh (requires compinit, which most frameworks and default configs run):

text
mkdir -p ~/.local/share/zsh/site-functions
floss --print-completion zsh > ~/.local/share/zsh/site-functions/_floss

fish:

text
mkdir -p ~/.config/fish/completions
floss --print-completion fish > ~/.config/fish/completions/floss.fish

Then restart your shell or start a new one.

Shellcode analysis options

Malicious shellcode often times contains obfuscated strings or stackstrings.
FLOSS can analyze raw binary files containing shellcode via the -f/--format switch. All
options mentioned above can also be applied when analyzing shellcode.

text
floss -f sc32 malware.raw32
floss -f sc64 malware.raw64

With --format auto (the default), FLOSS infers the sample format from its
contents. Shellcode is detected from the file name extension when the extension
matches .sc32/.raw32 (32-bit) or .sc64/.raw64 (64-bit); otherwise a file
is treated as a PE or ELF. You only need -f sc32/-f sc64 when the file name
does not follow these conventions or the contents do not identify themselves as
PE/ELF.


--- METRICS ---