Custom Processing Unit - Framework to Hook, Patch and Trace CPU Microcode

Admin

Custom Processing Unit is the first dynamic analysis framework able to hook, patch, and trace CPU microcode at the software level.

It works by leveraging undocumented instructions in Intel CPUs that allow access to the CRBUS. Using our microcode decompiler we reverse-engineered how the CPU uses the CRBUS and by replicating the interactions we have full control of the CPU.

Check out slides describing this work here.

Note: Custom Processing Unit requires a Red-Unlocked CPU: currently, only Goldmont CPUs (GLM) has a public Red Unlock. We tested Gigabyte GB-BPCE-3350C with CPU stepping 0x9 and 0xa (cpuid 0x000506C9 and 0x000506CA).

Custom Processing Unit is made up of a UEFI application and a few libraries. The UEFI application interacts with the GLM CPU, while the libraries provide different helpers to compile microcode into the UEFI application and analyze its output.

Prerequisites

  1. Follow the steps to red unlock your Goldmont CPU from https://github.com/ptresearch/IntelTXE-PoC.
  2. Create a bootable USB key with an EFI shell
  3. Install gnu-efi on your main host

Setup

GNU_EFI_DIR=<path_to_gnu_efi> make

This will build the source microcode files and the UEFI application into cpu.efi. Copy cpu.efi into the \EFI\ folder of the USB key, plug it in the GLM and boot into the EFI shell.

Run map -r in the efi shell to identify the USB key device and <deviceid>: to mount it.

Run Custom Processing Unit 

Run ./cpu.efi to print the help:

Usage:
  patch:        <tool> p
  patch & exec: <tool> x
  perf:         <tool> f
  zero out m&p: <tool> z
  hook:         <tool> h  [m&p idx] [uop addr] [patch addr]
  template:     <tool> m
  dump imms:    <tool> di
  dump rom:     <tool> dr
  dump msrs:    <tool> dm<
  dump SMM:     <tool> ds [address] [size]
  cpuid:        <tool> c  [rax] [rcx]
  rdmsr:        <tool> rm [msr]
  wrmsr:        <tool> wm [msr]
  read:         <tool> r  [cmd] [addr]
  write:        <tool> w  [cmd] [addr] [value]
  invoke:       <tool> i  [addr]
  update ucode: <tool> u  [size]
  ldat read:    <tool> lr [port] [array] [bank] [idx] [addr] [optional size]
  ldat write:   <tool> lw [port] [array] [bank] [idx] [addr] [value]



Get Custom Processing Unit