# Technical Documentation: mandiant/flare-floss

> ℹ️ **Provenance:** Multi-Tier Ingestion · [CodeWiki Reference](https://codewiki.google/github.com/mandiant/flare-floss)

### Overview (`README.md`)

[](https://github.com/mandiant/flare-floss/releases)
[](https://github.com/mandiant/flare-floss/actions/workflows/tests.yml)
[](https://github.com/mandiant/flare-floss/releases)
[](LICENSE.txt)



# 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](doc/theory.md).

Our [blog post](https://cloud.google.com/blog/topics/threat-intelligence/automatically-extracting-obfuscated-strings/) talks more about the motivation behind FLOSS and details how the tool works.

FLOSS version 2.0 updates are detailed in this [blog post](https://cloud.google.com/blog/topics/threat-intelligence/floss-version-2/).

### 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](doc/language_specific_strings.md).

### 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](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](doc/installation.md) for a detailed description of all methods to install FLOSS.

## Usage Examples
Extract obfuscated strings from a malware binary:

    $ floss malware.exe

Only extract stack and tight strings:

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

Do not extract static strings:

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

Display the help/usage screens:

    $ 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](doc/usage.md#shell-completions).

For a detailed description of using FLOSS, review the documentation
 [here](doc/usage.md).

## Scripts
FLOSS also contains additional Python scripts in the [scripts](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](scripts/README.md).

## Graphical viewer
Explore `floss -j` output in the hosted [web viewer](https://mandiant.github.io/flare-floss/):
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:

    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](viewer/README.md).

## Documentation

- [doc/usage.md](doc/usage.md) — CLI usage: extraction, filtering, rendering, and environment variables
- [doc/results_document.md](doc/results_document.md) — the versioned JSON results schema
- [doc/tags.md](doc/tags.md) — the semantic tag system and its tag families
- [doc/language_specific_strings.md](doc/language_specific_strings.md) — Go and Rust string extraction
- [doc/theory.md](doc/theory.md) — the deobfuscation algorithm
- [doc/installation.md](doc/installation.md) — all installation methods
- [doc/test.md](doc/test.md) — how to build and run the test suite
- [viewer/README.md](viewer/README.md) — web viewer development

## Mailing List
Subscribe to the FLARE mailing list for community announcements by sending an email with the subject "subscribe" to [flare-external@google.com](mailto:flare-external@google.com?subject=subscribe&body=subscribe).

---

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

# FLOSS Scripts

Auxiliary scripts live under `scripts/`, grouped by purpose:

| Directory | Purpose |
|-----------|---------|
| [`disassemblers/`](disassemblers/) | Convert classic FLOSS JSON output into import scripts for Binary Ninja, Ghidra, IDA Pro, Radare2, and x64dbg; includes the IDA plugin |
| [`tags/`](tags/) | Build and maintain FLOSS tag databases (global prevalence, OSS libraries, VT feeds) |
| [`analysis/`](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/`](disassemblers/) for per-tool scripts and the [IDA plugin](disassemblers/idaplugin.py) (`File → Script file…` in IDA Pro).

Install FLOSS from source first; see [installation](../doc/installation.md).

## tags/

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

## analysis/

- [`bulk_analyze.py`](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

```
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](../../floss/tags/data/oss/readme.md): 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":["moritz.raabe@mandiant.com"],
    "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](https://github.com/mandiant/capa) rules.
    Do not edit it by hand; regenerate it with the importer from a checkout of the capa
    rules repository:

    ```
    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](https://github.com/mandiant/capa-rules/tree/805f9eaccfb6a4e1ddffc809d71d1e2b5ccc15e5)
    (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:

    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](https://vcpkg.io/en/) 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](https://github.com/williballenthin/lancelot/blob/master/bin/src/bin/jh.rs)
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](https://github.com/mandiant/flare-floss/releases/latest).
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:

    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:

    #!/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](https://git-lfs.com/).
Ensure Git LFS is installed (`git lfs install`) and that the clone has the
filters enabled, then fetch the large objects with:

    `$ 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](https://github.com/mandiant/flare-floss) and [test data](https://github.com/mandiant/flare-floss-testfiles).
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 git@github.com: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 git@github.com: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:

  - [black](https://github.com/psf/black) code formatter
  - [isort](https://pypi.org/project/isort/) code formatter
  - [mypy](https://mypy-lang.org/) type checking

We use [pre-commit](https://pre-commit.com/) so that its trivial to run the same linters & configuration locally as in CI.

Run all linters liks:
```
❯ pre-commit run --all-files
isort....................................................................Passed
black....................................................................Passed
mypy.....................................................................Passed
```

Or run a single linter like:
```
❯ pre-commit run --all-files isort
isort....................................................................Passed
```

Importantly, you can configure pre-commit to run automatically before every commit by running:
```
❯ 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:

    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:

    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/`](../scripts/README.md) and the [web viewer](../viewer/README.md). The
model is defined in [`floss/results.py`](../floss/results.py).

## Loading

The format is self-describing: run

```
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:

```
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/`](../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](usage.md#filtering-arguments)).

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](../scripts/tags/README.md). Per-database notes sit next
to the data under [floss/tags/data/](../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:

```
#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/`](../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](installation.md#step-1-check-out-source-code).

---

### Doc Test (`doc/test.md`)

# FLARE Obfuscated String Solver

## Testing

We use [pytest](http://pytest.org/latest/usage.html) 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:

    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](installation.md#step-3-install-development-and-testing-dependencies)),
then run:

    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](../.github/workflows/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](https://github.com/mandiant/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](https://github.com/tpoechtrager/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:

    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](https://github.com/mandiant/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](language_specific_strings.md) doc, the
[tags](tags.md) doc, and the layout-aware static strings feature list in the
[README](../README.md).

---

### 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)

    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](#shellcode) 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.

    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.

    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.

    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](#tags) section and [layout-aware static strings](../README.md#layout-aware-static-strings)
in the README).

Filtering by binary section:

    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.):

    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:

    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](#tags) section); `--no-tag` drops them. Run `--summary` to see the tags
present in a specific sample.

Convenience shortcuts:

    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:

    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

    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](../README.md) 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](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.

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

The easiest way to explore this output is the hosted
[web viewer](https://mandiant.github.io/flare-floss/): upload the JSON file, then
filter by tag, structure, or search term, and copy the strings you keep. See
[results_document.md](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.

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

The report is a copy of the [web viewer](https://mandiant.github.io/flare-floss/)
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:

    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.

    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.

    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.

     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

    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 `--`.

    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.

    floss --print-completion bash

Install the output for your shell:

bash:

    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):

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

fish:

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

Then restart your shell or start a new one.


## <a name="shellcode"></a>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.

    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 ---
- Files Extracted: 15
- Estimated Token Budget: ~16648 tokens
- Canonical Reference: https://codewiki.google/github.com/mandiant/flare-floss
