リバースエンジニアリングのための新しいトレース手法 - pacsec 2010

84
リバースエンジニアリングのための新しいトレース手法 Niizh (Section 1b) : 背景と実装 (途中経過) 大居 司 (@a4lg)

Upload: tsukasa-oi

Post on 07-Jul-2015

926 views

Category:

Technology


3 download

TRANSCRIPT

Page 1: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

リバースエンジニアリングのための新しいトレース手法Niizh (Section 1b) : 背景と実装 (途中経過)

大居 司 (@a4lg)

Page 2: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

このセッションでは:• リバースエンジニアリングを効率的にする

―― かもしれない手法を紹介します。• “かもしれない” ?

– (2010年11月時点で) VM 上で汎用 OS が動作しない。• ライブデモができず申し訳ない!

– これにより、ある程度の推測なども含まれるため。

Page 3: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

関連分野• リバースエンジニアリング

– 特に動的解析、デバッガ、トレーサ• Intel x86 (32-bit) アーキテクチャ• 仮想化 / 仮想マシンモニタ (VMM)

– “Record and Replay”• 異常検出と解析 (ハニーポットなど)• バグ検出 (ファジングなど)

Page 4: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

アジェンダ• 多くの “トレーサ” が抱える問題• “Record and Replay” を改良した提案手法• x64 上における VMM の実装• 部分的な検証• 応用 (の可能性)• トレース VM の課題

Page 5: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

対象プラットフォーム• Intel x86 (16/32-bit) アーキテクチャ• PC/AT• 汎用 OS (Windows, Linux etc...)

Page 6: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

背景Background

Page 7: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

動的解析• 動作しているプログラムに介入するなどして、

その挙動、内部構造などを解析する。• 使用するツールは一般に多岐にわたる。(代表例)

– デバッガ• OllyDbg, Windbg, IDA Pro...

– モニター• Process Monitor, Wireshark...

– トレーサ• API Monitor, OllyDbg, Process Stalker...

• 今回は “トレーサのようなもの” に関わる話題です。

Page 8: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

トレーサ (1)• コンピュータ内で発生した特定の

イベントをキャプチャ、保存する。– 命令単位– 基本ブロック / 関数単位– API / システムコール / 入出力単位など

• 命令単位のトレース– 自動解析の対象にすることが容易

(自動 unpacking などが代表的)– コンピュータの内部状態を記録することができれば、

事実上コンピュータのすべてがトレースできる。

Page 9: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

トレーサ (2)• しかし、私が調査した命令トレーサには

共通する欠点があった。– 遅い

• 1 命令単位でフックとトレースを行うため、トレースに実時間の数十倍かかることも珍しくない。

– データ量が大きい• 実時間換算 (仮にトレースが元のプログラムと同等の速度で動作した場合) で数 GB/s のオーダー。

• トレースの書き込み処理そのものがボトルネックになってしまう。

Page 10: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

トレーサ (3)• この点を改善したトレーサを作成できないか?• 主要な要件:

– トレースにかかる時間は、エミュレーションしない環境と比較して 2 倍以内であること。

– トレースのサイズは、ネットワーク送信できるように 5MB/s 以下であること。

• このような要件を満たすトレーサをどのように実装 (する|した) かが今回のテーマです。

Page 11: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

理論 ‒ Record and ReplayTheory ― Record and Replay

Page 12: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

Record and Replay (0)• 実のところ独自に発見したつもりだった。

– 文献を十分に調査していなかった。• “ReVirt : Enabling Intrusion Analysis through Virtual-Machine Logging and Replay”

– 既存の論文に当てはめれば、提案手法は“Record and Replay” の変種に当たる。

– 両者は強く関連していて、分離が難しい。• そのため、提案手法と “Record and Replay” を

まとめて解説する。

Page 13: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

Record and Replay (1)• 文献によって呼び方が異なる場合がある。

– “Logging and Replay” “Lockstep” など。• 2 パス (Record + Replay) によって、トレースと、

そこからの情報の復元を行う。• 一般的なアーキテクチャに共通する特長を

利用し、データ量を極めて小さく抑えている。– 通常、ハードウェアなどからの入力は

その他の命令による操作よりはるかに少ない。

Page 14: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

• 多くのアーキテクチャ (ここでは 1 CPU とする) は次のようにモデル化することができる。– 入力 (空の場合もある)– 計算 / 処理 (+内部状態)– 出力 (空の場合もある)

• ここで、出力は内部状態から一意に与えられるものとする。(下式の関数 g)

• zn+1 = f(zn, in)on+1 = g(zn+1)

Record and Replay (2)

入力

出力

計算/処理+内部状態

Page 15: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

• CPU の全状態を保存することは、ここでは内部状態 (zn) をすべて保存することに相当する。– 前述の定義により、出力は内部状態から

一意に決定できるため、出力はモデルから便宜上省くことができる。

• 内部状態の初期値である z0 は別途与える。• 計算/処理に相当する関数 f は、いわゆる

数学的な「函数」であること。– 一定の入力で一定の出力を

行い、そこに曖昧さは無い。

Record and Replay (3)

入力

出力

計算/処理+内部状態

Page 16: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

• さらに依存関係を考える。– 入力 : 他のいずれにも依存しない独立した値– 計算 / 処理 (+内部状態) : 入力に依存

• この関係から…– このモデルにおける内部状態は初期状態と

入力にのみ依存する。これだけをトレースすれば、事実上コンピュータのすべてをトレースしたことになるのだ。

Record and Replay (4)

入力

計算/処理+内部状態

Page 17: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

• Pass 1 : Record– 初期状態をキャプチャし、トレースに保存。– すべての入力をキャプチャし、トレースに保存。

• ここでは、実際のハードウェアからの入力を受け入れる。

• これにより、Replay パスで復元可能なトレースを生成できた。

Record and Replay (5)

入力

トレース

計算/処理+内部状態

初期状態

Page 18: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

• Pass 2 : Replay– 初期状態をトレースから復元。– 仮想マシンを動作させる。ただし、すべての

入力はトレースから読み取る。• つまり、新たなハードウェア入力は受け付けない。

– 内部状態を読み取る。• Record パスと非常に類似している。

Record and Replay (6)

入力

トレース

計算/処理+内部状態

初期状態

Page 19: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

利点 (1)• これまでの説明なら単に 2 回実行するだけの

ようにも見えるが…– トレースを用いて、いつでも、あるいは

何回でも Replay パスを実行できる。• 解析結果が不十分ならば、別の解析手法を適用することができる。

– 必要ならば Replay を並列に実行することもできる。• 自動解析の時間を短縮できる可能性がある。(実際には解析の依存関係の問題がある。)

Page 20: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

利点 (2)• (続き)

– Replay パスの実行は Record パスに何の影響も与えない。これらはまったく独立している。

• どのような解析をしても Record パスは遅くならない。• Replay パスにおいて詳細な、これまで使用が難しかった解析手法が適用できる可能性もある。(ポインタの追跡や依存性解析など。)

• これらのことから、この手法はリバースエンジニアリングとの親和性が高い。

Page 21: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

実例 (1)• VMware Workstation (6 以降)

– “記録と再生” 機能がこれに該当する。• 実行を記録してビデオと同様に再生したり、あるいはデバッグのために使用できる。

– プロプライエタリであり、また堅牢性が高いとも言えないが、確かにこの理論を実用化した例である。

– トレース出力は一般に 1~10MB/s

Page 22: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

実例 (2)• VMware Workstation (6 以降)

– ただし…• “VMware” である (バックドアなどがよく知られている)• デバッグインタフェースが十分ではない。

– デバッグ機能さえ充実していればリバースエンジニアリングに使えたかも…。

• その他の例– ReplayDIRECTOR (Java デバッグツール)– Jockey (Linux 用記録 / デバッグ補助ツール)

• http://home.gna.org/jockey/

Page 23: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

• すべての決定論的でない要因を “入力” として扱うのは単純だが、VMM の実装には不向き。– データ入力のタイミングなどを考えれば、

不効率極まりない格納方法になる。• そこで、この “入力” をさらに細分する。

– 決定論的でない入力– 割り込み

• ただし、名称と内容は必ずしも一致しない。

x86 への適用 (1)

入力

トレース

計算/処理+内部状態

初期状態

Page 24: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

• 決定論的でない入力– x86 の in 命令のように、内部状態が不確定になる

タイミングは一意に決定できる。– ただし、その具体的な内容までは決定できない。– この場合、具体的な値や内容を保存する。ただし、

そのタイミング情報は保存しない。• 先行する入力や割り込みでタイミングを確定できるため、タイミング情報は余分である。

x86 への適用 (2.1)

Page 25: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

• 割り込み– x86 のハードウェア割り込みに代表されるように、

そのタイミングが不定 (一意に決定できない。)– また、その具体的内容も決定論的でない場合がある。– この場合、タイミング情報を保存する。また、

割り込みの具体的内容が決定論的でない場合、その内容も保存する。

• ハードウェア割り込みでは、その割り込みベクトル番号などがそれに該当する。

• これらの分類をベースに、VM 内部すべての要素を適切にモデル化することが最も重要である。

x86 への適用 (2.2)

Page 26: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

• モデル化 ― VM の内部ディスク– VMM の内部ディスクは信頼できると仮定し、

開始時の初期状態を記録する。– ほとんどを決定論的とみなし、トレースを原則として

行わない。ただし、ディスクが発生させる割り込みは“割り込み” として記録する。

• 読み取られたディスク内容は、以前に書き込んだディスクの内容と同一であることが保証されるため。

• ただし、ATA 割り込みなどのタイミングは一定とならないため、“割り込み” とみなせる。

x86 への適用 (3.1)

Page 27: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

• モデル化 ― マウス、キーボード、ネットワーク– これらは外部からの予測できない入力である。– デバイスからの入力は、割り込みと入力の両者を

使用するため、 “割り込み” と “決定論的でない入力”の複合的要素として扱う。

– ネットワーク出力は内部状態から決定できるため、トレースを行わない。

x86 への適用 (3.2)

Page 28: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

• モデル化 ― CPU のタイムスタンプカウンタ– RDTSC などで読み取ることの可能な、

リセット時からカウントされるクロック数。– “決定論的でない入力” とみなす。– 物理的な位置が CPU 内部だったとしても、決定論的な

モデル化が不可能である場合には外部入力と同様に扱うべきである!

• もしモデル化が可能であったとしてもほとんどの場合効率が下がってしまうため、敢えて決定論的でないとみなすことが効率の向上につながる。

x86 への適用 (3.3)

Page 29: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

• モデル化 ― CPU の例外– 例外はほとんどの場合発生するタイミングが

決定論的である。またほとんどの場合、例外処理の内容も決定論的に行われる。

– そのため、前述のどちらとしても扱わない。• モデル化 ― CPU の不定値

– 具体例は多数あるが、特定の操作を行った後、CPU の内部状態の一部が不定となることがある。この場合、タイミングは特定できるものとする。

– “決定論的でない入力” とみなす。

x86 への適用 (3.4)

Page 30: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

• モデル化 ― 厳密値のない算術命令– FSINCOS, FATAN などの超越関数命令は IEEE 754 の

規定に従った丸めを行うことが不可能であるため、満たすべき精度のみが定義されている。

– 具体的な値を特定できる最低限の情報を“決定論的でない入力” とみなす。

• などの様に、CPU 内外のあらゆる要素をモデル化する必要がある。– 本理論に基づく VMM を作成する最大の障害。

x86 への適用 (3.5)

Page 31: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

x86 への適用 (4)• あるものを “決定論的でない要因” として

扱うとはどのようなことか?– フックとトレース回数を増やすこと。– つまり、トレースは大きく、速度は遅くなる。– このような状況は可能な限り減らしたほうが良い。

• 設計当初、このような要因の発生する回数は一般命令数の多さに比べれば極めて小さく、それほど問題とならないと考えていた。– しかし、それは間違っていた。

Page 32: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

例えば次の例:• 次の命令は決定論的か否か

XOR edx, edx– x86 のアセンブリを読んでいれば

ご存知のように、edx を 0 にする命令だ。– しかし、前述の答えは No だ。

• 実際にはこのような命令を含めて、極めて多数の命令が内部状態の一部を不定にしてしまう。

– EFLAGS だ。

Page 33: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

EFLAGS の呪い? (1)• それでは内部状態を詳しく見てみよう。

– edx は 0 になっているが、同時に EFLAGS.AF が “?” になっている。

– このとき、AF の値はマニュアルによって未定義 (undefined) とされている。

xxx......xxx

000......000

x x x x x x

0 0 1 ? 1 0

XOR edx, edx

(next instruction)

OFedx SF ZF AF PF CF

EFLAGS

Page 34: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

EFLAGS の呪い? (2)• もちろんこれだけではない!

– 頻繁に使用される下記命令も同様!– 下記のものを含め、x86 の全実行命令のうち

10~15% がフラグの一部を不定にする。

0 M M ? M 0 AND, OR, XOR, TEST (論理演算)

OF SF ZF PF CFAF

M ? ? ? ? M MUL, IMUL (乗算)

? ? ? ? ? ? DIV, IDIV (除算)

? M M ? M ? SHL, SHR, SAL, SAR count (シフト)

Page 35: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

EFLAGS の呪い? (3)• 全く “小さく” などないではないか!

– 10% 程の命令であったとしても、フックにどれだけ時間を要するかを考えれば全く無視できない。

– これらの不定値を “トレース” するのでなく、決定論的な値に置き換えることも考えられるが…フラグを置換するのに必要な POPF 命令は極めて時間がかかる (割り込みにも劣らない)。

• Intel “Nehalem” MA で 24-25 clocks– 現実的な速度でトレースするには、

これらのトレースを何とか回避する必要がある。

Page 36: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

実装に内在する問題• 公開されている既存実装はこれらの不定要素に

対して最低限の対処しかしていない。– 同一の CPU ファミリで両者を動かす場合に限定。– 一般にアプリケーションは不定値に依存しないが、

1-bit の不定値であってもカオスを引き起こしうる。• 堅牢性がない。

– トレースを複数の手段で復元した場合、そのうちのどれが正しいかを特定できない。

• 情報の集積に支障を来しうる。• 移植性に乏しい。

Page 37: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

EFLAGS の遅延評価 (1)• しかし、EFLAGS には次の特性もある。

– 更新されたフラグが使用されるとは限らない。(現に、80%以上のフラグは単に破棄される。)

– フラグの更新と参照は大抵セットになっている。• 比較命令 + 条件分岐命令のように。• Intel は Macro-Fusion でそのような最適化を行う。

– では不定値はそれが使用されるまで許容し、それ以外の内部状態に影響を与える場合にトレースするのはどうか?

• 実験では極めて効果的であった。

Page 38: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

EFLAGS の遅延評価 (2)• 現時点での遅延評価実装:

– これは、JIT コンパイル時に行う。(実行時評価の排除。高速化に寄与。)

– 実行に寄与するブロック毎に評価する。• 分岐などで到達した地点から次の無条件分岐(例外などを含む) までの命令列を指す。

• このブロックについて順方向に命令をスキャンする。– 仮想的なフラグ (6-要素) の伝播を計算する。

• 決定論的/不定の二値 (ブロック開始時 : 不定)• 最後にフラグの値を更新した命令。• 一定条件下でヒューリスティクスも使用可能。

Page 39: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

EFLAGS の遅延評価 (3)• (実装続き)

– ブロック内の命令がフラグに依存し、対応する仮想フラグが次の条件を満たす場合、暫定的な不定値としてトレースする。

• 仮想フラグが不定である。• 仮想フラグは決定論的だが、更新した命令が32-bytes or 8-instructions 以上前である。(上記打ち切りはパラメータで設定する。)

• 現段階では極めて効果的である。– 実験段階では、トレースしたフラグのほぼ全てが

割り込み / コンテキストスイッチに絞り込まれた。

Page 40: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

Record and Replay : まとめ• Record and Replay を使用することにより、

トレースのオーバーヘッドとデータ量をともに削減することができる。

• 改善された手法により、x86 において堅牢的なトレースを取得できる。

Page 41: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

実装Implementation

Page 42: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

実装• VMM ベースのトレーサを実装する。

– 汎用 OS を動作させるため。• しかし良い選択ではなかったようだ。その複雑さのため、現時点 (2010/11) ではVM 上で OS を動作できるほど完成しなかった。

– バイナリ変換ベースの VM– x86 を対象 (ゲスト) とし、x64 をホストとする。

• 様々な観点から、x86 のバイナリ変換にはx64 が優れている。

Page 43: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

x86 on x64 (1)• x64 は x86 の 64-bit 拡張

– 命令フォーマットも x86 (32-bit) のものと類似。– ただし、幾つかの拡張が施された。

• 汎用レジスタと XMM レジスタの倍増 (8→16)• 新しいアドレッシングモード(64-bit、RIP [program counter] 相対)

• x86 のバイナリ変換を容易にする要素が多数存在する!

Page 44: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

x86 on x64 (2.1)• Benefit : 32-bit レジスタの clamp

– x64 のレジスタは x86 のものを拡張したものである。• 例 : ax (16-bit), eax (32-bit), rax (64-bit)

– ここで、32-bit レジスタを格納先とする演算を行うと、対応する 64-bit レジスタの上位32-bit がクリアされる。(これはロングモード固有)

0123

0123

4567

1234

MOV eax, 0x01234567

MOV ax, 0x1234

eaxax

Page 45: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

x86 on x64 (2.1)• Benefit : 32-bit レジスタの clamp

– x64 のレジスタは x86 のものを拡張したものである。• 例 : ax (16-bit), eax (32-bit), rax (64-bit)

– ここで、32-bit レジスタを格納先とする演算を行うと、対応する 64-bit レジスタの上位32-bit がクリアされる。(これはロングモード固有)

01234567

00000000

89abcdef

12345678

MOV rax, 0x0123456789abcdef

MOV eax, 0x12345678

raxeax

Page 46: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

x86 on x64 (2.2)• Benefit : レジスタの増加 (汎用/XMM)

– 8→16 個に増加。(XMM 含めた増加分は 16 個)– エミュレータやトレーサの状態を、

既存のレジスタを破壊することなく格納可能。rax r8

rcx r9

rdx r10

rbx r11

rsp r12

rbp r13

rsi r14

rdi r15

xmm0 xmm8

xmm1 xmm9

xmm2 xmm10

xmm3 xmm11

xmm4 xmm12

xmm5 xmm13

xmm6 xmm14

xmm7 xmm15

Page 47: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

x86 on x64 (2.2)• Benefit : レジスタの増加 (汎用/XMM)

– 8→16 個に増加。(XMM 含めた増加分は 16 個)– エミュレータやトレーサの状態を、

既存のレジスタを破壊することなく格納可能。eax cs.base

ecx es.base

edx emuinfo

ds.base ebx

stack esp

ebp tmp2

esi ss.base

tmp1 edi

xmm0 fs.base

xmm1 gs.base

xmm2 tmp3

xmm3 tmp4

xmm4 notused

xmm5 notused

xmm6 notused

xmm7 notused

実際のレジスタ再配置マップ。このマップに従い命令を変換する。

レジスタ使用を効率化するため、一部の x86 レジスタは再配置されている。

Page 48: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

x86 on x64 (2.2)• Benefit : レジスタの増加 (汎用/XMM)

– 8→16 個に増加。(XMM 含めた増加分は 16 個)– エミュレータやトレーサの状態を、

既存のレジスタを破壊することなく格納可能。– xmm レジスタはそのままでは使用が難しいが、

movq 命令を使用して汎用レジスタに転送する。

Page 49: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

x86 on x64 (2.3.1)• Benefit : アドレッシングの “非” 変化

– アドレッシングモードは追加されたものもあるが、基本は x86 のものをそのまま 64-bit 拡張しただけ。

– x86 は元々複雑なアドレッシングモードを持つ。• [esi+edx*4+123] のような複合演算も可能。• これを利用して、メモリ領域の隔離を行う。

– アドレス : [segbase+offset]• すべてのメモリアクセスは、セグメントベース(64-bit アドレス) との相対オフセットでアクセスする。

– メモリ領域さえ確保しておけば、その外にアクセスが漏れることがない。

Page 50: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

x86 on x64 (2.3.2)• Benefit : アドレッシングの “非” 変化

– 例 (1) : inc [ds:ecx] → inc [rbx+rcx]• rbx : DS セグメントのベースアドレス• rcx : ゲストの ecx レジスタ

– 32-bit レジスタの値を 64-bit として読み取っている! (そんなやり方で大丈夫か?)

• 問題ない。前述したように 32-bit 演算の結果は32-bit 範囲にしかならないため、アクセスされる領域を完全にコントロールすることができる。

Page 51: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

x86 on x64 (2.3.3)• Benefit : アドレッシングの “非” 変化

– 間違った例 (2) : inc [ds:ecx+edx] → inc [rbx+rcx+rdx]• 一時レジスタに中間結果を格納する。

– 正しい例 (2) : inc [ds:ecx+edx] →lea edi, [rcx+rdx] ; inc [rbx+rdi]

• edi/rdi : 一時レジスタ• これ以外はほとんど変わらない。

– 一番良いエンコーディングを頼む。• 64-bit のアドレス計算結果を 32-bit レジスタに格納。• これも正当なエンコーディングで、結果が 32-bit に切り詰められ、さらに命令が短くなる。

Page 52: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

x86 on x64 (2.4.1)• Benefit : 広大なメモリ領域

– アドレス幅は 64-bit• 有効な論理アドレスは 48-bit (符号拡張される。)• 例 : 0x0000_1234_5678 → 0x0000_0000_1234_5678• 例 : 0x8000_1234_5678 → 0xffff_8000_1234_5678

– ゲストがアクセス可能な場所の外にVMM だけが使用するデータやコードを配置できる。

• x86 on x86 ではアドレス空間が双方とも 4GB であり、双方のアドレスを圧縮しなければ配置できない。

• VMM の性能が向上する。

Page 53: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

x86 on x64 (2.4.2)• Benefit : 広大なメモリ領域

– ただし問題がある。64-bit でアドレス計算を行った結果は 32-bit の範囲を超えることがある。

– x86 (32-bit) は、32-bit におけるアドレス計算のオーバーフロー、アンダーフローを無視する。つまり、64-bit でアドレス計算を行った場合、下位 32-bit がアクセスされるアドレスである。

– ここで下位 32-bit が等価 == アドレスが等価という状態を作り出す。メモリに見かけ上のループを作り出すのだ。

Page 54: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

x86 on x64 (2.4.3)• Benefit : 広大なメモリ領域

– 仮想メモリ空間を確保する。– アドレスのオーバーフローなどを考慮し、

下に示す最大 44.5GB の連続領域を確保する。• 赤と青の領域 (4GB) は同じ 物理的領域を指す。• これはページテーブルを使用することで達成可能。

44.5GB42.25GB

2.25GB

Page 55: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

x86 on x64 (2.4.4)• Benefit : 広大なメモリ領域

– セグメントやアクセス制御毎に定義する。• ページテーブル置換を省略できる。

cs.base

ds.base

es.base

ss.base

data3

code0

data3

code3

Page 56: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

x86 on x64 (2.4.4)• Benefit : 広大なメモリ領域

– セグメントやアクセス制御毎に定義する。• ページテーブル置換を省略できる。

cs.base

ds.base

es.base

ss.base

data3

code0

data3

code3

Page 57: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

x86 on x64 (2.5.1)• Benefit : シンプルになったアーキテクチャ

– x64 のアーキテクチャは比較的単純化され、OS 上に Type-2 VMM を構築することが容易。

• 割り込みハンドラの種類の減少– 割り込みゲートとトラップゲートの二種類のみ。

• セグメント機構の事実上の形骸化– CS, DS, ES, SS セグメントについて

フラットメモリモデルを採用。– IDT (割り込みベクトル) を置き換えることで、

VM 専用のコンテキストを確保する。• PatchGuard の有効な Windows でも安全に動作する。

Page 58: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

x86 on x64 (2.5.2)• Benefit : シンプルになったアーキテクチャ

– 割り込みをパススルーする。• IDT の切り替えによって安全に行える。• 若干オーバーヘッドがある。

VM OS

実際にはもう少し複雑だが、ここでは概略のみ示す。

IDT switch

IDT switch

OS Kernel

VM Trampoline

OS IntHandler

VM Entry

VM IntHandler

VM Kernel

Page 59: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

x86 on x64 (3)• 以上の機構を用いて VMM を実装する

– …のだが、現時点での完成度は低い。• タイミングをトレースするには、

次の情報があればよい。– 分岐カウンタの値 (ソフトウェア実装も可能)– 現在のプログラムカウンタ (IP, EIP)– 繰り返しカウント (CX, ECX)

• “rep” 命令が実行中だった場合のみ。– いくつかこれについては例外があるのだが、

今回の範囲を著しく逸脱するため省略。

Page 60: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

Everything into the Ring-0• 権限の隔離は必要?

– JIT コンパイルされたコードは適切に隔離され、管理された領域以外にはアクセスできないため、すべてのコードを Ring-0 で実行可能。

• セキュリティチェックの一部を省略するなど、フックや VMM のオーバーヘッドを大きく減らすことができる。

• 現在の実装は Ring-0 上にすべてを構築している。– セキュリティ上この動作が危険であれば、

Ring-3 で動作させることも理論上可能。

Page 61: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

検証Tests

Page 62: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

トレースサイズの検証 (1.1)• トレースに必要なデータ量

– Bochs (2.45) 付属の DLX Linux 起動シーケンス• リセットからログイン画面の表示まで• 52,217,403 instructions (実時間換算 : 約 53 秒)

– 各種スペック• 1 MIPS (1,000,000 instructions/sec)• 32MB MEM, 10MB HDD

– Bochs のトレース機能で出力したテキスト形式のトレースを、提案手法と幾つかの対照手法の理論に従って変形する。

Page 63: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

トレースサイズの検証 (1.2)• トレースに必要なデータ量

– 初期状態のサイズは含まない。– Bochs 組み込みデバイスについて、

そのモデル化を行い、対応するトレースサイズの導出も行った。

– ただしモデル化は簡易的なものであるため、サイズは近似となる。

Page 64: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

トレースサイズの検証 (1.3)• 手法 (比較対象含む)

– RawBochs が出力する命令/メモリトレース (テキスト)

– Verbose一般的なトレーサが出力するトレース量の目安

– Dumb読み取ったメモリを記録する、マルチコアに適したRecord and Replay 類似の方式

– RnR (1)Record and Replay (EFLAGS をトレースする)

– 提案手法改良された Record and Replay アルゴリズム

– RnR (2)Record and Replay (EFLAGS の不定値を無視する)

Page 65: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

トレースサイズの検証 (2.1)手法 サイズ (bytes)

Raw 7,178,948,236 6.68GB

Verbose X > 419,430,400 400MB

Dumb 60,713,538 57.90MB

RnR (1) 6,932,542 6.61MB

提案手法 389,013 380KB

RnR (2) 31,788 31KB

ここに示すように、提案手法を含む Record and Replay 法は極めて小さなトレースで同様のデータを表現できる。一般的なトレーサの目安に相当する Verbose の数値に比べて1/1,000 というサイズを達成している。

Page 66: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

トレースサイズの検証 (2.2)

10,000

100,000

1,000,000

10,000,000

100,000,000

1,000,000,000

10,000,000,000

サイズ (bytes)

Page 67: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

トレースサイズの検証 (2.3)• まとめ

– この結果は実際の VMM から取得したものではないため、実装が要件を満たすかという点については若干の疑いもある。

– しかしながら、他のトレース手法よりはるかに小さいトレースを生成することだけはほぼ確実といえる。

Page 68: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

オーバーヘッド

0

10

20

30

40

min max

without Tracer

with Tracer

Page 69: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

応用Application

Page 70: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

応用の可能性 (1)• リバースエンジニアリング (一般)

– “動いた” ものはすべて “明らか” になっている。• すべてのプログラムの動作はトレース中に保存されているため、必要な情報はいつでもここから抽出できる。

• アンチデバッギングや VM 検出さえ回避すれば、プログラムの正常な動作を完全に記録できる。

– unpack されたプログラムコードももちろん含まれる。• 複数種類の解析を統合することができる。

Page 71: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

応用の可能性 (2)• アンチデバッギングの回避

– よく知られたバックドアは存在しないため、既存手法での VM 検出は困難である。

– しかし、バイナリ変換ベースの VMM はパフォーマンスに特有の癖が出てしまう。

• 自己書き換えによって極端に遅くなる、など。– もちろんどのように VM 検出が行われたかという

部分は解析が可能であるため、最悪でも次の解析を容易にするための情報は収集できる。

• 一般的なプログラムがもつプロテクトであれば、二度目の実行により高い確率で回避できるだろう。

Page 72: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

応用の可能性 (3)• リバースエンジニアリング (マルウェア)

– 今のところ、ソフトウェアを「そのまま」動作させることのみ想定しているため、マルウェアを VM 上で動作させることは危険である。

• マルウェアの解析に関して言えば、従来のエミュレータ使用のアプローチの方が安全かも。

– ただし、その点に適切な対処ができる場合、マルウェアの動作を確実に分析できるだろう。

– ハニーポットへの適用もあり得る

Page 73: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

応用の可能性 (4)• ファジング / 脆弱性分析 / バグ解析

– OS 全体に Valgrind を適用したような、高い精度、粒度の解析が可能である。

– 非リアルタイム解析により、メモリ破壊の位置やその影響などを追跡できる。

– 再現性の低い脆弱性であっても、一度動作すればその実行パスを詳細に分析できる。

– ただし、ファジングを効率的に実行できるかは実際の VMM 実装に強く依存する。

Page 74: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

応用の可能性 (5)• 解析の補助

– 特定ツールのためのデータを出力する。• Wireshark のパケットダンプなど

– このとき、プログラムの動作を考慮に入れてメタデータや追加処理を付加できるだろう。

• 例えば SSL/TLS の自動復号など。盗聴や外部からのモニタリングによる復号は不可能だが、VMM 上で動作させた場合には共通鍵を持つ端点をモニタできる。

Page 75: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

応用の可能性 (6)• <<Place Entry Here>>

– VMM 上で起こるほぼ全てを保存できるということは、他の応用も色々あるかも…。

– (マルウェア解析などの) 現場に携わったことのない私よりも真価を発見できる方は多いかと。

Page 76: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

課題・まとめFuture Challenges / Conclusion

Page 77: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

課題 : マルチコア (1)• “Record and Replay” はそのままでは

マルチコアに応用できない。– 複数の CPU が密に連携を取ることを想定していない。– 先行例である VMware Workstation も私の実装も、

1 CPU/thread の実行にのみ対応する。• ただし、全く不可能というわけでもない。

(一長一短はあるのだが。)– タイムスライスによる時分割– MESI プロトコルのソフトウェア実装– メモリ内容をトレースする

Page 78: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

課題 : マルチコア (2)• タイムスライスによる時分割

– 同時に実行する仮想 CPU は 1 個のみ。– ただし複数の仮想 CPU を切り替えながら実行する

ことで、複数の CPU が動作しているように見せかける。

• Pros.– 同期処理の必要性がほとんどないこと。

• Cons.– 仮想 CPU の数に比例して性能が悪くなる。– マルチスレッド特有の問題の再現が困難になる。

Page 79: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

課題 : マルチコア (3)• MESI プロトコルのソフトウェア実装

– メモリ一貫性アルゴリズムの一種– マルチコアなどの環境においては、CPU 内部の

ハードウェアはこれらのプロトコルを用いてメモリの状態を適切に管理する。

– これをソフトウェア (ページ単位) で実装する• Pros.

– 共有メモリが少ない場合、性能が向上し易い。• Cons.

– ソフトウェア実装は極めて遅い。

Page 80: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

課題 : マルチコア (4)• メモリ内容をトレースする

– 複数 CPU で共有されるメモリ領域について、そこからの読み取り結果をトレースする。

• Pros.– 一般に性能が向上し易い。

• Cons.– 厳密には完全情報ではなくなる。

(どの CPU が書き換えた情報かの追跡が困難。)– メモリトレースは遅い。

Page 81: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

課題 : 64-bit / その他• x64 on x64 の VMM 実装は極めて困難。

– 方法が無いわけではないが、実装コストとオーバーヘッドがかかる。

• SSE2 の逆数 / 逆数平方根命令– 精度が保証されないためかなり高速な命令であり、

不定値としてのトレースが難しい。• 結局ハイパーバイザベース?

– 移植性を確保するには、生成したトレースに対して別パス、同 CPU モデルで不定値を付加する。

– これは完璧ではないが、あり得る選択肢である。

Page 82: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

注意 : 特許• 構成技術の一部は特許化されている!

– “Record and Replay” の基礎部分– バイナリ変換 VMM の高速化に関するアルゴリズム– これらの回避は極めて難しい / 不可能である

• 確認した限りでは PCT 出願のない米国特許であり、米国外で使用する分には特に問題無いと考えられる。– が、利用には気をつける必要があるかも知れない。

Page 83: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

まとめ• ここでは、x64 上に x86 仮想マシンを構築し、

トレースする手法について解説した。• 提案手法を用いれば、トレースが小さくなり、

さらにオーバーヘッドも小さくなる。– ただし、リバースエンジニアリングに十分

使用できるか否かについては十分な検証が待たれる。• トレースは様々な応用が可能である。

– 紹介した以外にもあるかもしれない。

Page 84: リバースエンジニアリングのための新しいトレース手法 - PacSec 2010

contact me at : li at livegrid dot orgOpen Source Project : Niizh

will be available at http://niizh.org/

Thank you!Any questions?