第 5 章 呼出し元識別手法 45
5.7 スタック偽装耐性の評価
5.7. スタック偽装耐性の評価 57
図 5.4 マルウェアがAPIを呼び出したときのスタック [19]
フォルダ内に“out.txt”を作成し,“Hello, World!”を出力する.本評価は,5.6節の 評価と同様に FPOTest.dllをrundll32.exe にロードさせることで行う.
FPOTest.dllは,FPO オプション(/Oy) [54]を有効にしてコンパイルした.これに より,5.7.1項の(b)の隠蔽を実現する.さらに,5.7.1項の(a)の隠蔽は,偽の戻りア ドレスをスタックに積む手法を用いて実現する.FPOTest.dll は,FPOTest.dll 内に 定義した ApiCallWrapper 関数を経由してWindows APIを呼び出す.API呼出し時 の動作の流れを下記に示す.
(1) FPOTest.dll をロードしたrundll32.exe 内を探索し,ret 命令を発見する.
(2) 本来の戻りアドレスをスタックに積む.
(3) API に渡す引数をスタックに積む.
(4) (1)で発見したアドレスをスタックに積む.
(5) jmp 命令で API へ遷移する.
(6) API実行後,(4)で積んだ戻りアドレスにより,rundll32.exe内のret命令へ遷移 する.
(7) rundll32.exe内のret命令は,(2)で積んだ戻りアドレスを用いて,ApiCallWrapper へ戻る.
(8) ApiCallWrapper から呼出し元へ戻る.
5.7.3 評価結果
図5.5は,rundll32.exe により NtCreateFileシステムコールが発行されたとき の関 数呼出し階層である. 図5.5は,5.6.3項で述べた ImageMapや Writable などの一部 の項目を省略しているが,BTSから得られた関数呼出し階層を示すために分岐記録の 情報を追加している.Validは,5.6.3項で述べたものと同様に,スタックの戻りアド レスとBTSトレースにより取得した呼出し元アドレスとの比較結果を示す.ただし,
Valid: NOの場合,対応付けた分岐記録についての情報も合わせて出力する.図5.5で
は,[02]以降の戻りアドレスにおいて,Valid: NOとなっており,分岐記録に存在す る call 命令による分岐から期待される値と一致していない.[02]の戻りアドレスは,
bts[0681]の分岐記録と対応付けられている.bts[0681]は,BTSバッファの681番 目の分岐記録である.各分岐記録には,分岐元アドレス(from)と分岐先アドレス(to) を出力している.各アドレスについては,戻りアドレスと同様にAPI 名とファイルの 情報を付加している.
bts[0681]の分岐記録は,FPOTest.dll 内部の 0x10001094から,FPOTest.dll内部
の 0x100010a0への遷移を示す.スタックトレースで得た[02]の戻りアドレスである
0x1001c58は,rundll32.exe内のアドレスであり,FPOTest.dll の ApiCallWrapperが 呼出し元偽装のためにスタックに積んだものである.[03]以降のスタックトレースの 結果でも,FPOTest.dll が呼び出されたことは確認できなかった.一方,BTSトレー スで取得した関数呼出し階層では,FPOTest.dll が出現しており,FPOTest.dll を経 由してシステムコールに至ったことがわかった.したがって,スタックトレースは,
FPOTest.dllにより偽装された関数呼出し階層を取得してしまったのに対し,BTSト
レースは正しい呼出し階層を取得できている.以上から,BTSトレースは,スタック トレースと異なり,スタックを偽装された場合でも正しい関数呼出し階層を取得可能 であることが確認できた.