This report documents a security audit of the SMM (System Management Mode) SMI handlers present in the UEFI firmware image from an Intel NUC (Skylake generation). The firmware is an AMI Aptio V BIOS with clearly named modules. Analysis was performed using IDA Pro with MCP integration (ida-pro-mcp + idasql).
Overall Risk Assessment: CRITICAL
The firmware contains 8 CRITICAL and 3 MEDIUM severity findings (11 total) across 20 SW SMI handler registrations in 11 modules. Three distinct attack surfaces enable arbitrary SMRAM writes:
-
EBDA-based constant-value SMRAM writes (UsbRt, NvmeSmm, SdioSmm) — Three modules read their communication buffer pointer from the Extended BIOS Data Area (EBDA) via physical address 0x40E, which is attacker-controlled from Ring 0. By corrupting the EBDA segment, an attacker can make the buffer pointer target any physical address including SMRAM. The handlers then write constant status values (0xF0 or 0x07) to the buffer — enabling single-byte arbitrary writes to SMRAM. Critically, even the two modules with custom SMRAM validation (NvmeSmm, SdioSmm) are vulnerable because their error-handling path writes the status code to the same buffer that failed validation.
-
CPU saved-state pointer injection (ItkSmmVars) — Reads RSI/RBX register values from SMM CPU saved state via
EFI_SMM_CPU_PROTOCOL.ReadSaveState(). The attacker controls these registers at SMI trigger time. Command 3 dereferences an embedded pointer chain for SetVariable; command 5 provides a full arbitrary memcpy primitive. -
Shared buffer pointer dereferences (UsbRt) — Multiple command handlers (0x2B, 0x2F, 0x2D) dereference 64-bit pointers read directly from the communication buffer, and the core USB transfer function writes to attacker-specified addresses — all without any SMRAM validation.
The standard SmmIsBufferOutsideSmmValid() function is absent. Two modules (SdioSmm, NvmeSmm) implement custom inline SMRAM validation, but this is defeated by the error-path write pattern described above.
| Field | Value |
|---|---|
| Platform | Intel NUC (Skylake) |
| Firmware Vendor | AMI (Aptio V) |
| Image File | flash_image_nuc.bin |
| Image Size | 8 MB |
| MD5 | 664f34f760e8df77817282dd56f894df |
| Total Functions | 32,016 |
| SMM Entry Points | ~176 (36+ unique SMM modules) |
| SW SMI Handlers | 20 registrations across 11 modules |
| Architecture | x86_64 (UEFI) |
The following SMM modules were identified from named entry points in the IDA database:
| # | Module Name | Entry Address | SW SMI# | Handler Address | Risk |
|---|---|---|---|---|---|
| 1 | ItkSmmVars | 0x951850 | 0xEF, 0x44 | 0x952D90 | CRITICAL |
| 2 | UsbRt | 0x7D3F80 | 0x31 | sub_7D4888 (26-cmd dispatch) | CRITICAL |
| 3 | NvmeSmm | 0x7CA330 | 0x42 | sub_7CAE40 (12-cmd dispatch) | CRITICAL |
| 4 | SmmHddSecurity | 0x7C28C0 | 0xD1 | 0x7C30A4 + 6 others | MEDIUM |
| 5 | SmmLockBox | 0x7D02D0 | (GUID dispatch) | 0x7D0648 | MEDIUM |
| 6 | SdioSmm | 0x7CD870 | 0x40 | sub_7CDC94 (4-cmd dispatch) | CRITICAL |
| 7 | OemSmi | 0x95D840 | 0, 3, 4, 5 | 0x95DB84, 0x95DB44 | Clean |
| 8 | SmmPlatform | 0x76EBD0 | 3, 4, 5 | sub_76EDF8 / sub_76EE64 / sub_76EE74 | Clean |
| 9 | CrbSmi | 0x7EEB80 | 0xBF, 3, 0 | sub_7EED94 (stub) | Clean |
| 10 | CpuSpSMI | 0x61A40 | 0x56, 0x57 | sub_61B1C / sub_61C90 | Clean |
| 11 | AcpiModeEnable | 0x76BBA0 | 0xA0, 0xA1 | sub_76BF80 / sub_76C06C | Clean |
| 12 | BootScriptHideSmm | 0x7B5850 | 0xD6, 0xD7 | sub_7B5990 / sub_7B5B20 | Clean |
| 13 | CmosSmm | 0x7B9D10 | 0x61 | sub_7BA014 | Clean |
| 14 | SmramSaveInfoHandler | 0x76D2A0 | (dynamic) | sub_76D4F0 | Clean |
| 15 | NbSmi | 0x758CC0 | (SW dispatch) | 0x758ED4 | Clean |
| 16 | FlashSmiSmm | 0x7BE1D0 | (ready-to-boot) | 0x7BE67C | Low |
| 17 | NvramSmi | 0x74C840 | (infrastructure) | N/A | Low |
| 18 | PchInitSmm | 0x795B70 | (GPI/periodic) | 0x795D10 | Clean |
| 19 | BiosGuardServices | 0x775300 | (MSR check) | N/A | Clean |
| 20 | CryptoSMM | 0x7A2D10 | (protocol) | N/A | Clean |
| 21 | TcgSmm | 0x7D1340 | (protocol) | N/A | Clean |
| 22 | PchSmiDispatcher | 0x91E0C0 | (root dispatcher) | N/A | Clean |
| 23 | PttWrapper | 0x773B50 | (protocol) | N/A | Clean |
| 24 | SleepSmi | 0x764BB0 | (Sx dispatch) | sub_764DCC | Clean |
| 25 | PowerMgmtSmm | 0x78B5C0 | (IO trap) | sub_78BEE8 | Clean |
| 26 | SaLateInitSmm | 0x78E430 | (periodic timer) | sub_78E5D0 | Clean |
| 27 | AhciSmm | 0x79F800 | (storage protocol) | N/A | Clean |
| 28 | RuntimeSmm | 0x7B7810 | (protocol) | N/A | Clean |
| 29 | KbcEmul | 0x7C5A10 | (IO trap) | N/A | Clean |
| 30 | UsbS5Wakeup | 0x7EC850 | (Sx dispatch) | sub_7ED490 | Clean |
| 31 | StatusCodeSmm | 0x8BB520 | (protocol) | N/A | Clean |
| 32 | FlashDriverSmm | 0x736DA0 | — | — | Infra |
| 33 | NVRAMSmm | 0x73E390 | — | — | Infra |
| 34 | CpuIo2Smm | 0x74E2B0 | — | — | Infra |
| 35 | PiSmmCpuDxeSmm | 0x750D90 | — | — | Infra |
| 36 | SmmExceptionInfo | 0x757290 | — | — | Infra |
| 37 | PowerButton | 0x75CBB0 | (HW button) | — | Clean |
| 38 | SbRunSmm | 0x761BE0 | (SB runtime) | — | Clean |
| 39 | TcoSmi | 0x769800 | (TCO HW) | — | Clean |
| 40 | PchSmbusSmm | 0x79B270 | (SMBus HW) | — | Clean |
| 41 | PchSpiSmm | 0x79D2C0 | (SPI HW) | — | Clean |
| 42 | S3SaveSmm | 0x7B19F0 | — | — | Infra |
| 43 | PiSmmCommunicationSmm | 0x756360 | — | — | Infra |
| SW SMI# | Hex | Module | Handler | Purpose | Risk |
|---|---|---|---|---|---|
| 0 | 0x00 | CrbSmi | sub_7EED94 (stub) | Placeholder | Clean |
| 3 | 0x03 | OemSmi + SmmPlatform + CrbSmi | sub_95DB84 / sub_76EDF8 / sub_7EED94 | SIO config + HW regs | Clean |
| 4 | 0x04 | OemSmi + SmmPlatform | sub_95DB84 / sub_76EE64 | SIO config + HW regs | Clean |
| 5 | 0x05 | OemSmi + SmmPlatform | sub_95DB84 / sub_76EE74 | SIO config + PCI config | Clean |
| 49 | 0x31 | UsbRt | sub_7D4888 | USB runtime SMM API (26-cmd, EBDA) | CRITICAL |
| 64 | 0x40 | SdioSmm | sub_7CDC94 | SDIO storage ops (4-cmd, EBDA) | CRITICAL |
| 66 | 0x42 | NvmeSmm | sub_7CAE40 | NVMe storage ops (12-cmd, EBDA) | CRITICAL |
| 68 | 0x44 | ItkSmmVars | sub_952D90 | ITK variable ops | CRITICAL |
| 86 | 0x56 | CpuSpSMI | sub_61B1C | MSR save | Clean |
| 87 | 0x57 | CpuSpSMI | sub_61C90 | MSR restore | Clean |
| 97 | 0x61 | CmosSmm | sub_7BA014 | CMOS flag clear | Clean |
| 160 | 0xA0 | AcpiModeEnable | sub_76BF80 | ACPI enable | Clean |
| 161 | 0xA1 | AcpiModeEnable | sub_76C06C | ACPI disable | Clean |
| 191 | 0xBF | CrbSmi | sub_7EED94 (stub) | Placeholder | Clean |
| 209 | 0xD1 | SmmHddSecurity | sub_7C30A4 | HDD security (7 sub-handlers) | MEDIUM |
| 214 | 0xD6 | BootScriptHideSmm | sub_7B5990 | Boot script copy to SMRAM | Clean |
| 215 | 0xD7 | BootScriptHideSmm | sub_7B5B20 (stub) | Returns UNSUPPORTED | Clean |
| 239 | 0xEF | ItkSmmVars | sub_952D90 | NVRAM variable handler | CRITICAL |
| — | dynamic | SmramSaveInfoHandler | sub_76D4F0 | IO port / save state ops | Clean |
Location: sub_952D90 at 0x952D90 (ItkSmmVars module)
SW SMI#: 0xEF (239)
CVSS Estimate: 8.2 (High)
Vulnerability Class: CWE-822 (Untrusted Pointer Dereference), SMM Pointer Injection
The SW SMI# 0xEF handler implements an AMI NVRAM variable management interface. Unlike most handlers, it acquires its communication buffer pointer by reading the RSI register from SMM CPU saved state via EFI_SMM_CPU_PROTOCOL.ReadSaveState() (protocol at qword_956710). The attacker controls RSI by setting it before triggering the SMI.
; sub_952D90 — register read via EFI_SMM_CPU_PROTOCOL
mov rax, cs:qword_956710 ; EFI_SMM_CPU_PROTOCOL
lea r8d, [rdi+2Ch] ; register 0x2C (RSI)
call qword ptr [rax] ; ReadSaveState → var_1D7C = low 32 bits of RSI
; ...
mov ebp, var_1D7C ; ebp = communication buffer pointer (from RSI)The handler reads byte 0 as signature (must be 0xEF), byte 1 as command (1-5), and dereferences a 32-bit embedded pointer at offset 4 without validation. Command 3 is the most critical path:
Buffer layout (at RSI-controlled address):
offset 0: signature (0xEF)
offset 1: command byte (1-5)
offset 4: 32-bit pointer to parameter structure (v11)
When command == 3:
v11 = *(uint32_t*)(buffer + 4) // EMBEDDED POINTER
// Dereferences without validation:
variable_name = v11[4] // Wide string pointer
guid = v11[0..3] // 128-bit GUID
attributes = v11[5] // DWORD
data_size = v11[6] // Size value
data_pointer = v11[7] // ANOTHER pointer to data
SetVariable(variable_name, guid, attributes, data_size, data_pointer)
The error path also writes to the RSI-derived pointer: or dword ptr [rbp+0], 0x8200 and or dword ptr [rbp+18h], 1 — enabling OR-based arbitrary writes to attacker-controlled addresses.
The handler special-cases variable names "Setup", "IDESecDev", and "POSTCounter" for additional processing.
An attacker with Ring 0 (kernel) access can:
- Write arbitrary NVRAM variables by controlling the embedded parameter structure
- Read/corrupt SMRAM contents by pointing
v11into SMRAM — the handler will dereference SMRAM data as variable name/GUID/size, potentially leaking SMRAM contents through NVRAM - Achieve arbitrary SMM code execution through chained exploitation (write malicious variable → corrupt SMM data structures)
- Bypass Secure Boot by writing to protected NVRAM variables
- Install persistent firmware implants by manipulating flash-backed variables
| Command | Risk | Detail |
|---|---|---|
| 3 | CRITICAL | Reads embedded pointer, dereferences for SetVariable parameters |
| 5 | HIGH | Reads "TsegAddress", calls sub_956260 (memcpy) with embedded pointer values |
| 2 | Medium | Calls sub_95326F with shared buffer data |
| 1 | Unknown | JUMPOUT — decompiler couldn't resolve target |
| 4 | Low | Reads "HiiDB" variable, internal manipulation |
; Ring 0 exploit pseudocode
; 1. Prepare parameter structure in known physical memory
param_struct = allocate_physical_page()
param_struct[0..3] = target_guid
param_struct[4] = target_var_name ; wide string
param_struct[5] = 0x7 ; NV+BS+RT attributes
param_struct[6] = payload_size
param_struct[7] = payload_data_ptr
; 2. Prepare communication buffer
buffer = allocate_physical_page()
buffer[0] = 0xEF ; signature
buffer[1] = 3 ; command: SetVariable
*(DWORD*)(buffer+4) = physical_addr(param_struct)
; 3. Set RSI to buffer address and trigger SW SMI# 0xEF
mov rsi, physical_addr(buffer)
mov al, 0xEF
out 0xB2, al
Location: sub_952D90 at 0x952D90, command 5 path
SW SMI#: 0xEF (239)
CVSS Estimate: 8.2 (High)
Vulnerability Class: CWE-822 (Untrusted Pointer Dereference), Arbitrary Memory Read/Write
Command 5 of the same handler reads the "TsegAddress" NVRAM variable, then calls sub_956260 (a memcpy implementation) with three values read through an embedded pointer from the shared buffer. Since sub_956260 is an overlapping-safe memory copy function, and the source/destination/size are all derived from attacker-controlled pointers, this enables arbitrary memory read/write within SMM context.
The attacker controls:
- Destination address (via embedded pointer field)
- Source address (via embedded pointer field)
- Copy length (via embedded pointer field)
Direct arbitrary memory copy within SMM context. Can be used to:
- Copy shellcode into SMRAM
- Overwrite SMM handler dispatch tables
- Exfiltrate SMRAM contents to attacker-accessible memory
Location: sub_7C30A4 at 0x7C30A4 (SmmHddSecurity module)
SW SMI#: 0xD1 (209)
CVSS Estimate: 5.5 (Medium)
Vulnerability Class: CWE-20 (Improper Input Validation)
The SmmHddSecurity handler checks a signature value (0x244B4044) in the CommBuffer, then copies 112 bytes from the CommBuffer directly into a newly allocated SMRAM buffer:
if (*a3 == 0x244B4044) { // signature check
allocate(6, 512, &qword_7C4318); // allocate 512 bytes in SMRAM
allocate(6, 112, &v8); // allocate 112 bytes in SMRAM
// Copy 112 bytes from CommBuffer to SMRAM — NO SMRAM validation on a3
do {
*(BYTE*)(v5 + v8) = *((BYTE*)a3 + v5);
++v5; --v4;
} while (v4);
// Set up linked list pointers
qword_7C4408 = v8 + 96;
qword_7C4400 = 1;
qword_7C4410 = v8 + 96;
}The CommBuffer pointer a3 is not validated against SMRAM boundaries before the copy. However, the fixed 112-byte copy size limits exploitation.
- Attacker can inject controlled data into SMM-allocated structures
- The copied data populates a linked list used by subsequent HDD security operations
- Fixed copy size (112 bytes) limits severity compared to variable-size copies
- Requires further analysis of how the copied data is subsequently used
Location: sub_7D0648 at 0x7D0648 (SmmLockBox module)
CVSS Estimate: 5.0 (Medium)
Vulnerability Class: CWE-20 (Improper Input Validation)
The SmmLockBox handler processes CommBuffer commands for storing/restoring LockBox data across S3 resume. The handler performs basic input validation:
- Checks CommBuffer (a3) is not NULL
- Checks CommBufferSize (a4) is not NULL
- Checks CommBufferSize >= 0x10
- Calls
sub_7D041C(a3, *a4)— but this is only an integer overflow check
// sub_7D041C - "validation" function
bool sub_7D041C(uint64_t a1, int64_t a2) {
return a1 <= -1 - a2; // Only checks a1 + a2 doesn't overflow!
}This check verifies buffer + size doesn't wrap around, but does NOT validate that the buffer resides outside SMRAM. The handler then dispatches on command codes:
| Command | Min Size | Operation |
|---|---|---|
| 1 (Store) | 0x30 | Copies 48 bytes from CommBuffer, dereferences inner pointers for sub_7D09B8 |
| 2 (Restore) | 0x38 | Calls sub_7D0488 with CommBuffer |
| 3 (SetAttributes) | 0x30 | Calls sub_7D0578 with CommBuffer |
| 4 (Save) | 0x28 | Copies 40 bytes, dereferences inner pointer for sub_7D0970 |
| 5 (RestoreAll) | — | Iterates linked list, copies data between pointers |
- Command 1 copies data from CommBuffer and dereferences embedded pointers — potential SMRAM confusion
- Command 5 iterates a linked list and performs memory copies between pointer pairs from list nodes
- Exploitation difficulty is higher due to the structured command format requirements
- LockBox operations are typically performed during S3 resume — timing constraints may limit attack window
FINDING-5: CRITICAL — UsbRt Pointer Dereference via Shared Buffer (SW SMI# 0x31, Commands 0x2B/0x2F)
Location: sub_7D579C (cmd 0x2B) and sub_7D5810 (cmd 0x2F) in UsbRt module
SW SMI#: 0x31 (49)
CVSS Estimate: 8.2 (High)
Vulnerability Class: CWE-822 (Untrusted Pointer Dereference), SMM Arbitrary Read
Two UsbRt command handlers dereference pointers read directly from the attacker-controlled shared buffer:
Command 0x2B (sub_7D579C): Reads a 64-bit pointer from shared buffer offset 3, then dereferences it to read a byte:
if ( *(_QWORD *)(a1 + 3) ) // Read 64-bit pointer from shared buffer
{
if ( (**(_BYTE **)(a1 + 3) & 2) != 0 ) // DEREFERENCE: read byte at pointer
flags = 0x10;
if ( (**(_BYTE **)(a1 + 3) & 4) != 0 ) // DEREFERENCE again
flags |= 0x20;
if ( (*result & 1) != 0 ) // DEREFERENCE again
flags |= 0x40;
}
// Also reads another 64-bit pointer from buffer+11:
v4 = *(_QWORD *)(a1 + 11); // Second pointer from buffer
if (v4)
sub_7E430C(v4, ...); // Used as function argumentCommand 0x2F (sub_7D5810): Reads a 32-bit pointer from shared buffer offset 3 and dereferences it:
if ( *(_DWORD *)(a1 + 3) ) // Read 32-bit address from shared buffer
{
if ( (*(_BYTE *)*(unsigned int *)(a1 + 3) & 2) != 0 ) // DEREFERENCE
...
if ( (*(_BYTE *)*(unsigned int *)(a1 + 3) & 4) != 0 ) // DEREFERENCE
...
}No SMRAM validation is performed on either pointer before dereference.
An attacker with Ring 0 access can read arbitrary bytes from any physical address (including SMRAM) by:
- Setting the pointer in the shared buffer to a target address
- Triggering SW SMI# 0x31 with command 0x2B or 0x2F
- Observing the side effects on internal flags to determine bit values of the read byte
Location: sub_7D78D4 at 0x7D78D4 (USB transfer function called by multiple commands)
SW SMI#: 0x31 (49)
CVSS Estimate: 9.0 (Critical)
Vulnerability Class: CWE-787 (Out-of-bounds Write), SMM Arbitrary Write
The core USB transfer function sub_7D78D4 reads a 64-bit pointer from the shared buffer at offset 22 (*(QWORD*)(a3+19) where a3 is buffer+3) and writes to multiple offsets from that pointer without SMRAM validation:
// a3 points to shared_buffer + 3
// *(QWORD*)(a3+19) = *(QWORD*)(shared_buffer+22) = attacker-controlled pointer
*(_DWORD *)(*(_QWORD *)(a3 + 19) + 28LL) = 0; // WRITE 0 at ptr+28
*(_WORD *)(v23 + 66) -= *(unsigned __int8 *)(a1 + 72); // MODIFY word at ptr+66
*(_WORD *)(*(_QWORD *)(a3 + 19) + 70LL) -= ...; // MODIFY word at ptr+70
*(_WORD *)(*(_QWORD *)(a3 + 19) + 74LL) -= ...; // MODIFY word at ptr+74
*(_BYTE *)(v24 + 64) = 0; // WRITE 0 at ptr+64The writes are conditional on signature checks at the target memory (e.g., comparing *(DWORD*)(ptr+3) to known magic values), but these can be satisfied by pointing to crafted memory.
This function is called from USB control transfer (cmd 0x20 group), bulk transfer (cmd 0x21), and interrupt transfer (cmd 0x22) handlers.
An attacker with Ring 0 access can:
- Write zeros and modify words at controlled offsets from any physical address
- Target SMRAM to corrupt SMM handler code or data structures
- Chain with read primitives (FINDING-5) for full SMM code execution
; Ring 0 exploit pseudocode
shared_buffer[0] = 0x20 ; command: USB control transfer
shared_buffer[3] = device_index
shared_buffer[8..15] = 0 ; transfer size
shared_buffer[22..29] = target_smram_addr ; pointer to write target
outb(0xB2, 0x31) ; trigger SW SMI# 0x31
; Handler will write to target_smram_addr+28, +64, +66, +70, +74
FINDING-7: CRITICAL — UsbRt Dynamic Function Call with Attacker-Controlled Arguments (SW SMI# 0x31, Command 0x2D)
Location: sub_7D5EE0 at 0x7D5EE0 → sub_7D5DD0 at 0x7D5DD0
SW SMI#: 0x31 (49)
CVSS Estimate: 8.5 (High)
Vulnerability Class: CWE-822 (Untrusted Pointer Dereference), Controlled Function Call
Command 0x2D calls a dynamic function dispatcher (sub_7D5DD0) that:
- Selects an internal USB function from a table using indices from the shared buffer (
*(BYTE*)(buffer+1)and*(DWORD*)(buffer+11)) - Unpacks arguments from a pointer array located at shared buffer offset 3 (
*(QWORD*)(buffer+3)) - Calls the selected function with up to 7 attacker-controlled arguments
// sub_7D5EE0 — command 0x2D handler
sub_7D5DD0(
internal_function_table[index], // function selected by attacker
*(_QWORD *)(a1 + 3), // argument array from shared buffer
(*(DWORD*)(a1 + 15) + 3) & ~3 // argument count from shared buffer
);
// sub_7D5DD0 — dynamic dispatcher
// Unpacks a2[0], a2[1], ... a2[n-1] and calls a1(a2[0], a2[1], ...)While the function pointer comes from an internal table (not directly from the shared buffer), the arguments are entirely attacker-controlled. This allows calling internal USB protocol functions with arbitrary parameters, potentially achieving:
- Arbitrary memory read/write through internal copy functions
- USB hardware register manipulation
- SMRAM corruption through internal memory management functions
Location: sub_7CA52C (read) and sub_7CA714 (write) in NvmeSmm module
SW SMI#: 0x42 (66)
CVSS Estimate: 5.0 (Medium)
Vulnerability Class: CWE-20 (Improper Input Validation), Partial SMRAM Validation
The NvmeSmm SW SMI# 0x42 handler (sub_7CAE40) implements a 12-command dispatch table at 0x7CA2C0. The handler validates the CommBuffer against SMRAM using a custom inline validation function (sub_7CBE68), and checks a signature byte (*buffer == 39) and command index (buffer[1] < 12).
However, commands 3 (read, sub_7CA52C) and 4 (write, sub_7CA714) extract a data transfer physical address from buffer+15 as a DWORD, and use it as a source/destination for sector data memcpy operations — without validating this address against SMRAM boundaries.
// sub_7CA52C (NVMe read handler)
v9 = *(_QWORD *)(v1 + 5); // LBA
v11 = *(_WORD *)(v1 + 13); // sector count
LODWORD(v19) = *(_DWORD *)(v1 + 15); // DATA BUFFER ADDRESS — NOT validated!
// ...
sub_7CBEF0(v12, v14, v15); // memcpy with unvalidated destinationThe custom SMRAM validation function sub_7CBE68 iterates through SMRAM descriptor ranges (stored at qword_7CC288) checking for overlap — this is a correct implementation. But it is only called once for the CommBuffer itself, not for the data buffer pointer at offset 15.
An attacker with Ring 0 access can:
- Point the data buffer address into SMRAM to write arbitrary NVMe sector data into SMRAM (via read command)
- Point the data buffer address into SMRAM to exfiltrate SMRAM contents to a controlled NVMe device (via write command)
- Exploitation requires a functional NVMe device to be present and the transfer to succeed
- The data buffer address is a DWORD (32-bit), limiting the addressable range
- A successful NVMe I/O transfer must complete for data to actually move
- The CommBuffer itself IS validated against SMRAM
- Superseded by FINDING-11: The EBDA-based arbitrary write (below) provides a simpler and more reliable attack path against NvmeSmm
Location: sub_7D4B7C → sub_7D4888 (UsbRt module)
SW SMI#: 0x31 (49)
CVSS Estimate: 8.8 (High)
Vulnerability Class: CWE-822 (Untrusted Pointer Dereference), EBDA Confusion, Arbitrary SMRAM Write
The UsbRt SW SMI# 0x31 handler (sub_7D4B7C) acquires its communication buffer pointer from the Extended BIOS Data Area (EBDA) when no cached pointer is available:
; sub_7D4B7C — buffer pointer acquisition
mov rcx, [rax+6D78h] ; try cached pointer
test rcx, rcx
jz loc_7D4B9D ; if null → EBDA fallback
loc_7D4B9D:
movzx eax, word ptr ds:0x40E ; read EBDA segment from physical 0x40E
shl eax, 4 ; segment * 16
add eax, 104h ; + 0x104
mov ecx, [rax] ; read DWORD pointer from EBDA+0x104Physical address 0x40E is in conventional memory (below 640K), fully writable by an OS-level attacker. The handler then passes this pointer to sub_7D4888 (command dispatcher), which writes 0xF0 to buffer+2 when the command byte is outside the valid 0x20-0x38 range:
// sub_7D4888 — command dispatcher
if ( v1 < 0x20u || v1 > 0x38u )
{
a1[2] = 0xF0; // WRITE 0xF0 to EBDA-derived pointer + 2
return;
}No SMRAM validation is performed on the EBDA-derived pointer.
- Write a controlled 16-bit value to physical address 0x40E to set the EBDA segment
- At the computed address
(segment * 16) + 0x104, place a 32-bit value =target_SMRAM_addr - 2 - Trigger SW SMI# 0x31 with an invalid command byte (e.g., 0xFF)
- Handler writes 0xF0 to
target_SMRAM_addr
This provides a single-byte arbitrary write of 0xF0 to any physical address including SMRAM. The blog post "Exploiting AMI Aptio firmware on example of Intel NUC" demonstrates using this to patch SMI entry code in SMRAM, modifying a MOV instruction to redirect SMM execution.
Location: sub_7CDC94 (SdioSmm module)
SW SMI#: 0x40 (64)
CVSS Estimate: 8.8 (High)
Vulnerability Class: CWE-822 (Untrusted Pointer Dereference), EBDA Confusion, Validation Bypass
The SdioSmm handler acquires its buffer pointer exclusively from the EBDA (no CommBuffer fallback):
// sub_7CDC94 — SdioSmm handler (decompiled)
v0 = (unsigned __int8 *)*(unsigned int *)(16 * *(unsigned __int16 *)0x40E + 260);
if ( sub_7CEB08(v0, 103) < 0 || *v0 >= 4u )
v0[2] = 7; // ERROR STATUS WRITE — to the SAME pointer that failed validation!
else
funcs_7CDCDD[*v0](v0); // dispatch commandThe handler calls sub_7CEB08 (custom SMRAM validation) on the EBDA-derived pointer. If the pointer overlaps SMRAM, validation correctly returns a negative value. However, the error-handling branch writes 0x07 to v0[2] — which is the pointer that was just detected as being inside SMRAM.
The validation is completely defeated by the error-path write.
; NvmeSmm disassembly confirms the same pattern:
loc_7CAE9A: mov byte ptr [rbx+2], 7 ; write 0x07 to buffer+2
; reached when sub_7CBE68 returns < 0 (SMRAM overlap!)Single-byte arbitrary write of 0x07 to any SMRAM address + 2 offset. The attacker:
- Corrupts EBDA segment at 0x40E to make buffer pointer =
target_SMRAM_addr - 2 - Triggers SW SMI# 0x40
- Validation detects SMRAM overlap → returns error
- Error handler writes 0x07 to
target_SMRAM_addr
The root cause is writing error status to the communication buffer before checking whether the buffer is safe to write to. The correct pattern would be to return immediately without any buffer writes when validation fails. This same flaw affects NvmeSmm (FINDING-11).
Location: sub_7CAE40 (NvmeSmm module)
SW SMI#: 0x42 (66)
CVSS Estimate: 8.8 (High)
Vulnerability Class: CWE-822 (Untrusted Pointer Dereference), EBDA Confusion, Validation Bypass
Identical vulnerability pattern to FINDING-10. The NvmeSmm handler uses EBDA as a fallback when no CommBuffer is provided:
// sub_7CAE40 — NvmeSmm handler
v3 = *a3; // try CommBuffer
if ( v3 )
*a3 = 0; // clear it
else
v3 = *(DWORD *)(16 * *(WORD *)0x40E + 0x104); // EBDA fallback
v5 = sub_7CBE68(v3, 98); // SMRAM validation
if ( v5 < 0 )
goto LABEL_8; // validation failed → error path
if ( *v3 != 39 || v3[1] >= 0xCu )
LABEL_8:
v3[2] = 7; // WRITE 0x07 to SMRAM-overlapping buffer!
return;Same error-path write: mov byte ptr [rbx+2], 7 at 0x7CAE9A. When validation detects SMRAM overlap and returns negative, the handler still writes 0x07 to buffer+2.
Same as FINDING-10: single-byte arbitrary write of 0x07 to SMRAM. This supersedes FINDING-8 (data buffer validation gap) as a simpler and more reliable attack path.
| Field | Value |
|---|---|
| Module | UsbRt (USB Runtime SMM) |
| Entry | 0x7D3F80 |
| SW SMI# | 0x31 (49) |
| Handler | sub_7D4888 at 0x7D4888 |
| Functions | 316 (0x7D3F80 — 0x7EA2B0) |
| Dispatch Table | 26 entries at 0x7D3DF0 |
| Secondary Dispatch | 15 entries (funcs_7D4E66) via command 0x27 |
The UsbRt handler uses a shared memory communication buffer. The SW SMI# 0x31 handler (sub_7D4B7C) retrieves a pointer to this buffer from a global variable, then dispatches to sub_7D4888 which reads byte 0 of the buffer as a command code:
- Command 0x00: Device enumeration status query (sub_7D4E80) — CLEAN
- Commands 0x20-0x38: USB operations dispatched via 26-entry function table
- Command 0x27: Secondary dispatch to 15-entry sub-function table
| Index | Cmd | Handler | Purpose | Risk |
|---|---|---|---|---|
| 0 | 0x00 | sub_7D4E80 | Device enumeration | Clean |
| 1 | 0x20 | sub_7D5778 | (stub) | Clean |
| 2 | 0x21 | sub_7D4F34 | USB transfer setup | Low |
| 3-5 | 0x22-24 | sub_7D4F60 | NOP stubs | Clean |
| 6 | 0x25 | sub_7D4F68 | Device info query | Low |
| 7 | 0x26 | sub_7D4FB4 | Device lookup | Medium |
| 8 | 0x27 | sub_7D4E3C | Secondary dispatch (15 funcs) | High |
| 12 | 0x2B | sub_7D579C | Pointer dereference | CRITICAL |
| 13 | 0x2C | sub_7D5D14 | Flag toggle | Clean |
| 14 | 0x2D | sub_7D5EE0 | Dynamic function call | CRITICAL |
| 15 | 0x2E | sub_7D5F38 | Device info | Low |
| 16 | 0x2F | sub_7D5810 | Pointer dereference | CRITICAL |
| 17 | 0x30 | sub_7D5984 | (minimal) | Clean |
| 18 | 0x31 | sub_7D598C | USB controller ops | Medium |
| 19 | 0x32 | sub_7D5B74 | Device query | Low |
| 20 | 0x33 | sub_7D5BC8 | Virtual method call | Medium |
| 24 | 0x37 | sub_7D4FF4 | Device detail query | Low |
| 25 | 0x38 | sub_7D5164 | Device config | Low |
The USB transfer functions (for control, bulk, and interrupt transfers) follow this chain:
- Command handler reads device index and transfer parameters from shared buffer
- Looks up device structure via
sub_7D9E84(internal device array) - Calls
sub_7D78D4(core transfer function) withbuffer+3as parameter block sub_7D78D4reads: transfer size (*(QWORD*)(buf+5)), endpoint (*(WORD*)(buf+13)), data pointer (*(QWORD*)(buf+19))- Writes to the data pointer at offsets +28, +64, +66, +70, +74 — all without SMRAM validation
Severity: CRITICAL (Systemic)
Three SMM modules (UsbRt, NvmeSmm, SdioSmm) acquire their communication buffer pointer from the Extended BIOS Data Area (EBDA) — a region in conventional memory below 640K that is fully writable by an OS-level attacker:
movzx eax, word ptr ds:0x40E ; read EBDA segment (16-bit) from conventional memory
shl eax, 4 ; segment * 16 = EBDA base address
add eax, 104h ; + 0x104
mov ecx/ebx, [rax] ; read communication buffer pointer from EBDAThis pattern means the attacker controls the pointer itself, not just the buffer contents. By writing a crafted EBDA segment value to physical address 0x40E, the attacker can direct the handler to read its buffer pointer from any address in the first 1MB, and thus make the buffer point anywhere in physical memory — including SMRAM.
| Module | EBDA Usage | Fallback | Error-Path Write |
|---|---|---|---|
| UsbRt | Fallback (if cached ptr null) | Cached at [qword_7EA4F8+0x6D78] |
buffer[2] = 0xF0 |
| NvmeSmm | Fallback (if CommBuffer null) | CommBuffer from a3 | buffer[2] = 0x07 |
| SdioSmm | Always (no fallback) | None | buffer[2] = 0x07 |
Severity: CRITICAL
The ItkSmmVars handler reads its communication buffer address from CPU saved state registers (RSI and RBX) via EFI_SMM_CPU_PROTOCOL.ReadSaveState() at qword_956710:
mov rax, cs:qword_956710 ; EFI_SMM_CPU_PROTOCOL
mov rdx, 4 ; width = 4 bytes
lea r8d, [rdi+2Ch] ; register 0x2C (RSI)
mov r9, r12 ; CPU index
call qword ptr [rax] ; ReadSaveState → rbp = low 32 bits of RSIThe attacker sets RSI to a controlled value before triggering the SMI via outb(0xB2, 0xEF). The handler then uses this as a direct memory pointer, writing error status codes via OR operations to [rbp+0] and [rbp+0x18].
Severity: Informational
Two modules implement custom inline SMRAM validation (functionally equivalent to SmmIsBufferOutsideSmmValid):
| Module | Function | Implementation | Defeated By |
|---|---|---|---|
| SdioSmm | sub_7CEB08 | SMRAM range iteration, correct | Error-path v0[2]=7 writes to the failing buffer |
| NvmeSmm | sub_7CBE68 | SMRAM range iteration, correct | Error-path v3[2]=7 writes to the failing buffer |
Both functions correctly detect SMRAM overlap. However, the error handling code writes a status byte to the same buffer that was just identified as overlapping SMRAM. This completely defeats the validation — the attacker intentionally triggers validation failure to get the constant-value write into SMRAM.
Note: The IDA decompiler incorrectly showed both functions as trivial stubs returning EFI_UNSUPPORTED. The full SMRAM range-checking implementation was only visible in disassembly.
The standard SmmIsBufferOutsideSmmValid function is absent from the image. The remaining modules (UsbRt, ItkSmmVars, SmmHddSecurity, SmmLockBox) have no SMRAM validation at all. This indicates the firmware codebase predates industry-wide CommBuffer hardening (post-2016).
The Skylake platform supports SMM_Code_Chk_En (MSR 0x4E0 bit 0), which prevents code execution from physical addresses outside the SMRAM range. When enabled, attempts to execute non-SMRAM code from SMM trigger a machine check exception. On this NUC firmware, the capability is present (MSR 0x17D bit 58 = 1) but the feature lock status should be verified. This mitigation means exploitation via arbitrary write must target code/data within SMRAM rather than redirecting execution to attacker-controlled memory outside SMRAM.
| Field | Value |
|---|---|
| Module | NvmeSmm |
| Entry | 0x7CA330 (init: sub_7CAEC8) |
| SW SMI# | 0x42 (66) |
| Handler | sub_7CAE40 at 0x7CAE40 |
| Dispatch Table | 12 entries at 0x7CA2C0 |
| Buffer Source | CommBuffer (primary), EBDA fallback |
| SMRAM Validation | sub_7CBE68 (custom, correct but defeated by error-path write) |
Architecture: The handler first tries CommBuffer; if null, falls back to EBDA. Validates buffer against SMRAM via sub_7CBE68, checks signature (*buffer == 39) and index (buffer[1] < 12). On ANY failure, writes buffer[2] = 7 — to the same buffer that may overlap SMRAM (see FINDING-11). Only commands 3 and 4 are active.
Command Table:
| Index | Handler | Purpose | Risk |
|---|---|---|---|
| — | (error path) | Writes 0x07 to buffer+2 | CRITICAL (SMRAM write via EBDA) |
| 0-2 | sub_7CA8F0 | Stub | Clean |
| 3 | sub_7CA52C | NVMe sector read | MEDIUM (unvalidated data ptr) |
| 4 | sub_7CA714 | NVMe sector write | MEDIUM (unvalidated data ptr) |
| 5-11 | sub_7CA8F0 / sub_7CA8E8 | Stubs | Clean |
| Field | Value |
|---|---|
| Module | SdioSmm |
| Entry | 0x7CD870 (init: sub_7CDB04) |
| SW SMI# | 0x40 (64) |
| Handler | sub_7CDC94 at 0x7CDC94 |
| Dispatch Table | 4 entries at 0x7CD818 |
| Buffer Source | EBDA only (no CommBuffer fallback) |
| SMRAM Validation | sub_7CEB08 (custom, correct but defeated by error-path write) |
Architecture: The handler reads its buffer pointer exclusively from EBDA (no CommBuffer parameter). It then validates the buffer against SMRAM via sub_7CEB08. If validation fails OR command index >= 4, it writes buffer[2] = 7 — to the same buffer that was just detected as overlapping SMRAM (see FINDING-10). If validation passes, dispatches through 4-entry function table. Read and write commands additionally validate the secondary data buffer pointer against SMRAM.
Command Table:
| Index | Handler | Purpose | Risk |
|---|---|---|---|
| — | (error path) | Writes 0x07 to buffer+2 | CRITICAL (SMRAM write via EBDA) |
| 0 | sub_7CDCE8 | SDIO sector read | Low (data buffer validated) |
| 1 | sub_7CDE54 | SDIO sector write | Low (data buffer validated) |
| 2 | sub_7CE00C | Get device info | Clean |
| 3 | sub_7CE0A0 | Device reset | Clean |
Three distinct communication mechanisms are used by SMI handlers in this firmware:
1. EBDA pointer chain (UsbRt, NvmeSmm, SdioSmm): Reads EBDA segment from physical 0x40E → computes pointer address → dereferences. Fully attacker-controlled — the pointer itself can be redirected to any memory.
2. CPU saved state registers (ItkSmmVars): Reads RSI/RBX from SMM saved CPU state via EFI_SMM_CPU_PROTOCOL.ReadSaveState(). Fully attacker-controlled — registers are set by the caller before SMI.
3. NVRAM variable pointers (NvramSmi, FlashSmiSmm, NbSmi): Stores buffer addresses in NVRAM during DXE phase. Buffer addresses are set before SMM lockdown and are trustworthy, but buffer contents are attacker-controlled at runtime.
| Module | Mechanism | Buffer Source | Pointer Trust |
|---|---|---|---|
| UsbRt | EBDA | 0x40E → segment*16+0x104 | Untrusted |
| NvmeSmm | EBDA (fallback) | 0x40E → segment*16+0x104 | Untrusted |
| SdioSmm | EBDA (always) | 0x40E → segment*16+0x104 | Untrusted |
| ItkSmmVars | CPU saved state | RSI/RBX registers | Untrusted |
| NvramSmi | NVRAM variable | "NvramSmiBuffer" → qword_74D120 | Trusted (contents untrusted) |
| FlashSmiSmm | NVRAM variable | "FlashSmiBuffer" → qword_7C1548 | Trusted (contents untrusted) |
| NbSmi | NVRAM variable | "NbAslBufferPtrVar" → qword_75B5E8 | Trusted (contents untrusted) |
Handler: sub_95DB84 at 0x95DB84
The OemSmi handlers perform only hardware register I/O operations:
- Super I/O (SIO) chip access via ports 0x2E/0x2F
- MMIO write to 0xFDAF0568 (PCH register)
- Secondary handler
sub_95DB44: simple I/O port operations on 0xA01 and 0xA03
No user-controlled data is processed. Pure hardware management.
Handler: sub_758ED4 at 0x758ED4
Minimal handler that validates CommBuffer is not null and *CommBuffer != -1, then calls internal enable/disable SMI functions. No data processing from CommBuffer contents.
Handler: sub_795D10 at 0x795D10
Hardware SMI handler for PCH GPIO/GPI events. Reads PCIe configuration registers, programs I/O ports, manages PCH power states. No CommBuffer or shared memory processing.
Handler: sub_951C88 at 0x951C88
Handles capsule update preparation. Reads "CapsuleUpdateData" and "FlashUpdateSleepDelay" NVRAM variables, then performs RTC alarm programming via CMOS ports (0x70-0x73) and ACPI timer ports (0x1800-0x1804). No attacker-controlled data processing from shared buffers.
Entry: 0x775300
Checks MSR 0xCE (PLATFORM_INFO) and MSR 0x110 (BIOS_GUARD_CFG) for Intel BIOS Guard hardware capability. If supported, configures the protection and installs a protocol interface for other SMM modules. No SW SMI handler registration. Pure hardware capability management.
Entry: 0x7A2D10
Allocates a 48KB SMRAM buffer, installs an internal SMM protocol interface. No SW dispatch handler — operates as an internal SMM service consumed by other modules through protocol calls.
Entry: 0x7D1340
Minimal initialization that locates a TCG (Trusted Computing Group) protocol. No handler registration found — protocol consumer only.
Handlers: sub_76EDF8 (SMI# 3), sub_76EE64 (SMI# 4), sub_76EE74 (SMI# 5)
All three handlers perform pure hardware register operations:
- sub_76EDF8: Saves/restores PCIe configuration space registers
- sub_76EE64: Minimal handler, returns immediately
- sub_76EE74: Reads/writes PCI configuration space (bus/device/function encoding)
Additionally registers sub_76FA94 (protocol locate only), sub_76EEEC (PCIe config save/restore), and sub_76FB60 (CPU context save, writes "OfflineCpuContext" NVRAM). No user-controlled data processing.
Handler: sub_7EED94 at 0x7EED94 (registered for all three SMI numbers)
The handler is a stub: xor eax, eax; ret (3 bytes). Confirmed via raw memory read (33 C0 C3 CC). Decompilation and disassembly both failed — the function is too small for IDA to recognize. Harmless placeholder.
Handlers: sub_61B1C (SMI# 0x56, MSR save), sub_61C90 (SMI# 0x57, MSR restore)
Both handlers operate exclusively on CPU Model-Specific Registers (MSRs):
- sub_61B1C: Reads MSR values and saves them to internal SMRAM buffers
- sub_61C90: Restores previously saved MSR values
No CommBuffer or shared memory processing. Pure CPU state management.
Handlers: sub_76BF80 (SMI# 0xA0, ACPI enable), sub_76C06C (SMI# 0xA1, ACPI disable)
Pure ACPI register manipulation:
- sub_76BF80: Programs ACPI PM1 control register to enable SCI, disables SMI sources
- sub_76C06C: Reverses the ACPI enable — disables SCI, re-enables SMI sources
No user-controlled data. Standard ACPI mode switching.
Handlers: sub_7B5990 (SMI# 0xD6), sub_7B5B20 (SMI# 0xD7)
- sub_7B5990: Copies boot script data into SMRAM for protection during S3 resume. Defensive measure — locks boot script away from OS-accessible memory.
- sub_7B5B20: Returns EFI_UNSUPPORTED (stub). No operation.
Handler: sub_7BA014 at 0x7BA014
Minimal handler that clears a single internal flag variable. No CommBuffer data processing.
Handler: sub_76D4F0 at 0x76D4F0
Reads IO ports and manipulates internal SMM save state data. The SW SMI number is dynamically assigned from a configuration byte. No shared memory or CommBuffer processing — operates on hardware state only.
| Module | Dispatch Type | Handler | Analysis |
|---|---|---|---|
| SleepSmi | Sx dispatch (S1/S3/S4/S5) | sub_764DCC | Sleep state management only |
| PowerMgmtSmm | IO trap dispatch | sub_78BEE8 | Power management registers |
| SaLateInitSmm | Periodic timer / IO trap | sub_78E5D0 | System agent register programming |
| AhciSmm | Storage protocol | N/A | Internal AHCI protocol, no SW SMI |
| RuntimeSmm | Protocol installation | N/A | Installs runtime SMM protocol interface |
| KbcEmul | IO trap | N/A | Keyboard controller emulation via IO traps |
| UsbS5Wakeup | Sx dispatch + USB event | sub_7ED490 | USB wake-from-S5 handler |
| StatusCodeSmm | Protocol installation | N/A | Status code reporting protocol |
| PttWrapper | Protocol lookup | N/A | Platform Trust Technology, protocol only |
Handler: sub_952850 at 0x952850 (via sub_952D90 dispatch)
Trigger: SW SMI# 0x44 with signature 0xD042 at shared buffer offset 0
Command dispatcher based on byte at offset 4 of shared buffer:
| Command | Action | Risk |
|---|---|---|
| 0 | Calls sub_9523BC, writes result to buffer (version query) | Low |
| 1 | Calls sub_95246C | Low |
| 2 | Validates byte at offset 5 (range 0-1), enables/disables flag | Low |
| 3 | Calls sub_952758 | Low |
The 0x44 sub-handler is simpler than 0xEF and performs less dangerous operations. Commands manipulate flags and return version/status information through the shared buffer. Risk is lower but the same fundamental lack of SMRAM validation applies.
-
Eliminate EBDA-based buffer pointer acquisition — Replace the EBDA pointer chain (
0x40E → segment*16 + 0x104 → read ptr) in UsbRt, NvmeSmm, and SdioSmm with a trusted mechanism (e.g., SMRAM-resident pointer set during DXE, like the NVRAM variable pattern used by NvramSmi). The EBDA is attacker-controlled memory and must never be used as a source of trusted pointers in SMM. -
Fix error-path writes in NvmeSmm and SdioSmm — The validation functions (
sub_7CBE68,sub_7CEB08) correctly detect SMRAM overlap, but the error handling code writes status bytes to the same untrusted buffer. The fix: return immediately without any buffer writes when SMRAM validation fails. Do not write error codes to untrusted memory. -
Patch UsbRt SW SMI# 0x31 handler — Beyond the EBDA issue, multiple command handlers dereference attacker-controlled pointers:
- Commands 0x2B/0x2F: Add SMRAM validation before pointer dereferences
- Core transfer function (sub_7D78D4): Validate
*(QWORD*)(buffer+22)data pointer - Command 0x2D: Validate argument array pointer and all arguments
- Error path in sub_7D4888: Do not write 0xF0 to unvalidated buffer
-
Patch ItkSmmVars SW SMI# 0xEF handler — Add SMRAM boundary validation for the RSI-derived pointer and all embedded pointers before any dereference or write:
- Validate RSI-derived buffer address is outside SMRAM before any access
- Validate
v11(pointer at buffer+4) before dereference - Validate
v11[4],v11[7](variable name, data pointers) before use - For command 5: validate all three memcpy arguments
-
Implement global SmmIsBufferOutsideSmmValid — Add a standard SMRAM boundary check function and apply it at every point where SMM dereferences or writes to externally-supplied addresses.
-
Patch SmmHddSecurity handler — Add CommBuffer SMRAM validation before the 112-byte copy.
-
Patch SmmLockBox handler — Replace the integer overflow check (sub_7D041C) with proper SMRAM boundary validation.
-
Upgrade to modern AMI Aptio with PI 1.4+ CommBuffer validation — The firmware codebase should be updated to a version with standard CommBuffer hardening and SmmIsBufferOutsideSmmValid.
-
Audit remaining UsbRt secondary dispatch table — The 15-entry secondary dispatch (command 0x27) was not fully analyzed and likely contains additional pointer vulnerabilities.
-
Verify SMM_Code_Chk_En lock status — Confirm that MSR 0x4E0 bit 0 (SMM code checking) is enabled and locked via MSR 0x4E0 bit 1 in production firmware, as this mitigates arbitrary code execution via SMRAM write primitives.
- Tools: IDA Pro 9.x with ida-pro-mcp (mrexodia) and idasql (allthingsida) MCP servers
- Approach: Manual decompilation and analysis of all ~43 SMM module entry points, handler registration chains, and handler callback functions. Each module's initialization function was decompiled to identify dispatch protocol registrations (SW, Sx, IO trap, periodic timer, GPI). All SW SMI handlers were then decompiled and analyzed for pointer dereference, SMRAM validation, and input validation vulnerabilities.
- Focus: SW SMI dispatch handlers, communication buffer acquisition patterns (EBDA, CPU saved state, NVRAM variables), SMRAM validation, and pointer dereference chains
- Coverage: All 43 identified SMM modules were analyzed. 20 SW SMI handler registrations were discovered across 11 modules. All handlers were individually examined.
- Validation: Findings were cross-referenced against the published vulnerability research "Exploiting AMI Aptio firmware on example of Intel NUC" (d-olex, October 2016) which analyzed the same firmware image. This comparison identified the EBDA-based communication mechanism and error-path validation bypass patterns (FINDING-9, 10, 11) that were initially missed.
- Decompiler caveats: The IDA decompiler incorrectly rendered two custom SMRAM validation functions (sub_7CEB08 in SdioSmm, sub_7CBE68 in NvmeSmm) as trivial stubs returning EFI_UNSUPPORTED. Disassembly verification was required to discover the full SMRAM range-checking implementation. The EBDA pointer acquisition pattern (
*(WORD*)0x40E * 16 + 0x104) was visible in decompiler output but required domain knowledge to recognize as a security-critical attacker-controlled input. One handler (sub_7EED94 in CrbSmi) was too small for decompilation — raw memory reads confirmed it was a stub. - Limitations: efiXplorer annotations were not relied upon per auditor guidance. The UsbRt secondary dispatch table (15 entries via command 0x27) was not fully analyzed. SmmHddSecurity has 6 additional sub-handlers beyond the primary that were not deeply analyzed.
Report generated: 2026-03-02 Auditor: Claude (AI-assisted static analysis via IDA Pro MCP) Cross-referenced against: d-olex "Exploiting AMI Aptio firmware" (2016)