
The first analysis framework for CPU microcode
Custom Processing Unit — это первый фреймворк динамического анализа, способный перехватывать, изменять и трассировать микрокод CPU на программном уровне.
Он работает за счёт использования недокументированных инструкций в процессорах Intel, которые предоставляют доступ к CRBUS. С помощью нашего декомпилятора микрокода мы реконструировали то, как CPU использует CRBUS, и, воспроизводя эти взаимодействия, получаем полный контроль над CPU.
Фреймворк статического анализа доступен как поддерево в этой папке или по адресу https://github.com/pietroborrello/ghidra-atom-microcode.
Посмотрите наши слайды с описанием этой работы здесь.
Примечание: Custom Processing Unit требует Red-Unlocked CPU: в настоящее время только процессоры Goldmont (GLM) имеют публичный Red Unlock. Мы тестировали Gigabyte GB-BPCE-3350C с шагом CPU 0x9 и 0xa (cpuid 0x000506C9 и 0x000506CA).
Custom Processing Unit состоит из UEFI-приложения и нескольких библиотек. UEFI-приложение взаимодействует с CPU GLM, а библиотеки предоставляют различные вспомогательные средства для компиляции микрокода в UEFI-приложение и анализа его выходных данных.
GNU_EFI_DIR=<path_to_gnu_efi> make
Это соберёт исходные файлы микрокода и UEFI-приложение в cpu.efi.
Скопируйте cpu.efi в папку \EFI\ на USB-флешке, вставьте её в GLM и загрузитесь в EFI shell.
Выполните map -r в EFI shell, чтобы определить устройство USB-флешки, и <deviceid>: для её монтирования.
Запустите ./cpu.efi, чтобы вывести справку:
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]
cpu предоставляет вспомогательные функции для выполнения простых инструкций из командной строки:
cpu предоставляет интерфейсы к сложным процедурам CPU, которые полезно выполнять для изучения поведения CPU:
u: обновить микрокод CPU предоставленным (подписанным) патчемf: собирать счётчики производительности при выполнении микрокодаcpu предоставляет низкоуровневые интерфейсы к недокументированным инструкциям udbrd и udbgwr.
Наиболее интересные команды, которые они предоставляют:
cpu предоставляет процедуры доступа LDAT для чтения и записи. Укажите параметры [port] [array] [bank] [idx] [addr], чтобы выполнить чтение или запись.
Интересные порты:
Обратите внимание, что доступ к некоторым из этих внутренних компонентов может привести к зависанию CPU.
cpu предоставляет функции для установки патчей в микрокод.
bios/ucode_patches/ucode_patch.u (посмотрите на другие патчи для примеров)cpu.efi p, чтобы установить патч по адресу, указанному в .org.Обратите внимание, что в микрокоде только адреса от 0x7c00 до 0x7e00 доступны для записи и имеют смысл для патчинга.
При запуске cpu.efi x также будет выполнен пропатченный микрокод и выведены регистры rax, rbx, rcx, rdx в качестве результата.
Для автоматического выполнения микрокода при определённых событиях CPU или точках микрокода cpu использует механизм Match and Patch.
Он определяет адрес микрокода для перехвата и адрес микрокода, на который нужно перейти при срабатывании перехвата.
z: сбрасывает все match & patch.h: устанавливает перехват, задавая индекс (0-0x20), адрес перехвата (0-0x7c00) и целевой адрес для выполнения (0x7c00-0x7e00).Устанавливая несколько перехватов и непрерывно выполняя инструкцию, cpu может трассировать микрооперации, выполняемые этой инструкцией, и выгружать их. Для трассировки:
// [TRACED INSTRUCTION HERE] в get_trace_clock_at().cpu.efi m.
Будет создан файл trace.txt, содержащий все адреса, которые были задействованы.uasm-lib/uasm.py -t trace.txt > parsed_trace.txt.
Будет создана полная трасса микрокода, выполненного во время инструкции.Обратите внимание, что uasm.py использует файлы ms_arrayX.txt в своей папке для генерации дизассемблерного листинга выполняемых микроинструкций. Эти файлы предназначены для GLM со stepping 0x9 (cpuid 0x000506C9). При другом stepping сгенерируйте соответствующие массивы.
Вы можете использовать функции дампа LDAT для этой цели.
В CPU есть различные недоступные с точки зрения архитектуры буферы, для которых мы предоставляем процедуры дампа:
smm: SMROM (или любой другой адрес с отключённой защитой SMM)rom: внутреннее ПЗУ (ROM)imms: зашитые в CPU непосредственные значения (immediates)msrs: внутренние конфигурации MSRМы предоставляем ассемблер, который генерирует заголовочные файлы для компиляции в UEFI-приложение cpu.efi.
Посмотрите на предоставленные патчи в bios/ucode_patches для ознакомления с синтаксисом.
Он поддерживает простые операции и метки.
Соберите патч микрокода командой uasm.py -i ucode_patch.u -o ucode_patch.h.
cpu.efi будет скомпилирован и автоматически включит патч микрокода, который вы хотите применить.
файл: code_patch.u
.org 0x7c00
rax:= ZEROEXT_DSZ32(0x00001337)
rbx:= ZEROEXT_DSZ32(0x00001337)
rcx:= ZEROEXT_DSZ32(0x00001337)
rdx:= ZEROEXT_DSZ32(0x00001337)
перекомпилируйте, затем выполните в GLM:
cpu.efi z # zero out match & patch
cpu.efi p # apply the patch
cpu.efi h 0 0x0428 0x7c00 # rdrand entry point
теперь при каждом выполнении rdrand в регистрах будет возвращаться 0x1337.
Наша работа опубликована в статье на WOOT 2023:
@inproceedings{Borrello2023CustomProcessingUnit,
title = {{CustomProcessingUnit}: Reverse Engineering and Customization of Intel Microcode},
author = {Borrello, Pietro and Easdon, Catherine and Schwarzl, Martin and Czerny, Roland and Schwarz, Michael},
booktitle = {IEEE Workshop on Offensive Technologies (WOOT 23)},
year = {2023},
}
Эксперименты, описанные в статье, можно запустить с помощью:
cpu.efi e [exp_idx]
где [exp_idx]: