ExeRadar
Static analysis of executables: PE first, ELF and Mach-O after. Headers, imports, readable strings, code signing.
Status: PE works. Headers, sections with entropy, the import table and its categories, classified strings, the three signature paths, and reports as console, JSON or Markdown. ELF and Mach-O are recognised by their magic number and declined by name — not mistaken for an unknown format. That includes a universal ("fat") Mach-O, the ordinary shape of a shipped macOS binary, whose magic it shares with Java class files: the fat header is validated rather than guessed at, so a class file is still declined.
The design is written down first, in ARCHITECTURE.md, and the part worth reading is section 3.
Install
pip install exeradar
Python 3.11 or later.
Why section 3
A spike against Windows' own notepad.exe found that LIEF reports zero
embedded signatures for a file that Windows reports as validly signed: the
signature lives in a catalog under CatRoot, which is how most Windows system
binaries are signed and which no PE parser can see.
So signature checking has three paths, not one, and on Linux and macOS — where
the catalog cannot be consulted — the absence of an embedded signature is
reported as unknown and never as unsigned. Calling a catalog-signed
Microsoft binary unsigned would be the worst false positive this tool could
ship.
The same rule applies to the file and not only to the platform. A file that
cannot be parsed, and one whose own headers place the certificate table past the
end of it — an interrupted download — are unknown too: the signature could not
be looked for, which is not the same as finding none. Nothing is cited against
either. On Windows the catalog check itself can fail — PowerShell missing,
blocked or silent — and that is unknown as well: a file is unsigned only
when Windows was asked and answered that it is not signed.
Use
exeradar analyze FILE [--output report.json|report.md] [--online]
exeradar batch DIR [--output report.json|report.md]
exeradar verify FILE
analyze — one binary in full
$ exeradar analyze python.exe
python.exe
PE AMD64, 106,208 bytes, built 2026-08-05 10:58:33 UTC
sha256 4942b86a6597e5aee0128daa00050ed79bc21f6e709a78eb19cbfeb0c2f39ac9
version 3.14.7150.1013, written as 3.14.7
overlay 14,048 bytes past the last section, not read for strings
Signature embedded
Embedded Authenticode signature; the file matches what was signed.
signer C=US, ST=Oregon, L=Beaverton, O=Python Software Foundation, CN=Python Software Foundation
signed 2026-08-05 11:45:32 UTC
Imports 8 libraries, 44 functions — no category claimed
api-ms-win-crt-runtime-l1-1-0.dll 18
KERNEL32.dll 15
VCRUNTIME140.dll 5
api-ms-win-crt-stdio-l1-1-0.dll 2
python314.dll 1
api-ms-win-crt-math-l1-1-0.dll 1
api-ms-win-crt-locale-l1-1-0.dll 1
api-ms-win-crt-heap-l1-1-0.dll 1
Libraries none stated
A version here is one the file states about itself. A library missing from this list is not absent: a dynamically linked one
leaves an import, not a string, and some state no version at all.
Strings 1 urls, 0 ips, 0 hosts, 1 paths
url http://schemas.microsoft.com/SMI/2016/WindowsSettings
path D:\a\1\b\bin\amd64\python.pdb
section virtual raw entropy
.text 3,628 4,096 6.00
.rdata 3,942 4,096 4.27
.data 1,664 512 0.53
.pdata 348 512 3.77
.rsrc 80,928 81,408 6.17
.reloc 48 512 3.90
Findings none raised
Four things in that output are the tool refusing to overclaim.
"no category claimed" — KERNEL32.dll imports 15 functions and the
categoriser says nothing about them, because a library that every binary loads
tells you nothing about what this one does. Categories are decided from the
imported functions, not from the library name.
"Libraries none stated" — and this binary does carry a version. 3.14.7 is
in there as a bare string with nothing beside it to say what it belongs to, so it
is not reported. The same shape is also what an OID and a few bytes of debris look
like, and a number attributed to whichever library the filename suggests is a
guess with a citation attached. Four of the fifteen libraries measured while this
was written say their version that way; none of them is claimed. What is claimed
is what a file states about itself — OpenSSL 3.5.8 25 Aug 2026, libcurl/8.22.0,
inflate 1.3.1 Copyright … — plus, for a library it only imports, the name of the
DLL whose version to go and read.
One URL, not eleven — the certificate table is excluded from string extraction. Everything in there belongs to whoever signed the file: on this binary it was ten Microsoft CRL and OCSP endpoints, which describe the signer and not the program.
And that one URL is not a finding. http://schemas.microsoft.com/... is an
XML namespace out of the PE manifest, not an endpoint the program contacts. A
"plaintext endpoint" finding would fire on every Windows binary with a
manifest, so there isn't one.
--output picks its format from the extension, .json or .md, and refuses an
extension it does not know rather than guessing. The name is checked before the
scan starts, so a rejected filename never costs the work.
batch — a directory
Walks recursively and analyses every PE, chosen by magic bytes and not by extension, sorted by path so two runs stay comparable.
$ exeradar batch ./downloads
file sha256 signature findings
clean.exe 4942b86a6597 embedded 0
nested.exe 4942b86a6597 embedded 0
tampered.exe ec7e1e10899c embedded 1
3 files, 2 matching their signature, 1 with findings
With --output it writes the whole run: a JSON array, or one Markdown section
per file.
verify — a gate for a script
Reads the signature and nothing else: no hashing, no imports, no strings, so it stays fast on a large binary.
$ exeradar verify python.exe
embedded
Embedded Authenticode signature; the file matches what was signed.
signer C=US, ST=Oregon, L=Beaverton, O=Python Software Foundation, CN=Python Software Foundation
signed 2026-08-05 11:45:32 UTC
$ echo $?
0
Change one byte in the code section and the signature still parses, still names its signer, and no longer describes the file:
$ exeradar verify tampered.exe
embedded
Embedded Authenticode signature, and the file does not match what was signed (bad_digest, bad_signature).
signer C=US, ST=Oregon, L=Beaverton, O=Python Software Foundation, CN=Python Software Foundation
signed 2026-08-05 11:45:32 UTC
$ echo $?
1
The exit code carries the answer:
| Exit | Meaning |
|---|---|
0 |
signed, and the signature verifies |
1 |
not signed, or signed and the signature does not verify |
2 |
could not be determined: unreadable, truncated, not a PE, or no way to check here |
The third code is the point. Off Windows the catalog cannot be consulted, so a
file with no embedded signature may be perfectly signed and the tool cannot
tell. Returning 1 there would fail a build over a missing capability rather
than over the file; || exit still catches it.
Legal citations
law_checker maps findings to the provisions they concern — Cyber Resilience
Act, NIS2, GDPR — and cites each with the SHA-256 of the exact wording applied.
Nothing is cited that the acts do not contain: a test reads them and fails on
any reference they lack. See ARCHITECTURE.md section 4 for what is deliberately
not cited, and why.
analyze ends with the findings and, when there are any, a "Provisions applied"
section: each provision with its SHA-256 and the date of its wording, then the
notes that qualify it — the CRA applies from 11 December 2027, and binds a
manufacturer, which one file cannot establish. Nothing is downloaded unless you
ask: by default analyze cites from the local cache in ~/.exeradar
($EXERADAR_HOME), and a provision that is not cached is cited without a hash
rather than with a guess, with a line saying so. --online downloads the texts
the findings need, compares them with the cache and stores them, so the next
offline run cites them with their hash:
$ exeradar analyze tampered.exe --online # once, to fill the cache
$ exeradar analyze tampered.exe # from then on, from the cache
A clean file cites nothing and touches no network either way. The Markdown report carries the same section; the JSON carries the findings, not the citations.
Security
Report a vulnerability as described in SECURITY.md, which also gives the response times, how customers are told and how to roll back.
Every GitHub release carries CycloneDX SBOMs of the Docker image and of the Python environment, and dated Trivy reports of the image and of the repository at the tag. They are an automated scan for known vulnerabilities, not a penetration test.
For customers subject to NIS2, docs/nis2-compliance.md (in Italian) answers the seven questions a supplier of software gets asked: what the software is made of, which hosts it contacts and with what data, how it is checked before release, and what it does not have.
Part of the Radar family
Alongside apkradar, mailradar, cookieradar and patchradar.
How this is built
Developed with Claude Code, reviewed and released by maksimtech. The suite is the contract: every change lands with it green.
Licence
MIT.
Metadata
Release files for exeradar 2026.45
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| exeradar-2026.45.tar.gz | 519.3 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| exeradar-2026.45-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 610.2 kB
Release files / exeradar-2026.45.tar.gz
| Download URL | exeradar-2026.45.tar.gz |
|---|---|
| Size | 519.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
5527b103eae1330b6b78117e18b2ed3676372daa908506d02b0c2aa709143b9c
|
|
BLAKE2b-256 checksum How to use checksums |
a3cb10ce0d56a9edb4b247067f735a72388e297d5444288d8f9cb3ccf46288e2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.
Transparency logRelease files / exeradar-2026.45-py3-none-any.whl
| Download URL | exeradar-2026.45-py3-none-any.whl |
|---|---|
| Size | 90.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a5e7c0e9908cb6f55ea4486e7a69c1ccef9041093969a2dfbb5879eb40c6611f
|
|
BLAKE2b-256 checksum How to use checksums |
8232877f95a05a7648af85646bfb76b6675d0d8c9184e3f219520ccf609f6490
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.
Transparency logSecurity for exeradar 2026.45
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for exeradar-2026.45.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.