Link
Embed
Share
Beginning
This slide
Copy link URL
Copy link URL
Copy iframe embed code
Copy iframe embed code
Copy javascript embed code
Copy javascript embed code
Share
Tweet
Share
Tweet
Slide 1
Slide 1 text
独自VM解析 ~Sleighによるプロセッサ定義を添えて~ 2025/03/16 katagaitai勉強会 0x421AA4
Slide 2
Slide 2 text
コンテンツ 目次 — 前提知識 — 独自VMとは — Ghidraとは — Sleighとは — 実践 — 独自VM問解説 — プロセッサ定義作成 — 独自形式バイナリ解析 — 総括 Who am I • 0x421AA4 • セキュリティ関連のお仕事 • CTF活動 • CTF歴:2020年~ (主にRev) • 所属チーム:katagaitai 今回の話 • GhidraでSleighを書いて独自のプロセッサ定義を作成 しようという話。 • 独自VM問を題材として、未知の形式のバイナリをディス アセンブル及びデコンパイルする。 • 実際にSleighを書いてみての利点や課題の共有。 2
Slide 3
Slide 3 text
前提知識 3
Slide 4
Slide 4 text
前提知識 / 独自VMとは • CTFのReverseカテゴリ ※1 においてたまに見かける問題のジャンル(?) • 独自形式のバイナリを実行するプログラム(VM)が与えられ、主にそのVM上で動作する プログラムの挙動を解析する問題のこと。 • 解析対象は問題固有のVMおよびバイナリとなるため、既存のディスアセンブラ(当然デコ ンパイラも)は利用できない。 • 解析するには、VMにてどのようなバイナリ表現であればどんな処理が行われるのかを理解 する必要がある。 • 今回は独自VMによるプログラムの解析に、 GhidraでSleighによるプロセッサ定義を作成して進める。 4 ※1: 特定のプログラムの挙動を理解する(リバースエンジニアリングする)ことに主眼が置かれている問題。 独自VM 独自 バイナリ Ghidra 独自バイナリを 解釈して実行している 1. 独自VMの解釈 方法を解析 2. プロセッサ定義を作成して 独自バイナリを解析
Slide 5
Slide 5 text
前提知識 / Ghidraとは • バイナリのプログラムをリバースエンジニアリングする際に、バイナリのまま では解析することが困難。 • Ghidraでバイナリから人が読めるアセンブリコードに変換 • Ghidraでバイナリから人が読みやすい疑似Cコードに変換 5 Ghidra (ギドラ、 [ˈɡiːdrə])は、アメリカ国家安全保障局(NSA)によって開発された オープンソースのリバースエンジニアリングツールである。 wikipediaより引用 バイナリ アセンブリ コード 疑似Cコード Ghidra※1 Ghidra ※1: アセンブリコードからバイナリに変換することもできるが完全ではない。
Slide 6
Slide 6 text
前提知識 / Ghidraとは / 参考文献 • 基本的に以下の本を読んでおけば一通りわかる。 • あるいはGhidraから見れるヘルプドキュメントを読めば詳しくわかるはず。 6 ※1: https://www.amazon.co.jp/dp/4839973776 ※2: https://www.amazon.co.jp/dp/4873119928 リバースエンジニアリングツールGhidra実践ガイド ※1 • Ghidraを使ってマルウェアを実際に解析していくなかで使い方を学べる。 • 解析対象が主にwindowsのマルウェア。 • 初めてGhidraを触るという場合は解析の流れを理解しやすい。 マスタリングGhidra ※2 • Ghidraの機能を一つずつ紹介していて、リファレンスとして利用しやすい。 • Ghidraのローダやプロセッサの仕組み、プラグインの作成方法の説明もある。 • Sleighについても記載あり。
Slide 7
Slide 7 text
前提知識 / Sleighとは • sleighの役割は以下の2つ。 1.ビットパターンとアセンブリ表現との紐づけ 2.ビットパターンのp-code※1 への変換 7 SLEIGHは、GHIDRAリバースエンジニアリングプラットフォーム用に設計され、GHIDRAの2つの 主要コンポーネントである逆アセンブリエンジンと逆コンパイルエンジンを容易にするのに十分な 詳細さでマイクロプロセッサを記述するために使用されます。 Ghidraドキュメントより引用 ※1: Ghidra内で利用する中間表現(IR) ※2: アセンブリコードからバイナリに変換することもできるが完全ではない。 バイナリ アセンブリ コード p-code エミュレート 疑似Cコード Sleigh※2 Sleigh Ghidra Ghidra
Slide 8
Slide 8 text
前提知識 / Sleighとは / Sleighプラグインの構成要素 • GhidraにてディスアセンブルやデコンパイルをするにはSleighだけではなく、 他にもxml形式の設定ファイルを用意しプロセッサ定義を作成する必要がある。 • プロセッサ定義のスケルトン※1 が公式にあるので、それを元にして作成すると楽。 8 ※1: https://github.com/NationalSecurityAgency/ghidra/tree/master/GhidraBuild/Skeleton/data/languages 必要ファイル 説明 .ldefs プロセッサ定義の全体の設定。 プロセッサの名前などの説明を記載する。ghidraでプログラムをロードすると きに出てくる概要を記載する。 .cspec コンパイラ関連の設定。 アドレス空間の定義やポインタのサイズ、関数の呼び出し規則などを記載する。 .pspec プロセッサ関連の設定。 プログラムカウンターやデフォルトで存在するシンボルを記載する。 .slaspec (+.sinc) 実際にsleighを書いていくファイル。 エンディアンやメモリ空間、レジスタの設定から、命令の指定までを行う。
Slide 9
Slide 9 text
前提知識 / Sleighとは / ldefs • language definitionsのこと。 • プロセッサ名やバイナリをロードするときに出てくる概要等を記載する。 • とりあえず動けばよいのであればあまり気にする点はない。 9 Ghidraへのバイナリ読み 込み時に表示される 後に出てくるslaspec、 pspec、cspecの指定
Slide 10
Slide 10 text
前提知識 / Sleighとは / cspec • compiler specのこと。 • メモリ空間の指定や、スタックポインタの指定、関数の呼出規約を定義する。 • 最低限一つは呼出規約を入れておかないと正常に動かなかったので、以下の例では仮の呼出 規約を書いている。 10 スタックポインタの指定 メモリ空間の指定 デフォルトの関数呼出規約の指定
Slide 11
Slide 11 text
前提知識 / Sleighとは / pspec • processor specのこと。 • プログラムカウンタやデフォルトで存在するシンボルを定義する。 • 以下の例ではプログラムカウンタだけ指定している。 • メモリ上の特定の位置にシンボル(エントリーポイント等)が存在することがわかっている のであれば、ここに記載しておけばプログラムのロード時に自動で設定できる。 11 プログラムカウンタの指定
Slide 12
Slide 12 text
前提知識 / Sleighとは / slaspec • sleigh specのこと ※1 ? • 実際にsleighを書いていくファイル。 • 他のファイルをincludeすることも可能。 • includeするファイルは.sincの拡張子が ついていることが多い。 • メモリ空間やエンディアン、レジスタの 設定から命令の定義を行う。 • 独特な構文 • ディスアセンブル部とp-code指定部で分 かれている。 • 定義したトークンを元にビットパターン の解釈方法の定義する。 • ビットパターンの持つ意味(セマンティ クス)を記載し、p-codeへの変換方法を 記載する。 12 メモリ空間のアドレス サイズや用途を指定 命令の定義に利用 するトークン ビットパターンの 解釈を分割する p-codeの処理は マクロも利用可能 レジスタのメモリ 空間への割り当て 実際の命令の定義 ビットパターンの解釈と表示、 p-codeへの変換を行う ※1: Sleighをコンパイルすると.slaというファイルができるのでそこから取っているかもしれない。ところでslaとは...?
Slide 13
Slide 13 text
前提知識 / Sleighとは / Sleighのコンパイル • Sleighを書いたらコンパイルする必要がある。 ※1 • ”/support/sleigh.bat”を利用すればSleighをコンパイ ルできる。 • 他のプロセッサ定義と同じようにファイルを配置して以下のコマンドを実行。 • コンパイルしただけではGhidraに反映されないが、Script Managerから ReloadSleighLanguage.javaを実行すると反映される。 13 ※1: 正確にはコンパイルせずともGhidraを再起動すれば勝手にコンパイルされるが、毎回再起動するのは面倒なので自分でやってしまう。
Slide 14
Slide 14 text
実践 14
Slide 15
Slide 15 text
実践 / 独自VM問解説 • Automotive CTF Japan 予選で出題されたPowerというReverseカテゴリの問 題 ※1 を題材にSleighを書いて解析する。 • 配布されているバイナリはPowerPCの実行ファイルで、実行してみても文字列 が出力されるのみ。 15 ※1: 2024/08/25-2025/09/08に開催されていて、今はCTFのサイトも閉じており問題にアクセスできない。
Slide 16
Slide 16 text
実践 / 独自VM問解説 / VM解析1 • とりあえずGhidraで確認。 • 起動後の処理を追いかけると関数ポインタの 配列(関数テーブル)から色々な関数を呼び 出している箇所が見つかる。 • 関数の数は27個。 16 このテーブルの中のいずれか の関数が実行される。
Slide 17
Slide 17 text
実践 / 独自VM問解説 / VM解析2 • 関数テーブルの関数を調査。 • それぞれの関数が引数を1つか2つ受け取り、 何らかの操作をしているということがわかる。 • 実行する関数や引数は何らかのデータによっ て決定される。 ⇒これが独自VMだとわかる。 17 add_one関数を次に実行 する関数として登録。 add_one関数に渡す引数を準備する。 ここでは一つの引数を準備しているが、 関数によっては引数が二つのこともある。
Slide 18
Slide 18 text
実践 / 独自VM問解説 / VM解析3 • 関数テーブル内のどの関数をどの引数で実 行するかを調査する。 • 本題ではないので細かい解析は省くが、entry関 数で指定されている.dataセクションのデータに よって挙動が制御されていることがわかる。 • このデータが延々と10MB以上続いている。 ⇒この部分が独自バイナリ。 • この部分を抽出して次の解析に進む。 18 バイナリの解釈例として最初の部分は... 0x1a番目の関数(call_jmp ⇒ 引数は一つ)を 続く4byte分のデータ(0x197)を引数にして実行する。 ことを表している。
Slide 19
Slide 19 text
実践 / プロセッサ定義作成 • 独自バイナリがどのような処理を意味しているか調べたい。 ⇒Sleighを用いて専用のプロセッサ定義を作る! • 解析してわかった内容をSleighに書き起こしていく。 • Sleigh以外のxmlファイルは”前提知識”の場所で見た内容のように、必要最低限のものだけ 書いておく。 19 以下再掲(左からldefs, cspec, pspec)
Slide 20
Slide 20 text
実践 / プロセッサ定義作成 / slaspec • Sleighのメイン部分を書いていく前に基本的な設定をする。 20 ※1: 一時的に入れていた関数の呼出規約で利用しているレジスタや、プログラムカウンタ、スタックポインタなどを定義する。 ※2: プロセッサの状態を表す特殊なレジスタ。例としてARMのプロセッサ定義ではTHUMBモードへの切り替えの表現などで利用されている。今回は独自バイナリの引 数が特殊な扱いをしていたため止む無く利用している。 • エンディアンの設定 • 今回はPowerPCと同じくbig • バイトアライメントの設定 • メモリ空間の設定 • 今回は命令が存在している領域と、データを 扱う領域とを別々に定義している。 • レジスターもメモリに配置するという考え方 となるため、ここで定義している。 • レジスターの設定 • Sleighとして動作する最低限のレジスタを設 定。※1 • context※2 として利用するレジスタやフラグレ ジスタの設定。
Slide 21
Slide 21 text
実践 / プロセッサ定義作成 / slaspec / tokenの定義 • バイナリを解釈する単位となるトークンを設定する。 • トークン全体のbit数を指定しつつ、トークン内のbitの区切 り方(フィールド)を決めていく。※1 • この後の命令の定義ではこのフィールドを利用してビットパ ターンを表していく。 21 ※1: 今回は引数の扱いが複雑で命令が可変長となってしまっているため、トークンをいろいろと区切ってしまっているが、同じ命令長であればbitの区切り方が異なって いても同じトークンで扱うこともできる。 16bitのトークンを定義 0~7bit目をart_1、8~15bit目を art1_2というフィールドとして定義 ここではbitの範囲は被っていないが、 被るようにしても問題ない。
Slide 22
Slide 22 text
実践 / プロセッサ定義作成 / slaspec / 引数の定義 • 今回の独自バイナリでは、引数のバ イト数が可変長となっている。 • 一方で命令ごとの引数のビットパター ンの解釈方法は同じであるため一つの テーブルとして定義しておく。 22 ビットパターンの定義。artフィール ドが”3”かつ続くart3tフィールドが 4の時にこの命令と解釈する。 続くart3t4フィールド分のビット を取得して、ディスアセンブルの 結果として表示する。 ディスアセンブルをする前の操作。 ここではarg contextにart3t4を渡し、 それをこの後の命令で有効化している。 exportすることで、この結果をarg1の 結果として扱うことを指定する。 ここまでに出てきていないビットパター ンは未定義扱いと明示する。※1 ※1: このようにしておかないとSleighのビルド時にエラーが出たため入れている部分。
Slide 23
Slide 23 text
実践 / プロセッサ定義作成 / slaspec / 命令の定義 • 実際の命令を定義していく。 • 全て載せると大変なので、 少し抜粋。 23 さっき定義した引数 命令の意味を書いていく。 ここでは引数に+1する。 独自のp-codeを定義することもできる。 Sleighで記述することが大変な場合など に利用すると楽ができる。 引数が2つの命令も同じ ように定義する。 レジスタの値によって処理を 分岐させることができる。 gotoでjmpやcallなどの命令を 扱うことができる。※1 ※1: すぐ上の行のgotoとは意味合いが異なる。一行上のgotoはプログラムカウンタの移動ではなく、jeqの処理定義部3行目で指定したSleighのタグに移動するもの。if 分内で直接プログラムカウンタを移動させるgotoを利用できない都合上このような記載になっている。
Slide 24
Slide 24 text
実践 / 独自バイナリ解析 • Sleighを先述の方法でコンパイルしてから、Ghidraに抜き出した独自バイナリ を読み込ませる。 • Ghidraにインポートする際に、ldefsで設定した通りの内容が表示される。 24
Slide 25
Slide 25 text
実践 / 独自バイナリ解析 / ディスアセンブル • Ghidraへの読み込み後にディスアセンブルしてみると、以下のように想定して いた通りに表示される ※1 。 25 ※1: オペランドの表示は既にある程度解析を進めて変数名を付けている都合上このように表示されている。 slaspecの表示名フィールドに 記載した通りになっている。
Slide 26
Slide 26 text
実践 / 独自バイナリ解析 / デコンパイル • 同様にデコンパイル結果を見てみる。 • ちゃんと疑似Cコードとして表示されている※1※2 。 • この後はデコンパイル結果等を確認しつつ独自バイ ナリの解析を進めていくだけ。 • ただし今回の主題ではないので以降は省略とする。 26 ※1: 変数名の変更等は別途実施済み。 ※2:ぱっと見わかりにくいが、引数を準備しつつsyscall(5)=openとsyscall(0x8d)=getdentsを実行し、 特定のファイルを取得しようとしている。 p-codeを元にGhidraが勝手に デコンパイルしてくれる。
Slide 27
Slide 27 text
総括 27
Slide 28
Slide 28 text
総括 • 良い点 • ディスアセンブラを作成する+α程度の内容でデコンパイルまでできる。 • Ghidraの仕組みがわかる。 • 今回は触れなかったがGhidraで動作をエミュレートできるようになる。 • なんとはなしに楽しい • 良くはない点 • 新しくsleighを覚える必要あり。 • ドキュメントは少なめ。とはいえ公式のドキュメントがあるので、困ったらそれかソースコード を見ればよい。 • あまり独自バイナリ部分が多くないのであれば、pythonなどでディスアセンブラだけ書いて理解 したほうがよっぽど早い。 • この問題固有のものとして、関数のように処理が区切られておらず、一つの処理の流れが大 き過ぎてデコンパイルできる限界を超えている※1 。 • 無理やり何とかする方法はある※2 。 • 独自VM問の場合処理を丁寧に分割しているか怪しいので、同じ問題に直面する可能性はある。 28 ※1: デコンパイルの設定を弄って上限を上げて試してみたが、メモリを20GB弱使ってもデコンパイルが完了せず結局失敗した。 ※2: 処理の途中にjmp命令などをバイナリを編集して挟みこむことで、そこで処理の流れが止まるとGhidraに思わせる等。
Slide 29
Slide 29 text
独自VM解析 ~Sleighによるプロセッサ定義を添えて~ まとめ • 前提知識 • GhidraやSleighについての概要説明 • 実践 • CTFの問題を通したプロセッサ仕様の作成及び解析 • 独自VMの解析 • Sleighによる定義の作成 • ディスアセンブル、デコンパイルの確認 • 総括 • 独自VM問にSleighを利用するPros&Cons Thank you