リメイクがこの秋に出ると聞いてPSPを引っ張り出し、『俺の屍を越えてゆけ(ダウンロード版)』をリプレイしている。発売当時、大学生だった筆者を廃ゲーマーと化させたこのゲーム、実は少し前にも再プレイしていた。このゲームの「家族」というテーマが、あれからしばらく経った自分にどんなかたちで受け入れられるのか、知りたくなったからだ。
結論から言うと、このゲームの主題歌である『花』について、往事は何とも思わなかったのが、今は「やばい!」と感じるようになった。そう、やばいのは涙腺だ。ゲームどころではなくなってしまう(笑)
さて、冒頭はいつも通りの回り道をしてから、今日はEMETに追加されたEAF(Export Address Table Access Filtering)について紹介したい。ただ、EAFについて理解するためには、少し予備知識が必要だ。
一般に、いわゆるバッファオーバーフロー脆弱性を悪用するためにはシェルコードが必要になる。シェルコードを使用することによって、ファイルのダウンロードや実行が可能になり、マルウェアを新たに感染させるといったことができる。シェルコードがどのような構成をとるのかといえば、概要としては次の図の通りとなる(XORでシェルコードを難読化といった手段については、この主題についての本質ではないので省く)。
シェルコードの構成概略 |
このように、シェルコードにはおよそ3つの要素があるといっていい。すなわち、
- 攻撃動作で使用するWin32 APIのアドレスを特定するコード
- 実際に攻撃動作を発生させるコード
- Win32 API呼び出しを使用する際の引数に使用される文字列
である。このうち、(1)については次のWin32 APIが使用されることが一般的である。
- LoadLibraryA()
- GetProcAddress()
ファイルをダウンロードさせる、ファイルを実行するといった攻撃動作を実現するためにはURLDownloadToFileA()やWinExec()といったWin32 APIに適切な引数を与えて呼び出すのが効率的である。その障壁のひとつとなるのが、これらのAPIがロードされているアドレス(APIのエントリポイント)を特定しなければならない、という条件である。一般的なプログラムであれば、PEヘッダに含まれるImport Address Table(IAT)のエントリをもとにこれらのアドレスはローダによって自動的に用意されるが、シェルコードではそれらの情報は使用できないためだ。よって、前記のLoadLibraryA()とGetProcAddress()を使用して攻撃動作で使用するAPIを特定し、使用する必要がある。しかし、LoadLibraryA()もGetProcAddress()もkernel32.dllに含まれるWin32 APIである。よって、通常の方法では、シェルコードはAPIを使用することができない。
そこで、一つの解決法としてFSレジスタのオフセット0x30(fs:[30h])にセットされるプロセス環境ブロック(PEB)の値を使用することがある。この構造体には、ロード済みのDLLのリスト(InInitializationOrderModuleList)が含まれており、これを使用することによってリンク構造を辿り、kernel32.dllのExport Address TableからLoadLibraryA()とGetProcAddress()のアドレスを特定することができる。
PEBからkernel32.dllのアドレスを抜き出す役割を担うコードの例(Phrack issue64 #7より抜粋)
mov eax,fs:[30h] ; PEB base
mov eax,[eax+0ch] ; goto PEB_LDR_DATA
; first entry in InInitializationOrderModuleList
mov esi,[eax+1ch]
lodsd ; forward to next LIST_ENTRY
mov ebx,[eax+08h]
Microsoft社の公開している資料の一つに「Enhanced Mitigation Experience Toolkit 2.0 Fact Sheet July 2010」というものがある。これによると、次のような説明がある。
- 同様に、EMET 2.0にはハードウェアブレークポイントを使用し、モジュール外のアドレスを命令ポインタが示している場合には、kernel32.dllとntdll.dllのExport Address Tableへのアクセスをフィルタします。これにより、一般的なMetaSploitタイプのシェルコードの実行を抑止します。(抄訳)
MetaSploitタイプのシェルコードの実行というのが、まさに前記のものである。すなわち、PEBからLoadLibraryA()とGetProcAddress()のアドレスを抜き出し、それぞれを使用することで攻撃動作に使用するAPIのアドレスを取得する、というものだ。この場合、シェルコードはスタックやヒープといったモジュール(.textセクション)以外の箇所に存在するため、命令ポインタ(EIPレジスタ)はスタックやヒープのアドレスを差していることになる。したがってEAFの検知処理によって特定される、というメカニズムである。
ただし、EAFに関しては迂回法の提案がなされており、同時に、ROPのようなモジュール中のコードを使用する(Return-into-Libc方式の)攻撃コードに対しては意味がないといった指摘もみられている。とはいえ「一般的なシェルコード」への対策としては一定の効果が認められると考えることもできるだろう。