Skip to content

Output and Reports

Ryan edited this page Jul 18, 2026 · 1 revision

Output and Reports

This page explains what RE-Toolkit produces, how the output tree is organized, the structure of _summary.json, how severity is computed, and how to read a report.

Contents

Output tree

Each target gets its own directory under the output root, with per-stage subdirectories named to match the stage that produced them.

out/
├── index.html                  Codebase-wide index across all targets
├── _run.json                   Run manifest and toolchain versions
├── _similarity-matrix.json     Cross-target similarity, when applicable
└── target.exe/
    ├── _input/                 Sandboxed copy of the original
    ├── 00-triage/              Identity, hashes, entropy, signatures
    ├── 10-pe/                  PE structure
    ├── 12-lief/                Format-agnostic structural parse
    ├── 20-dotnet/              IL disassembly and decompilation
    ├── 22-de4dot/              Deobfuscation output
    ├── 30-ghidra/              Ghidra headless dump
    ├── 40-r2/                  radare2 analysis
    ├── 42-rizin/               rizin analysis
    ├── 80-iocs/                Extracted and classified indicators
    ├── 81-fuzzyhash/           Fuzzy hashes for similarity comparison
    ├── 89-viz/                 Inline SVG visualizations
    ├── 90-logs/                Per-tool logs and the run ledger
    ├── _summary.json           Structured findings, the source of truth
    ├── _verdict.txt            One-line human-readable verdict
    └── _report.html            Self-contained tabbed report

Which subdirectories appear depends on the detected type. An ELF target has no 20-dotnet/, and a PDF has neither. Subdirectory numbering matches the stage that produced it, so output is traceable back to a specific stage file.

The directory layout mirrors the input by default only when --preserve-tree is passed. Otherwise every target gets a flat subdirectory under the output root.

Per-target artifacts

Three files matter most, and they have a strict relationship.

File Role
_summary.json The authoritative structured findings
_report.html A rendering of _summary.json
_verdict.txt A one-line verdict for scripting and quick review

_summary.json is the source of truth. The report presents it and is never independent of it, so any disagreement between the two is a report bug rather than an analysis discrepancy. When automating, read the JSON.

90-logs/ holds the per-tool logs and the run ledger. When a tool produced no findings, this is where you determine whether it ran and found nothing, was skipped, timed out, or failed. That distinction is not visible from the presence or absence of output files alone.

Run-level artifacts

File Contents
index.html Every target with its verdict and score, linked to its report
_run.json What was analyzed, with which toolchain versions, and when
_similarity-matrix.json Pairwise similarity across targets

_run.json records the resolved version of every tool used. This is what makes a result reproducible: rerunning months later against a different toolchain can produce different findings, and the manifest is how you detect that rather than being surprised by it.

Similarity output only appears for multi-target runs, since a single binary has nothing to be compared against. It is computed from the fuzzy hashes each target contributed, which is why per-target hashing has to complete before any comparison can happen.

The summary schema

_summary.json is a single object whose top-level keys group findings by source. Keys present depend on the target type and which stages ran.

Key Contents
_meta Schema version, generation timestamp, target path, output path
file Name, size, type, hashes
entropy Overall and per-section entropy
die, trid Packer, compiler, and file-type fingerprints
yara_hits, clamav_hits Signature matches
capa, capability_matrix Detected capabilities and MITRE ATT&CK mapping
strings_stats String extraction statistics
iocs Extracted indicators with classification
pe, dotnet PE structure and managed-code detail
macho, wasm, pyc, jar, pdf, ole Format-specific findings
apk, manifest, dex, apksig Android findings
mitigations Hardening posture, for example canary, NX, PIE
authenticode, authenticode_chain Signature validation
ghidra Function inventory, decompilation, cross-references
code_structure, function_purpose, data_flow Structural characterization
obfuscator_unified Detected obfuscator across all detection sources
fuzzy_hashes ssdeep and TLSH digests
crypto_keys Recovered cryptographic material
go_info, rust_info Runtime-specific findings
dynamic Dynamic tier results, when dynamic analysis ran
viz Visualization metadata

_meta.version is the schema version and is intentionally distinct from the RE-Toolkit release version. A consumer should key on the schema version when deciding how to parse, not on the tool version.

Absent keys and empty keys mean different things. An absent key means the stage did not run. A present key with empty contents means the stage ran and found nothing. Consumers should distinguish the two rather than treating both as "no findings".

Severity and scoring

Severity comes from a weighted, explainable model. Each contributing signal is recorded as a named tuple:

Field Meaning
name Stable identifier for the signal
weight Points contributed to the total
evidence The specific observation supporting it

The total maps to a band:

Band Score
Critical 100 and above
High 60 to 99
Medium 30 to 59
Low 10 to 29
Informational Below 10

Two behaviors matter more than the thresholds.

Related signals do not compound. When a composite indicator fires, the narrower signals it subsumes are suppressed, so one underlying observation cannot inflate a score by being counted several ways. Without this, a packed binary would accumulate points from entropy, packer detection, section characteristics, and import scarcity, all describing a single fact.

Evidence is ordered by weight. The explanation of a verdict leads with what drove it, not with whichever check happened to run first.

A score is a triage aid, not a verdict on intent. A high score means several weighted indicators fired and the evidence list says which. A legitimate packed commercial application and a packed malware sample can score similarly, because the observable properties overlap. Read the evidence, not just the band.

Reading a report

_report.html is a tabbed document. A productive order to read it:

  1. The verdict banner. The score, the band, and the top contributing signals. If the evidence list explains the score to your satisfaction, you may be done.
  2. Capabilities. What the binary can do, mapped to ATT&CK techniques. This is usually the fastest route to understanding intent.
  3. Indicators. Behavioral indicators are listed first; infrastructure indicators are tagged separately, because a certificate authority hostname is not evidence of malicious behavior in the way a hardcoded command-and-control address is.
  4. Structure. Sections, imports, and hardening posture, for how the binary is built and what it links against.
  5. Code. Decompilation and function inventory, when you need to read the logic itself.
  6. Tool coverage. Which tools ran, were skipped, timed out, or failed. Check this before concluding that a quiet result means a clean binary.

That last step is the one most often skipped and most often decisive. An absence of findings from a stage that never ran is not evidence of anything.

Visualizations

Visualizations are rendered as inline SVG under 89-viz/, each independently viewable and also embedded in the report:

Visualization Shows
Section treemap Relative section sizes and entropy
Imports chart Imported libraries and their function counts
capa and ATT&CK heatmap Detected capabilities against the ATT&CK matrix
IOC distribution Indicator counts by category
Severity contribution How each signal contributed to the score
Dynamic behavior Observed behavior, when dynamic analysis ran
Graphs Call graph and control-flow graph

Missing input degrades to an empty visualization with explanatory text rather than failing the stage, so a partial run still produces a readable report.

Working with the JSON

_summary.json is designed for programmatic consumption.

# Verdict and score for one target
jq -r '.file.name, ._meta.version' out/target.exe/_summary.json

# Every target above a score threshold
for f in out/*/_summary.json; do
  jq -r 'select(.score >= 60) | .file.name' "$f" 2>/dev/null
done

# Collect behavioral indicators across a run
jq -r '.iocs[]? | select(.ioc_class != "infrastructure") | .value' \
    out/*/_summary.json | sort -u

When writing a consumer, treat unknown keys as forward compatibility rather than error, and check _meta.version before assuming a structure.

Self-contained by design

Reports and visualizations use inline SVG and inline styling. There are no external stylesheets, no content delivery network references, and no JavaScript libraries fetched at view time.

This is deliberate for two reasons. Analysts frequently work on isolated networks, and a report that only renders with internet access is a report that fails where it is needed most. It also means opening a report generates no outbound network traffic, so the act of reviewing a sample cannot signal that analysis is underway.

A report can be copied to another machine, attached to a ticket, or archived, and it will render identically years later.

Clone this wiki locally