Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Introduction

hereticus compares two versions of a binary or firmware. It finds the functions that changed, and puts the security fix near the top.

$ hereticus before.bin after.bin

Note

Coding agents wrote much of this code.

Why hereticus

A vendor ships a security update with one line of advisory: “a memory corruption issue was fixed”. To know what the bug was, you must find the function that the update changed. This is patch diffing. Three problems make it slow:

  • The binaries are stripped. Firmware and kernels ship with no symbols, and often with no ELF header at all.
  • Everything moves. A new release moves each function and each global, so a byte diff marks almost all the code as changed.
  • The usual tools are heavy. BinDiff and Diaphora need IDA, and Ghidra Version Tracking needs a project, a GUI and an analysis of each program. None fits in a shell script or a CI job.

hereticus is one static binary. It reads the two files, pairs their functions, and prints a short list, the most likely fix first.

It finds the fix, on the first rows

On published security fixes, the fixed function is on the first rows of the report:

FixBinaryRow of the fixRows in the report
CVE-2026-30874procd, OpenWrt, stripped124
CVE-2026-35385dropbear scp, OpenWrt, stripped119
CVE-2024-23265AppleDiskImages2, iOS kernelcache133
CVE-2021-30883AppleCLCD, iOS kernelcache1333

See Real-Life Examples for all of them, each with the commands to do it again.

It shows less noise than other tools

On 35 stripped libraries, each built before and after one upstream fix:

ToolFixes foundFix on row 1Rows the fix did not touch
hereticus35200
radiff22092418
Ghidra3318629

This is a narrow test, which hereticus was developed with. See Comparison With Other Tools for how it scores each tool, and for its limits.

It finds the functions of stripped code

Before a tool can compare functions, it must find them. In one raw OpenWrt kernel, with no symbols and no sections, hereticus finds 19277 of the 20988 real function starts, and Ghidra finds 13210. The Ghidra extension adds the functions that Ghidra misses.

It is made for coding agents too

Ghidra, IDA and BinDiff are made for a person at a GUI. An agent can use them only through a server or a plugin. hereticus is one command that gives one answer, so an agent runs it as it runs grep:

  • The answer comes first. The most likely fix is on the first rows, so | head is enough, and the agent reads a few rows, not a project.
  • The output is short. --format compact gives one line for each pair, and --format json gives one object for each pair.
  • Each name works as input. The report names a stripped function sub_7630, and --diff sub_7630 shows its diff.
  • The diff reads alike on each architecture. --view il shows a compare, a call or a text in one form, as if (w0 == 0) goto ... and call strncmp, so the agent does not need to know each instruction set.
  • An error tells what to do next. With no --base, the error gives the base that the calls of the image show, where they show one. A failure exits with 2.
  • No setup. One static binary, with no IDA, Ghidra, Python, server or project. --exit-code lets a CI job or a script stop on a change.

See Use With a Coding Agent.

It reads what firmware ships

  • Architectures: A32, Thumb-2, AArch64, MIPS32, MIPS16e, x86-64 and 32-bit x86.
  • Files: ELF (also with no section headers, as sstrip leaves it), Mach-O and iOS kernelcaches, and raw flash dumps.
  • Firmware images: zImage, FIT, uImage, sysupgrade, lzma-loader and TP-Link containers, with --unpack.

Who It Is For

  • Security researchers who find the bug that an update fixed.
  • Vendors and integrators who check that a backport of a fix is in a build.
  • Malware analysts who compare two builds of one family. See Malware.

Where to Go Next

  1. Installation: get the binary.
  2. Usage: read the report, and the options.
  3. Examples: a raw firmware stub, and the diff of one function.
  4. Real-Life Examples: published fixes, step by step.
  5. Methods: how it finds and pairs the functions, and why each method is there.