前回、2回に分けてProcess Hollowingで展開された後のプロセスから実行形式ファイルを戻す方法を書きましたが。
この記事では、OEPの求め方をしっかり書いていませんでした。
我が鎮守府が艦〇れ2019年夏イベを無事オール甲突破して心の余裕もできた(ただし、まだ掘ってる)ので、検証しなおしてみました。
(え?艦隊の疲労抜きの合間に記事書いてるだろうって?ヨクワカッテルジャナイカ。)
結論から言えば、通常のPEヘッダの分析でわかります。
PEヘッダの開始位置+0x28にある4バイトのリトルエンディアンの値が、エントリーポイントのオフセット値になります。
DOSヘッダ、PEヘッダの復習も兼ねてメモっておきます。
DOSヘッダ、PEヘッダの参考
以下のページにヘッダの詳しいレイアウトが出ていました。
(相変わらず、解説は他所のページにお任せする手抜きブログ。)
PE(Portable Executable)ファイルフォーマットの概要
http://home.a00.itscom.net/hatada/mcc/doc/pe.html
PEファイルフォーマットについて
https://qiita.com/cha1aza/items/f64dc4351517a2477ef1
また、以下の書籍も参考にしました。
私の持っている版では流石にツール類の紹介が古くなっていますが、基礎的な知識ではまだ参考になるかなと。
アナライジング・マルウェア
https://www.oreilly.co.jp/books/9784873114552/
Process Hollowingで展開されたプロセス上のヘッダの解析
ヘッダを分析するタイミングは、Process Hollowingで展開された後の実行プログラムの抽出方法(その1)で新しいプロセスにアタッチしようとした、ResumeThread直前のタイミングです。
ここで新しいプロセスにアタッチし、0x00400000のアドレスを表示します。すると、「MZ」で始まる領域が見えます。これがDOSヘッダ(MZヘッダ)です。
Windowsの実行形式ファイルのヘッダ部は、概ね「DOSヘッダ(MZヘッダ)」、「DOSスタブ」、「PEヘッダ」の3つに分かれています。
以下に、今回の検体のProcess Hollowingで展開された後の実行プログラムのヘッダ部を表示します。
上に挙げたサイトや書籍の中でDOSヘッダのレイアウトを見ると、最後に「LONG e_lfanew」があります。これが、PEヘッダの開始位置を示すオフセット値です。
図では、DOSヘッダ(オレンジの枠)の末尾が「80 00 00 00」になっています。
これはリトルエンディアンのため、これをmovなどでレジスタに入れたときの値は0x00000080となります。
これはオフセット値なので、ベースアドレスの0x00400000を加えると0x00400080になり、これがPEヘッダの開始位置の求め方となります。
まあ、ASCIIで「PE」となっているので、計算しなくても見れば分かるんですけどね。
一応、システム的な予備知識として・・・。
次に、このPEヘッダを見ていきます。
PEヘッダは、更に「Signiture」、「FileHeader」、「OptionalHeader」に分かれます。
今回の検体のProcess Hollowingで展開された後の実行プログラムのヘッダ部のうち、PEヘッダ部を分類した図を表示します。
「Signiture」は、「PE」の2文字+0x00が2つ続く4バイトで固定です。
「FileHeader」は、セクション数やOptionalHeaderのサイズがあります。エントリーポイントの算出には関係ないので、詳細は割愛します。サイズは20バイト(0x14)で固定になります。
「OptionalHeader」は、様々なバージョン情報やサイズ情報などがあり、エントリーポイントのオフセットもここに含まれます。PEヘッダのオフセット0x18から開始されます。
OptionalHeaderの「AddressOfEntryPoint」が、エントリーポイントのオフセットアドレス値となります。この例では、リトルエンディアンで[B0 14 00 00]となっているので、0x14B0となります。
このため、ベースとなる0x00400000を加算すると0x004014B0となり、Process Hollowingで展開された後の実行プログラムの抽出方法(その1)の記事で示したOEPになる、というわけです。
「AddressOfEntryPoint」はPEヘッダの開始位置のオフセット+0x28で固定のため、「PE」を見つけて+0x28の位置の4バイトを参照する、と憶えておけばいいでしょう。
私が今回やったズル
ところで、私は今回ちゃんと真面目に計算もせずOEPを求めていたのですが、この時の方法も一応紹介します。
「IDAでViewメニューからSegmentsタブを開き、0x00400000で始まるセグメントを選択して右クリックでハードウェアブレークポイントを設置する」という、極めて大雑把な方法でやっちゃいました(てへぺろ)。
そんなんだから、TLSコールバックを最初に捕まえちゃうんですけどね。
まあ、雑と言えば雑ですが・・・理には適ってるんですよね。マルウェアは最初はコードセクションで実行されることには変わらないので・・・。
むしろ、TLSコールバックも見逃さなかったと思えば(言い訳)。
当然保証はできないし、推奨もしませんが、割と現実的には使える手で、たまに私は使っているので、一応紹介しておきます。