-
-
Notifications
You must be signed in to change notification settings - Fork 310
Expand file tree
/
Copy pathuefi_fv_varstore.hexpat
More file actions
212 lines (176 loc) · 5.52 KB
/
Copy pathuefi_fv_varstore.hexpat
File metadata and controls
212 lines (176 loc) · 5.52 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
/*
* 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.