Extract readable strings out of a game binary, without the usual flood of hashes, padding, and one-off symbol fragments strings.exe/GNU strings leave behind.
Reads PE, ELF and Mach-O binaries directly (no OS-specific APIs to load them), pulls candidate strings out of the sections that actually hold them, drops the non-string bytes that look like text (import names, relocation targets, unwind data), demangles the C++ symbols that survive, and prints the result sorted and deduplicated.
- Format-aware section scanning - PE (
.data/.rdata, falls back to.text), ELF (.dynstr,.rodata,.rodata.str*,.data,.strtab, ...), Mach-O (__cstring,__const,__data, ...). No dependency on the host OS matching the binary's format - a.socan be scanned from Windows and vice versa. - Symbol filtering - strings of 10 characters or fewer that are mostly symbols are dropped. printf conversions such as
%sor%-5.2fcount as letters, so short format strings are kept. - Fragment filtering - in data sections a string must be followed by a NUL byte (or the end of the section, or a UTF-8 character). This drops chunks of tables, pointers and serialized protobuf descriptors that only look like text.
- C++ demangling - both Itanium (
_Z...) and MSVC (?...,.?AV...) manglings, including the RTTI-only forms compilers emit without the usual mangling prefix, MSVC's array/pointer type descriptors, and nested lambda/local-class names. - Sorted, deduplicated output - one string per line, alphabetical, no repeats.
- Parallel multi-binary processing - pass several binaries at once and they're scanned concurrently, one worker per binary, each written to its own
<binary>.txt.
Grab an archive from the latest release:
| Archive | Needs .NET installed? | Use when |
|---|---|---|
strings-win-x64.zip |
No | Windows, just run it |
strings-linux-x64.zip |
No | Linux, just run it |
strings-win-x64-portable.zip |
.NET 10 runtime | Windows, smaller download |
strings-linux-x64-portable.zip |
.NET 10 runtime | Linux, smaller download |
Those links always resolve to the newest stable release. On Linux, chmod +x strings after unzipping.
strings --binary=<path|glob>[,<path|glob>...] [options]
Results are written to <binary-filename-without-extension>.txt (one file per binary, next to each other) - not printed to stdout. Pass multiple binaries (comma-separated, or repeat --binary) and they're processed in parallel, one thread per binary. --binary also accepts glob patterns (*.dll, bin/**/*.so, ...) which get expanded to every matching file. While a binary is being scanned, the console prints its live throughput (strings/s) every half-second; as soon as a binary finishes, its output path and final string count are printed immediately - it doesn't wait for the others.
| Flag | Description |
|---|---|
--binary=<path|glob> |
Path(s)/glob(s) of the binaries to parse (required); comma-separated or repeat the flag, processed in parallel |
--target=<type> |
Binary format: pe, elf, or macho - auto-detected from magic bytes if omitted |
--demangle=<bool> |
Demangle C++ symbols (default true) |
--min-length=<n> |
Minimum string length to keep (default 3) |
--sym-length=<n> |
Strings at or under this length are dropped if they're majority non-alphanumeric (default 10) |
--terminated=<bool> |
Drop text-like fragments not followed by a NUL byte (default true; set false for Go/Rust binaries, whose strings are not NUL-terminated) |
--mask-protobufs=<bool> |
Blank serialized protobuf descriptors (.proto file descriptors embedded by protoc) before extracting strings (default true) |
--print-sections |
List every section name in the binary and exit |
--output-dir=<path> |
Directory to write <binary-without-extension>.txt results to (default: current directory) |
Examples:
# Auto-detect format, demangle, write to libserver.txt
./strings --binary=libserver.so
# Multiple binaries at once, scanned in parallel, one .txt each
./strings --binary=client.dll,server.dll,libserver.so --output-dir=out
# Glob every DLL in a tree, scanned in parallel
./strings --binary='bin/**/*.dll' --output-dir=out
# Skip demangling
./strings --binary=client.dll --demangle=false
# See what sections exist before picking one to inspect further
./strings --binary=server.dll --print-sectionsRequires the .NET 10 SDK.
git clone https://github.com/Swiftly-Tracker/strings.git
cd strings
dotnet build strings.slnx -c ReleaseOutput lands in bin/Release/net10.0/.
To produce a standalone binary like the release archives:
dotnet publish strings.csproj -c Release \
-r linux-x64 --self-contained true \
-p:PublishSingleFile=true -p:PublishReadyToRun=true -p:PublishTrimmed=false \
-o out/linux-x64strings/
├── src/
│ ├── Entrypoint.cs # CLI entry point, per-format section lists, filter pipeline
│ ├── CliOptions.cs # Flag parsing
│ ├── FileReader.cs # Magic-byte format detection, dispatch, string extraction
│ ├── PeSections.cs # PE section-table reader
│ ├── PeStrings.cs # PE blanking and rewrites (imports, relocations, unwind data)
│ ├── EndRule.cs # End-of-string rule for data sections
│ ├── ElfSections.cs # ELF32/64 section-table reader
│ ├── MachOSections.cs # Mach-O32/64 section-table reader
│ └── Util.cs # Escaping, symbol-density filter, C++ demangling
- Issues: Report bugs and request features
GPL-3.0. See LICENSE.