mcpField
R
re-uefi

re-uefi

github.com/dslsdzcセキュリティ20651 回インストール2 週間前に更新
リポジトリ

re-uefi について

re-uefiは、DXEドライバー、UEFIモジュール、ブートキットを調べるファームウェア解析スキルです。構造解析やコード分析、隔離環境でのエミュレーションに先立ち、ファームウェアの段階とモジュール種別を見極めます。

主な機能

  1. 01UEFIの段階とモジュール種別の分類
  2. 02ファームウェアボリュームとFFSの解析
  3. 03EFIドライバーの抽出と逆コンパイル
  4. 04ブートキットのフックとコールバックの特定
  5. 05OVMFエミュレーションによる検証

活用シーン

  1. 01BIOS更新イメージ内のドライバー調査
  2. 02Secure Bootと起動チェーンの分析
  3. 03SMMハンドラーと起動フックの調査
  4. 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最初期セキュリティと初期化のエントリーポイント。汎用メモリ環境はありません
PEIMPEIPPI。PEI の主なタスクの 1 つは恒久メモリの確立です
DXE driverDXEProtocol。boot services 環境にのみ存在します
DXE runtime driverDXE + Runtimeライフサイクルをまたいで存在:ExitBootServices() 後も存在し、SetVirtualAddressMap() 時に再配置されます
UEFI driver / applicationDXE/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/RHEL ls /usr/share/edk2/ovmf/OVMF_CODE.fd、Arch ls /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]])。

  1. 固件镜像解析(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)
  2. 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]]),再进反编译器
  3. 模块分析(入口 / 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)
  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
  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_DRIVER vs DXE_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]])

コメント