Command-line PE file identifier for Windows. Feed it a path to a .exe (or any PE image) and it prints the filename, size, MD5, image size from the optional header, and the compilation timestamp from the file header. Output goes to the console, no file is written.
Uses LIEF for PE parsing and OpenSSL EVP for the MD5. Despite the function name (ExtractStrings), it does not dump ASCII or Unicode strings from the binary. It extracts identity metadata, not string literals.
For a given PE input:
- File name
- File size in bytes
- MD5 hash (hex)
- Image size (from
OptionalHeader.SizeOfImage), printed asPcaSvc: 0x... - Compilation timestamp (from
FileHeader.TimeDateStamp), printed asDPS: !...
The PcaSvc: and DPS: prefixes are cosmetic labels used in the current build. Rename them in strings-extractor.cpp if you want plain field names.
string-extractor/
├── strings-extractor.sln
└── strings-extractor/
├── strings-extractor.cpp # main, ExtractStrings, MD5, LIEF calls
├── strings-extractor.vcxproj # x64 EXE project
├── strings-extractor.vcxproj.filters
├── strings-extractor.vcxproj.user
└── x64/
- Visual Studio 2019 or newer with the Desktop C++ workload.
- Windows 10/11 SDK.
- C++17 or newer.
- Third-party libraries (linked at build time):
| Library | Purpose |
|---|---|
| LIEF | PE header parsing |
| OpenSSL | MD5 via the EVP API |
| spdlog (optional) | Structured logging |
| fmt | String formatting |
Install these via vcpkg for the smoothest experience:
vcpkg install lief:x64-windows openssl:x64-windows spdlog:x64-windows fmt:x64-windows
vcpkg integrate installVisual Studio:
- Open
strings-extractor.sln. - Set configuration to
Release | x64. - Ensure the include and library search paths for LIEF, OpenSSL, spdlog, and fmt are visible to the project (vcpkg integration handles this automatically).
- Build the solution.
- Output:
strings-extractor/x64/Release/strings-extractor.exe.
Command line (Developer Command Prompt for VS):
msbuild strings-extractor.sln /p:Configuration=Release /p:Platform=x64strings-extractor.exe <path\to\file.exe>If no argument is supplied, the tool prints usage and exits.
Example:
strings-extractor.exe C:\Windows\System32\notepad.exeSample output:
File: notepad.exe
Size: 201216 bytes
MD5: <32 hex chars>
PcaSvc: 0x38000
DPS: !<unix_timestamp>
-
main(argc, argv)validates arguments and handsargv[1]toExtractStrings(). -
The tool opens the file, streams it through OpenSSL EVP:
EVP_MD_CTX_new()allocates a digest context.EVP_DigestInit_ex(ctx, EVP_md5(), nullptr)selects MD5.EVP_DigestUpdate()chunks in the file bytes.EVP_DigestFinal_ex()produces the 16-byte digest, which is converted to a 32-char hex string.
-
LIEF::PE::Parser::parse(peFilePath)builds aLIEF::PE::Binaryobject. -
From that object:
binary->optional_header().sizeof_image()gives the mapped image size.binary->header().time_date_stamps()gives the compile timestamp (seconds since 1970).
-
All fields print to stdout in the format shown above.
- Console-only. Redirect stdout if you want a file:
strings-extractor.exe app.exe > report.txt. - MD5 is trivially collidable. Fine as a fingerprint for triage, do not use it as an integrity primitive against a motivated adversary. Swap to SHA-256 by changing
EVP_md5()toEVP_sha256()and widening the buffer. TimeDateStampis trivially spoofable. Many packers and protectors zero it or set an arbitrary value. Cross-check against Rich header or debug directory timestamps for real forensic work.- LIEF's parser tolerates most malformed PEs and will still return a
Binary*where possible. If it returns null, the tool bails cleanly. - Works on any Windows PE image (EXE, DLL, SYS). x86, x64, and ARM64 headers all parse.
- No signature verification, no import walk, no section dump. That surface belongs in a fuller triage tool.
Common additions to bolt on top of the current entry-point:
- Real string extraction: walk each section, iterate bytes, emit runs of printable ASCII (length ≥ 4) and UTF-16LE runs.
- Section listing:
for (auto& s : binary->sections()) { ... }for name, virtual size, characteristics. - Import table dump:
binary->imports()for DLL and function names. - Authenticode summary: presence, signer common name, chain validity.
- JSON output: replace the
printf/fmt::printcalls with a serializer for scriptable use.