UEFI互換ファームウェアのNVRAMデバイス、パート2

UEFI互換ファームウェアのNVRAMフォーマットについての会話を続けます。これは最初の部分で始まりました 。 今回、AppleファームウェアからのFsysブロックフォーマット、TianoCoreプロジェクトガイドラインに従ったファームウェアからのFTWブロック、およびInsydeコードベースに基づいたファームウェアで見つかるFDCブロックがアジェンダにあります。

なぜ必要なのか、NVRAM以外のデータがどのように見えるのか疑問に思っている場合は、さまざまなメーカーのファームウェアのNVRAMの横にあります。Catへようこそ。



免責事項2



いつものように、作者は起こりうる間違い以外には一切責任を負いません。すべてのバグは機能として自動的に認識されます。 それでもこの記事で何が起こっているのか、どこで実行するのか、何をすべきなのか、誰が責任を負うのか理解できない場合は、 こちらこちらを読ん戻ってください。 戻ったのか、去らなかったのか? 素晴らしい、続行できます。



Fsysブロック



Fsysブロック形式から始めましょう。この形式では、Appleは特定のハードウェアモデルの設定を保存します。 これらの設定は、特別なDXEドライバ( dmidecodeユーティリティを使用してOSから読み取ることができるドライバ)を使用してSMBIOSデータに変換されます。



もちろん、このフォーマットはAppleのファームウェアに固有のものであり、「ずっと昔から」、つまり 最も古いファームウェアと最新のファームウェアの両方にあります。 この形式のデータブロックは通常、最初の2つのVSSリポジトリ(プライマリおよびバックアップ)の直後にあり、理論上はユーザーが変更するべきではなく、そのデータはUEFIランタイムサービスからアクセスできないため、NVRAMとは見なされませんしかし、1つのボリュームでNVRAMを使用する(幸運な)場合は、特にフォーマットが簡単であるため、それらにも対処する必要があり、C構造なしでほとんどすべてを1つのスクリーンショットで表示できます。 ブロックヘッダーと変数は次のようになります。



ブロックは4バイトの署名で始まり、通常はFsysです(比較的古いマシンではGaid 署名のある同じフォーマットの2番目のブロックがあり、最新のマシンではすべてを1つのFsysブロックに入れます)。 署名の後には、5つの不明なバイトが続きますが 、私が持っているすべてのダンプでは、0x01 0x0E 0x00 0x00 0x00ですが、もちろん、異なる場合があります。 これらの後には、2バイトの合計ブロックサイズが続き、その直後に、アライメントなしで、最大のパッキングで変数が始まります。 変数(Appleはエンドユーザーがこのデータを変更することを許可しないため、このエンティティを「レコード」と呼ぶ方がよい)は、シングルバイトの名前の長さ 、ASCIIエンコード 、2バイトのデータ長 、およびデータそのものです。 スクリーンショットでは、タイトルに加えて、3つ半のエントリが表示されていることがわかりました-dcktdckhdck_ 、およびoverrides

データの先頭に注意してください:BZ- 署名 、h- ハフマンコードの使用の表示、1- ブロックサイズの表示、そして一般的にBCDでエンコードされPi番号 ... Ba、旧友、 Bzip2形式 ! 入手し、開梱して、これを入手します。
overrides.txt
ADD_DEVICE()[class = "USBPort"、type = "USB 2.0"、location = "right"、speed = "480"、uhci-id = "0xFA133000"、ehci-id = "0xFA130000"]

ADD_DEVICE()[class = "USBPort"、type = "USB 2.0"、location = "left"、speed = "480"、uhci-id = "0xFD113000"、ehci-id = "0xFD110000"]

ADD_DEVICE()[class = "SensorController"、location = "U5510"、model = "EMC1413"、device-key = "SensorController @ U5510"]

ADD_DEVICE()[class = "SensorController"、location = "U5530"、model = "EMC1704"、device-key = "SensorController @ U5530"]

ADD_DEVICE()[class = "ThunderboltPort"、location = "Left"、port1 = "1"、port2 = "2"、mcuaddr = "0x26"]

SET_PROPERTY(class = "Processor")[ptype = "iCore"]

SET_PROPERTY(class = "Battery")[cell-count = "2"]

SET_PROPERTY(class = "Sensor"&location = "VC0C")[下限= "0.0"、上限= "1.23"、タイプ= "電圧"、説明= "電圧センサーCPU 0 VCore"]

SET_PROPERTY(class = "Sensor"&location = "VP0R")[下限= "7.2"、上限= "8.9"、タイプ= "電圧"、説明= "電圧センサーPBus 0レール"]

SET_PROPERTY(class = "Sensor"&location = "VN0C")[下限= "0.0"、上限= "1.23"、タイプ= "電圧"、説明= "電圧センサーAGX 0 VCore"]

SET_PROPERTY(class = "Sensor"&location = "VD0R")[下限= "13.5"、上限= "15.5"、タイプ= "電圧"、説明= "電圧センサーDCIN"]

SET_PROPERTY(class = "Sensor"&location = "VC1R")[下限= "7.2"、上限= "8.9"、タイプ= "電圧"、説明= "電圧センサーCPUハイサイド"]

SET_PROPERTY(class = "Sensor"&location = "ID0R")[下限= "0.0"、上限= "3.5"、タイプ= "電流"、説明= "電流センサーDC入力0レールAMON"]

SET_PROPERTY(class = "Sensor"&location = "IB0R")[下限= "0.0"、上限= "10.0"、タイプ= "現在"、説明= "現在のセンサーCHGR 0レールBMON"]

SET_PROPERTY(class = "Sensor"&location = "IC0R")[下限= "0.0"、上限= "12.0"、タイプ= "現在"、説明= "現在のセンサーチップセット0 INAハイサイド"]

SET_PROPERTY(class = "Sensor"&location = "IC1R")[下限= "0.0"、上限= "12.0"、タイプ= "現在"、説明= "現在のセンサーチップセット0 SMBUSハイサイド"]

SET_PROPERTY(class = "Sensor"&location = "IC0C")[下限= "0.0"、上限= "25.0"、タイプ= "現在"、説明= "現在のセンサーCPU 0 VCore"]

SET_PROPERTY(class = "Sensor"&location = "IN0C")[下限= "0.0"、上限= "10.0"、タイプ= "現在"、説明= "現在のセンサーIG GFX VCore"]

SET_PROPERTY(class = "Sensor"&location = "IM0R")[下限= "0.0"、上限= "10.0"、タイプ= "現在"、説明= "現在のセンサーメモリ電力"]

SET_PROPERTY(クラス= "センサー"&場所= "Ts0P")[ノイズ許容値= "3.0"、下限= "10"、上限= "50"、タイプ= "温度"、タイプ= "TEMPセンサーMLB »]

SET_PROPERTY(class = "Sensor"&location = "TPCD")[ノイズ許容値= "3.0"、下限= "15"、上限= "100"、タイプ= "温度"、説明= "TEMPセンサーPCH »]

SET_PROPERTY(class = "Sensor"&location = "TC0D")[ノイズ許容値= "3.0"、下限= "10"、上限= "110"、タイプ= "温度"、説明= "TEMPセンサーCPU 0ダイ "]

SET_PROPERTY(class = "Sensor"&location = "TC0P")[ノイズ許容値= "3.0"、下限= "20"、上限= "87"、タイプ= "温度"、説明= "TEMPセンサーCPU 0近接”]

SET_PROPERTY(class = "Sensor"&location = "TM0P")[ノイズ許容値= "3.0"、下限= "20"、上限= "75"、タイプ= "温度"、説明= "TEMPセンサーインレット»]

SET_PROPERTY(class = "Sensor"&location = "Ta0P")[ノイズ許容値= "3.0"、下限= "20"、上限= "80"、タイプ= "温度"、説明= "TEMPセンサーインレット»]

SET_PROPERTY(class = "Sensor"&location = "Tm1P")[ノイズ許容値= "3.0"、下限= "10"、上限= "65"、タイプ= "温度"、説明= "TEMPセンサーインレット»]

SET_PROPERTY(class = "Sensor"&location = "Tm0P")[ノイズ許容値= "3.0"、下限= "10"、上限= "65"、タイプ= "温度"、説明= "TEMPセンサーインレット»]

SET_PROPERTY(クラス=「センサー」&ロケーション=「THSP」)[ノイズ許容値=「3.0」、下限=「10」、上限=「65」、タイプ=「温度」、タイプ=「TEMPセンサーPCH近接 "]

SET_PROPERTY(class = "Sensor"&location = "Th1H")[ノイズ許容値= "3.0"、下限= "10"、上限= "65"、タイプ= "温度"、タイプ= "TEMPセンサーフィンスタック "]

SET_PROPERTY(クラス= "センサー"&場所= "TB1T")[ノイズ許容値= "1.0"、下限= "10"、上限= "50"、タイプ= "温度"、タイプ= "TEMPセンサーBMU 1 "]

SET_PROPERTY(class = "Sensor"&location = "TB2T")[ノイズ許容値= "1.0"、下限= "10"、上限= "50"、タイプ= "温度"、タイプ= "TEMPセンサーBMU 2 "]

SET_PROPERTY(class = "Sensor"&location = "TB0T")[ノイズ許容値= "1.0"、下限= "10"、上限= "50"、タイプ= "温度"、タイプ= "TEMPセンサーバッテリー»]

SET_PROPERTY(class = "Sensor"&location = "TC0C")[ノイズ許容値= "1.0"、下限= "15"、上限= "105"、タイプ= "温度"、タイプ= "TEMPセンサーCPUダイ-デジタルコア0 "]

SET_PROPERTY(クラス= "センサー"&場所= "TC1C")[ノイズ許容値= "1.0"、下限= "15"、上限= "105"、タイプ= "温度"、タイプ= "TEMPセンサーCPUダイ-デジタルコア1 "]

SET_PROPERTY(class = "Sensor"&location = "PCPT")[ノイズ許容値= "1.0"、下限= "0"、上限= "55"、タイプ= "電源"、説明= "電源センサーCPUパッケージ総電力 "]

SET_PROPERTY(class = "Sensor"&location = "PCPG")[ノイズ許容値= "1.0"、下限= "0"、上限= "22"、タイプ= "電源"、説明= "電源センサーCPUパッケージGfx Power "]

SET_PROPERTY(class = "Sensor"&location = "PCPC")[ノイズ許容値= "1.0"、下限= "0"、上限= "33"、タイプ= "電源"、説明= "電源センサーCPUパッケージコアパワー”]

SET_PROPERTY(クラス= "センサー"&場所= "MO_X")[タイプ= "加速度計"、説明= "モーションセンサー"]

SET_PROPERTY(class = "Sensor"&location = "MSC0")[下限= "9750"、上限= "14500"、タイプ= "CalibrationKeys"、説明= "キャリブレーションキー0"]

SET_PROPERTY(class = "Sensor"&location = "MSLD")[type = "磁力計"、説明= "磁力計"]

SET_PROPERTY(class = "HardDrive"&type = "SSD")[throttling-support = "TRUE"]

REMOVE_DEVICE(クラス= "センサー")(クラス= "センサー"&タイプ= "?")





ブロック内のエントリは、名前がEOFのレコードが存在するまで互いに続きます。その後、ブロックの最後にゼロが続き、ブロックの内容全体のCRC32チェックサムが、最後の4バイトを除く最後の4バイトに書き込まれます。 Appleは一般にCRC32を非常に愛しており、Fsysレコード、VSS NVRAM変数、EFI実行可能ファイル、ボリューム、イメージ全体に対しても文字通りすべてを考慮しています。 誠実さの神への誠実さ、支配の玉座へのコントロール!



手動で分解する気分がなければ、 UEFITool NEが再び助けになります。上のスクリーンショットのFsysブロックは次のようになります。





FTWブロック



準備リストの次のブロックはFTWです 。これは、NVRAMでのトランザクション記録をサポートするために使用され、記録中の停電後に整合性を復元するのに役立ちます。 残念ながら(または、おそらく幸いなことに)、このブロックのエントリでファームウェアダンプに遭遇したことはないので、ここでヘッダーを解析することしかできません。コンテンツ形式のTianoCoreプロジェクトコードにアクセスする必要があります。 ただし、理論は理論ですが、実際には、ファームウェアの1つの美しくて楽しいタイトルの代わりに、次のように2つのほぼ同一のタイトルが突然表示されます。
struct EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER32 { EFI_GUID Signature; // EFI_SYSTEM_NV_DATA_FV_GUID UINT32 Crc; // CRC32      Crc  State. //      ErasePolarity  NVRAM UINT8 State; //  ,  (0xFE  0x01,    ErasePolarity)   ( ) UINT8 Reserved[3]; //   UINT32 WriteQueueSize; //   ,  UINT32 //UINT8 WriteQueue[WriteQueueSize]; //  };
      
      





そしてそのような:
 struct EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER64 { EFI_GUID Signature; // EFI_SYSTEM_NV_DATA_FV_GUID  EDKII_WORKING_BLOCK_SIGNATURE_GUID UINT32 Crc; // ~~~ UINT8 State; // ~~~ UINT8 Reserved[3]; // ~~~ UINT64 WriteQueueSize; //  UINT64,     //UINT8 WriteQueue[WriteQueueSize]; // ~~~ };
      
      





そのような予想外の多様性は、構造のどのバージョンが目の前にあるかを推測しようとするときに、特定の困難を生み出します。 幸いなことに、ほとんどの場合、総FTWブロックサイズは16バイトの倍数であるため、 WriteQueueSizeの値を完全に16で除算できるかどうかをチェックするだけで十分です。除算する場合、2番目のオプションがあります。この構造の別のバージョン、歓声。



スクリーンショットでは、2番目のタイプのヘッダーのみを表示します。 最初のものは、ゴロフ王の時代からのいくつかの古いファームウェアでのみ見つかります。



すべてが仕様に従っており、 GUIDはFFF12B8D-7696-4C8B-A985-2747075B4F50、 CRC32は0xB0458FB9、 ブロック状態は有効、 データサイズは0xFE0で、16で完全に割り切れるため、ヘッダーの最後の4バイトはまだヘッダーではありませんすでにデータの一部。



UEFITool NEでは、同じブロックは次のようになります。





FDCブロック



UEFIフォーラムがNVRAMにSecureBootのキーを保存することを決定した後、VSS形​​式( 最初に説明しました)を真剣に作り直すだけでなく、これらの変数の「デフォルト」を保存する問題を解決する必要があり、ベンダーは再びそれを解決することができました自分で。 Insydeのそのようなソリューションの1つ、すなわちFDCユニットは、ここで分析します。

そこにあるフォーマットは非常にシンプルですが、その開発者が何によって導かれたかは私には完全にはわかりません。 ブロックのタイトルは次のとおりです。

 struct FDC_VOLUME_HEADER { UINT32 Signature; //  _FDC UINT32 Size; //       //EFI_FIRMWARE_VOLUME_HEADER VolumeHeader; //  NVRAM-,    -   //VSS_VARIABLE_STORE_HEADER VssHeader; //   VSS,       //       ,   };
      
      





スクリーンショットでは、この悪夢は次のようになっています。



合計: 署名は_FDC、 合計ブロックサイズは0x4000、 NVRAMボリュームのヘッダー、何も使用されていない、VSSストレージの署名は フォーマットされた正常 状態で満たされていない 、および変数のある領域です 。 一般的には何も必要のないヘッダーに88バイトも費やされたことが判明しましたが、私の内部オプティマイザーはinしています。



UEFITool NEでは、これらの不要なヘッダーをすべて表示しないことにしました。したがって、同じFDCブロックは次のようになります。





おわりに



さて、NVRAMボリュームの中央に保存されるあらゆる種類の奇妙なブロックのフォーマットを決定しましたが、EVSAとNVARはデザート用に残りました。これについては第3部で説明します。 ご清聴ありがとうございました。



All Articles