mirror of
https://github.com/WerWolv/ImHex-Patterns.git
synced 2026-03-27 23:37:04 -05:00
* Add UEFI Firmare Volume Variable Store pattern Add a pattern for UEFI Firmare Volume Variable store. This file type is commonly used with virtual machine UEFI variable files, like OVMF.fd used with QEMU. You could also extract a UEFI firmware binary from a flash device, search for the FV Variable Store, and set this pattern to the FV address. Signed-off-by: Marc Jones <marcj303@gmail.com> * Fixed description pragma --------- Signed-off-by: Marc Jones <marcj303@gmail.com> Co-authored-by: Nik <werwolv98@gmail.com>
213 lines
5.5 KiB
Rust
213 lines
5.5 KiB
Rust
/*
|
|
* ImHex Pattern for UEFI Firmware Volume Variable Store
|
|
*
|
|
* This file type is commonly used with virtual machine UEFI variable files, like OVMF.fd
|
|
* used with QEMU. You could also extract a UEFI firmware binary from a flash device,
|
|
* search for the FV Variable Store, and set this pattern to the FV address.
|
|
*
|
|
* A 'custom_vars.fd' can be generated with these tools:
|
|
*
|
|
* https://gitlab.com/kraxel/virt-firmware
|
|
* https://github.com/rhuefi/qemu-ovmf-secureboot/tree/master
|
|
* https://github.com/LongSoft/UEFITool
|
|
*
|
|
* 1. Generate a blank .fd file with ovmfvartool.
|
|
*
|
|
* $ ovmfvartool generate-blank blank.fd
|
|
*
|
|
* 2. Enroll the Redhat and Microsoft keys with virt-fw-vars in custom_vars.fd.
|
|
*
|
|
* $ virt-fw-vars -i blank.fd -o custom_vars.fd --enroll-redhat --secure-boot
|
|
*
|
|
* 3. Dump custom_vars.fd contents
|
|
*
|
|
* $virt-fw-vars -i custom_vars.fd -pvx
|
|
*
|
|
* or
|
|
*
|
|
* $ uefitool custom_vars.fd
|
|
*
|
|
* or use this pattern with ImHex!
|
|
*/
|
|
|
|
#pragma author Marc Jones
|
|
#pragma description UEFI Firmware Volume Variable Store
|
|
// #pragma debug
|
|
|
|
import std.core;
|
|
import std.mem;
|
|
import type.guid;
|
|
|
|
|
|
// --- GUIDs ---
|
|
|
|
#define NVRAM_FV "{FFF12B8D-7696-4C8B-A985-2747075B4F50}"
|
|
#define NVRAM_VARSTORE "{AAF32C78-947B-439A-A180-2E144EC37792}"
|
|
|
|
|
|
// --- Enumerations and Bitfields ---
|
|
|
|
// Describes the type of a file within the Firmware File System.
|
|
enum FfsFileType : u8 {
|
|
RAW = 0x01,
|
|
FREEFORM = 0x02,
|
|
SECURITY_CORE = 0x03,
|
|
PEI_CORE = 0x04,
|
|
DXE_CORE = 0x05,
|
|
PEIM = 0x06,
|
|
DRIVER = 0x07,
|
|
COMBINED_PEIM_DRIVER = 0x08,
|
|
APPLICATION = 0x09,
|
|
SMM = 0x0A,
|
|
FIRMWARE_VOLUME_IMAGE = 0x0B,
|
|
COMBINED_SMM_DXE = 0x0C,
|
|
SMM_CORE = 0x0D,
|
|
FFS_PAD = 0xF0,
|
|
};
|
|
|
|
// Attributes for a UEFI variable, indicating its properties and accessibility.
|
|
bitfield VariableAttributes{
|
|
NON_VOLATILE : 1;
|
|
BOOTSERVICE_ACCESS : 1;
|
|
RUNTIME_ACCESS : 1;
|
|
HARDWARE_ERROR_RECORD : 1;
|
|
AUTHENTICATED_WRITE_ACCESS : 1;
|
|
TIME_BASED_AUTHENTICATED_WRITE_ACCESS : 1;
|
|
APPEND_WRITE : 1;
|
|
RSVD: 25;
|
|
};
|
|
|
|
//
|
|
// Variable Store Header Format & State flags
|
|
//
|
|
enum VariableStoreFormat : u8 {
|
|
VARIABLE_STORE_FORMATTED = 0x5a,
|
|
};
|
|
|
|
enum VariableStoreState : u8 {
|
|
VARIABLE_STORE_HEALTHY = 0xfe,
|
|
};
|
|
|
|
|
|
//
|
|
// Variable State flags. See https://countchu.blogspot.com/2014/09/the-life-cycle-of-uefi-variable-in.html
|
|
//
|
|
enum VariableState : u8 {
|
|
VAR_IN_DELETED_TRANSITION = 0xfe,
|
|
VAR_DELETED = 0xfd,
|
|
VAR_HEADER_VALID_ONLY = 0x7f,
|
|
VAR_ADDED = 0x3f,
|
|
VAR_ADDED__VAR_IN_DELETED_TRANSITION__VAR_DELETED = 0x3c,
|
|
VAR_ADDED__VAR_IN_DELETED_TRANSITION = 0x3e,
|
|
VAR_ADDED__VAR_DELETED = 0x3d,
|
|
};
|
|
|
|
|
|
// --- Other Structures ---
|
|
|
|
struct EFI_TIME {
|
|
u16 Year;
|
|
u8 Month;
|
|
u8 Day;
|
|
u8 Hour;
|
|
u8 Minute;
|
|
u8 Second;
|
|
u8 Pad1;
|
|
u32 Nanosecond;
|
|
u16 TimeZone;
|
|
u8 Daylight;
|
|
u8 Pad2;
|
|
};
|
|
|
|
|
|
// --- Firmware Volume Structures ---
|
|
|
|
// Header for a block in the firmware volume map.
|
|
struct EFI_FV_BLOCK_MAP_ENTRY {
|
|
u32 NumBlocks;
|
|
u32 Length;
|
|
};
|
|
|
|
// The main header for a Firmware Volume.
|
|
struct EFI_FIRMWARE_VOLUME_HEADER {
|
|
u128 ZeroVector;
|
|
type::GUID FileSystemGuid;
|
|
u64 FvLength;
|
|
u32 Signature;
|
|
u32 Attributes;
|
|
u16 HeaderLength;
|
|
u16 Checksum;
|
|
u16 ExtHeaderOffset;
|
|
u8 Reserved;
|
|
u8 Revision;
|
|
EFI_FV_BLOCK_MAP_ENTRY BlockMap[while(std::mem::read_unsigned($, 4) != 0 || std::mem::read_unsigned($ + 4, 4) != 0)];
|
|
EFI_FV_BLOCK_MAP_ENTRY BlockMapTerminator; // After the loop, explicitly parse the (0,0) terminator entry
|
|
}[[single_color]];
|
|
|
|
|
|
// --- UEFI Variable Structures ---
|
|
|
|
struct VARIABLE_STORE_HEADER {
|
|
type::GUID Signature;
|
|
u32 Size;
|
|
VariableStoreFormat Format;
|
|
VariableStoreState State;
|
|
u16 Reserved;
|
|
u32 Reserved1;
|
|
}[[single_color]];
|
|
|
|
|
|
#define VAR_START_ID 0x55AA
|
|
|
|
struct VARIABLE_HEADER {
|
|
u16 StartId;
|
|
VariableState State;
|
|
u8 Reserved;
|
|
VariableAttributes Attributes;
|
|
u32 NameSize;
|
|
u32 DataSize;
|
|
type::GUID VendorGuid;
|
|
};
|
|
|
|
struct AUTHENTICATED_VARIABLE_HEADER {
|
|
u16 StartId;
|
|
VariableState State;
|
|
u8 Reserved;
|
|
VariableAttributes Attributes;
|
|
u64 MonotonicCount;
|
|
EFI_TIME TimeStamp;
|
|
u32 PubKeyIndex;
|
|
u32 NameSize;
|
|
u32 DataSize;
|
|
type::GUID VendorGuid;
|
|
};
|
|
|
|
struct UEFI_VARIABLE {
|
|
AUTHENTICATED_VARIABLE_HEADER Header; // TODO: Check authenticated vs normal variable...
|
|
char16 Name[Header.NameSize / 2]; // Name is a UTF-16 string
|
|
u8 Data[Header.DataSize];
|
|
// Align to the next 4-byte boundary for the next variable.
|
|
u8 pad[std::mem::align_to(4, sizeof(this)) - sizeof(this)];
|
|
} [[name(this.Name), single_color]];
|
|
|
|
|
|
// --- Main Pattern Entry Point ---
|
|
|
|
EFI_FIRMWARE_VOLUME_HEADER FV_Header @ 0;
|
|
|
|
if (std::core::formatted_value(FV_Header.FileSystemGuid) != "{FFF12B8D-7696-4C8B-A985-2747075B4F50}") {
|
|
std::error(std::format("Unknown FV_Header.FileSystemGuid {}", std::core::formatted_value(FV_Header.FileSystemGuid)));
|
|
}
|
|
|
|
// The next structure should be the Variable Store Header
|
|
VARIABLE_STORE_HEADER VarStore @ $;
|
|
|
|
if (std::core::formatted_value(VarStore.Signature) != NVRAM_VARSTORE) {
|
|
std::error(std::format("Unknown VarStore.Signature {}", std::core::formatted_value(VarStore.Signature)));
|
|
}
|
|
|
|
// Index through the Uefi variables until we don't find a Variable Signature 0x55AA
|
|
UEFI_VARIABLE UefiVars[while(std::mem::read_unsigned($, 2) == VAR_START_ID)] @ $;
|
|
|
|
// TODO: grey out the Uefi variables that are in the non-active state, != VAR_ADDED.
|