FLOSS Version 2.0
The FLARE Obfuscated String Solver (FLOSS) has been supporting analysts to extract hidden strings from malware samples for many years now. Over the last few months, we’ve added new functionality and improved the tool’s performance. In this blog post we will share exciting new features and improvements including a new string deobfuscation technique, simplified tool usage, and much faster result output. We’ve also updated the FLOSS logo:
Reminder: FLOSS extracts strings from malware
FLOSS analyzes compiled programs, identifies functions that may decode data, and automatically deobfuscates hidden strings. Initially, FLOSS extracted three major string types: static strings included verbatim, encoded strings decoded by dedicated functions, and stack strings constructed piecemeal. For more background, or a refresher on FLOSS, please review our original blog post.
With this new release, we’ve taught FLOSS how to decode a whole new class of obfuscated strings...
New string deobfuscation: tight strings
With our newest update, FLOSS handles an additional string obfuscation technique that we call “tight strings”. Tight strings are a combination of stackstrings and encoded strings. Like stackstrings, a tight string consists of individual bytes that get constructed on the stack at runtime. And like an encoded string, these bytes are decoded before their usage. This decoding often happens in a tight loop, a short code sequence that repeats many times, hence the name tight strings. Kudos to Blaine Stancill for the tight name and the core algorithm.
We were motivated to add support for tight strings due to their prevalence in malware families such as KEGTAP, BEERBOT, and ANCHOR that we encountered dozens of times during 2021. We wonder if FLOSS’s success at decoding obfuscated strings encouraged the malware authors’ development of tight strings. It should also be noted that tight strings may be purposefully included in a binary via inlined string decoding routines, such as those provided by the ADVobfuscator project.
Figure 1 shows an example of a tight string in the malware sample with MD5 hash 9a16a348d3f4e7da3e8746667624115f and SHA256 hash 2065157b834e1116abdd5d67167c77c6348361e04a8085aa382909500f1bbe69.
After storing the obfuscated string bytes (0x6D, 0x28, 0x46, …) into consecutive stack offsets (var_630, var_62F, var_62E, …) in the top block, the malware executes the second block repeatedly to decode the data.
Figure 2 shows the decompilation of these two blocks. It’s debatable whether a visit to the dentist or reverse engineering this statically is more fun. Luckily, FLOSS can now save you from both! Like our existing algorithms, we emulate over identified program parts. FLOSS constructs the obfuscated data on a virtual stack and decodes the data by emulating the tight loop, extracting strings from the virtual stack once the loop ends.
In this example, FLOSS recovers the string
InternetReadFile that the malware uses to dynamically resolve the corresponding Windows API function. Figure 3 shows FLOSS’ verbose output of the recovered string.
Besides adding a new string deobfuscation algorithm, we’ve made the existing identification and emulation algorithms more reliable and performant. FLOSS results now include fewer false positive deobfuscated strings. This means that you’ll be distracted by junk output less often when running the new version of FLOSS. To facilitate this, we added library function recognition via FLIRT signatures and improved the string filtering and sanitization methods.
Faster emulation and shortcutting emulation of functions that don’t decode strings significantly boost FLOSS’ overall runtime. During testing we’ve noticed an average speed up of 47%! This means you can process malware more quickly, especially as part of a large-scale processing pipeline. Earlier versions of FLOSS only provided results after complete analysis. As shown in Figure 4 the updated tool now provides decoded strings as they are uncovered and indicates the analysis progress. We find this makes the tool feel more responsive: we get a good sense for if it’s working right away and tend to have more patience (or perhaps just an obsession watching progress bars complete).
Finally, we’ve added more API emulation hooks and updated the emulation engine as well as the underlying analysis framework. Combining all our improvements means FLOSS can now emulate more malware samples than before!
Improved FLOSS usage and results output
For FLOSS users, the new version significantly simplifies the command-line arguments. To extract all strings, you simply run FLOSS like before:
$ floss malware.exe
When you know you don’t care about a class of strings, such as if you want to ignore static strings and focus only on obfuscated strings, you can now use the
--no argument, e.g., to not extract static strings:
$ floss malware.exe --no static
To focus on specific string type(s) you want to extract, use the
$ floss malware.exe --only tight decoded
Figure 5 shows an example of the new FLOSS results output. Prior FLOSS versions did not successfully decode any strings from this file.
Please consult the help via
floss -h to see all available options.
FLOSS API and integration
We’ve migrated FLOSS from Python 2 to Python 3 (finally!). This brings FLOSS up to speed with most other modern Python projects and enables additional performance improvements.
If you use FLOSS as a module in a larger project, please be aware that many APIs have changed, and that you will likely need to update your tools accordingly. To ease the integration and interoperability with other tools, all FLOSS results can easily be exported to a JSON document via the -j argument. This way you can trivially run FLOSS as a subprocess from any programming language and programmatically manipulate the results.
Call to FLOSS and thank you
Thanks to the community for the continuous support, bug reports, and feature requests. Dozens of people have contributed to FLOSS over the years. We hope you find the updates useful and look forward to hearing from you at https://github.com/mandiant/flare-floss/issues. You can find all FLOSS releases at https://github.com/mandiant/flare-floss/releases and the source code at https://github.com/mandiant/flare-floss.