re-uefi について
re-uefiは、DXEドライバー、UEFIモジュール、ブートキットを調べるファームウェア解析スキルです。構造解析やコード分析、隔離環境でのエミュレーションに先立ち、ファームウェアの段階とモジュール種別を見極めます。
主な機能
- 01UEFIの段階とモジュール種別の分類
- 02ファームウェアボリュームとFFSの解析
- 03EFIドライバーの抽出と逆コンパイル
- 04ブートキットのフックとコールバックの特定
- 05OVMFエミュレーションによる検証
活用シーン
- 01BIOS更新イメージ内のドライバー調査
- 02Secure Bootと起動チェーンの分析
- 03SMMハンドラーと起動フックの調査
- 04疑わしいファームウェアの隔離検証
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ dslsdzc/ rev-skills --skill re-uefiインストール後、Claude Code で/re-uefiを入力して読み込まれたか確認します。
同梱ファイルreferences/pi-stages.md
詳細
UEFI ファームウェアのリバースエンジニアリング(DXE ドライバー/UEFI モジュール/bootkit)
**PE32/PE32+ を見て通常の Windows PE アプリケーションとして分析することは、この分野で最初に排除すべき判断ミスです。**最初のステップは必ずフェーズとモジュールの種類を判定することです:
SEC → PEI → DXE → BDS → OS / Runtime(+ SMM 独立一路)
同じファームウェア内でも、フェーズが異なればモジュールはまったく異なる実行環境で動作します。使用できるメモリ、呼び出せるサービス(PPI/Protocol/Runtime Services)、ライフサイクルが異なります(DXE_DRIVER と DXE_RUNTIME_DRIVER は別物です)。
したがって、順序はまずフェーズと種類を判定し、その後でロジックを考えるです。種類を誤判定すると、その後の「なぜこのように実装されているのか」という推論はすべて間違ってしまいます。詳しくは [[pi-stages]] を参照してください。 </CORE RULE>
フェーズとモジュールの種類(まず分類)
| 種類 | フェーズ | サービス形式/ライフサイクル |
|---|---|---|
| SEC | 最初期 | セキュリティと初期化のエントリーポイント。汎用メモリ環境はありません |
| PEIM | PEI | PPI。PEI の主なタスクの 1 つは恒久メモリの確立です |
| DXE driver | DXE | Protocol。boot services 環境にのみ存在します |
| DXE runtime driver | DXE + Runtime | ライフサイクルをまたいで存在:ExitBootServices() 後も存在し、SetVirtualAddressMap() 時に再配置されます |
| UEFI driver / application | DXE/BDS 以降 | UEFI 環境で実行されるドライバー/アプリケーションであり、ファームウェア組み込みモジュールとは別物です |
| SMM/MM driver | 独立 | SMM 内で実行され、特権レベルとライフサイクルは独自のものです |
頻出する判定基準は次の 3 つです(詳細と決定木は [[pi-stages]] を参照):
- producer xref のない構造体を連続して読み取っている → まず HOB を考えます(PEI から DXE への一方向の受け渡しであり、DXE 側は読み取りのみ)
LocateProtocol(&guid)→ GUID 辞書を照合し、EFI_XXX_PROTOCOL_GUIDとインターフェースの vtable を復元します。直接の呼び出しグラフより、プロトコルグラフのほうが重要です- ファームウェアのアドレス ≠ OS runtime アドレス → 必ずしも hook や再配置の誤りとは限りません。まず、どのフェーズのマッピングを比較しているのか確認してください
使用する場合/使用しない場合
- 前提:ファームウェアイメージを入手したものの、UEFI/PI 構造なのか組み込みイメージなのか不明 → [[re-analyze/system-fingerprints]] のファームウェアのセクション(FV → FFS → section の階層)
- 使用:ファームウェアイメージに EFI 構造(Firmware Volume/FFS ファイル/DXE ドライバー)が含まれる場合——BIOS 更新パッケージ(.fd/.rom/.bin)、UEFI ドライバー、EFI アプリケーション
- 使用:bootkit の特定(SMM handler、タイマーコールバック、起動パスの hook)と検証
- 使用:Secure Boot/起動チェーン関連の分析(署名、証明書、NVRAM 変数)——適法な許可が必要です。落とし穴 4 を参照してください
- 使用しない:ファームウェアが従来型の Linux 組み込み rootfs の場合([[re-fw-extract]]/[[re-fw-rootfs]] を使用。[[re-firmware]] のゲートウェイでまず判定)
- 使用しない:Legacy BIOS Option ROM/非 EFI の従来型ファームウェアの場合(binwalk を使用して [[re-fw-extract]] へ進みます)
- 使用しない:内容全体を展開して確認するだけの場合(まず [[re-fw-extract]] で初期判定し、UEFI 構造だと確認できてから本スキルへ進みます)
- 注意:まず静的分析を行います(大型ファームウェアの原則)。bootkit のエミュレーションは悪意あるコードの実行にあたるため、デフォルトでサンドボックスを使用します([[re-analyze/platform-tips]] の最優先原則)
ツールの準備
すべてのツールは使用前に検証してください。ファームウェアイメージの解析/モジュールの静的分析にはサンドボックスは不要です。OVMF のエミュレーション(手順 5)は動的実行となるため、デフォルトでサンドボックスとネットワーク隔離を使用します([[re-analyze/platform-tips]] の最優先原則)。
UEFITool / UEFIExtract(ファームウェア解析の主力)
- Debian/Ubuntu:
apt install uefitool uefitool-cli(公式パッケージ:GUI + CLI。CLI には UEFIExtract/UEFIFind が含まれます) - Arch:AUR
yay -S uefitool(またはuefitool-git。非公式リポジトリ) - Fedora:公式パッケージなし → GitHub releases の Linux x64 バイナリ(https://github.com/LongSoft/UEFITool/releases)またはソースからビルド(qmake + Qt6)
- macOS:GitHub releases の universal macOS バイナリ(同じページ)
- Windows:GitHub releases の win64 バイナリ(またはミラーが利用できる場合は
choco install uefitool) - 検証:
uefiextract --helpで使い方が表示されること。GUI のuefitoolでファームウェアイメージを開けること
UEFIFind(パターン文字列でファイルを特定。uefitool-cli に同梱)
- NE 版は位置引数の構文のみです:
uefifind imagefile {header|body|all} {list|count} pattern。-g/-t オプションはありません - GUID での特定には、代わりに UEFIExtract の GUID パラメータ形式を使用します:
uefiextract fw.bin <GUID>(下記参照) - インストール方法は上記と同じです(Debian/Ubuntu の uefitool-cli に含まれます)
- 検証:
uefifind --help
ghidra / ida(モジュールの逆コンパイル。インストール方法は [[re-ghidra]]/[[re-ida]] を参照)
- .efi モジュールは PE/COFF(subsystem EFI_BOOT_SERVICE_DRIVER / EFI_APPLICATION)であり、どちらのツールにもそのままインポートできます
- EfiRom プラグイン(任意):EDK2 ツール。ROM ファイルと .efi の相互変換/サイズ確認に使用します
- 検証:抽出した .efi をインポートすると、subsystem が EFI boot service driver として自動認識されること
ovmf —— OVMF(Open Virtual Machine Firmware、UEFI エミュレーションファームウェア)
- Debian/Ubuntu:
apt install ovmf(/usr/share/OVMF/OVMF_CODE.fd、OVMF_VARS.fd) - Fedora/RHEL:
dnf install edk2-ovmf(パスは /usr/share/edk2/ovmf/OVMF_CODE.fd。古い /usr/share/OVMF の配置は廃止されています) - Arch:
pacman -S edk2-ovmf(/usr/share/edk2/x64/OVMF_CODE.4m.fd のみインストールされます。4m 形式) - macOS:
brew install qemuにファームウェアが同梱されています($(brew --prefix)/share/qemu/edk2-x86_64-code.fd。qemu パッケージに含まれます) - Windows:QEMU インストーラーパッケージに同梱されています(share/qemu/ 内の edk2-x86_64-code.fd)
- 検証:ディストリビューションに応じたパスを確認します——Debian/Ubuntu
ls /usr/share/OVMF/OVMF_CODE.fd、Fedora/RHELls /usr/share/edk2/ovmf/OVMF_CODE.fd、Archls /usr/share/edk2/x64/OVMF_CODE.4m.fd、macOS は brew のプレフィックスパスを使用します
qemu-system-x86_64(OVMF の実行環境)
- Debian/Ubuntu:
apt install qemu-system-x86 - Fedora:
dnf install qemu-system-x86-core(仮想化の完全なグループはdnf install @virtualization) - Arch:
pacman -S qemu-system-x86 - macOS:
brew install qemu - Windows:qemu.weilnetz.de のインストーラーパッケージ
- 検証:
qemu-system-x86_64 --version
操作步骤
按顺序执行,每步记录证据(路径 + sha256,见 [[re-triage]])。初勘先做:file fw.bin + 熵确认是否 UEFI 结构([[re-triage]])。
-
固件镜像解析(Firmware Volume → File → Section):
file fw.bin uefiextract fw.bin all # 全量递归解包(含嵌套 FV 与压缩节,见坑 1/2) ls fw.bin.dump/ # 树:Volume0/ → File0/ → Section0/ → PE32 等- GUI: UEFITool 打开 fw.bin,左侧树自上而下 FV → FFS File → Section;先数 FV 数量与类型——主 DXE FV 通常最大、含成百上千模块;PEI FV 与 SEC Core 在最前
- 先确认镜像里有几层 FV(嵌套/恢复卷),别只盯着第一层(坑 1)
-
DXE 驱动提取:
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: 右键 File → Extract body,导出"裸 PE"(去掉 FFS/节头,见坑 3)
- 提取产物先
sha256sum存证([[re-triage]]),再进反编译器
-
模块分析(入口 / Protocol 服务):
- [[re-ghidra]] / [[re-ida]] 打开 .efi;入口 = 镜像 entry(DriverEntry),它是理解驱动的起点
- Protocol 服务是 UEFI 的"API":
gBS->LocateProtocol(&guid,...)(获取服务)、gBS->InstallProtocolInterface(...)(注册服务)、gBS->CreateEvent(...)(事件/回调)、gST->ConOut(控制台输出) - GUID 即"符号"——识别出 LocateProtocol 的 GUID 等于识别 API 调用;用 UEFITool 内置 GUID 数据库(界面里 GUID 旁显示协议名)或搜 UEFI 规范/UEFI GUID 表
strings driver.efi | grep -iE 'protocol|runtime|efi_' | head -30- 记录:入口函数、安装/获取了哪些 Protocol、是否注册了事件回调(接步骤 4)
-
bootkit 定位(SMM / 定时器回调 / 启动路径挂钩):
- 定时器回调:
gBS->CreateEvent(EVT_TIMER, TPL, Callback, ...)+gBS->SetTimer(..., PERIODIC/ONESHOT, ...)→ 回调函数就是周期执行恶意逻辑的地方(最常见挂点) - SMM:
SmiHandlerRegister/ SMST 服务 → SMM driver 注册 SMI handler(SMM 内执行的代码,比内核 ring0 更高特权、SMRAM 内执行的持久层) - 启动路径挂钩: BDS 阶段篡改(NVRAM 变量 BootOrder/BootNext、替换 EFI 启动项、hook 启动管理器/PXE 路径);S3 恢复路径(AP 唤醒代码)
- 运行时服务钩子: 拦截/替换
gRT->SetVariable/GetVariable等 Runtime Services 指针 - 判定特征: 驱动不卸载、携带自定义 GUID、DXE_DEPEX 依赖其他启动器模块、strings 里出现路径/密钥/URL;确认可疑模块 GUID 与依赖关系后进步骤 5
- 定时器回调:
-
OVMF 仿真验证(运行恶意代码——沙箱内,网络
-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- 验证固件能启动到 UEFI Shell/系统 → 再把提取的驱动/固件修改(UEFITool 插入或重建固件镜像)挂入同一 OVMF 观察行为差异
- 无真实固件时 OVMF 就是基线环境(无 Secure Boot 签名约束,见坑 4);仿真细节与用户态替代见 [[re-fw-emulate]]
- 动态行为确认(回调触发/变量篡改)→ 沙箱 + 快照([[re-sandbox]]),行为分析转 [[re-malware]];每步产物存证
分支(references)
- [[pi-stages]] —— PI 阶段模型:SEC/PEI/DXE/BDS/Runtime/SMM 的判定与执行环境差异;HOB(PHIT 开头、PEI 单向生产、DXE 只读、
Build*Hob在 DXE 会断言);GUID 字典解析(Protocol/PPI/FFS/HOB/变量命名空间/配置表);FV → FFS → section → PE 层次(别按 PE 魔数直接 carve);DXE_DRIVERvsDXE_RUNTIME_DRIVER(ExitBootServices后 boot services 全不可用、EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE通知函数禁调任何服务、ConvertPointer、EFI_RUNTIME_ARCH_PROTOCOL的VirtualMode/AtRuntime判据)
跨域联合
- [[re-firmware]]:本技能由 re-firmware 网关引用——UEFI 固件分支;整体流程仍按网关 提取→rootfs→仿真 编排
- [[re-fw-emulate]]:步骤 5 的 OVMF/QEMU 全系统仿真就是本技能对 [[re-fw-emulate]] 的 UEFI 具体化
- [[re-binary-core]]:DXE 驱动静态反编译([[re-ghidra]] / [[re-ida]] / [[re-radare2]])、导入表 [[re-imports]]
- [[re-triage]]:初勘(hash / 架构 / 熵),每层产物存证
- [[re-malware]]:bootkit 动态验证进沙箱([[re-sandbox]]),恶意行为分析转 [[re-malware]]
- 非 EFI 固件(传统 BIOS / 嵌入式镜像)→ [[re-fw-extract]](binwalk 初判)
- [[re-analyze/platform-tips]] 相关分支:静态优先(大型固件样本)、动态默认沙箱(仿真 bootkit 时网络 -net none)、Linux/Windows 平台分支
よくある落とし穴と注意点
- ファームウェアイメージ内の FV の多重ネスト:現象——UEFITool で開いても少数のファイル/モジュールしか表示されず、探しているドライバーが見つかりません。原因——最近のファームウェアでは FV がネストして格納されます(PEI FV に DXE FV が内包される、リカバリボリューム/Capsule、ACPI テーブルに FV が内包されるなど)。外側だけを分析すると、当然ながら不足が生じます。対策——
uefiextract fw.bin allで全体を再帰的に展開します(ネストも自動処理されます)。または GUI で子 FV を階層ごとに展開します。分析前に、まずイメージの構造を確認してください - 圧縮/パディング領域に内容が隠れている:現象——FFS ファイルのセクションが圧縮データまたは FREE_SPACE/FIXED のパディングとして表示され、PE32 コードが見えません。原因——ベンダーが DXE ボリューム全体を圧縮しているためです(EFI/LZMA 圧縮セクション)。空き領域は正常なレイアウトです。対策——UEFITool/UEFIExtract は自動的に解凍し、解凍後の Section を表示します(確認にはこれを使い、binwalk の生バイト列は使わないでください)。binwalk の結果で「コードが見つからない」からといって、コードがないとは限りません。UEFITool で確認してください
- PE ヘッダーが FFS 内でオフセットされている:現象——ファームウェアから取り出した「ファイル」を file/IDA で直接開くと失敗するか、逆コンパイル結果が文字化けします。原因——FFS File Header(24/32 バイト)+ Section Header + アラインメント用パディングの後に、PE32 本体が続くためです。PE ヘッダーはファイルオフセット 0 にありません。対策——UEFITool で右クリックして Extract body を選ぶか、
uefiextract fw.bin <GUID> -m bodyで PE 本体をエクスポートします。エクスポート後、fileで出力に "PE32+ executable (EFI boot service driver)" が含まれることを確認してから逆コンパイラーにかけてください。手動で抽出する場合は、Section のレイアウトに基づいてオフセットを計算してください - Secure Boot の署名検証を回避する分析には、適切な許可が必要です:現象——実験のために「Secure Boot を回避」したり「ファームウェアに再署名」したりしようとして、実際の署名済みファームウェアを変更し、問題が発生します。原因——署名回避、ファームウェアの鍵/証明書の抽出、実機での bootkit の検証には、いずれも法的・許可上の制約が伴います。対策——原則として、署名の制約がない OVMF 開発ファームウェアで分析と動作検証を行ってください。実際のファームウェアを操作する前に、許可の範囲(所有デバイス、脆弱性研究の許可)を確認し、許可がない場合は触れないでください。レポートでは境界を明確にしてください([[re-hardware-io]] の許可範囲と同種の記述)
- ステージ間データを、生成元のない通常のグローバル変数として扱う:現象——ある関数が読み込む構造体が見つからず、削除されたか、コードが不完全だと疑います。原因——それは HOB(PEI→DXE の一方向の引き継ぎ)かもしれません。DXE 側では読み取り専用で、構築を行う呼び出しにはアサーションも含まれます。対策——まず HOB list として解析し、「どのステージが生成し、誰が消費するか」の対応関係を整理してください([[pi-stages]])
- GUID を意味のない UUID として扱う:現象——大量の GUID 定数を説明できず、「定数を渡しているだけ」という段階で分析が止まります。原因——GUID は Protocol/PPI/FFS ファイル/HOB/変数の名前空間/設定テーブルのいずれかを表している可能性があります。対策——GUID→シンボルの辞書を作成し、
LocateProtocolのような呼び出しを意味のある名前とインターフェースの vtable に対応付けてください。プロトコルグラフで呼び出しグラフを補完してください DXE_DRIVERとDXE_RUNTIME_DRIVERを区別しない:現象——ファームウェア内のアドレスと、OS の runtime ステージで取得したアドレスを比較して、フックされていると判定します。原因——runtime driver はExitBootServices()後も存在し、SetVirtualAddressMap()のマッピングに従って再配置されます。そのため、ファームウェア上のアドレスと runtime アドレスは、もともと一致しません。対策——整合性を論じる前に、モジュールの種類とライフサイクル上の位置を判定してください(EFI_RUNTIME_ARCH_PROTOCOLのVirtualMode/AtRuntimeは、そのまま使える判定基準です)([[pi-stages]])