toruのブログ

月1くらいで記事書きたい。

バイナリエディタの ImHex を使ってみた

背景

  • UltraHDR の調査中に画像ファイルのメタデータを確認する必要が生じた
  • 今までは VS CodeHex Editor を使っていたが、もっと拡張性のあるツールを使わないと解析が厳しかった
  • Chat GPT 先生にバイナリエディタについて相談したところ、ImHex を勧められたので実際に使ってみた

目的

結論

  • ImHex は大変便利なバイナリエディタであった
  • Pattern editor でデータの取得、および取得したデータを使った計算ができるのは大変助かった
    • ImHex の Pattern editor で解析をしている様子を図1 に示す。
  • 一方で ImHex はとても多機能なバイナリエディタであり、使いこなすには修練が必要だと感じた

図1. ImHex の Pattern editor を使い JPEGメタデータを確認している様子

詳細

解析対象の紹介

今回、筆者が解析したのは UltraHDR形式の JPEG ファイルの Application Segment の ISO 21496-1 の Gain Map のメタデータである。

筆者は ISO 21496-1 を購入するほどのモチベーションはなかったため、メタデータの構造に関しては libultrahdr のソースコードから判断した。下記リンクのコードのuseCommonDenominator == falseかつchannelCount == 3が筆者が解析したいメタデータの内容である。

github.com

上記のソースコードから ImHex で扱えるように構造体を作った結果が以下となる*1s32u32などの型の定義については Pattern Language の Data Types の項目を参照(Pattern Language は ImHex 用に開発された専用言語である)。

// 1チャンネル分(useCommonDenominator == false のときの並び)
struct ChannelFrac {
    s32 gainMapMinN;        // streamWriteS32
    u32 gainMapMinD;        // streamWriteU32
    s32 gainMapMaxN;        // streamWriteS32
    u32 gainMapMaxD;        // streamWriteU32
    u32 gainMapGammaN;      // streamWriteU32
    u32 gainMapGammaD;      // streamWriteU32
    s32 baseOffsetN;        // streamWriteS32
    u32 baseOffsetD;        // streamWriteU32
    s32 alternateOffsetN;   // streamWriteS32
    u32 alternateOffsetD;   // streamWriteU32
};

// ヘッダ+本体(useCommonDenominator == false / channelCount == 3 固定)
struct GainmapMetadata {
    // ヘッダ
    u16 min_version;        // streamWriteU16
    u16 writer_version;     // streamWriteU16
    u8  flags;              // streamWriteU8(bit3 は 0 の想定)

    // 共通分母を使わない経路(順序に注意)
    u32 baseHdrHeadroomN;       // streamWriteU32
    u32 baseHdrHeadroomD;       // streamWriteU32
    u32 alternateHdrHeadroomN;  // streamWriteU32
    u32 alternateHdrHeadroomD;  // streamWriteU32

    // 3 チャンネル分
    ChannelFrac channels[3];
};

ImHex の Pattern editor を使ったメタデータの抽出

ImHex の画面右側には Pattern editor という画面がある。Pattern editor 内に構造体を定義して、構造体の先頭アドレスを指定すると Pattern editor に構造体の情報が表示される。言葉だけだとわかりづらいので、実際に作業をした様子を図2 の ①~③ に示す。

図2. Pattern Data で定義した構造体の情報を表示している様子

先頭アドレスは ImHex の Find タブを使って調べた。Find タブはメニューバーの View -> Find で表示できる。

UltraHDR の ISO 21496-1 のメタデータは、以下のソースコードを見るとkIsoNameSpace.c_str()の後に続いていることが分かる。これは"urn:iso:std:iso:ts:21496:-1"という文字列で定義されているので、この文字列を Find タブで検索した*2

github.com

ImHex の Pattern editor を使った簡単な計算の実施

Pattern editor では構造体の定義だけでなく、バイナリから取得したデータを使った簡単な計算も可能である。

Gain Map のメタデータは Numerator と Denominator に分かれて格納されているため、実際の値を知るには割り算が必要だったが、Pattern editor の機能を使って簡単に計算することができた。各種パラメータの値を計算、表示している様子を図3 の ①~③ に示す。

図3. Pattern editor を使って簡単な計算をしている様子

感想

凄く便利だった。ドキュメントを見ると非常に多機能であり、バイナリ解析を日常的に行う人は凄く重宝するのだと感じた。

筆者はバイナリ解析はそんなに頻繁にやらないので、すぐに使い方を忘れてしまいそうで心配である(というのもあって記事を書いた)。

参考資料

[1] Pattern Language, "Data Types", https://docs.werwolv.net/pattern-language/core-language/data-types

*1:作成は Chat GPT先生にやってもらった

*2:細かいが "urn:iso:std:iso:ts:21496:-1" の後に終端文字が 1文字入っているので、1Byte ほど間を開けたアドレスをメタデータの先頭アドレスとしている