最近ソフトの話題がなかったので久々に。
DEPというのはWindowsXP XP2から使えるようになったセキュリティ機能で、コード領域以外からのプログラムの実行を抑制します。
要するにAMD OpteronのNX-bit(No eXecute bit)の機能をWindowsが対応したものです。
NX-bitはデータ領域とコード領域を区別するためのフラグで、データ領域からのコード実行をできないようにします。
何のことだか判りづらいですね。。。
この機能の主たる狙いはバッファオーバーフローによるクラッキングからコンピュータを保護する事です。
バッファオーバーフローが起こるというのはプログラムのバグが原因です。
そういう仕様だったとすれば仕様のミスです。
かつて「セキュリティ」なんて言葉が連呼されなかった頃のソフトウエアにはほとんどこの問題が入っていて、今でもWindows自体やIEでも頻繁にバッファオーバーフローの問題は見つかりますよね。
つまりそのくらい起きやすいミスなのです。
しかもこのミスは最悪の場合、悪意あるユーザーが任意のコードを実行する事が出来てしまい、結果的にコンピュータを乗っ取られます。・・・とマイクロソフトの説明を見てもよくわからんが。
まぁ、そういう時は実際にやってみるのが一番。
って事でバッファオーバーフローが発生するプログラムをわざと書いてみましょう。
ついでにDEPに対応したコンピュータで実行してみて、実際に実行が阻止されるか確かめてみます。
DEPを利用するためには、NX-bitに対応したハードウエア(CPU)が必要ですが、最近ではPentiumDやXeonなどのIntelのプロセッサでも対応しているものがあります。
ただしIntelでの名称はExecute Disable Bitです。
Intelの「プロセッサ識別ユーティリティ」で確認できます。
「ビット無効化の実行」・・・って明らかに日本語としておかしい。
Execute Disable Bitを直訳したんだろうな・・。
余談ですが技術系の日本語の資料は翻訳が不適切で返って判りづらい事が多いので英語マニュアルも必須です。。
気を取り直して、プログラムプログラム。
コード領域以外のメモリにコードを書き込んで、そこが実行されるようにすればDEP機能が働くはずです。
典型的なパターンといえば、バッファのサイズチェックミスかなぁ。
って事で以下のようなコードを書きました。
この関数はパスワードをチェックするもので、パスワードが正しければ1、間違っていれば0を返します。
でも省略してあるので絶対に0しか返ってきません。
このコードの問題は一目瞭然ですが、パスワードに26バイト以上を指定するとバッファオーバフローが発生します。
(正確には配列が4バイトのアライメントに置かれるでしょうから28バイトくらいまでは大丈夫かもしれませんが)
というわけでこれを利用して不正なコードを実行しましょう。イェイ。
そもそも上の関数が実行されるとき何が行われているのか。
まず関数を呼ぶ前に現在実行しているアドレスを保存しておく必要があります。
そうしないと、関数の処理が終わった後に元の位置に戻ってこれません。
というわけで現在の実行位置を表すeipレジスタの内容をスタックに入れます。
スタックはどんどん上に増えていく仕組みになってます。
図解するとこんな感じ。
最初にeipがスタックに積まれ、次にスタックの位置を表すebp、そして関数のローカル変数に使われる領域になっていきます。
関数が終了したときはその逆で、スタックからebp、eipを取り出して元の位置に戻ります。
さて、上の関数でいうローカル変数はbyTestBuffer[25]です。
25バイト(+アライメント)分の領域は自由に使えますが、その次にあるのはebpとeipです。
上の関数に長いパスワードを与えてバッファオーバーフローを起こさせればeipの値が格納されているメモリを任意の値に書き換えてしまう事ができますね。
eipの内容を書き換えると、例えば100という値に書き換えるとこの関数が終了したとき、CPUは100番地を実行しはじめます。
そこに実行させたいコードを書いておけば不正なコード実行成功です。
おめでとうございます。
という訳でお試しに以下のような呼び出し方をしてみました。
色々いい加減というか今みるとおかしいですが、テストって事で多めに見てください。。
PasswordCheck関数に不正な36バイトのパスワードを与えてます。
これぶっちゃけ書くの結構大変でした。。。
根気のない僕には手動アセンブリは辛い。
(ほんとはだいぶ前に書いていたんですが、めんどくさくて・・)
簡単に解説すると、[32]~[35]の部分がちょうどeipの部分になります。
関数が終了するとeipが0x0013fe90になります。
そうするとCPUは0x0013fe90番地を実行しはじめます。
ところがしかし0x0013fe90番地というのは元々ローカル変数があった場所です。
つまり[0]~[28]でコピーしたデータがある部分です。
このデータをCPUはコードだとみなして実行していきます。
VisualC++のデバッガで追っかけてみると確かに送り込んだコードが実行されています。
赤で囲った部分が引数として不正に渡したコードです。
つまり不正なデータを関数に与えたことによって任意のコードが実行されてしまっているわけですね。
コードの内容は特に意味はありませんが、以下のようなコードになってます。
1.関数の戻り値を1にする
2.壊してしまったebpの値を復元する
3.元の位置にジャンプする
(*上のは僕の環境でたまたま動くように書いただけです
実行のたびにアドレスは変わる可能性があるので、アドレス直書の部分は本来は毎回変えなければなりません)
よってこのプログラムを実行するとPasswordCheck関数の結果は1になります。
パスワード通っちゃいました。
めでたしめでたし。
あ、本来の目的忘れる所だった。
DEPを有効にしてもう一度実行するとちゃんと保護機能が働き、アプリケーションが強制終了させられました。
こんな感じで。
除外設定もできます。
ただし、カーネルモードで動くものは除外設定できないのでOS全体のDEP機能を無効にする必要があります。
boot.iniを編集して、/NoExecuteを/executeにすれば無効になります。
ちなみにeMbedded Visual C++付属のWindowsCEエミュレータがDEPのせいで起動しませんでした。
詳細をクリックすると製造元にWindowsXPに適したバージョンをもらえだそうです。
製造元Microsoft・・・。
ま、エミュレータ等は動的にコード作らないといけないのでどうしても仕方ないのですがね。
のっ、ハンドアセンブルおつかれさまです。メモリモデルをsmallモデル(フラットモデル)じゃなくて、セグメント分割(largeモデルに)すれば良かったのではないかといつも思うんですが、なぜしなかったのでしょうね。WindowsもPC-UNIXも。結局、自動変数の扱いやすさの問題だったのか、セグメント機構がないCPUに合わせたのか……謎です。
みかんさん>><br>x86って現在において不思議なアーキテクチャですよねえ。<br>根底が古くて、CISCで流れからすれば少数派なアーキテクチャのくせにすげえ普及率ww<br>IA-32だからハンドアセンブルが出来るのであって、PowerPCでやれって言われたら無理ですよwww<br>IA-32は判りやすさ故に狙いやすいのかも。<br>メモリモデルは効率を最重視した結果でしょうか。。
ポロシャツ フレッドペリーレディースファッション 通販パーカ楽天通販テーラージャケットフィデリティ春と秋の服<a href="http://www.tyczl.com" title="vネックカーディガン">vネックカーディガン</a>アスレタ ピステトラックジャケットpコート メンズhttp://www.baijleaq.com/フィデリティ pコート<a href="http://www.hloes.com" title="tシャツ 通販">tシャツ 通販</a>モンクレール激安メンズファッション コーディネートモンクレール ダウン レディース<a href="http://www.cghfr.com" title="モンクレール レディース">モンクレール レディース</a>スウェットパーカーモンクレール ベストhttp://www.baijlebr.com/フレッドペリー モッズコートduvetica ダウン服 通販 メンズ<a href="http://www.tfekw.com" title="レディースtシャツ">レディースtシャツ</a>ダウン メンズ三井アウトレットパーク セールフットサル ジャージライトダウンメンズファッション通販サイト<a href="http://www.mpofh.com" title="アシックス ジャージ">アシックス ジャージ</a>http://www.hlocg.com/