Analyzer SDK
External analyzers are discovered from the r2inspect.analyzers Python entry
point group. A plugin may expose a BaseAnalyzer subclass or a callable that
receives the registry.
A complete minimal package is available in the external plugin example.
Analyzer class
from typing import Any
from r2inspect.abstractions.base_analyzer import BaseAnalyzer
from r2inspect.registry import AnalyzerCategory, AnalyzerSpec
class ExampleAnalyzer(BaseAnalyzer):
spec = AnalyzerSpec(
id="vendor.example",
version="1.0.0",
category=AnalyzerCategory.DETECTION,
formats=frozenset({"PE"}),
architectures=frozenset({"x86", "x86_64"}),
output_schema="vendor.example/v1",
)
def analyze(self) -> dict[str, Any]:
return {"available": True, "detected": False, "evidence": []}
Register it in the plugin package:
[project.entry-points."r2inspect.analyzers"]
example = "vendor_plugin:ExampleAnalyzer"
The loader reads AnalyzerSpec without constructing the analyzer. Classes
without a spec retain the legacy metadata-method discovery path; callable entry
points should call registry.register() with an explicit category and formats.
Constructors must accept the runtime dependencies used by the analyzer factory:
adapter, r2, config, and filepath/filename as applicable. Do not open
sessions or perform analysis at import time. Return JSON-compatible values and
preserve extraction errors as explicit unavailable/failed results.
Run the conformance suite against a class or installed entry point before publishing a plugin:
r2inspect-plugin-check vendor_plugin:ExampleAnalyzer
r2inspect-plugin-check example --sample ./fixture.exe
The second form constructs the analyzer through the production factory, runs it
against the sample, and rejects non-mapping or non-JSON output. The command emits
r2inspect.plugin-conformance/v1 JSON and exits non-zero on any failed check.
Independent backends
Backend packages can expose an independent implementation through the
r2inspect.backends entry point group. The factory receives filename plus
optional configuration and must return a BinaryInspector: analyze, close,
__enter__, and __exit__ are required and checked when the backend loads:
[project.entry-points."r2inspect.backends"]
pe-core = "vendor_pe_core:create_backend"
r2inspect --backend consensus --consensus-backend pe-core sample.bin runs
radare2 and the independent backend and preserves field-level disagreements as
backend_disagreement records instead of silently choosing a value. Each record
contains the canonical field path, both backend names and values, severity, and
status. Built-in pe-core, elf-core, and macho-core implementations provide
this independent structural view without radare2 or optional Python parsers.
Optional engines
The deep and forensic profiles run capa and FLOSS when those executables are
on PATH. Deep mode bounds FLOSS to static strings; forensic mode runs full
FLOSS extraction and preserves exact capa/FLOSS stdout in its evidence bundle.
Missing tools produce dependency_unavailable analyzer outcomes. capa rules
are exposed as report capabilities and FLOSS strings as report artifacts. Each
external-tool result records the executable path, version, SHA-256 digest, and
rule-source digest when applicable.
External commands use bounded temporary-file capture instead of pipes. The
defaults limit the captured preview to 4 MiB, each output spool to 256 MiB,
resident memory to 1 GiB, child processes to 32, CPU time to 120 seconds, and
wall time to the analyzer timeout. Override them with
R2INSPECT_CMD_MAX_OUTPUT_BYTES, R2INSPECT_CMD_MAX_SPOOL_BYTES,
R2INSPECT_CMD_MAX_MEMORY_MB, R2INSPECT_CMD_MAX_PROCESSES,
R2INSPECT_CMD_CPU_SECONDS, and R2INSPECT_CMD_TIMEOUT_SECONDS. Set
R2INSPECT_CMD_OUTPUT_DIR to relocate temporary output or
R2INSPECT_CMD_SANDBOX_PREFIX to prepend an argv-only sandbox/container
wrapper. Set R2INSPECT_CAPA_RULES to select and fingerprint a capa rules path.
Signed YARA pack directories contain manifest.json and are verified before
any rule is compiled. Use r2inspect rules build|sign|verify|install|list|update
to manage them. Installed packs carry their trusted public key; direct pack
paths require R2INSPECT_RULE_PACK_PUBLIC_KEY. Manifest entries that resolve
outside the pack directory, including symlink escapes, are rejected. The YARA
compile cache is invalidated by the verified manifest digest or by a digest of
the rule contents for unpackaged directories.