INDEPENDENT RESEARCH // X86 MICROCODE[00]

REVERSETHE SILICON.

CPU microcode isn't supposed to be readable. We read it anyway.

A home for AMD low-level reversing, binary analysis, and the things hiding below the ISA. Powered by Zenella — a Binary Ninja plugin for taking AMD microcode updates apart, byte by byte.

zenella_inspect.py :: zen5c● READY
// representative structural report
➜ python3 zenella_inspect.py update.bin
0000loader_id=0x8015
0004generation=ZEN 5c
0008patch_size=0x3820
000Cmatch_regs@0x0328 [31]
0010mask_regs@0x03A4 [31]
0014op_quads@0x0420
0018uop_quad_size=36 bytes
[+] decode structure OK
[!] semantics inferred / experimental
➜
VIEW: STRUCTURE / NOT EXECUTIONBINJA + PYTHON3
SCROLL TO DISASSEMBLEAMD.RIP / 2026
01 / THE MISSION
0x0000 — ENTRY POINT

THE TOOL / ZENELLA

WE DON'T
GUESS.
WE DISASSEMBLE.

Zenella reverses AMD microcode updates inside Binary Ninja. Open a microcode .bin, run one command, and the update container is typed and labelled. K8/K10 patches (families 0x0F–0x12) have their obfuscated triads decoded and disassembled. Zen 1/2 payloads are disassembled and lifted to LLIL and HLIL. Zen 5 updates get register geometry and decoded 36-byte op-quads in Linear view.

Zen updates share a signed container: header, RSA material, options, match registers, then microcode. Earlier K8/K10 patches use a smaller 0x40-byte header-and-match-register container followed by obfuscated triads. Zenella identifies the profile from the header and applies it to the bytes in front of you.

Nothing is executed, decrypted or signed by the plugin. It defines types, data variables, symbols, and comments in your analysis database. Apply operations are one undoable transaction; a bad hypothesis costs a Ctrl + Z, not a corrupted analysis.

↳
001 / ENGINE

BINARY NINJA

Typed data, decoded structures, symbols, cross-references and graphs where supported. Work inside the analysis UI you already know.

{ }
002 / CORE

DEPENDENCY-FREE DECODERS

zenella_core.py and prezen_core.py work without Binary Ninja. The same core drives command-line inspection and JSON output.

⟲
003 / SAFETY

UNDOABLE BY DESIGN

Data-only analysis and reversible changes. Verification runs before applying a Zen 5 structural transaction.

//
004 / METHOD

INFERENCE ≠ FACT

Zen 5 field names and sequence flow come from published research and experiments. Undocumented semantics stay explicitly labelled.

02 / TARGET ARCHITECTURES
THREE ANALYSIS PATHS

GENERATIONS / BINARY FORMATS

DIFFERENT SILICON.
SAME CURIOSITY.

From scrambled K8 triads to Zen 5c op-quads. One toolkit, multiple generations of AMD update formats.

[ 0x8000 / 0x8003 ]01 — 03
K8/K10
DE-OBFUSCATION + DISASSEMBLY

Pre-Zen patches are 0x40 + 28·N bytes. Each scrambled triad holds three 64-bit micro-ops and a sequence word. Zenella de-obfuscates the triads, mirrors them into an executable patch RAM section at uc_0c00, and follows match-register handlers and branches.

28-BYTE TRIADSGHIDRA-COMPATIBLE TEXTNO LLIL
[ 0xC80 ]04 — 05
ZEN1+2
DISASSEMBLY + LLIL / HLIL

Each update has 64 instruction packages. The packages become executable code in the amd_zen1_ucode or amd_zen2_ucode architecture. Micro-ops are decoded in the ZenUtils style and lifted to LLIL, from which Binary Ninja derives MLIL and HLIL.

64 PACKAGESGRAPH VIEWHLIL

! Zen 5 micro-op encodings and operand projections are empirical inferences, not a vendor-confirmed ISA. Its sequence-ordered report is read-only and experimental.

03 / PATCH ANATOMY
STRUCTURE / OFFSETS / TYPES

HEX IS A MAP

SLICE OPEN
THE UPDATE.

Three layouts, exact offsets and structures from Zenella. Select a generation to inspect the decoded file map.

● SELECT_PATCH_FORMAT / decoded layout
0x0000ZEN 5c / LOADER 0x80150x3820
0x0000HEADER0x20
0x0020RSA SIGNATURE0x100
0x0120KEY MODULUS0x100
0x0220CHECK BLOCK0x100
0x0320OPTIONS / REVISION0x08
0x0328MATCH REGISTERS31 × u32
0x03A4MASK REGISTERS31 × u32
0x042036-BYTE OP-QUADS0x2A304 × u64 micro-ops + 1 × u32 sequence word
0x2E50ZERO PADDING0x9D0
DISPLAY: NOT TO BYTE SCALE ↳ 300 op-quads in reference updates
ZEN 5c / field breakdown
OffsetSymbol / typeBytes
0x0000amd_mc_header0x20
0x0020amd_mc_signature0x100
0x0120amd_mc_modulus0x100
0x0220amd_mc_check0x100
0x0320amd_mc_options0x04
0x0324amd_mc_rev0x04
0x0328amd_mc_match_regs0x7C
0x03A4amd_mc_mask_regs0x7C
0x0420amd_ucode_body0x2A30
0x2E50amd_mc_zero_padding0x9D0
Observed in the two reference updates: 300 op-quads (revisions 0x0B10104E and 0x0B101054). The count follows the actual zero padding. Loader 0x8010 uses a searched equal match/mask split; 0x8004 / 0x8005 use zentool's fixed tables.
04 / TOOLING & COMMANDS
PLUGINS → AMD MICROCODE

ONE MENU. MANY WAYS IN.

THE WORKFLOW
IS THE WEAPON.

All apply commands support file start for standalone updates and at cursor for firmware-embedded updates.

01 DEFAULT

AUTO-DETECT AND APPLY

Reads the header, picks K8/K10, Zen 1, Zen 2 or Zen 5, and applies the matching structure. Start here; the log explains the chosen profile.

Plugins → AMD Microcode
02 PRE-ZEN

APPLY LAYOUT + DISASSEMBLY

Types the container and obfuscated triads; mirrors decoded triads under amd_prezen_ucode at uc_0c00. Handler functions, conditional jumps and sequence-word branches become edges.

K8 / K10
03 REPORT

SHOW DECODED TRIAD LISTING

Read-only report: header, match registers, every decoded triad, raw words and sequence word, using the same text as GhidraAmdMicrocode's K8/K10 specification.

Pre-Zen → Listing
04 LIFT

ZEN 1 / ZEN 2 LLIL + HLIL

Maps 64 executable packages into the matching Binary Ninja architecture. Cross-references, graph view and lifting work like any other supported target.

Zen1 / Zen2 → Apply
05 REPORT

ZENUTILS-STYLE DISASSEMBLY

A plain-text report of Zen 1/2 match registers and packages, rendered in a ZenUtils-compatible listing format.

Zen1-Zen2 → Listing
06 ZEN 5c

APPLY STRUCTURAL LAYOUT

Applies loader 0x8015 geometry: 31 match + 31 mask registers at 0x328, op-quads from 0x420. Adds types, data variables, symbols, opcode names and annotations; checks the result before committing.

Zen5 → Apply
07 EXPERIMENTAL

ALTERNATIVE GEOMETRIES & FLOW

Four alternative Zen 5 research layouts, plus two read-only sequence-ordered reports. The flow view follows observed patch targets and match-register hooks; it does not change the database.

Zen5 → Experimental
[ ! ] INFERRED CONTROL FLOW

The experimental Zen 5 listing begins at the observed patch RAM base 0x1f00. A target inside 0x1f00 … 0x1f00 + quads continues in-patch; a match-register target re-enters at that hook's quad. ROM targets terminate a run. Expect many short runs: each update contains multiple hooks, and the CPU's ROM microcode is not present in the file.

04.1 / HEADLESS ANALYSIS
PYTHON3 / STANDARD LIBRARY

NO GUI REQUIRED

PIPE IT.
DIFF IT.

zenella_inspect.py prints the same regions, op-quads, sequence words and alignment diagnostics as text or JSON. Run prezen_core.py directly for K8/K10 decoded triads. The decoders have no Binary Ninja dependency.

Sequence order uses inferred rules and is intended for research, not as a proven execution model.

● terminal // cli examples
# Structural regions, op-quads & sequence words
python3 zenella_inspect.py update.bin

# Export machine-readable JSON
python3 zenella_inspect.py update.bin --json

# Force layout / inspect an embedded update
python3 zenella_inspect.py update.bin --layout exact
python3 zenella_inspect.py image.bin --base 0x1000

# Experimental sequence-ordered micro-ops
python3 zenella_inspect.py update_dec.bin --flow
python3 zenella_inspect.py update_dec.bin --flow-detail
python3 zenella_inspect.py update_dec.bin --flow --patch-base none

# Pre-Zen: header, match registers, triads
python3 prezen_core.py k10_patch.bin
STDOUT / JSONZERO EXTRA DEPENDENCIES
05 / TYPE REFERENCE
PACKED STRUCTURES / BITFIELDS

STRUCTURE IS SIGNAL

NAME EVERY
BIT.

A compact reference to the packed types and bitfields Zenella applies. Expand any structure to inspect its fields.

01AMD_MC_Header shared · 0x20 bytes

Shared across Zen generations. The proc_sig CPUID is expanded and annotated using cpuid_descriptions.json.

TypeField
u16year
u8day, month
u32update_revision
AMD_MC_LoaderIdTagloader_id
u16size_of_patch
u32minimum_patch_level
u16nb_ven, nb_dev, sb_ven, sb_dev
AMD_MC_CpuIdproc_sig
u8bios_revision, flags, reserved, reserved2
02AMD_Zen5_MicroOp64 Zen 5 · 8 bytes

Empirical 64-bit encoding. Bit zero is least significant. Names derive from published ZenUtils / zentool research.

BitsField
0–15imm16
16–20imm_flags
21–25rt
26–30rs
31–35rd
36–41flags
42–44size
45load
46store
47–54opcode (AMD_Zen_Opcode)
55–58mid
59–61exec_unit (spec, br, ld, stn, st, regx, reg)
62–63hi
03AMD_Zen5_OpQuad Zen 5 · 36 bytes
TypeField
AMD_Zen5_MicroOp64 × 4uop0 … uop3
u32sequence_word

Linear view displays opcode name, class and inferred operands. The sequence word is annotated, not lifted.

04AMD_MC_Patch Zen 5 · 0x3820 bytes
TypeField
AMD_MC_Headerheader
u8[256]signature
u8[256]modulus
u8[256]check
AMD_MC_UcodeOptionsoptions
u32rev
AMD_MC_MatchRegisterBlockmatch_regs
AMD_MC_MaskRegisterBlockmask_regs
AMD_Zen5_OpQuad[300]body (reference updates)
u8[2512]zero_padding (reference updates)

Also registered as AMD_Zen5_Patch; body length and padding follow the actual update, and can differ.

05Options, loader & register blocks Zen 5 / shared

AMD_MC_UcodeOptions (4 bytes): u8 autorun, u8 encrypted, u16 loaderid.

AMD_MC_LoaderIdTag is a u16 enum:

ValueIdentifier
0x8004AMD_MC_LOADER_8004
0x8005AMD_MC_LOADER_8005
0x8010AMD_MC_LOADER_8010
0x8015AMD_MC_LOADER_8015
0x8016AMD_MC_LOADER_8016

AMD_MC_MatchRegisterBlock = u32 match_reg[31]. AMD_MC_MaskRegisterBlock = u32 mask_reg[31]. Each is 124 bytes for loader 0x8015; other loaders have scoped widths.

06Zen 1 / Zen 2 structures 0xC80-byte patch

AMD_Zen12_InstructionPackage (36 bytes): u64 uop0…uop3 + u32 sequence_word. AMD_Zen12_MatchEntry (4 bytes): u32 raw.

TypeAMD_Zen12_Patch field
AMD_MC_Headerheader
u8[256] × 3signature, modulus, check
AMD_Zen12_UcodeOptionsoptions
u32revision_copy
AMD_Zen12_MatchEntry[22]match_entries
AMD_Zen12_ExecutablePayloadpayload
07AMD_PreZen_Header K8/K10 · 0x20 bytes
TypeField
u32date (BCD: 0xMMDDYYYY)
u32patch_level
AMD_PreZen_LoaderIdTagloader_id
u8op_triad_count
u8init_flag
u32op_triad_checksum
u32nb_dev_id
u8[4]unknown0
u16cpuid (equivalence ID)
u8[6]unknown1

Loader enum: 0x8000 PREZEN_K8_K10_0x8000, 0x8003 PREZEN_FAMILY12_0x8003.

08Pre-Zen triad types 28-byte obfuscated / decoded

AMD_PreZen_MatchRegister: u32 raw, low 16 bits identify the ROM triad (0xFFFF means unused).

AMD_PreZen_TriadObfuscated: u32 obfuscated_word[7].

AMD_PreZen_Triad: three u64 ops (op0…op2) plus a u32 sequence_word. Decoding happens per instruction using its original address, and the sequence controls branches or completion.

09Pre-Zen micro-op bitfields 64-bit word
BitsField
54–62operation (9 bits)
59–62hi4 = 5 marks jcc
54–58cc (32 condition codes)
523op
46–51dst (64 register names)
30–31size (.b .w .d .q)
24–29src1
23regmode (1=register, 0=imm16)
9–14src2reg
0–15imm
0–11braddr (jcc target triad)

Sequence actions: 0 → sw_next, 1 → sw_complete, 2 → sw_branch (target in bits 0–11), others → sw_raw.

Recognized operations include add, or, adc, sbb, and, sub, xor, cmp, test, rll, rrl, sll, srl, writepc, mov, mul, imul, muleh, mulel, div1, div2, ld, st, lea, bswap, not, crash. Unknown operations display as unk_op. Register names follow the GhidraAmdMicrocode specification.

10AMD_Zen_Opcode op name reference

Names come from published ZenUtils research. Values above 0xFF are synthetic; load/store class does not follow just the opcode bits.

ValueOpcode
0x00UOP_LD_ST_00
0x100LD (synthetic)
0x101ST (synthetic)
0x05BR_JMP
0xFFSPEC_NOP
0xDETYPE5_READ
0x19REG_NSUB
0x30REG_AND
0x40REG_SHL
0x41REG_BLL
0x42REG_ROL
0x44REG_RLC
0x46REG_RRD
0x47REG_SRC
0x48REG_SHR
0x4AREG_ROR
0x4CREG_RRC
0x4FREG_SRD
0x50REG_SUB
0x52REG_SBB
ValueOpcode
0x55REG_NADD
0x5CREG_ADD2
0x5DREG_ADC
0x5EREG_ADD3
0x5FREG_ADD
0x6FREG_VZEROUPPER_64B
0x70REG_POPCNT
0x72REG_SBIT
0x7FREG_VZEROUPPER_32B
0x93REG_MOV2
0xA0REG_MOV_SREG
0xA9REG_BSWAP
0xB5REG_XOR
0xBEREG_OR

Displayed register-operation names omit the common AMD_ZEN_ prefix for readability.

Packed structures preserve older names for existing databases and scripts. New identifiers are generation-prefixed, and K8/K10 types use AMD_PreZen_.

06 / INSTALLATION
OPEN SOURCE / GPL-3.0

GET HANDS-ON

CLONE.
LOAD. REVERSE.

Zenella is a plugin folder, not a single Python file. It runs on the Python runtime shipped with Binary Ninja. The standalone inspectors need only Python 3.

01

OPEN THE PLUGINS FOLDER

In Binary Ninja, select Plugins → Open Plugin Folder… or navigate to your platform's path.

macOS~/Library/Application Support/Binary Ninja/plugins/
Windows%APPDATA%\Binary Ninja\plugins\
Linux~/.binaryninja/plugins/
02

CLONE THE WHOLE REPO

Place the entire zenella directory in the plugins folder. Remove any older standalone amd_zen_ucode.py copy to avoid duplicate menus.

03

RESTART BINARY NINJA

Check Plugins → AMD Microcode. The log reports the loaded Zenella version and module path.

04

OPEN AN UPDATE

Load a .bin as raw bytes, run Auto-detect and apply at the beginning of the file, or move the cursor to the header of an embedded update.

● terminal // setup
git clone https://github.com/ercihan/zenella.git
PLUGIN DIRECTORYNO PIP INSTALL
GITHUB REPOSITORYercihan/zenellaSOURCE / INSTALL / RELEASES ↗
REQUIREMENTS

Binary Ninja Desktop with Python scripting enabled. No third-party Python packages. CLI inspectors use Python 3 and the standard library.

Read the GPL-3.0 license ↗

07 / AFTER THE LOAD
FROM BYTES TO STRUCTURE

HOW TO ACTUALLY USE IT

FOLLOW
THE EVIDENCE.

Use each architecture's strongest supported view. Do not treat inferred Zen 5 control flow as proven silicon behavior.

01 / INSPECT

IDENTIFY THE PATCH

Open the raw update (or place the cursor on its embedded header) and run auto-detect. The log reports which profile was chosen and why.

02 / ANNOTATE

FOLLOW THE HEADER

Find amd_mc_header in Linear view. Read the revision, loader ID, CPUID and processor-name comment.

03 / DISASSEMBLE

GO TO THE PAYLOAD

K8/K10: uc_0c00 and handler labels. Zen 1/2: graph or HLIL view on mapped packages. Zen 5: amd_ucode_body, with NOP and finalization sections labelled.

04 / COMPARE

DIFF THE UNKNOWN

Use the standalone JSON and --flow reports to compare updates. On decrypted Zen 5 patches, the experimental listing can follow sequence-word chains rather than file order.

!

DON'T CONFUSE DECODING WITH UNDERSTANDING.

Zen 5 semantics remain undocumented: opcode labels and operand projection are inferred, and Zen 5 code is not claimed to be executed or lifted to IL. K8/K10 triads are disassembled with control-flow edges but not data-flow lifted. That's the point of a research tool: expose the evidence without inventing certainty.

EOF // YOU REACHED THE BOTTOM

THE CPU
DOESN'T
GET THE LAST WORD.

Read the bytes. Share the findings. Keep reversing.