The Angry Path to Zen: AMD Zen Microcode Tools and Insights

Day 3 20:10 Fuse en Security
Dec. 29, 2025 20:10-20:50
[EntrySign](https://bughunters.google.com/blog/5424842357473280/zen-and-the-art-of-microcode-hacking) opened the door to custom microcode on AMD Zen CPUs earlier this year. Using a weakness in the signature verification we can load custom microcode updates and modify behavior of stock AMD Zen 1-5 CPUs. While AMD has released patches to address this weakness on some CPUs, we can still use unpatched systems for our analysis. In this talk we cover what we found out about microcode, what we saw in the microcode ROM, the tooling we build, how we worked to find out more and how you can write & test your own microcode on your own AMD Zen systems. We have our tools up on [GitHub](https://github.com/AngryUEFI) for everyone to play around with and hopefully help us understand microcode more than we currently do.

Modern CPUs often translate the complex, user visible instruction set like x86_64 into a simpler, less feature rich internal instruction set. For simple instructions this translation is done by a fast path decoding unit. However some instructions, like wrmsr or rdrand are too complex to decode that way. These instructions instead are translated using a microcode decoder that can act almost like an execution engine. The microcode decoder still emits internal instructions into the pipeline, but allows for features like conditional branches and calls & returns. All of this logic happens during a single x86_64 instruction and is usually hidden from the outside world. At least since AMD K8, launched in 2003, AMD CPUs allowed updating this microcode to fix bugs made in the original implementation.

Building on our previous experience with AMD K8 & K10 microcode and EntrySign published earlier this year, we took a closer look at AMD Zen 1-5 CPUs. We build on top of Zentool to understand more instructions and created a set of tools to easily create microcode patches as well as apply them on CPUs. We can modify the behavior of instructions and observe some usually not visible internal state by supplying our own microcode update.

Like on K8, we extracted the physical ROM on the CPU using an electron microscope to read the hardcoded microcode on a Zen 1 CPU. Using the understanding of the microcode encoding we could then start disassembling the contents and understand how some instructions are implemented. While there are still a lot of things we don't understand, we could follow control flow and analyze algorithms like the XXTEA decryption of the microcode update.

To start off this work, we implemented a set of tools that allow easy testing of microcode updates without the need for a fully featured OS. That way we can run timing tests with low noise and don't risk data corruption if we corrupt a vital instruction. To continue our naming scheme from our work on K8 we dubbed this the AngryTools, all of them available on GitHub. The core components are a UEFI application running from RAM, AngryUEFI, and a Python framework for test writing on a client computer, AngryCAT. AngryUEFI starts on the test system and waits for AngryCAT tests supplied via TCP. These tests usually consist of a microcode update that gets loaded on the target CPU core and a buffer with x64 instructions that get run afterwards. AngryUEFI then sends back information about the test execution. AngryUEFI also recovers most faults caused by invalid microcode, often even allowing reuse of a CPU core after a failed test run. We also added some syscall-like interfaces to support more complex data collection like IBS.

To make it easier to write custom microcode updates we also implemented ZenUtils, a set of Python tools. So far we support single line assembly and disassembly based on architecture specification for Zen 1 & 2 with limited support for other Zen architectures. We also include a macro assembler that can create a full microcode update from an assembly-like input file. Later we will also extend ZenUtils with utilities to sign and en/decrypt microcode updates. Currently we rely on Zentool for these tasks.

We also show some basic examples of how microcode programs work, from a simple CString strlen implementation in a single x64 instruction to a subleq VM implemented entirely in microcode. These show off the basics of microcode programming, like memory loads & stores, arithmetic and conditional branches. We are also currently looking at other examples and more complex programs.

We hope this talk shows you how to start throwing random bits at your own AMD Zen CPU to figure out what each bit does and help us in further understanding the instruction set. We welcome improvements to the tooling and even entirely new tools to help analyze microcode updates and the ROM.

If you are already familiar with EntrySign, we only cover the very basics of it and focus more on what we learned after having a foothold in the microcode.

Speakers of this event