読者です 読者をやめる 読者になる 読者になる

Log.i53

Themidaのアンパックを目指すブログ改め使い物になるえんじにゃを目指すブログ

UPXにおけるIATのマニュアル再構築 【分析編】

Unpack

i53.hatenablog.jp
 前回の記事でIATについて大雑把に勉強したので、その情報を元にIATのマニュアル再構築を試みます。

# 勉強したてホヤホヤなので間違いなどがあれば是非コメントにて指摘して頂けると助かります...!

パック前のIATの確認

 まず、UPXでパックされたnotepad.exe(SHA-1:A81680E5B6C44A288A4B40A849A95AF85B285584)のIATを確認してみます:
f:id:i53:20150725074548p:plain

 インポートディレクトリの内容ですが、インポートディスクリプタのRVAが0x1CE14、サイズが0x24Cであることが分かります。また、各セクションのVirtualSizeVirtualAddressPointerToRawDataはそれぞれ図でハイライトされているとおりです。

 インポートディスクリプタのRVAは0x1CE14ですので、これを内包するのはVirtualAddressが0x16000から始まる.rsrcセクションであることが分かります。したがって、この例におけるインポートディスクリプタのファイルオフセットは .rsrcセクション.PointerToRawData + (インポートディレクトリ.VirtualAddress - .rsrcセクション.VirtualAddress) で求まります。計算の結果インポートディスクリプタのファイルオフセットは 0x4A00 + (0x1CE14 - 0x16000) = 0xB814となります:
f:id:i53:20150725081141p:plain

 さて、毎度このようにバイナリエディタで確認していくのは面倒ですので、以降はPEビューワ/エディタなどのツールで確認することにします。例えば、PEiDには各セクションの情報を確認するためのSection Viewerが用意されています:
f:id:i53:20150725074808p:plain

 さらに、各インポート情報を確認するためのImports Viewerが用意されています:
f:id:i53:20150725075204p:plain

 パックされた状態のインポートルーチンは(隠蔽されていなければ)アンパックなどに利用されるAPIが確認されることとなり、これはパック前のものとは異なります。

UPXにおけるIAT再構築処理

 パックされた実行ファイルを実行するとアンパックスタブにおいて元の実行ファイルをメモリ上に解凍・展開してIATの再構築を行った後で、展開した元の実行ファイルに実行を遷移させます。したがって、テールジャンプを少し遡ればIATの再構築処理を確認することができるかと思います。UPXのアンパックスタブはそれほどサイズが大きくないので上から順に見ていくことにします。

# あくまでパッカーの話でありプロテクターの場合はそう簡単には見つからない可能性もあります

 UPXでパックされたnotepad.exeのアンパックスタブの内容をIDAのグラフビューで確認します。途中で確認される様々な条件分岐やループは主にパックされたバイナリの展開を行っている部分です。一見複雑そうに見えますが、この処理の途中で自前のサブルーチンの呼び出しは一切行われておらず、解凍・IAT再構築までの一連の処理が全てこの中に収まっています。UPXがウェブサイトの紹介文に「高速な解凍」をかかげているだけのことはあります:)
f:id:i53:20150727124210p:plain

 簡単に処理を確認します。エントリポイント直後に以下の命令が確認できます。

01015380 > 60               PUSHAD
01015381   BE 00100101      MOV ESI,notepad_.01011000
01015386   8DBE 0000FFFF    LEA EDI,DWORD PTR DS:[ESI+FFFF0000]
0101538C   57               PUSH EDI
0101538D   83CD FF          OR EBP,FFFFFFFF
01015390   EB 10            JMP SHORT notepad_.010153A2


 まずレジスタの退避を行うためのPUSHAD命令が確認され、その後ESIレジスタに0x1011000、EDIレジスタ0x1001000(= ESI + 0xFFFF0000)を格納しています。PEiDでPEの詳細を確認するとImageBaseが0x1000000であり、さらにセクションビューワを確認してみると、これはそれぞれUPX1セクションとUPX0セクションの開始アドレスであることが分かります:
f:id:i53:20150727150108p:plain

 また、EBPへのOR演算ですがこれは単に-1を代入するものと等価であり、このレジスタは後でオフセット値として利用されます。UPX1セクションにはパックされたバイナリが格納されており、それを読み込んで元のバイナリに復元した後でUPX0セクションを起点に逐次展開していきます。試しにアンパック前のテールジャンプのジャンプ先アドレスにHBP(write)を設置して実行を再開します:
f:id:i53:20150727184222p:plain

 実行を再開すると以下の命令でブレークします。EDXは既に解凍が済んだアドレスを指しているため、これはおそらく先に展開されたバイナリの再利用を行っている部分です。UPXの圧縮・解凍の方法についてはここでは論じませんが興味がある方はUPXのソースコードを確認して下さい:
f:id:i53:20150727191442p:plain

 解凍処理がしばらく続いた後、テールジャンプに到達する少し前に以下の興味深い命令群(オフセット値)に遭遇します:
f:id:i53:20150728103252p:plain

 色枠で囲った部分のESIレジスタ(ベースアドレス)には現在0x1001000という値が格納されており、この値はImageBase(0x1000000) + SizeOfHeaders(0x1000)となります。そして赤枠のオフセット値はIATの再構築のためにPEフォーマット上の必要な情報にアクセスするためのものです。例えば、LEA EAX,DWORD PTR DS:[EAX+ESI+1BE14]のオフセット値0x1BE14は、ImportDiscriptorを参照するためのものであることが分かります:
f:id:i53:20150728085348p:plain

 紫枠のオフセット参照先だけはUPX1セクションにあり、これは元々圧縮されていたデータですが、HBPを設置して確かめてみるとアンパック後に解凍処理が行われていることが分かりました…これはおそらくUPXがパック時に埋め込んだIAT再構築のためのメタデータを参照するためのものです。実際にHexビューで解答前と解凍後のアドレス0x1014000周辺を確認してみましょう:
f:id:i53:20150728110653p:plain

 左が解凍前、右が解凍後のバイナリになります。オレンジ色でハイライトされているデータ0x124は1つ目のDLLのILT(インポートルックアップテーブル)を参照するためのオフセットです。また、黄緑色でハイライトされているデータは1つ目のDLLのIATを参照するためのオフセットになります。その後にインポートされるAPIの数だけIMAGE_IMPORT_BY_NAMEという構造体が続いています。

 試しに、LEA EAX,DWORD PTR DS:[EAX+ESI+1BE14]が最初に実行される時の参照先、EAX(0x124) + ESI(0x1001000) + 0x1BE14 = 0x0101CF38を実際に確認してみると元の実行ファイルでインポートされるDLL名を参照していることが分かります:
f:id:i53:20150728112825p:plain

 OllyDbgの方に分析結果をコメントとして加えたものを以下に示します。元の実行ファイルのIATとILTを参照して、LoadLibrary関数とGetProcAddress関数を用いてアドレスを取得してインポートテーブルの再構築を行っていることが分かります:
f:id:i53:20150728125244p:plain

 最後の方にUPX0とUPX1セクションのCharacteristicsフィールド(セクションフラグ)を修正していますが、これは何を行っているのでしょうか? 修正後の値を確認してみましょう:
f:id:i53:20150728125618p:plain

 セクションフラグの4バイト目が0x60に書き換わっています。これによりIMAGE_SCN_MEM_EXECUTE(0x40000000)とIMAGE_SCN_MEM_READ(0x20000000)のセクションフラグが有効になり、そのセクションメモリの実行と読み出しが可能となります。これはUPXが元のバイナリをセクション上に展開するためです。

 これで、UPXにおけるIATの再構築の分析が終わりました。この後はOEPの再構築を行うOllyScriptを作成しようと思いましたが思いのほか面倒だったので断念しましたああああああああ

IAT再構築の自動化について

 ImpRecのような著名なツールを含む様々なツールが公開されています。
http://www.woodmann.com/collaborative/tools/index.php/Category:IAT_Restore_Tools