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:
- static strings: "regular" ASCII and UTF-16LE strings
- stack strings: strings constructed on the stack at run-time
- tight strings: a special form of stack strings, decoded on the stack
- 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:
- Go
- 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.
$ floss sample.exe
$ floss sample.exe -jFeatures:
- 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:
$ floss malware.exeOnly extract stack and tight strings:
$ floss --string-type stack tight -- suspicious.exeDo not extract static strings:
$ floss --no-string-type static -- backdoor.exeDisplay the help/usage screens:
$ floss -h # show all supported argumentsEnable 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:
floss --html malware.exe > report.htmlYou can also build the viewer yourself into a single, self-contained offline HTML
file, see viewer/README.md.
Documentation
- doc/usage.md โ CLI usage: extraction, filtering, rendering, and environment variables
- doc/results_document.md โ the versioned JSON results schema
- doc/tags.md โ the semantic tag system and its tag families
- doc/language_specific_strings.md โ Go and Rust string extraction
- doc/theory.md โ the deobfuscation algorithm
- doc/installation.md โ all installation methods
- doc/test.md โ how to build and run the test suite
- 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 [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.
- Run a render script, redirecting stdout to a file.
- Import or run the generated artifact in the target tool.
Example (Ghidra):
$ python render-ghidra-import-script.py results.json > apply_floss.pySee 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โ runflossover 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
flossJSON 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--htmlfills this from the builtdist/index.htmltemplate so the report opens with results already loaded. Leave itnullfor the hosted viewer and the Download-viewer copy.
Development
To set up the development environment, first install the dependencies:
npm installThen, run the development server:
npm run devThis 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:
npm run lint
npm run buildThis 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)
Extract raw strings from PEs:
console$ python scripts/tags/extract_strings.py C:\Windows outdirGenerate the global-prevalence database from extracted JSON:
console$ python scripts/tags/generate_gp_db.py outdir gp.jsonl.gz --type nativeInstall the result at
floss/tags/data/gp/gp.jsonl.gz(and related hash files).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.
$ python scripts/tags/build_oss_db.py --libraries zlib curl --output-dir floss/tags/data/ossVirusTotal 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).
$ python scripts/tags/fetch_vt_hashes.py 202305010000 202305020000Overview (`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:
{
"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:textpython floss/tags/data/expert/import_from_capa.py ~/code/capa/rules/ > floss/tags/data/expert/capa.jsonlThe importer needs Python 3.10+ with capa 7 or newer, msgspec and FLOSS importable
(for examplePYTHONPATH=.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 ofcapa.jsonlto prevent false positives. Each entry hastype,valueand an
optionalmodifierskey (missing means""). A rule is skipped only if itstype,valueandmodifiersare all equal to an entry; an entry withoutmodifierstherefore does not match a rule withmodifiers: "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:
{
"type":"metadata",
"version":"1.0",
"timestamp":"2023-05-11T12:49:35.328896",
"note":null
}The subsequent lines look like:
{
"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: nullThe 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:
- build static libraries via vcpkg
- extract features via jh
- convert to JSONL format with
jh_to_oss.py - 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):
PS > C:\vcpkg\vcpkg.exe install --triplet x64-windows-static zlibWhy 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:
x64-windows-static,msvc143,bzip2,1.0.8#3,release,CMakeFiles/bz2.dir/bzlib.c.obj,BZ2_bzBuffToBuffCompress,number,0x00000100For example, to invoke jh:
$ ~/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.csvConvert to OSS database format
We use the script jh_to_oss.py to convert these CSV lines into JSONL file prepared for FLOSS:
$ python3 jh_to_oss.py zlib.csv > zlib.jsonlThese files are then gzip'd:
$ gzip -c zlib.jsonl > zlib.jsonl.gzThe 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:
xattr -d com.apple.quarantine ./flossMethod 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 ofsys.argv[1:].floss.pipeline.analyze(options)โ run the full analysis pipeline and return afloss.results.ResultDocument. You must build afloss.pipeline.Options
object (sample path,min_length, anAnalysisconfig, 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 underfloss.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.
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 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:
โฏ pre-commit run --all-files
isort....................................................................Passed
black....................................................................Passed
mypy.....................................................................PassedOr run a single linter like:
โฏ pre-commit run --all-files isort
isort....................................................................PassedImportantly, 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-pushThis 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 pyinstallerBuild standalone executable:
$ pyinstaller .github/pyinstaller/floss.specDistribute 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:
- 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.
- Identify the longest continuous sequence of monotonically increasing string lengths to find the string blob.
- Use the byte sequence
00 00 00 00as a delimiter to accurately mark the boundaries of the string blob. - Extract the string blob located between the identified boundaries.
- 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-L825Rust 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:
- Extract all UTF-8 encoded strings
- Analyze data and code references to identify substring boundaries
- 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.rsDoc 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 underscripts/ and the web viewer. The
model is defined in floss/results.py.
Loading
The format is self-describing: run
floss sample.exe -j > sample.jsonand 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 --summaryScripts can load and validate a document programmatically:
from floss.results import ResultDocument
doc = ResultDocument.parse_file(path)layout, analysis, and strings are always present (possibly empty); themetadata 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
{
"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,sha256versionโ 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 lengthlanguage,language_version,language_selectedโ Go/Rust identificationruntimeโ 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_tagsfunctionsโdiscovered,library, and per-stage counts such asanalyzed_decoded_stringsanddecoding_function_scores
strings groups the results by extraction technique:
static_stringsโ plain ASCII/UTF-16LE stringsstack_stringsโ strings constructed on the stack at run timetight_stringsโ a special form of stack strings decoded in a tight loopdecoded_stringsโ strings decoded in a functionlanguage_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:
{
"name": ".rdata",
"offset": 1890752,
"length": 1476336,
"strings": [
{
"string": "open",
"offset": 1906840,
"size": 4,
"encoding": "ASCII",
"tags": ["#winapi"],
"structure": "import table"
}
],
"children": [ { "...": "..." } ]
}nameis 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'sstructurefield.offset/lengthgive the node's byte range; each string records itsoffset,size,encoding,taglist, and thestructureit lives in.structureis the name of the file format structure that contains the string,
such asimport table(which includes delay-load imports),export table,section header, orstring table. It is the empty string"", nevernull, 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 theflare-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 infloss/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/:
gp.pyโ global-prevalence (#common,#code-junk) and hashesoss.pyโ open-source library membershipwinapi.pyโ Windows API usageexpert.pyโ expert/capa rules (#capa), plus an optional#decodedmarker
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:
pip install pytestRunning 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:
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:
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 installYou 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/templatetotests/data/src/decode-rot-13. - Update the
test.ymldocument 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 totest-decode-rot-13. - Move the file
template.ctodecode-rot-13.cand 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."
cdtotests/data/src/decode-rot-13and runmake 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
- Analyze control flow of malware to identify functions, basic blocks, etc.
- Use heuristics to find potential decoding routines
- Brute force emulate all code paths among basic blocks and functions
- Snapshot emulator state (registers, memory) at appropriate points
- Extract arguments to decoder functions from emulator snapshots
- Emulate decoder functions using extracted arguments and emulator state
- Diff memory state from before and after decoder emulation
- 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)
floss.exe malware.exeThe 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.
floss.exe --no-string-type static -- malware.exeSince --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.exeEnable 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.exePlease 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:
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.exeStructure 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 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--interestingdrops 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 REGEXkeeps only strings matching the given regular expression(s).
Repeatable; patterns are ORed.--max-strings Ncaps the emitted strings per section to the topNby
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--plainrenders a flat list of strings, one per line, without layout context
or tags. Use it when piping output into line-oriented tools like grep.--summaryemits 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 aretags,offset,structure,encoding;
the default istagsandoffset.
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-fileallows 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 PATHspecifies a.sig/.patfile (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/--debugenables 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.
floss.exe -j malware.exe > malware_strings.jsonThe 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.
floss.exe --html malware.exe > malware_strings.htmlThe 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:
floss.exe --html malware_strings.json > malware_strings.htmlLoad 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.jsonVerbose 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.exeQuiet 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.exeMinimum 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.exeDecoding 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.exeInstall/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 bashInstall 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' >> ~/.bashrczsh (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/_flossfish:
mkdir -p ~/.config/fish/completions
floss --print-completion fish > ~/.config/fish/completions/floss.fishThen 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.
floss -f sc32 malware.raw32
floss -f sc64 malware.raw64With --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