Skip to content
Ryan edited this page Jul 18, 2026 · 1 revision

Usage

analyze-binaries.sh is the run-time driver. It detects each target's type, dispatches it through the applicable analysis stages, and produces structured JSON plus a self-contained HTML report.

Contents

Basic usage

analyze-binaries.sh -t TARGET -o OUTPUT_DIR [options]

A single binary:

analyze-binaries.sh -t suspicious.exe -o ./out

A directory, recursed fully:

analyze-binaries.sh -t ./samples -o ./out

Several targets at once:

analyze-binaries.sh -t first.exe second.dll third.elf -o ./out

Results open from the codebase index:

xdg-open ./out/index.html

Static analysis is the default. Nothing executes the target unless you explicitly enable a dynamic tier that requires it.

Target and output options

Option Default Purpose
-t, --target FILE... Required Files, globs, or directories. Directories are recursed fully.
-o, --output DIR ./re-analysis-out Output root
--max-depth N Unlimited Limit directory recursion depth
--include-ext EXT[,EXT] All files Allowlist extensions during the directory walk
--exclude-ext EXT[,EXT] None Denylist extensions. Applied after --include-ext.
--preserve-tree Flat layout Mirror the input directory layout under the output root
--overwrite Skip analyzed Re-analyze targets that already have output

-t consumes tokens until the next flag, so -- can be used to mark the end of a target list explicitly:

analyze-binaries.sh -t a.exe b.exe -- -o ./out

By default an already-analyzed target is skipped, which is detected from its recorded hash. That makes re-running against a large tree cheap: only new or changed targets are processed. Use --overwrite to force reanalysis.

Extension filtering happens during the directory walk, before type detection. Without it, every file under the target directory is enumerated and type detection filters at dispatch time. On a large mixed tree, filtering first is considerably faster:

analyze-binaries.sh -t ./firmware -o ./out --include-ext=exe,dll,sys
analyze-binaries.sh -t ./drop -o ./out --exclude-ext=txt,log,md

Performance and timeouts

Option Default Purpose
-j, --parallel N 1 Parallel workers, one target each
--tool-timeout SEC 600 Per-tool timeout
--angr-timeout SEC 600 angr stage timeout
--yargen-timeout SEC 600 yarGen stage timeout
-T, --ghidra-timeout SEC 3600 Ghidra per-file timeout
-H, --jvm-heap SIZE 4G Ghidra JVM heap

Each parallel worker takes one target end to end, so parallelism helps batches rather than a single large binary. Four workers is a reasonable balance on most hosts. Keep it at 1 for deterministic, readable output during interactive review.

Raise --tool-timeout for large or heavily obfuscated targets, where a tool that would eventually succeed is otherwise killed partway:

analyze-binaries.sh -t large.exe -o ./out --tool-timeout 1800 -H 8G

Ghidra options

Option Default Purpose
-g, --ghidra DIR /opt/ghidra Override the Ghidra install path
-T, --ghidra-timeout SEC 3600 Per-file analysis timeout
-H, --jvm-heap SIZE 4G JVM heap, for example 8G or 1024M
--keep-project Cleaned up Keep Ghidra project directories after analysis
--force-jython Auto-detect Use plain analyzeHeadless instead of PyGhidra
--script FILE GhidraDump.py Override the postscript location
--no-ghidra Enabled Skip Ghidra entirely

Ghidra is usually the slowest stage. --no-ghidra is the single most effective option when triaging quickly, at the cost of the function inventory, decompilation, and cross-reference data that several summary features depend on.

--keep-project is useful when you intend to open the target in the Ghidra GUI afterward, since the analysis work is already done.

Disabling stages

Every --no-* option disables a stage or tool. A disabled stage is recorded as skipped, so the report distinguishes "did not run" from "ran and found nothing", which matters when interpreting an absence of findings.

Cross-format:

Option Skips
--no-ghidra Ghidra entirely
--no-ghidra-dotnet Ghidra for .NET targets only
--no-dotnet .NET disassembly and decompilation
--no-de4dot .NET deobfuscation
--no-capa capa capability detection
--no-floss FLOSS string extraction
--no-clamav ClamAV scanning
--no-yara YARA matching
--no-r2 radare2 and rizin
--no-bulk bulk_extractor
--no-viz Visualization rendering

PE-specific: --no-manalyze, --no-peframe, --no-signsrch, --no-oldrod, --no-dnspy-ex, --no-authenticode.

ELF-specific: --no-elf-extras disables the whole extras group, or disable them individually with --no-checksec, --no-scanelf, --no-dumpelf, --no-pahole, --no-bloaty, --no-nm-demangled.

Format pipelines: --no-macho, --no-wasm, --no-pyc, --no-jar, --no-pdf, --no-ole, --no-apk, --no-dex, --no-axml, --no-apksig.

Cross-cutting: --no-fuzzyhash, --no-cryptokeys, --no-go-detect, --no-rust-detect.

The complete mapping of options to stages is in Stage Reference.

Opt-in stages

These are off by default because each is slow, situational, or both.

Option Enables Notes
--enable-cwe-checker Static CWE detection Requires --with-cwe-checker at install time
--enable-angr angr CFGFast recovery Slow on large binaries; cap with --angr-timeout
--enable-yargen YARA rule generation For building detection rules from a known-bad sample
--deep-analysis Deeper radare2 and rizin analysis Uses aaaa rather than aaa; slower
--use-nofuserex NoFuserEx deobfuscation Alternative to the default ConfuserEx chain

--deep-analysis is worth the cost on heavily obfuscated targets, where the default analysis depth leaves functions unresolved.

Comparing binaries

analyze-binaries.sh -t patched.exe -o ./out --diff-against original.exe

One option drives two complementary perspectives: a structural diff comparing functions, imports, and strings, and a byte-level diff with offset detail. The structural view answers what changed semantically; the byte view answers exactly where.

This is the standard approach for patch analysis, for confirming whether two samples are variants of one family, and for identifying what a packer modified.

Dynamic analysis

Dynamic analysis adds execution-based stages on top of static analysis. It never replaces it, and there is no dynamic-only mode: static analysis produces the strings, imports, signatures, and indicators that dynamic stages cross-reference.

# Tier 1 only, no real execution
analyze-binaries.sh -t sample.exe -o ./out --dynamic

# Every applicable tier, including those that execute the target
analyze-binaries.sh -t sample.elf -o ./out --dynamic --allow-real-execution
Option Default Purpose
--dynamic Off Enable dynamic analysis in auto-tier mode
--dynamic-auto Explicit alias for --dynamic
--dynamic-mode MODE Auto Run exactly one tier: qiling, firejail, docker, or cuckoo
--dynamic-timeout SEC 60 Hard timeout per binary
--dynamic-network MODE none none, tap, or host
--allow-real-execution Off Required for every tier above Tier 1
--no-dynamic-qiling and similar Skip an individual tier

With --dynamic alone, every applicable and available tier runs and each reports its own status. Without --allow-real-execution, only Tier 1 runs, because it is the only tier that does not execute the target.

Read Dynamic Analysis before using --allow-real-execution.

Rules and knowledge base

Option Default Purpose
--yara-rules DIR|FILE $YARA_RULES or /opt/yara-rules/_master.yar YARA rules
--capa-rules DIR $CAPA_RULES or /opt/capa-rules capa rules

The installer exports both environment variables system-wide, so these options are only needed to override the defaults with your own rule sets:

analyze-binaries.sh -t sample.exe -o ./out --yara-rules ~/rules/custom.yar

Logging

Option Default Purpose
-v, --verbose Off Verbose output
--log-level LEVEL info debug, info, warn, or error
--log-file FILE Per-run file Override the log file location
-V, --version Print the version and exit
-h, --help Print help and exit

Each level emits its own messages and all higher-priority ones. Use --log-level=debug when diagnosing why a stage skipped, since the skip reason is logged at debug level.

Worked examples

Fast triage of an unknown sample. Skip the slowest stage to get a verdict quickly, then follow up with a full run if the result warrants it.

analyze-binaries.sh -t unknown.bin -o ./triage --no-ghidra --tool-timeout 120

Full-depth analysis of a confirmed sample.

analyze-binaries.sh -t malware.exe -o ./deep \
    --deep-analysis --enable-angr -H 8G --tool-timeout 1800

Batch processing a sample collection. Parallel workers, mirrored directory layout, and extension filtering.

analyze-binaries.sh -t ./collection -o ./results \
    -j 4 --preserve-tree --include-ext=exe,dll

Patch analysis.

analyze-binaries.sh -t patched.exe -o ./diff --diff-against baseline.exe

Building a detection rule from a known-bad sample.

analyze-binaries.sh -t known-bad.exe -o ./rulegen \
    --enable-yargen --yargen-timeout 1200

Analyzing an Android application.

analyze-binaries.sh -t app.apk -o ./android

The APK pipeline extracts the container, decodes the manifest, verifies the signature, and decompiles the DEX through several engines. No extra options are needed: type detection routes it automatically.

Full dynamic analysis in an isolated VM.

analyze-binaries.sh -t sample.exe -o ./dyn \
    --dynamic --allow-real-execution --dynamic-timeout 120 --dynamic-network none

Only do this inside a disposable virtual machine with no network path to anything you value. See Security Model.

Full option index

Run analyze-binaries.sh --help for the authoritative reference generated from the driver itself. That output is always correct for the version installed, which this page cannot guarantee across releases.

For how each option maps to a stage, see Stage Reference. For environment variables and persistent configuration, see Configuration.

Clone this wiki locally