SuperAPI AI Directory

re-uefi

General & other

View repository

Updated 10-16 05:07

About this skill

UEFI firmware reverse engineering (DXE drivers / UEFI modules / bootkits)

The first step is alwaysdetermine the stage and module type:

SEC → PEI → DXE → BDS → OS / Runtime(+ SMM 独立一路)

Within the same firmware, modules from different stages run incompletely different execution environments: different available memory, different callable services (PPI / Protocol / Runtime Services), different lifecycles (DXE_DRIVER and DXE_RUNTIME_DRIVER are not the same thing).

So the order is:first determine the stage and type, then discuss the logic—if the type is determined incorrectly, all subsequent reasoning about "why it is written this way" will be wrong. See [[pi-stages]] for details. </CORE RULE>

Stages and module types (classify first)

Type Stage Service form / lifecycle
SEC Earliest Security and initialization entry point, no general memory environment
PEIM PEI PPI; one of PEI's main tasks is to establish permanent memory
DXE driver DXE Protocol; exists only in the boot services environment
DXE runtime driver DXE + Runtime Cross-lifecycle:ExitBootServices() still exists after,SetVirtualAddressMap() is relocated at
UEFI driver / application After DXE/BDS Drivers/applications running in the UEFI environment; not the same thing as firmware built-in modules
SMM/MM driver Independent Executes within SMM; privilege level and lifecycle form their own separate system

Three high-frequency criteria (for details and the decision tree, see [[pi-stages]]):

  • Read a series of structures with no producer xref → first think HOB(one-way handoff from PEI to DXE, read-only on the DXE side)
  • LocateProtocol(&guid) → do GUID dictionary parsing, restore to EFI_XXX_PROTOCOL_GUID and interface vtable;the protocol graph is more meaningful than the direct call graph
  • Firmware address ≠ OS runtime address → it is not necessarily a hook or a relocation error; first confirm which stage's mapping is being compared

When to use / when not to use

  • Prerequisite: you have a firmware image but are not sure whether it is a UEFI/PI structure or an embedded image → the firmware section of [[re-analyze/system-fingerprints]] (FV → FFS → section hierarchy)
  • Use: the firmware image contains EFI structures (Firmware Volume / FFS files / DXE drivers)—BIOS update packages (.fd/.rom/.bin), UEFI drivers, EFI applications
  • Use: bootkit localization (SMM handlers, timer callbacks, boot path hooks) and verification
  • Use: Secure Boot / boot chain related analysis (signatures, certificates, NVRAM variables)—requires legal authorization, see pitfall 4
  • Do not use: the firmware is a traditional Linux embedded rootfs (go through [[re-fw-extract]] / [[re-fw-rootfs]]; the [[re-firmware]] gateway determines first)
  • Do not use: Legacy BIOS Option ROM / non-EFI legacy firmware (binwalk goes through [[re-fw-extract]])
  • Do not use: you only need to unpack the whole thing and look at the contents (first do a preliminary check with [[re-fw-extract]], and once confirmed to be a UEFI structure, enter this skill)
  • Note: static analysis comes first (the principle for large firmware); emulating a bootkit = running malicious code, sandbox by default (the highest principle in [[re-analyze/platform-tips]])

Tool preparation

Verify all tools before use. Firmware image parsing/module static analysis may skip the sandbox; OVMF emulation (step 5) is dynamic execution, sandboxed by default + network isolation ([[re-analyze/platform-tips]] highest principle).

UEFITool / UEFIExtract (mainstay for firmware parsing)

  • Debian/Ubuntu: apt install uefitool uefitool-cli(official package: GUI + CLI; CLI includes UEFIExtract/UEFIFind)
  • Arch: AUR yay -S uefitool(or uefitool-git; unofficial repository)
  • Fedora: no official package → Linux x64 binary from GitHub releases (https://github.com/LongSoft/UEFITool/releases)或源码构建(qmake + Qt6)
  • macOS: universal macOS binary from GitHub releases (same page)
  • Windows: win64 binary from GitHub releases (or choco install uefitool if the mirror is available)
  • Verify: uefiextract --help outputs usage; GUI uefitool can open the firmware image

UEFIFind (locate files by pattern string, ships with uefitool-cli)

  • The NE version only has positional-argument syntax:uefifind imagefile {header|body|all} {list|count} pattern, no -g/-t options
  • To locate by GUID, use UEFIExtract's GUID argument mode instead:uefiextract fw.bin <GUID>(see below)
  • Installation same as above (included in Debian/Ubuntu's uefitool-cli)
  • Verify: uefifind --help

ghidra / ida (module decompilation; see [[re-ghidra]] / [[re-ida]] for installation)

  • .efi modules are PE/COFF (subsystem EFI_BOOT_SERVICE_DRIVER / EFI_APPLICATION), both can import them directly
  • EfiRom plugin (optional): EDK2 tool, used for converting between ROM files and .efi / querying size
  • Verify: importing the extracted .efi automatically identifies the subsystem as EFI boot service driver

ovmf —— OVMF (Open Virtual Machine Firmware, UEFI emulation firmware)

  • Debian/Ubuntu: apt install ovmf(/usr/share/OVMF/OVMF_CODE.fd、OVMF_VARS.fd)
  • Fedora/RHEL: dnf install edk2-ovmf(path /usr/share/edk2/ovmf/OVMF_CODE.fd—— the old /usr/share/OVMF layout is deprecated)
  • Arch: pacman -S edk2-ovmf(install only /usr/share/edk2/x64/OVMF_CODE.4m.fd, 4m format)
  • macOS: brew install qemu ships with firmware ($(brew --prefix)/share/qemu/edk2-x86_64-code.fd, with the qemu package)
  • Windows: bundled with the QEMU installer (edk2-x86_64-code.fd under share/qemu/)
  • Verify: look up the corresponding path by distribution —— Debian/Ubuntu ls /usr/share/OVMF/OVMF_CODE.fd;Fedora/RHEL ls /usr/share/edk2/ovmf/OVMF_CODE.fd;Arch ls /usr/share/edk2/x64/OVMF_CODE.4m.fd; on macOS use the brew prefix path

qemu-system-x86_64 (OVMF runtime host)

  • Debian/Ubuntu: apt install qemu-system-x86
  • Fedora: dnf install qemu-system-x86-core(full virtualization group is dnf install @virtualization)
  • Arch: pacman -S qemu-system-x86
  • macOS: brew install qemu
  • Windows: qemu.weilnetz.de installer
  • Verify: qemu-system-x86_64 --version

Procedure

Execute in order, record evidence for each step (path + sha256, see [[re-triage]]). Do this first for initial reconnaissance:file fw.bin + entropy to confirm whether it is a UEFI structure ([[re-triage]]).

  1. Firmware image parsing (Firmware Volume → File → Section):

    file fw.bin
    uefiextract fw.bin all            # 全量递归解包(含嵌套 FV 与压缩节,见坑 1/2)
    ls fw.bin.dump/                   # 树:Volume0/ → File0/ → Section0/ → PE32 等
    
    • GUI: open fw.bin in UEFITool, the left tree goes top-down FV → FFS File → Section; first count the number of FVs and their types —— the main DXE FV is usually the largest, containing hundreds or thousands of modules; the PEI FV and SEC Core are at the very front
    • First confirm how many layers of FV are in the image (nested/recovery volumes), don't just stare at the first layer (pitfall 1)
  2. DXE driver extraction:

    ueifind fw.bin all list <GUID>    # 按模式串(含 GUID 文本)定位文件——NE 版仅位置参数语法,无 -g/-t
    # 按 GUID 直接提取指定文件(UEFIExtract 的 GUID 参数模式):
    #   -m 合法值: all|body|header|info|file;-t 是十六进制节类型(PE32=0x10,即 -t 10)
    uefiextract fw.bin <GUID> -o driver.efi -m body -t 10
    file driver.efi                   # 期望输出: PE32+ executable (EFI boot service driver)
    
    • UEFITool GUI: right-click File → Extract body, export the "raw PE" (strips FFS/section headers, see pitfall 3)
    • Hash the extracted artifact first with sha256sum for evidence ([[re-triage]]), then take it into the decompiler
  3. Module analysis (entry / Protocol services):

    • Open the .efi with [[re-ghidra]] / [[re-ida]]; the entry = image entry (DriverEntry), which is the starting point for understanding the driver
    • Protocol services are UEFI's "API":gBS->LocateProtocol(&guid,...)(Get Service),gBS->InstallProtocolInterface(...)(Register Service),gBS->CreateEvent(...)(Event/Callback),gST->ConOut(Console Output)
    • GUID is the "symbol"—recognizing the GUID of LocateProtocol is equivalent to recognizing the API call; use UEFITool's built-in GUID database (the protocol name is shown next to the GUID in the UI) or search the UEFI specification/UEFI GUID table
    strings driver.efi | grep -iE 'protocol|runtime|efi_' | head -30
    
    • Record: entry function, which Protocols were installed/obtained, whether event callbacks were registered (connect to step 4)
  4. bootkit localization (SMM / timer callback / boot path hooking):

    • Timer callback: gBS->CreateEvent(EVT_TIMER, TPL, Callback, ...) + gBS->SetTimer(..., PERIODIC/ONESHOT, ...) → the callback function is where the malicious logic is executed periodically (the most common hook point)
    • SMM: SmiHandlerRegister / SMST service → SMM driver registers an SMI handler (code executed within SMM, a persistence layer running with higher privilege than kernel ring0, inside SMRAM)
    • Boot path hooking: tampering at the BDS stage (NVRAM variables BootOrder/BootNext, replacing EFI boot entries, hooking the boot manager/PXE path); S3 resume path (AP wake-up code)
    • Runtime Services hook: intercept/replace gRT->SetVariable/GetVariable and other Runtime Services pointers
    • Identifying characteristics: the driver does not unload, carries a custom GUID, DXE_DEPEX depends on other launcher modules, paths/keys/URLs appear in strings; after confirming the suspicious module's GUID and dependencies, proceed to step 5
  5. OVMF emulation verification(running malicious code—inside a sandbox, network -net none):

    # 只读代码固件 + 可写变量固件(两片 pflash 标准做法);OVMF_CODE.fd 路径按发行版:
    #   Debian/Ubuntu: /usr/share/OVMF/OVMF_CODE.fd
    #   Fedora/RHEL:   /usr/share/edk2/ovmf/OVMF_CODE.fd(旧 /usr/share/OVMF 布局已废弃)
    #   Arch:          /usr/share/edk2/x64/OVMF_CODE.4m.fd(4m 格式)
    qemu-system-x86_64 -drive if=pflash,format=raw,readonly=on,file=/usr/share/OVMF/OVMF_CODE.fd \
      -drive if=pflash,format=raw,file=OVMF_VARS.fd \
      -m 1024 -net none -boot menu=on
    
    • Verify that the firmware can boot to the UEFI Shell/system → then hook the extracted driver/firmware modifications (UEFITool insertion or rebuilding the firmware image) into the same OVMF to observe behavioral differences
    • When there is no real firmware, OVMF is the baseline environment (no Secure Boot signature constraints, see pitfall 4); for emulation details and user-space alternatives see [[re-fw-emulate]]
    • Dynamic behavior confirmation (callback triggered/variable tampering) → sandbox + snapshot ([[re-sandbox]]), behavior analysis goes to [[re-malware]]; preserve evidence for each step's artifacts

Branches (references)

  • [[pi-stages]] —— PI stage model: identification of SEC/PEI/DXE/BDS/Runtime/SMM and differences in execution environment;HOB(PHIT at the beginning, PEI one-way production, DXE read-only,Build*Hob asserts in DXE);GUID dictionary parsing(Protocol/PPI/FFS/HOB/variable namespace/configuration table);FV → FFS → section → PE layers (do not carve directly by PE magic number);DXE_DRIVER vs DXE_RUNTIME_DRIVER(ExitBootServices after, all boot services are unavailable,EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE notification functions are prohibited from calling any service,ConvertPointer、EFI_RUNTIME_ARCH_PROTOCOL the VirtualMode/AtRuntime criterion)

Cross-domain federation

  • [[re-firmware]]: this skill is referenced by the re-firmware gateway—UEFI firmware branch; the overall process is still orchestrated by the gateway as extract→rootfs→emulate
  • [[re-fw-emulate]]: the OVMF/QEMU full-system emulation in step 5 is this skill's UEFI concretization of [[re-fw-emulate]]
  • [[re-binary-core]]: static decompilation of DXE drivers ([[re-ghidra]] / [[re-ida]] / [[re-radare2]]), import table [[re-imports]]
  • [[re-triage]]: initial survey (hash / architecture / entropy), preserve evidence for each layer's artifacts
  • [[re-malware]]: bootkit dynamic verification goes into the sandbox ([[re-sandbox]]), malicious behavior analysis goes to [[re-malware]]
  • Non-EFI firmware (legacy BIOS / embedded images) → [[re-fw-extract]] (binwalk preliminary assessment)
  • [[re-analyze/platform-tips]] Related branches: static-first (large firmware samples), dynamic default sandbox (network -net none when emulating bootkits), Linux/Windows platform branches

Common pitfalls and traps

  • Firmware images with multiple nested FVs: Symptom—UEFITool shows only a few files/modules when opened, and the driver you are looking for cannot be found; Cause—modern firmware encapsulates FVs in nested form (PEI FV embedding DXE FV, recovery volume/Capsule, FV embedded in ACPI tables), so analyzing only the outer layer naturally misses components; Countermeasure—use uefiextract fw.bin all to fully recursively expand (automatically handling nesting), or expand sub-FVs layer by layer in the GUI; confirm the image structure before analyzing
  • Compressed/padding regions obscuring content: Symptom—FFS file sections appear as compressed data or FREE_SPACE/FIXED padding, and PE32 code cannot be seen; Cause—vendors compress the entire DXE volume (EFI/LZMA compressed section), and the empty regions are normal layout; Countermeasure—UEFITool/UEFIExtract will automatically decompress and show the decompressed Section (use it to view, not binwalk's raw bytes); "no code found" in binwalk results does not mean there is none, go back to UEFITool to confirm
  • PE header offset within FFS: Symptom—the "file" extracted from firmware fails to open directly with file/IDA or decompiles into gibberish; Cause—the FFS File Header (24/32 bytes) + Section Header + alignment padding come before the PE32 body, so the PE header is not at file offset 0; Countermeasure—use UEFITool right-click Extract body / uefiextract fw.bin <GUID> -m body to export the bare PE, and after exporting use file to confirm the output contains "PE32+ executable (EFI boot service driver)" before entering the decompiler; manual extraction requires calculating offsets according to the Section layout
  • Secure Boot signature verification bypass analysis requires legal authorization: Symptom—wanting to "bypass Secure Boot"/"re-sign firmware" for experiments, and problems arise when touching real signed firmware; Cause—signature bypass, firmware key/certificate extraction, and validating bootkits on real devices all involve legal and authorization boundaries; Countermeasure—by default, analyze and validate behavior in OVMF development firmware (without signing constraints); before working on real firmware, confirm the scope of authorization (owned devices, vulnerability research authorization), and do not touch anything unauthorized; state the boundaries clearly in the report (same type of expression as the authorization boundary in [[re-hardware-io]])
  • Treating cross-stage data as ordinary global variables whose producer is missing: Symptom—a chain of structures read by a function has no visible construction point, leading to suspicion that it was trimmed or the code is incomplete; Cause—it may be HOB(a one-way handoff from PEI to DXE, read-only on the DXE side, and the construction call also asserts); Countermeasure—first parse according to the HOB list, and establish the correspondence of "which stage produces it, who consumes it" ([[pi-stages]])
  • Treating GUIDs as semantically meaningless UUIDs: Symptom—a large number of GUID constants cannot be explained, and analysis stops at "a constant was passed in"; Cause—a GUID may be any one of a Protocol/PPI/FFS file/HOB/variable namespace/configuration table; Countermeasure—build a GUID→symbol dictionary, restore calls like LocateProtocol into semantic names and interface vtables, anduse a protocol graph to supplement the call graph
  • Not distinguishing between DXE_DRIVER and DXE_RUNTIME_DRIVER: Symptom—comparing addresses in firmware with addresses captured during the OS runtime stage and concluding it is hooked; Cause—runtime drivers still exist after ExitBootServices() and will be relocated according to the mapping of SetVirtualAddressMap() , so firmware addresses are inherently not equal to runtime addresses; Countermeasure—first determine the module type and lifecycle stage (EFI_RUNTIME_ARCH_PROTOCOL 's VirtualMode/AtRuntime is an off-the-shelf criterion), then discuss consistency ([[pi-stages]])