
Static reverse-engineering of a GIGABYTE H510M K V2 (`H510MKV2.F3`) BIOS image: full UEFI firmware-volume extraction analysis of the PI-spec SMM Core memory allocator and a targeted hunt for the four SMM memory-corruption vulnerabilities GIGABYTE/Binarly disclosed in 2025 (CVE-2025-7026 CVE-2025-7027 CVE-2025-7028 CVE-2025-7029).
Static reverse-engineering of a GIGABYTE H510M K V2 (H510MKV2.F3) BIOS image: full
UEFI firmware-volume extraction analysis of the PI-spec SMM Core memory
allocator and a targeted hunt for the four SMM memory-corruption
vulnerabilities GIGABYTE/Binarly disclosed in 2025
(CVE-2025-7026 CVE-2025-7027 CVE-2025-7028 CVE-2025-7029).
Status: 1 of 4 CVEs confirmed present (CVE-2025-7027). The other 3 were actively searched for across the entire accessible firmware and not found see Unconfirmed CVEs for exactly what that does and doesn't mean.
This is n-day research not a 0-day disclosure. All four CVEs referenced here were already publicly disclosed and patched by GIGABYTE (patched firmware began shipping 2025-06-12) assigned CVEs and written up by Binarly and CERT/CC before this research began. Nothing in this repository is new vulnerability discovery it is an independent static-analysis verification of whether the previously-disclosed previously-patched bug classes are present in one specific publicly-downloadable BIOS build.
uefi-firmware-parser) 356 FFS files enumerated across the SMM/DXE
volume 302 with an extractable PE32/TE image.PiSmmCore (the PI-spec SMM Core)
confirming and naming the real SMM pool/page allocator
(SmmAllocatePool/SmmFreePool/SmmAllocatePages/SmmFreePages
internals) via its hard-coded "sphd"/"tail" guard signatures an
exact match to EDK2's open-source MdeModulePkg/Core/PiSmmCore/Pool.c.GenericComponentSmmEntry: an NVRAM variable
(SetupXtuBufferAddress) is fetched via with no validation
and used directly as a write pointer reachable via SW SMI this
matches Binarly's public root-cause description point for point.uefi_firmware
(uefi-firmware-parser -e) recursively unpacked the BIOS image: Intel
Flash Descriptor regions → firmware volumes → FFS files → sections
decompressing every LZMA/Tiano-compressed firmware volume it found..ui (driver display name)
section and a .pe/.te image section was copied out as a standalone
PE32+/TE binary named <DriverName>__<GUID8>.<pe32|te>.ida-pro-mcp / idalib headless worker interface) with the Hex-Rays
decompiler one database per module. Auto-analysis + Hex-Rays only no
FLIRT signatures or EDK2 type libraries were available in this
environment (noted as a limitation below).The BIOS image contains four Intel Flash Descriptor regions; only
region-bios contains GIGABYTE/OEM code (region-me.fd region-gbe.fd
region-pdr.fd are Intel Management Engine / GbE / descriptor firmware
separate components out of scope not explored).
Within region-bios four firmware volumes were found and extracted:
All four were extracted and marker-scanned (see Unconfirmed CVEs).
SMM/
├── README.md this file
├── CVE_ANALYSIS.md full technical deep-dive (code-level detail confidence notes)
├── flash.fd copy of the extracted 16MB BIOS image
├── regions/ raw recursive extraction (every FV/FFS/section as produced by uefi_firmware)
├── smm_modules/ PiSmmCore isolated + fully analyzed (.pe32 + Hex-Rays .i64 renames applied)
├── smm_modules_all/ all 51 `Smm*`-named drivers as standalone PE32/TE + manifest.txt
│ (4 extra ones PiSmmCpuDxeSmm SmmAccess SmmControl SmmLockBox
│ FlashSmiSmm FlashDriverSmm have auto-analyzed .i64 databases)
├── all_modules/ every extractable module from the main DXE/SMM volume (302 not just Smm*-named)
├── extra_volumes_modules/ modules from the two smaller auxiliary firmware volumes
└── f641_pei_modules/ modules from the duplicate PEI-phase volume copy
Common thread across all four: a Software SMI handler trusts a register or an NVRAM-sourced value as a pointer into memory without validating that it actually lies outside SMRAM letting a ring-0 (Administrator/root) attacker turn a normal SW SMI trigger into an SMM-privileged (ring -2) arbitrary read/write full firmware compromise Secure-Boot bypass and persistence below the OS.
Not a vulnerability background research that grounded the rest of the work by proving the toolchain (extraction → PE isolation → IDA/Hex-Rays → manual RE) actually recovers genuine source-verifiable EDK2 internals before it was pointed at security bugs.
PiSmmCore (GUID e94f54cd-81eb-47ed-aec3-856f5dc157a9) is the PI-spec SMM
Core: it owns SmmAllocatePool/SmmFreePool/SmmAllocatePages/SmmFreePages
and the SMI handler dispatch table.
Call chain (addresses inside smm_modules/PiSmmCore.pe32.i64):
_ModuleEntryPoint (0x1184)
-> SmmCoreEntryPointHelper (0x14D4) writes the "SMST" table signature
-> SmmInternalAllocatePool_wrapper (0x95EC)
-> InternalAllocPoolByIndex_sphd_tail (0x57A8) <- the allocator
-> SmmAllocateZeroedPool (0x961C) alloc + zero wrapper
SmmFreePool_wrapper (0x9714)
-> SmmIsBufferInsideSmram (0x95A8) decides SMRAM-resident vs not
-> SmmInternalFreePool_sphd_tail (0x591C) validates sphd/tail frees
-> InternalFreePages (0x6A2C) page-granularity free + coalesce
InternalFindFreePages (0x6820) page-granularity alloc (mirror of InternalFreePages)
InternalAllocPoolByIndex_sphd_tail (0x57A8) is confirmed as the genuine
EDK2 MdeModulePkg/Core/PiSmmCore/Pool.c allocator: it hard-codes the
literal ASCII signatures "sphd" (SMM_POOL_HEAD_SIGNATURE) and "tail"
(SMM_POOL_TAIL_SIGNATURE) the exact magic constants from the open-source
implementation. Requests ≤ 0x800 bytes go through a size-class free-list
suballocator; larger requests walk a page free-list and wrap the returned
chunk with head/tail guard signatures. The free-side counterpart
(SmmInternalFreePool_sphd_tail) validates the same signatures before
returning memory to the free list.
All renames are baked into smm_modules/PiSmmCore.pe32.i64 open it in IDA
with Hex-Rays to inspect directly.
Module: GenericComponentSmmEntry (GUID 9caa3071-3459-4c5b-bbf0-ee68fe4dd46d)
File: smm_modules_all/GenericComponentSmmEntry__9caa3071.pe32 (+ analyzed .i64)
Every extracted module (51 Smm*-named then all 302 in the main volume
then the auxiliary volumes) was byte/string-scanned for SetupXtuBufferAddress
the exact NVRAM variable name Binarly's CVE-2025-7027 writeup cites. It
matched as a UTF-16LE string inside GenericComponentSmmEntry (and its DXE
counterpart GenericComponentDxeEntry which presumably sets/exposes it).
1. GetXtuBufferAddress_FromNvram (0x1F270) calls
gRT->GetVariable(L"SetupXtuBufferAddress" &Guid NULL &Size=8 &OutBuffer)
(offset +72 in the runtime-services-style table = GetVariable). Returns
the raw 8-byte value stored in this NVRAM variable no validation of what
that value actually is.
2. SUSPECTED_CVE_2025_7027_UnvalidatedXtuPtrWrite (0x18400) calls the
above to get v3 (the NVRAM-sourced "address") then loops (bounded by a
count taken from its own input structure a1[3]) doing:
*(WORD *)(v3 + 2 * v7 + 12) = v9; // v3 = raw NVRAM value v9 = attacker-influenced data
v3 is never checked to be a real in-bounds non-SMRAM address before
being used as a write target. SetupXtuBufferAddress is a normal
(non-SMM-locked in this build) NVRAM variable a ring-0 attacker can
SetVariable() it to any address they choose (e.g. an SMRAM address or a
sensitive kernel/hypervisor structure) before triggering the SMI producing
a controlled SMM-privileged write-what-where.
3. ComponentDispatch_KeymapOrXtu (0x18590) the dispatch callback:
fetches a component-type byte from an internal component database and if
type == 1 calls the vulnerable function above. Type 0 goes to
SetupVar_SafeKeymapWrite_bounded (0x18234) which for contrast does
do proper size-vs-capacity bounds checking against a real Setup NVRAM
variable. That contrast is what makes the XTU path stand out as the
anomalous unchecked one.
4. sub_18698 registers ComponentDispatch_KeymapOrXtu against
dispatch value 0xB2 (178 decimal) the exact SwSmiInputValue 0xB2
Binarly's advisory names for this bug class. This ties the software-SMI
trigger port directly to the vulnerable dispatch path.
SetupXtuBufferAddress) verbatim.0xB2).RBX
register at SMI entry feeds the component-selection input reaching
ComponentDispatch_KeymapOrXtu/a1[3] was not traced all the way to
the raw CPU-save-state read. That would need one more pass through
whatever dispatches on the registered 0xB2 value before calling into
GenericComponentSmmEntry's registered callback.This is static-analysis confirmation that the vulnerable pattern described in the CVE is present in this BIOS build not a working exploit or PoC. No SMRAM contents save-state layout or runtime behavior was verified.
Every marker named in Binarly's public writeups for these three CVEs
$DB$ 2DB$ SwSmi OcHeader FuncBlock CommandRcx0 ReadFlash
WriteFlash EraseFlash GetFlashInfo was searched as both a literal
byte sequence and (where applicable) a UTF-16LE string across:
flash.fd image.all_modules/).extra_volumes_modules/).f641_pei_modules/).None of these markers were found anywhere. Only SetupXtuBufferAddress
(CVE-2025-7027) and generic OverClock UI-text strings (unrelated
BIOS Setup menu labels) matched.
SetupXtuBufferAddress had to appear as a literal string because it's a
real NVRAM variable name passed to GetVariable() the string is
functionally required. CommandRcx0 OcHeader and FuncBlock by
contrast read like Binarly's own internal labels for anonymous/stripped
functions they reverse-engineered not identifiers embedded in the binary.
Their absence as strings proves nothing about whether the underlying code
exists. The $DB$/2DB$ magic constants would show up as a byte-level
match if present (they'd appear as an immediate operand in the compiled
comparison string or not) their absence is somewhat more meaningful but
still not conclusive (a different immediate encoding a per-model firmware
variant or a slightly different check order could all evade a raw substring
scan).
FlashSmiSmm (GUID 6c289241-...)
and FlashDriverSmm (GUID 0c375a90-...) are the strongest candidates
their names line up with ReadFlash/WriteFlash/EraseFlash/GetFlashInfo
almost exactly. Both were extracted and auto-analyzed (.i64 databases in
smm_modules_all/ Hex-Rays-ready) but not manually traced that's
174 and 243 functions respectively with no distinguishing static markers
requiring the same kind of manual dispatcher-tracing done for
CVE-2025-7027 (find the SW SMI 0xB2-equivalent registration follow it
to a function-pointer-table dispatch check whether the table pointer is
validated).OcHeader). Good candidates:
itself (already a proven source of an
unchecked-pointer bug in this exact module)
none manually
traced yet.None of this was completed in this pass it's flagged here explicitly so the gap is visible rather than silently implied to be "checked and clean."
If you own this board (or any of the 240+ GIGABYTE models covered by this
advisory): update to the current BIOS from GIGABYTE's support site.
GIGABYTE began shipping patched firmware 2025-06-12; the build analyzed here
(H510MKV2.F3 dated 2023-12-20) predates that by roughly 18 months and is
consistent with being unpatched. This isn't a theoretical recommendation
this research found the actual vulnerable code path for CVE-2025-7027
present in this specific build.
.til) was available in this analysis
environment so the SMM System Table (gSmst)/private-data structure
fields could not be auto-mapped by Hex-Rays; some struct-offset
interpretations in the analysis are based on manual tracing rather than
applied type information.region-me.fd region-gbe.fd region-pdr.fd (Intel ME / GbE /
descriptor regions) were not explored out of scope (separate firmware
components not GIGABYTE/OEM SMM code).CVE_ANALYSIS.md for the full code-level technical
deep-dive this README summarizes.| Board | GIGABYTE H510M K V2 (H510MKV2) |
| BIOS file | H510MKV2.F3 |
| File size | 16777216 bytes (16 MB) |
| File date | 2023-12-20 |
| MD5 | a9bca8aeb55061824af1c3eedfb5c846 |
| SHA-256 | 934a935e5faba8d2cea4e1d51e9edb6aed86b32f412d0da5bae602bd9fd8f9f3 |
| Chipset | Intel H510 |
| Vendor patch available since | 2025-06-12 (this build predates it by ~18 months) |
GetVariable()0xB2| Volume (container FFS GUID) | Contents | Files extracted |
|---|
file-9e21fd93-... → volume-ee4e5898-... | Main DXE/SMM driver volume all Smm* drivers platform DXE drivers | 302 |
file-f641ac56-... → volume-ee4e5898-... | Duplicate/PEI-phase copy of the above (smaller subset: PiSmmCommunicationPei IT8728FSmmFeaturesPei etc.) | 22 |
file-3417f275-... → volume-3417f275-... | Early PEI/DXE bring-up volume (DxeIpl FspS3Notify ...) | 21 (2 with images) |
file-05ca020b-... → volume-05ca020b-... | Small auxiliary volume no executable images | 2 |
| CVE | Binarly ID | CVSS | Public root-cause summary |
|---|
| CVE-2025-7026 | BRLY-2025-008 | 8.2 | SW SMI handler (SwSmiInputValue 0xB2) trusts the RBX register as an unchecked pointer inside a function Binarly calls CommandRcx0; if *RBX matches '$DB$'/'2DB$' the handler performs an arbitrary SMRAM write. |
| CVE-2025-7027 | BRLY-2025-009 | 8.2 | Double pointer dereference: an unvalidated NVRAM variable (SetupXtuBufferAddress) combined with an attacker-controlled RBX-derived pointer → arbitrary SMRAM write. |
| CVE-2025-7028 | BRLY-2025-010 | 8.2 | Lack of validation of function-pointer structures (FuncBlock) derived from RBX/RCX reachable through ReadFlash/WriteFlash/EraseFlash/GetFlashInfo. |
| CVE-2025-7029 | BRLY-2025-011 | 8.2 | Unchecked use of RBX controls an attacker-influenced OcHeader pointer in power/thermal (overclock) configuration logic → arbitrary SMRAM write. |
GenericComponentSmmEntryPowerMgmtSmmRealTimePowerSmmThermalFanCtrSmmPpamPlatformSmm$DB$/2DB$ signature check). Since SwSmiInputValue 0xB2 is shared across at least CVE-2025-7026 and CVE-2025-7027 per
Binarly's writeups and this dump proved 0xB2 is a real actively-used
dispatch value in GenericComponentSmmEntry the next step is enumerating
every driver in the main volume that registers a callback against
0xB2 (not just the one already found) and checking each for an
unchecked-pointer-plus-magic-value pattern.