[-]=======================================================================[-] Wizard Bible vol.32 (2007,4,6) [-]=======================================================================[-] x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x ---- 第0章:目次 --- x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x ○第1章:SPAMボット対策 金床 著 ○第2章:バイナリプロテクション1 〜Packed file loader〜 sourcerian 著 ○第3章:バイナリプロテクション2 〜アプリケーションデバッギングの防止〜 sourcerian 著 ○第4章:バイナリプロテクション3 〜解除されにくいアンチデバッギングの実装〜 sourcerian 著 ○第5章:PS2ソフトの音楽差し替え エクセル小林 著 ○第6章:ハニーポットを作ろう(連載第12回) Narusase 著 ○第7章:初めての量子コンピュータ 〜スパコンを超える超並列計算〜 結城瀬名 著 ○第8章:はじめてのハッキング 〜番外編:パスワードクラック〜 Defolos 著 ○第9章:基礎暗号学講座 〜 第8回 〜 IPUSIRON 著 ○第10章:お知らせ ○第11章:著者プロフィール x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x --- 第1章: SPAMボット対策 --- 著者:金床 x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x ■0x01.) はじめに 本稿では掲示板やブログに対し無差別に宣伝目的の書き込みを行う、いわゆる SPAMボットを取り上げる。これらは主に英語圏で作成されており、自動的にウェ ブページを巡回し、フォームタグを見つけると手当たり次第に書き込みを行う。 筆者の掲示板にも最近いくつかのSPAMボットが入り込んでくるようになったため、 対策を講じる必要に迫られた。 ■0x02.) SPAMボットと砲台の違い SPAMボットはかつてアングラシーンで戦争をまきおこした「砲台」とは異なり、 特定の掲示板に対しての爆撃のような多重投稿は目的としていない。そのため、 対策もやや方向性が異なる。たとえば強度の弱いCAPTCHAでも十分対策ができる。 特定の掲示板を執拗に(自動化したプログラムで)荒らすことを目的としている 場合にはCAPTCHAの画像を自動的に解析しそこを突破するような技術が用いられる 可能性があるが、SPAMボットはそのようなことはしないと考えられる。 ■0x03.) CAPTCHA 前項で触れたが、CAPTCHAを用いればほぼ確実なSPAMボット対策になる。CAPTC HA画像を解析するほどの高度なSPAMボットの登場はまだまだ先となるだろう。た だし、俗に「エログリッド」などと呼ばれる仕組みが投入された場合はこの限り ではない。 しかし、CAPTCHAにはユーザビリティの面で難点がある。ちょっと書き込みた いだけなのにわざわざ数字や文字を読みとり、さらにそれを入力するのはとても 面倒であるため、(特に無意識のうちに)ユーザが書き込みを避けてしまう可能 性がある。コメント欄への書き込みは反射的に行いたい。思いついたことを一瞬 にして書き、書き終えたその瞬間に「投稿」ボタンを押下。書き込み終わった画 面を見てtypoに気づき「orz」状態。これが望ましい姿である。画像から文字列を 読みとっているとその掲示板なりブログなりに生じている「空気」が逃げてしま うような気がするのは筆者だけだろうか。 このような理由から、可能ならばCAPTCHA以外の、ユーザビリティに優れた対策 が好ましい。 ■0x04.) JavaScript 掲示板やブログのコメント欄のような書き込みが生じる場面では、「書き込み 前」の画面と、「書き込む先」の画面が存在する(以下「画面1」及び「画面2」 とよぶ)。ここでユーザに対してJavaScriptの使用を強制できる場合には、画面 1においてJavaScriptのコードが動作しない場合コメントが投稿できないようにす るという手法が考えられる。例えば次のようなものだ。 -----
----- SPAMボットがJavaScriptを解釈しない場合には、「js=js」というパラメータが 送信される。一方でJavaScriptを有効にしているユーザのウェブブラウザからは 「js=ss」というパラメータが送られる。この部分を画面2において判別すること で、多くのSPAMボットを遮断できる。 この方法のメリットはかなりの有効性があることと、ユーザビリティに優れて いることだ。そしてデメリットはJavaScriptを有効にしていないと書き込みがで きなくなってしまうことにある。そのため、もともとJavaScriptが有効でないと 利用できないように作られたウェブアプリケーションでは十分に実用的な対策と なる。 ■0x05.) Cookie 同じようにCookieを利用する方法も考えられる。しかしSPAMボットにはCookie に(不完全ながら)対応しているものも多く見られるため、ただ単に画面1でCoo kieを発行し、それを画面2で確認するという方法は回避されてしまう可能性が高 い。そこで、Cookieの細かな仕組みを利用するのがよいだろう。 例えば次のように、domain属性に間違った値(ウェブサイトのホストとは異な る値)を指定する。 ----- Set-Cookie: foo=bar; Path=/; Domain=.foobar ----- domain属性の値が不正なため、ウェブブラウザはこのCookieを受け入れない。 一方で実装が甘いSPAMボットでは受け入れてしまうかもしれない。このような細 かな点を付くことで、Cookieを利用する対策も可能である可能性はある。 Cookieを利用する方法のメリットおよびデメリットはJavaScriptの場合とほぼ 同じである。 ■0x06.) 文字参照 文字参照とはHTML中で使用されるいわゆるエスケープ処理のことだ。XSS対策で シングルクオートを「'」に変換する例がよく知られている。これを次のよう に使う。 ----- ----- ここで「あ」の部分が文字参照によって記述されたデータだ(12345では なく12354であることに注意)。「あ」は日本語のひらがなの「あ」のこと である(http://www.fileformat.info/info/unicode/char/3042/index.htm)。そ のため、意味としては次のように記述されている場合と等しい。 ----- ----- ウェブブラウザがフォームを実行する際に、この「あ」はさらにURLエンコード されて送られる。例えばShift_JISを用いているページであれば、この値はリクエ スト中で「param1=%82%A0」となる。つまりここでは以下の処理が行われる。 ・あが「あ」であると認識する ・ページの文字コードがShift_JISであると認識する ・「あ」のURLエンコードが必要であると認識する ・「あ」をURLエンコードして「%82%A0」とする この4つのステップは通常のウェブブラウザは問題なく行うが、SPAMボットには なかなか難しい処理となる。12354が「あ」であることを認識するためにはUnico deに対応している必要があるし、さらにShift_JISという日本語の文字コードにも 対応している必要があるからだ。そのため、画面2においてparam1の値が「%82%A 0」でない場合の書き込みを拒否することで対策となる。 筆者はいくつかのウェブアプリケーションでこの方法を試してみたが、これを 突破したボットは今のところ存在しない。 この方法はJavaScriptやCookieを用いる場合のデメリットであった「ユーザが 設定を有効にしていないと書き込みできない」という点をクリアする。JavaScri ptとCookieがともに無効であっても正しく書き込みが可能であり、この点が大き なメリットとなる。また、もちろんCAPTCHAの読み込みのような無駄なステップが 不要となり、ユーザビリティにも優れているといえるだろう。 ■0x07.) まとめ このように、8-1においてはBボタンをほぼ押しっぱなしで駆け抜ける疾走感が 何より大事であることがわかった。ただし、後半の2連続ジャンプが必要となる箇 所ではあえてBダッシュは使用せず、落ちる寸前まで通常の歩行で近づいてからジ ャンプすることで、確実にクリアーできる。SPAMボットでの書き込みに辟易して いる管理者の方々には是非文字参照の方法をテストしてほしい。もちろんこれも 「いたちごっこ」であり、SPAM業者がこの方法を認識する時点で使えなくなる方 法ではある。しかし特に海外からやってくるボットにはしばらくの間は有効なの ではないかと考えている。 読者を代表してひとこと 「 ま た 小 細 工 か (`Д´)ノ ゴ ラ ァ 」 x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x --- 第2章: バイナリプロテクション1 〜Packed file loader〜 --- 著者:sourcerian x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x ■0x01.) はじめに はじめまして、sourcerianと申します。解析から引退して6年の月日がたち、V BやVB.NETで業務アプリを書くつまらない日々が続いておりましたが、目にとまっ たWizard Bibleを読んで冷え切っていた魂がふつふつと燃え上がり、自分も何か 書きたいと思った次第です。 しかし解析から遠ざかったこの身では、解析の説明は荷が重いと感じましたの で、プロテクションに焦点を置いて説明していきたいと思います。説明で登場す るコードはすべてC言語で書いてあるため理解しやすいと思います。それでは、ま ずはpacked file loaderから始めます。 ●使用するファイル ・http://wizardbible.org/32/AntiDebugging.v1.zip ・http://wizardbible.org/32/PackedFileLoader.zip ■0x02.) Packed file loader Packed file loaderとはパッカの一種です。端的に説明すると、パックされた 実行可能ファイルを読み込んでメモリに展開およびマップし、パックされる前の 動作を行います。アプローチとしてはWizard Bible vol.22の「自前でDLLをプロ セスへマッピングさせる方法 〜LoadLibrary関数の作成〜」に近いものがありま す。逆アセンブルを難しくするとともに機能制限版と製品版を分けてロードする といったことを可能にします。 ソースファイルはVS.NET 2003用のソリューションで3つのプロジェクトがあり ます。 ・target:テスト用に作成したパック対象。Win32アプリケーションのデフォルト 構成で作られたものです。 ・packer:ターゲットとなる実行可能ファイルをパックしてファイルに保存しま す。 ・loader:パックされたファイルをロードして実行します。 各々を順に追って説明していきます。 ■0x03.) target Packed file loaderでパックできるファイルは限られていて、ベース再配置情 報が含まれていることが条件になります。ベース再配置情報とは実行可能ファイ ルが想定していたメモリアドレスとは異なる位置にロードされた時に、コード内 で参照されているアドレスを修正するためのデータです。また、そのアドレスを 修正することをベース再配置といいます。 一般的なパッカはターゲットがロードされるメモリアドレスを変えずにローダ ーを埋め込みますが、Packed file loaderではターゲットを異なるアドレスにロ ードするためにベース再配置情報が必要となるのです。 ベース再配置情報はDLLには付与されますが、EXEファイルには通常付与されま せん。一番最初にロードされる実行可能ファイルなのでロードに失敗することが ないためです。ですからビルドするときはリンカーオプションに/FIXED:NOを追加 してベース再配置情報を付与してやります。 ■0x04.) packer 処理の流れとしては次のようになります。 イメージファイルの読み込み ↓ 不要なヘッダ情報を削除 ↓ 圧縮 ↓ ファイルに保存 EXEファイルをそのままパックしてしまうと、ロードされた後にメモリをダンプ することで簡単にアンパックすることができてしまいます。それを防ぐために不 要なヘッダ情報は削除してやります。実際にロードするために必要なデータは次 のようになります。 ・ヘッダのサイズ セクション数によってヘッダサイズが可変になるから必要です。 ・セクションの数 これがわからなければセクションをロードできません。 ・エントリポイント これがないとロードした後にどこから開始すればよいかわかりません。 ・イメージベース(想定していたロードされるアドレス) ベース再配置に必要です。 ・イメージファイルをロードするために必要なサイズ ロードするためのメモリを確保するためです。PEファイルフォーマットではヘ ッダを含めたサイズですが、ロードした後はヘッダが不要になるので全セクショ ンをロードするためのサイズとします。 ・インポートアドレステーブル(IAT)のデータディレクトリエントリ IATをヘッダに含ませてセクションから削除したほうが強固になりますが面倒な ためセクションにそのまま残してバインドすることにします。 ・リソースのデータディレクトリエントリ リソース関連のAPIに必要なために必要です。 ・ベース再配置情報のデータディレクトリエントリ ベース再配置に必要なために必要です。。これもIAT同様ヘッダに含ませてセク ションから削除した方がより強固になるでしょう。 ・セクション コードやデータなどのプログラム本体なので当然必要です。 PEファイルフォーマットと比べると随分すっきりしました。本来ならマルチス レッド用にTLS初期化情報のデータディレクトリエントリも必要ですが、今回は対 象外としました。 これを圧縮したファイルを私はスマートイメージ(Smart Image)と名づけ、拡 張子はSEXにしました。今回使用した圧縮はランレングスです。単純なアルゴリズ ムで圧縮率も良くありませんが、暗号化という点ではそこそこ効果があります。 ■0x05.) loader 処理の流れとしては次のようになります。 ファイルをロード ↓ ランレングスを展開 ↓ VirtualAlloc()でメモリを確保 ↓ セクションをロード ↓ インポート関数のバインド ↓ ベース再配置 ↓ 自分自身のリソースディレクトリへのアドレスを変更 ↓ セクションのアクセス保護属性を適用する ↓ オリジナルエントリポイントにジャンプ 全体を通してそれほどややこしい点はありませんが「自分自身のリソースディ レクトリへのアドレスを変更」では注意が必要です。リソース関連のAPIはリソー スディレクトリへのアドレスがイメージ内にあるかどうかチェックしているため、 自身のPEヘッダのイメージサイズをリソースを含めるように変更してやる必要が あります。また、リソースデータのアドレスはRVA(Relational Virtual Addres s:実アドレスからイメージベースを引いた値)で表現されており、実アドレスは 「イメージベース(リソース関連のAPIに渡されたHMODULE)+RVA」となるのでそ のままでは正しい実アドレスを取得できません。「ロードされたアドレス+RVA」 となるようにRVAに「ロードされたアドレス−自分のイメージベース」を足してや ります。「VirtualAlloc()でメモリを確保」する際にはフラグにMEM_TOP_DOWNを 指定しましょう。MEM_TOP_DOWNを指定するとVirtualAlloc()はできるだけ上位の アドレスにメモリを確保します。ツールを使ってイメージをダンプするとサイズ が2Gバイト近いファイルになるので嫌がらせになります(ネタばらしすると簡単 に解除されますが)。 ■0x06.) 最後に 解析を防ぐにはPacked file loaderだけでは不十分です。いくつもの妙技を組 み合わせてより強固なものにしていきましょう。次回はアプリケーションデバッ ギングを防ぎます。「デバッギングされるのが嫌=デバッガにアタッチされるの が嫌」ということですのでアタッチされる前に自分でアタッチしてしまえばよい のです。 x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x --- 第3章: バイナリプロテクション2 〜アプリケーションデバッギングの防止〜 --- 著者:sourcerian x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x ■0x01.) はじめに デバッガには大別してカーネルデバッガとアプリケーションデバッガがありま す。SoftIceやWinDBGなどはカーネルデバッガ、W32DasmやOllyDbgなどはアプリケ ーションデバッガに分類されます。今回はそのアプリケーションデバッガによる デバッギングを防ぐというお話です。退出 本題に入る前に用語の説明をしないと頭が混乱しそうです。プログラムの不具 合をバグ(bug)、バグを取り除くことをデバッグ(debug)、バグの原因を突き 止める作業をデバッギング(debugging)、デバッギングの手助けをするツールを デバッガ(debugger)、ついでにデバッギングされるプログラムのことをデバッ ギ(debuggee)といいます。クラッカ達は「ある日付を超えたら動作しなくなる バグ」や「シリアル番号を入力しないと機能に制限があるバグ」などを、様々な ツール(そのうちのひとつがデバッガ)を使って、「何故そのような動きになる のか」を調査して(デバッギング)、取り除いてしまいます(デバッグ)。 そこで今回の目的は、アプリケーションデバッガでブレイクポイントを設置し たりAPIコールで停止させて引数を調べたりスタックフレームを調べてバグの箇所 を推定したりすることを防ぐことになります。以後、いちいちアプリケーション デバッガと書くのは面倒なので「デバッガ」と表記した場合は「アプリケーショ ンデバッガ」を指すこととします。 ●使用するファイル ・http://wizardbible.org/32/AntiDebugging.v3.zip ・http://wizardbible.org/32/DebuggerSample.zip ■0x02.) どうやって防ぐのか よくあるのがデバッガが検出された場合プログラムを終了させてしまうという ものです。デバッガの検出方法はDegital Travesiaの『OllyDbg』Q&A(http://h p.vector.co.jp/authors/VA028184/OllyDbgQA.htm)に記載されていますのでそち らをどうぞ。他にもgoogleなどで「detect debugger」や「anti debugging」など をキーワードに検索するとたくさんひっかかります。 しかしこの方法はあまり効果がありません。クラッカにしてみればデバッガの 検出部分を調べて取り除いてしまえばよいだけの話です。デバッガの検出は決ま りきった処理のため突き止めるのも簡単です。デバッガ検出部分を巧妙に隠して あるようなものもありますが生半可な知識で仕込んでも熟練のクラッカ相手には 3分ともたないでしょう。 そこで今回紹介するのが「デバッギングされてしまうのが嫌なら自分が先にし てしまえ」という方法です。 デバッガは最初に「このプロセスを私にデバッギングさせてください」とWind owsにお願いしなければいけません。このとき、ターゲットプロセスが他のデバッ ガによって既にデバッギングされていた場合、そのお願いは却下されてしまいま す。「こいつ(デバッギ)にはもう恋人(デバッガ)がいるので諦めなさい」と いわれるのです(XPやVistaにはその恋仲を壊してしまう方法もあったりしますが)。 したがって、デバッギングされたくないプロセスがあるなら、自分が先にその プロセスをデバッギングしてしまえばよいことになります。ただし、自プロセス をデバッギングすることはできませんので、デバッガ担当とデバッギ担当(実作 業担当)にプロセスを分けて動作させます。デバッガ担当はデバッギングされて しまいますが、実作業担当のほうはデバッギングすることができなくなります。 ■0x03.) デバッガの基礎 さて、先にデバッギングしてしまえばよいというのは簡単ですが、デバッガと なるにはいくつかの手順や決まりがあります。 デバッガの基本的な構造は次のようになっています。 ①新規プロセスをデバッギとして生成(または既存プロセスをアタッチ) ②デバッグイベントを待機 ③デバッグイベントを処理 ④続行方法を指定してスレッドを再開 ⑤②へ戻る 各々のステップを順を追って説明していきます。 ①プロセスをデバッギとして生成(または既存プロセスをアタッチ) 前述した「ターゲットプロセスを私にデバッギングさせてください」とWindow sにお願いする部分です。CreateProcess()APIでプロセスを新しく生成する時にD EBUG_PROCESSフラグを指定すると新しく作られるプロセスはデバッギとなり、デ バッギプロセスを生成したデバッガにとってデバッギング対象となります。 DEBUG_PROCESSフラグだけではデバッギが作った子プロセスもデバッギング対象 となります(ただし、子プロセスの生成にDEBUG_PROCESSフラグを指定した場合を 除く)。DEBUG_ONLY_THIS_PROCESSフラグを指定すると子プロセスはデバッギング 対象外となります。 既存プロセスをデバッギングしたい場合はDebugActiveProcess()APIを使います。 その場合、子プロセスはデバッギング対象外となります。 ②デバッグイベントの待機 デバッギの実行中に例外が発生したりDLLをロードしたりするとデバッグイベン トとしてデバッガ側に伝えられます。デバッグイベントは例外発生、プロセスの 生成・終了、スレッドの生成・終了、DLLのロード・アンロードに分類され、例外 発生はブレイクポイントへの到達(INT 3の実行)やアクセスバイオレーションな どさらに細かく分類されます。 デバッギの起動時またはアタッチ時には必ずブレイクポイント例外が発生しま す(このブレイクポイントはAPIが設置したものでその場所はエントリポイントで はありません)。これをファーストチャンスイベントと言い、この時にブレイク ポイントの設置など初期化を行います。 デバッグイベントの待機にはWaitForDebugEvent()APIを使います。 ③デバッグイベントを処理 デバッグイベントがデバッガに伝えられるとデバッギの全スレッドが停止状態 になります。これを利用してメモリの内容やスタックの状態を表示したり、デバ ッギが処理を続けられるように例外の処理を行います。また、デバッギが終了し た場合、つまりデバッグイベントがこれ以上発生しなくなった場合には、デバッ グイベント待機のループから抜けないとデバッガがいつまでたっても終了しない ことになります。 ④続行方法を指定してスレッドを再開 デバッグイベント処理中はデバッギの全スレッドが停止状態にあるわけですか ら、処理が終わったことをWindowsに伝えて、デバッギの全スレッドを再開させて やらなければいけません。この時、例外をデバッギの例外ハンドラに渡すかどう かを指定します。ただし例外発生以外のデバッグイベントではこの指定は無視さ れます。 この例外を渡すかどうかの指定をデバッガは適切に判断しなければいけません。 例外をデバッギの例外ハンドラで処理しなければいけないのにデバッガでブロッ クしてしまうと同じデバッグイベントが無限に発生したり、デバッガが設置した ブレイクポイントへの到達をデバッギの例外ハンドラに渡してしまうと強制終了 してしまう可能性があります。 Digital Travesiaに記載されている「6.構造化例外ハンドラを用いたデバッグ 検出」(http://hp.vector.co.jp/authors/VA028184/OllyDbgQA.htm)で検出され るようなデバッガは適切に判断していないデバッガです。適切な判断をするデバ ッガは検出されません。サンプルプログラムDebuggerSample.zipを用意しました。 debuggee.exeは「構造化例外ハンドラを用いたデバッグ検出」とIsDebuggerPres ent()APIの戻り値の表示を行います。debugger.exeはdebuggee.exeをデバッギと して起動して、ブレイクポイント例外が発生した場合に例外をデバッギに渡すか どうか確認してきます。渡すかどうかでその後の処理の違いを確認してください。 ■0x04.) デバッガの実装 ここまで説明すれば後はソースファイルを見たほうが早いでしょう。C言語で記 述すると次のようになります。 ---------------------------------------------------------------------------- DEBUG_EVENT de = { 0 }; // デバッグイベント情報 STARTUPINFO si = { 0 }; // CreateProcess() から戻される情報 PROCESS_INFORMATION pi = { 0 }; // CreateProcess() から戻される情報 // プロセスをデバッグ対象として生成する BOOL bCreate = CreateProcess( NULL // lpApplicationName , "debuggee.exe" // lpCommandLine , NULL // lpProcessAttributes , NULL // lpThreadAttributes , FALSE // bInheritHandles , DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS // flags , NULL // lpEnvironment , NULL // lpCurrentDirectory , &si // lpStartupInfo , &pi); // lpProcessInformation if( bCreate == FALSE ) { return 1; } // デバッグイベントの待機 while( WaitForDebugEvent(&de, INFINITE) ) { // スレッドの続行方法 DWORD dwContinueStatus = DBG_CONTINUE; // 初期値は例外をデバッギに渡さない // 例外発生 if( de.dwDebugEventCode == EXCEPTION_DEBUG_EVENT ) { EXCEPTION_RECORD* per = &de.u.Exception.ExceptionRecord; // ブレイクポイントに到達 if( per->ExceptionCode == EXCEPTION_BREAKPOINT ) { // ファーストチャンスイベント if( bFirstChance ) { bFirstChance = FALSE; // ブレイクポイントの設置など初期化を行う } else { // 身に覚えのないブレイクポイントはデバッギに処理させる。 dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED; } } // その他の例外処理 else { // デバッギの例外ハンドラに例外を処理させる。 dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED; } } // プロセスが終了した else if( de.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT ) { // デバッグイベントの待機を辞める。デバッギの子プロセスを含めて // デバッグ対象としている場合は全てのプロセスが終了するまで処理 // を続ける break; } // その他、DLLのロード/アンロード、プロセスの生成、スレッドの生成/終了 //else //{ //} // 続行方法を指定してスレッドを再開 if( !ContinueDebugEvent(de.dwProcessId , de.dwThreadId, dwContinueStatus) ) { break; } } // プロセスハンドルとスレッドハンドルをクローズする CloseHandle(pi.hProcess); CloseHandle(pi.hThread); ---------------------------------------------------------------------------- ■0x05.) アンチデバッギングの実装 デバッガの骨組みが出来たところでアンチデバッギングの実装に取り掛かりま す。前述したようにデバッガ担当とデバッギ担当(実作業担当)にプロセスを分 けて動作させます。しかし、プログラムをデバッガ担当とデバッギ担当に分ける 必要はありません。Cランタイムスタートアップルーチン(WinMainCRTStartup) が実行される前にデバッガ部分が実行されるようにして、次の手順を行います。 ①自プログラムをデバッギとして起動 ②ファーストチャンスイベントでエントリポイントにブレイクポイントを設置 ③エントリポイントに設置したブレイクポイントに到達したらオリジナルエント リポイント(WinMainCRTStartup)にジャンプ ブレイクポイントの設置とは、設置したい場所のプログラムコードを0xCC(IN T 3のマシン語コード)に変更することです。また、オリジナルエントリポイント へのジャンプはスレッドのCPU状態(CONTEXT)を操作するGetThreadContext()AP IとSetThreadContext()APIを使って現在実行中のアドレス(EIP)を変更します。 これを実装したのがAntiDebugging.cです。デバッギングを防止したいプログラム のプロジェクトにAntiDebugging.cを追加し、プロジェクトの設定でエントリポイ ントをEntryPointにするだけでデバッギングが防止できます。サンプルとしてAn tiDebugging.v1.zipを用意しましたので、OllyDbgなどでデバッギングを試してみ て下さい。ブレイクポイントは上手く機能しないし、既存プロセスのアタッチも 失敗します。 ■0x06.) 簡単に解除されてしまうアンチデバッギング 確かにデバッギングが防げましたが、これを簡単に解除してしまうことができ ます。 ①SetThreadContext()APIにブレイクポイントを設置。 ②①で設置したブレイクポイントに到達したら、APIに渡された引数のCONTEXT構 造体のEipの値を控える。 ③プログラムのエントリポイントを②のEipの値で書き換える。 たったこれだけです。これはデバッガ部分がデバッギをオリジナルエントリポ イントにジャンプさせるだけの役割しか果たしていないからです。これを防ぐに はデバッガ部分が動作しないとデバッギが動作しないようにしてやる必要があり ます。次回はその方法と説明を行います。 ■0x07.) 最後に 前回のPackedFileLoaderではPEフォーマットの知識ありきで説明してしまった ためかなり説明を省いてしまいましたが、今回はいかがでしたでしょうか。ほと んどデバッガの説明で終わってしまった気もしますが、デバッガの仕組みを理解 するのはとても重要なことです。アンパック後に逆アセンブルするdispeやジェネ リックアンパッカなどもデバッガなので対策をたてる上で役にたつからです。例 えば親プロセスのプログラムがWaitForDebugEvent()APIをインポートしている場 合はデバッガがアタッチされていると判断できます。自分でもいろいろと考えて みてください。 x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x --- 第4章: バイナリプロテクション3 〜解除されにくいアンチデバッギングの実装〜 --- 著者:sourcerian x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x ■0x01.) はじめに 前回ではアンチデバッギングを実装しましたが簡単に解除されてしまうので、 デバッガ部分が動作しないとデバッギ部分が動作しないように改良しましょうと いう話で終わりました。今回はその改良方法の説明です。 ●使用するファイル ・http://wizardbible.org/32/AntiDebugging.v3.zip ■0x02.) PackedFileLoaderとアンチデバッギングを組み合わせる 第1回のPackedFileLoaderと第2回のアンチデバッギングを組み合わせて、デバ ッガ部分にローダを担当させることでエントリポイントを修正しただけでは解除 できないようにします。PackedFileLoaderのローダ部分をデバッガ部分に組み込 むので処理の流れは次のようになります。 ①自プログラムをデバッギとして起動する。 ②ファーストチャンスイベントでエントリポイントにブレイクポイントを設置す る。 ③エントリポイントに設置したブレイクポイントに到達したらデバッギプロセス にスマートイメージファイルをロードする。 ④スマートイメージファイルのロードが完了したらデバッギのスレッドのEIPをオ リジナルエントリポイントに変更する。 ここで色々と問題が発生します。 PackedFileLoaderではインポートアドレステーブルのバインドにLoadLibrary( )APIとGetProcAddress()APIを使っていました。ところが、今回は別プロセスにD LLをロードさせるわけですから、LoadLibrary()APIとGetProcAddress()APIは使用 できません。そこで別プロセスにDLLをロードさせるInjectLibrary()関数と、別 プロセスにロードされたDLLのエクスポート関数のアドレスを取得するGetProcAd dressEx()関数を作ります。 しかしここで別の問題が発生します。InjectLibrary()関数はCreateRemoteThr ead()関数にスレッドルーチンとしてLoadLibraryを指定してスレッドをつくり、 DLLのロードが完了するまでWaitForSingleObject()APIで待機します。しかし、デ バッグイベントの処理中はデバッギの全スレッドが停止されることを思い出して ください。つまりデバッグイベントの処理中にInjectLibrary()関数を使うことは できないのです。そこでスマートイメージをロードするのは別スレッドに担当さ せ、デバッガを担当するスレッドはデバッギのスレッドをSuspendThread()APIで 停止させた後、スレッドの続行・デバッグイベントの待機に入ります。そうする ことで、CreateRemoteThread()APIで作られたスレッドが動き出してDLLをロード するのです。そしてスマートイメージファイルのロードが終わった時点でデバッ ギのスレッドのEIPをオリジナルエントリポイントに変更してResumeThread()API でスレッドを再開させます。 以上を反映させるとデバッガ部分の処理の流れは次の通りです。 ①自プログラムをデバッギとして起動する。 ②ファーストチャンスイベントでエントリポイントにブレイクポイントを設置す る。 ③エントリポイントに設置したブレイクポイントに到達したらSuspendThread()A PIでデバッギのスレッドを停止、デバッガ側の別スレッドでスマートイメージフ ァイルをデバッギのプロセスにロードする。 ④スマートイメージファイルのロードが完了したらデバッギのスレッドのEIPをオ リジナルエントリポイントに変更してResumeThread()APIによりデバッギのスレッ ドを再開させる。 これまでの内容を実装したAntiDebugging.v2.zipを用意しました。AntiDebugg ing.v2.zipにはPackedFileLoaderと同じソリューション構成のソースが入ってい てloader以外は全く同じです。Loaderプロジェクトには以下のソースファイルが 含まれています。 ・Except.h/Except.c 今回からエラー処理の簡略化に構造化例外処理(SEH:Structured Exception Handling)を使うことにしました。SEHのラッパの宣言と定義がこの2ファイルに なります。 ・ApiWrapper.h/ApiWrapper.c ReadProcessMemory()やWriteProcessMemory()などのAPIのラッパ関数の宣言と 定義です。APIコールに失敗するとSEHの例外を投げるようにしただけの単純なも のです。 ・InjectLibrary.h/InjectLibrary.c 前述したInjectLibrary()関数とGetProcAddressEx()関数の宣言と定義です。 ・LoadSmartImageEx.h/LoadSmartImageEx.c スマートイメージファイルのロードを行う関数とそれに付随する関数の宣言と 定義です。第1回のLoadSmartImage()関数のメモリI/OをひたすらReadProcessMem ory()APIとWriteProcessMemory()API(のラッパ関数)で行うようにし、それらを別 スレッドで実行するようにしたものがLoadSmartImageEx()関数です。 ・Loader.c WinMain()関数とデバッガ部分です。前回はEntryPoint()関数をエントリポイン トとしましたが、VisualC++でSEHを使うとCランタイムライブラリを使うことにな るためWinMain()で定義してあります。 実際にスマートイメージファイルを実行させてみてOllyDbgなどでデバッギング できないことを確認してみてください。 ■0x03.) ダンプ対策にAPIコールをフックする PackedFileLoaderそのものの弱点ですが、スマートイメージファイルがロード された後にメモリをファイルにダンプしてPEファイルフォーマットの整合性をと ることで、そのまま実行できてしまいます。それをデバッギングされてしまって は意味がありません。 そこで一部のAPIにブレイクポイントを仕掛けて、そのブレイクポイントに到達 した時点で本来とは異なる動作をするように変更します。当然、デバッギ側は変 更された動作でないと正しく動作しないようにします。 抽象的にいっていてもわかりにくいので具体的な説明をしましょう。今回、私 が目をつけたのはLoadResource()APIです。PackedFileLoaderのローダ部の説明で、 次のように記述しました。 ----- リソースデータのアドレスはRVA(relational virtual address:実アドレスからイ メージベースを引いた値)で表現されており、実アドレスは「イメージベース(リ ソース関連のAPIに渡されたHMODULE)+RVA」となるのでそのままでは正しい実ア ドレスを取得できません。「ロードされたアドレス+RVA」となるようにRVAに「 ロードされたアドレス−自分のイメージベース」を足してやります。 ----- この説明の実アドレスを取得するAPIがLoadResource()APIで、そのほかのLoad String()APIなどリソースを取得するAPIは全てLoadResource()APIをコールしてい ます。LoadResource()APIは第二引数のHRSRCからRVAを取り出し、第一引数のモジ ュールハンドルにそのRVAを足したものを返します。つまり、ロード時にRVAを修 正しなくてもLoadResource()の戻り値に「ロードされたアドレス−自分のイメー ジベース」を足してやれば良いことになります。戻り値を修正するにはAPIのコー ル元(戻り先)にブレイクポイントを設置してそのブレイクポイントに到達した際 にEAXレジスタの値を書き換えます。 したがって、処理の流れは次のようになります。 ①LoadResource()APIにブレイクポイントを設置する。 ②LoadResource()APIに設置したブレイクポイントに到達したら以下の処理を行う。 ②−①スタックから戻り先を調べて戻り先にブレイクポイントを設置する。 ②−②LoadResource()関数本来の動作をさせるためにブレイクポイント設置前に 戻し、EIPを一つ前(INT 3実行する前)に戻す。 ②−③ブレイクポイント設置前の動作を行わせた後に再度ブレイクポイントを設 置するために、スレッドのシングルステップフラグをオンにする。 ③②−③で設定したシングルステップフラグのせいでスレッドは1命令実行毎にシ ングルステップ例外を発生します。この時LoadResource()APIにブレイクポイント を再設置してシングルステップフラグを解除します。 ④②−①で設置した戻り先のブレイクポイントに到達し、戻り値が自分のリソー スを指しているようだったら、戻り値(EAXの値)を修正します。 これでメモリをダンプしてもリソースのRVAが正しくないのでリソースのロード に失敗して正常に動作してくれません。ただし、逆アセンブルはできますのでシ リアルナンバーのチェック部分などクリティカルな部分は隠しておきましょう。 上記を実装したAntiDebugging.v3.zipを用意しました。v2からの修正箇所はス マートイメージファイルのロード時にリソースのRVAを修正しないのと、デバッガ 部分で上記の流れを追加したものになります。 ■0x04.) 最後に というわけで、アンチデバッギングの話は終わりです。SoftIceなどのカーネル デバッガによるデバッギングは防げませんが、OllyDbgなどを防げるだけでも非常 に効果が高いと思います。個人的にはこれにアンチカーネルデバッガが(巧妙に) ついていたらもう解析する気が起きないです。 そういえばSoftIceの開発・販売が終了したようですね。64ビットの転換期が近 くクラッカご用達のSoftIceがなくなってしまった解析の世界はどのようになって いくのでしょうか。 x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x --- 第5章: PS2ソフトの音楽差し替え --- 著者:エクセル小林 x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x ■0x01.) 自己紹介&はじめに どうも初めましてこんばんわ。 元ネタを知ってる人は知ってる、知らない人は売れない芸人みたいな名前だな と思われるエクセル小林です。 さてこの度は周りの皆様が素敵な文章を載せてるのを気にせずに、PS2ソフトの 音楽差し替えについて書きたいと思います。この記事を参考にすれば、自分の好 きな音楽に変えることができます。中には音声を変えられるのもあります。 さぁ、あなたも———世界でひとつしかないソフトを作ってみませんか? ■0x02.) 差し替え可能ソフトについて 題名にはPS2ソフト音楽差し替えと書いてありますが、全部が全部差し替え可能 ってワケでなく、ソフト起動時にこんな感じの画面が出るゲームが差し替え可能 になります(図1参照)。 (図1)http://sfx64.hp.infoseek.co.jp/ps2/20070219_85610.jpg 要するにCRI社のADXを使用してサウンド再生してるか否かってことですね。こ ちらでその画面が出る「.hack//G.U. Vol.1〜3」「モンスターハンター2」を試し てみたところ、一応不具合なく起動して遊べました。しかし、上記の画像が出る からといっても、すべてがうまくできるワケではありません。自分で色々確認し てみてください。 例をあげると、ADXファイルがCVMファイルに音楽が格納されている「メルティ ブラッド アクトカデンツァ」は、以下に書いてある方法では差し替え不可能にな ります。 ■0x03.) 注意 自分用に差し替えたところで、バックアップディスクを起動させることができ なければまったく意味がありません。個人的にはSwapMagicが一番お手軽です。一 回だけ知り合いに借りてメモカブートも楽でGOOD。まあそこら辺の解説は検索す ればすぐわかると思いますので、割愛します。 ■0x04.) 差し替えディスクのつくりかた ●AFSファイルのエクスポート 1:差し替えたいPS2ゲームディスクをドライブに入れ、中身を全て適当なフォル ダにコピーします。 2:「afsexplorer.zip」をダウンロードして解凍します。 http://sfx64.hp.infoseek.co.jp/ps2/tool/afsexplorer.zip 3:「afsexplorer.exe」を起動し、File→configで"Ignore descriptor's lengt h"をチェックします。 4:File→Import AFS fileから、ステップ1でコピーした「*.AFS」を読み込ませ ます。 5:Action→Export folderで適当なフォルダにエクスポートします。 ●ADXオーディオファイルの作成 1:差し替え用の音楽ファイルを用意します。 2:フォーマットが「48,000 kHz,16ビット,ステレオ」のWAVファイルに変換しま す。 3:「adxencd.zip」をダウンロードして解凍します。 http://sfx64.hp.infoseek.co.jp/ps2/tool/adxencd.zip 4:コマンドプロンプトを起動し、「adxencd.exe」を実行します。 5:"adxencd [ファイル名]"(例:adxencd 1.wav)と入力し、エンタキーを押し ます。 6:音楽をループして再生させるために"adxencd [ファイル名] -lps0 -lpe[ルー プ終了ブロック]"(例:adxencd 1.wav -lps0 -lpe54568525)と入力してエンタ キーを押します。[ループ終了ブロック]は入力音声サンプル数の右にある数字を 入力します。 ●AFSファイルのインポート 1:作成したADXファイルを、AFSファイルのエクスポートした中にある差し替えた い音楽のファイル名にし、元ファイルに上書きします。 2:「afsexplorer.exe」を起動し、適当なAFSファイルを読み込ませます。 3:Action→Import folderを選び、AFSファイルのエクスポートのステップで読み 込ませたAFSファイル名で適当な場所にインポートします。 ●バックアップディスクの作成 1:インポートしたAFSファイルを、AFSファイルのエクスポートで保存したフォル ダに移動し、元ファイルに上書きします。 2:空のDVD-Rをドライブにセットします。 3:「Nero」をダウンロードし、インストールします。 4:Nero Burning ROMを起動します。 5:プルダウンメニューから「DVD」を選び、「DVD-ROM (UDF/ISO)」を選択して新 規作成ボタンを押します。 6:AFSファイルのエクスポートのステップ1で保存したフォルダの中身をすべてド ラッグアンドドロップします。 7:書き込みボタンを押し、適度な書き込み速度に設定して、書き込みを開始しま す。 8:以上で完成です。 AFSExplorerは3.7が最新版だそうですが、こちらの環境でしっかり動いてくれ なかったので3.2を使用しました。バックアップディスク作成編で使うのはNeroじ ゃなくても構いません。ウルトラISOなどがよいんじゃないでしょうか? しかし、 Neroならば面倒なLBAの設定をしなくていいので、非常に楽な作業になります。 ■0x05.) おわりに どうだったでしょうか? きちんと起動しましたか? これで友達に自慢でき ますね(笑 さて、これよりが需要ありそうな音声の差し替えですが、大体のソフトがAHXが 利用しているため、こちらはまだまだできないソフトが多いです。噂ではAHXファ イルの中身はmp2+ADXヘッダらしいので、ソース書き換えたらなんとかなるかもし れないらしいですが…。今後の発展に期待です。 では、機会があったらまた会いましょう。 x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x --- 第6章: ハニーポットを作ろう(連載第12回) --- 著者:Narusase x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x ■0x01.) はじめに 前回はSnortのフロントエンドであるACIDのインストールと設定について解説し ました。今回はTripwireかnepentesについて解説する予定でしたが、ちょっと趣 向を変えて、最低限必要なファイルの作成と削除だけに絞ってHIDSもどきを自作 する方法を紹介してみたいと思います。 ・・・いや、手抜きとかじゃないですよ(汗。 ■0x02.) HIDSもどきの作成 今回作るスクリプトで実現できる機能は、ファイルが作成または移動されたこ とと、ファイルが削除あるいは移動されたことを発見することです。行うことと しては、ある時点でのファイルのリストと、現在のファイルのリストの差分を取 ることで、変更のあったファイルを見つけ出し、その後、作成された物と、削除 された物をその中から抽出します。 まずは、ある時点でのファイルのリストを作るスクリプトを作ります。そのた めのスクリプトのファイル名は「hids-mklist-org.sh」としておきます。 ----- # vi hids-mklist-org.sh ----- ----- 「hids-mklist-org.sh」ファイルの内容(行番号付き) 01: #!/bin/bash 02: FILENAME="/root/list" 03: find / > ${FILENAME}.org ----- 行っていることはごくごく簡単で、findコマンドを用いて1行毎に1つのファイ ルをフルパスで表示させ、それをリダイレクトしてファイルに書き込んでいるだ けです。 次は、現在のファイルのリストを作り、差分を取るスクリプトを作ります。そ のためのスクリプトのファイル名は「hids-mklist.sh」としておきます。 ----- # vi hids-mklist.sh ----- ----- 「hids-mklist.sh」ファイルの内容(行番号付き) 01: #!/bin/bash 02: FILENAME="/root/list" 03: find / > ${FILENAME}.now 04: cat ${FILENAME}.now ${FILENAME}.org | sort | uniq -u > ${FILENAME}.uniq 05: cat ${FILENAME}.org ${FILENAME}.uniq | sort | uniq -d > ${FILENAME}.del 06: cat ${FILENAME}.now ${FILENAME}.uniq | sort | uniq -d > ${FILENAME}.make 07: echo "#########################################################" 08: echo "削除もしくは移動されたファイル" 09: cat ${FILENAME}.del 10: echo "`cat ${FILENAME}.del | wc -l`個のファイルを発見しました" 11: echo "#########################################################" 12: echo "作成もしくは移動されたファイル" 13: cat ${FILENAME}.make 14: echo "`cat ${FILENAME}.make | wc -l`個のファイルを発見しました" 15: echo "#########################################################" ----- 03行目は、先ほどのスクリプトとの違いはファイル名だけで、現在のファイル のリストを作っています。 04行目は、まず現在と過去のファイルのリストを出力し、それをソートし、un iqコマンドを使い「重複がなかった行」のみをファイルに出力しています。つま りこの時点でlist.uniqファイルの内容は新しく作られたファイルと移動されたフ ァイル、削除されたファイルのリストということになります。 05行目は先ほどとほぼ同等でuniqコマンドのオプションのみが違います。これ は、過去のファイルのリストとユニークなファイルのリストを出力し、それをソ ートし、uniqコマンドを使い「重複があった行」のみをファイルに出力していま す。つまりこの時点でlist.delファイルの内容は削除されたもしくは移動された ファイルのリストということになります。 06行目はも同じようなことをしていますがこちらでは現在のファイルのリスト とユニークなファイルのリストを比較しています。list.makeファイルの内容は当 然、作成されたもしくは移動されたファイルのリストということになります。 07行目からは見つけたファイルを表示しています。 ■0x03.) HIDSもどきの使い方 これらのスクリプトの使い方は簡単です。 まず、hids-mklist-org.shを実行し、正しい状態を記録します。 次に、hids-mklist.shを定期的に実行し不審なファイルが作成されたり、必要 なファイルが削除されていないか目視で確認するという感じです。loggerコマン ドとかを使ってsyslogにログを吐かせるのもよいかも知れません。また、cloneに 登録すれば自動的に一定時間ごとに問題が起きていないか調べることも可能です。 ■0x04.) スクリプトの拡張(宿題?) ここまでくると移動されたファイルを見つけ出したいと思うでしょうが、それ は皆さんの宿題(?)ということで・・・。 ヒントとしてはファイルは移動された場合であってもi-node番号が変わらない という性質を利用すれば良いということです。さらにヒントを出すと「stat FIL E -c"%n %i"」とするとファイル名とi-node番号が表示されますので、findで作っ たファイル名のリストからひとつひとつのファイル名を取り出しに繰り返し同じ コマンドを実行すればi-node番号まで含んだリストを作れそうです。後は、i-no de番号が同じでファイル名が違う物を探し出せばそれが移動したファイルだとい うことがわかると思います。 ■0x05.) おわりに 今回はHIDSもどきの作成について話しました。 色々と忙しかったため、内容に欠ける物になってしまって申し訳ありません。 次回はこそは、nepentesのインストールと設定に関してきちんと説明したいと思 います。 x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x --- 第7章: 初めての量子コンピュータ 〜スパコンを超える超並列計算〜 --- 著者:結城瀬名 x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x ■0x01.) はじめに 皆さんは量子コンピュータというものをご存知でしょうか。恐らく初めて耳に するという方も多いのではないかと思います。量子コンピュータとは量子力学の 原理を用いたコンピュータの総称です。一般に広く普及しているコンピュータと は計算の仕組みがまったく異なっており、近年ではカリフォルニア工科大学やス タンフォード大学といった海外の大学や専門の研究機関を中心に開発が進められ ています。日本においても北海道大学などにおいて研究開発が進められています。 今回はその量子コンピュータの魅力について解説したいと思います。 ■0x02.) 量子コンピュータとは何か 量子コンピュータが量子力学の原理を利用したコンピュータであることはすで に述べました。では「量子」とはそもそも何でしょうか? 量子とは簡単に説明 するならば粒子と波の性質をあわせ持つもののことです。例えば、エネルギー単 位「光子」によって構成される光、単位として「電子」によって構成される電気 などといった光や電気を構成する基本単位が量子の代表例です。この他にもC60と 呼ばれる炭素原子から構成される巨大分子についても粒子と波の性質を持つこと が知られていますが、一般的には上記の2つの例が一番想像が付きやすいのではな いかと思います。 量子コンピュータはこのような粒子と波の性質をもつ基本単位を利用して並列 計算を行うコンピュータです。我々が現在使用しているコンピュータ(以降、古 典的コンピュータと呼ぶ)は1ビットの値に0か1という2つのパターンの値しか持 ちません。一方、量子コンピュータが扱うビットはこれら2つの値の状態を同時に 取る「重ね合わせ」という性質を持ちます。そうしたビットを量子ビットと呼び ます。つまり、古典的コンピュータと量子コンピュータの大きな違いはまさにこ の「量子ビット」にあります。「重ね合わせ」は単に0もしくは1を確率的にとっ ているのではなく、その間に確定的な位相関係がある不思議な状態のことです。 量子コンピュータが「重ね合わせ」の性質を持っていることが古典的コンピュ ータとの大きな違いであり、ここに量子コンピュータがそれらの古典的コンピュ ータとは比較にならないほど高速に計算をこなせる秘密があります。例えば、2個 の量子ビットを用いると4つ(=2^2)の状態を、3個の量子ビットを用いると8つ (=2^3)の状態といった感じで重ねあわせにある状態の数は量子ビットの数に対 して指数的に増大します。仮に、この量子ビットの数が40ビットなら状態数は1兆 にも達します。 このような重ね合わせの状態をフルに活用することができれば、少ない量子ビ ット数で結果として膨大な数の重ね合わせを用いた超並列計算が可能になるので す。 ■0x03.) 計算不可能とされる問題が見事に解決? これまでの説明でなんとなく漠然としながらも「とにかく量子コンピュータを 用いることで超高速な計算が可能になるんだな」ということはわかっていただけ たかと思います。現在広く普及しているいわゆる市販の古典的コンピュータが1秒 間にこなす計算は平均して約10億回とされています。数年前まで世界最速と謳わ れた地球シミュレータは最大で毎秒40兆回の計算が可能とされていましたが、こ れだけ高速な計算を可能とする計算機をもってしても計算が不可能とされる問題 が現実的に存在するのです。 代表的な計算不可能問題としていくつか次に示します。 ・10,000桁の素因数分解 ・巡回セールスマン問題 これらの問題が現代の古典的コンピュータでは「計算不可」とされる共通した 理由として計算に時間がかかり過ぎることが挙げられます。 それでは各問題の簡単な解説に入りたいと思います。 ●10,000桁の素因数分解 これは文字通り10,000桁の整数の素因数分解です。素因数分解とは、ある整数 を因数が素数になるまで分解することです。 素因数分解のもっとも基本的なアルゴリズムとして、エラトステネスのふるい があります。素因数分解の対象である整数nがあったときに、√n(小数点切り捨 て)以下のすべての素数で割れるかどうかを調べれば十分であるという定理です。 アルゴリズムの世界ではひとつでも素因子がわかれば、素因数分解に成功したと 考えることに注意してください。エラトステネスのふるいは総当りの対象を減ら してくれるのに役に立ちますが、それでも素因数分解の対象が10,000桁もあれば、 古典的コンピュータで解くのは到底無理です。 他にも素因数分解アルゴリズムとして、Pollard(ポラード)の(p-1)法、Poll ard-ρ(ロー)法、2次ふるい法、数体ふるい法などがあります。現在もっとも効 率のよい素因数分解アルゴリズムは数体ふるい法となっています。余談ですが、 暗号解読チャレンジのRSA-129(10進数で129桁という意味)は1994年に2次ふるい 法で解読されました。その後RSA-130,140,155などは数体ふるい法で解読されまし た。 このように素因数分解を解くのが困難ということは広く信じられていますし、 暗号理論のもっともよく登場する基本的な概念となっています。もし量子コンピ ュータで計算できてしまえば、素因数分解問題が困難であることをベースにして いる暗号理論はすべて崩壊してしまうといえます。ただし、量子コンピュータで 解けるのはあくまで素因数分解問題や離散対数問題といった数論的なものが対象 なので、それ以外の暗号は大丈夫です(そうした暗号は使いにくいのでマイナー ですが)。また共通鍵暗号系ならば、単に鍵長を2倍にするだけで、古典的コンピ ュータにおける従来の安全性と同値になります。 ●巡回セールスマン問題 具体的な都市を登場させてみると、この問題は次のようになります。ある会社 の営業員が東京から出発し札幌・青森・仙台・新潟・横浜・名古屋・大阪・金沢 ・京都・神戸・広島・福岡の各都市を移動距離が最短になるように回り、最後に また東京に戻るというものです。 ここで話を簡単にするために次の2つの条件を付け加えます。 ・すべての都市間では道がつながっており、その間の距離は直線距離とする。 ・同じ都市には2度立ち寄らなくもよい。 上記で挙げた都市は東京を除くと全部で12都市あります。これらの都市の回り 方の順序の総数は12!(=12×11×10×・・・×1)ですから、これを計算すると約4億 8千万となります。都市の数をさらに4都市増やし16都市とすると上記の総数は約 21兆となり爆発的に総数が増加することがわかります。 例えばこれにさらに14都市を足して30都市にしたとします。これを1秒間に約 10億回の計算をこなす一般のPCで計算すると、解答に要するまでの時間は1,000兆 年以上になります。 このように巡回セールスマン問題は都市の数をほんの数個足しただけで計算に かかる時間が莫大に増加してしまうということが上記の例からお分かりいただけ るかと思います。 ●古典的コンピュータ vs 量子コンピュータ では古典的コンピュータでの解答は不可能とされるこれらの問題に対し量子コ ンピュータはどれくらいの時間で解答を導き出すことが可能なのでしょうか。 10,000桁の素因数分解は、スパコンで大体1,000億年かかりますが、量子コンピ ュータを使うと数時間程度で計算できます。 また、巡回セールスマン問題は、最新のPCで1,000兆年以上かかります。量子コ ンピュータを使った計算結果はまだわかりませんが、現在世界中の量子コンピュ ータ研究者が挑戦中です。 他にも計算不可能問題の種類はここで挙げた以外にいくつか存在しますが、こ の2つの例から量子コンピュータの計算速度がどれほどのものか分かっていただけ たのではないでしょうか。 ■0x04.) 終わりに ここまで古典的コンピュータと比較しつつ量子コンピュータがいかに速く計算 を行えるのかということについて書きましたが、量子コンピュータの研究はまだ まだ開発段階の途上にあり課題も山積しています。現在の日本においてもこれら の研究を行っている施設は極少数であり、完成まで少なくともこれからまだ10年 以上を要するといわれています。 今回はお題に「初めて」とあるように量子コンピュータとはどのようなもので あるのか、あくまでその表面的な概要についてのみ書かせていただきました。し たがって、内容についてもほとんど深みはなく書いている著者本人としてもなん だか味気のないものになってしまった感は否めません。しかしながら今回の記事 を元に少しでも量子コンピュータについて知っていただき、また興味をもってい ただけたなら筆者としても幸いです。意欲がありさらに詳しく学んでみたいと思 われる方は『量子コンピュータ 〜超並列計算のからくり〜』竹内繁樹 著(講 談社ブルーバックス)をお勧めします。 最後に、今回の記事を書くにあたり応援してくださったMaDさん、Defolosさん には深く感謝いたします。 x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x --- 第8章: はじめてのハッキング 〜番外編:パスワードクラック〜 --- 著者:Defolos x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x ■0x01.) はじめに プログラミングの基礎の確認を終えたところで、C言語によるプログラミングの 練習を行いましょう。題材としてはハッキングにも関係が深いパスワードクラッ カーの作成を通して、パスワードの基礎およびプログラミング技術の確認を行い ます。 近年では、パスワードクラッカーは多くの種類が出回っています。John The R ipperをはじめ、高性能なパスワードクラッカーが簡単に手に入り、その気になれ ば小学生でさえパスワードクラックを楽しむことができるようになりました。し かし、パスワードの原理やパスワードクラッカーに必要な動作を知らずしてツー ルを用いることは、何の進歩にもなりえないと考えます。そこで、簡単なパスワ ードクラッカーを作成し、パスワードとそれを取り巻く技術について知識を深め ることを本レポートの目的とします。 パスワードクラッキングに関するより詳しい解説はWizard Bible vol.7のKenj iさんの記事を参照ください。 参考→http://wizardbible.org/7/7.txt ■0x02.) Linuxログインパスワード Linuxのログインパスワードは「/etc/passwd」に暗号化されてテキストファイ ルとして保存されています。/etc/passwdはすべてのユーザが閲覧できるようにな っているため、セキュリティの観点からは好ましいものではありませんでした。 そのため、一般ユーザが閲覧さえできない「/etc/shadow」に暗号化したパスワー ドを置く方法が一般的になっています。この方法のことをShadowと呼びます。 以前まで多くのLinuxはパスワードの暗号化にDESを用いていましたが、近年で はMD5で暗号化することが一般的になっています。そこで、このレポートでは事前 に入手した「/etc/shadow」内のMD5で暗号化されたパスワードをクラックし、も とのパスワードを入手するツールを作成します。 ●単方向のハッシュ関数 MD5(Message Digest 5)は単方向のハッシュ関数と呼ばれるものです。また、 DES(Data Encryption Standard)は共通鍵暗号(ブロック暗号と呼ばれるタイプ )ですが、連鎖して使うことでハッシュ関数のように使うこともできます。 ある文字列を入力すると、まったく別の文字列(ビット長が小さい)を出力す る関数をハッシュ関数と呼び、出力された文字列をどういじくっても入力された 文字列を求めることはできません。ハッシュ関数を用いて文字列を変形させる場 合、正確にはエンクリプトとは呼ばずエンコード(あるいはハッシュ化)と呼び ます。また、出力されたエンコードされた値はハッシュ値と呼びます。 Linuxではエンコードされたパスワードは「/etc/shadow」に置かれます。ログ イン時に入力されるパスワードを同じアルゴリズムでエンコードし、「/etc/sha dow」に格納されているエンコード済みのパスワードと比較します。もし、両者が 一致すれば正確なパスワードが入力されたとして認証可能とします。上記のハッ シュ関数の性質のうちで、特に一方向性の概念が大きく影響していることがわか るでしょう。こうしたログイン時と同じ原理を用いてパスワードクラッカーの作 成に応用することができます。 ●ソルト 単方向ハッシュ関数をクラックする最も高速な方法は、事前にすべての文字列 をエンコードし、それと/etc/shadow内に保存されているエンコードされたパスワ ードとの比較を行う方法です。この方法では文字列が一致した場合、その文字列 がパスワードであったと判断できます。この方法では、パスワードによく使われ る文字列をエンコードして保存しておいても10Gバイトにも満たないことが多く、 なおかつ高速でクラックが可能です。このような弱点を克服するため、単方向ハ ッシュ関数にはソルト(salt)という概念を導入している場合が多いです。本レ ポートの攻撃対象であるMD5関数にもソルトは導入されています。 ソルトはエンコードパターンに多様性を持たせるための仕組みです。ソルトは ごく短い文字列で構成されます。入力文字列の先頭にソルトを配置し、エンコー ドします。エンコード結果の先頭にはソルトを配置します。これで認証時に照合 は可能になりながらエンコードパターンが一意に定まらず、事前に文字列をエン コードする手法は防ぐことができます。仮にソルトの長さが8文字、使える文字が [A-Z],[a-z],[0-9],[.],[/]の64文字だとすれば、エンコードパターンはあるひと つの入力に対して4,398,046,511,104通り考えられることになります。もしパスワ ードによく使われる文字列を事前にエンコードして保存しておくとすれば、10Tバ イトではすまない可能性もあります。 このため、本レポートで作成したパスワードクラッカーは別のアプローチを行 っています。簡単に言えば、エンコードされたパスワードからソルトを取得し、 そのソルトを用いてパスワードによく使われる文字列をMD5でエンコードします。 それを比較し、一致した場合その文字列がパスワードであったと判断します。非 常に多くの文字列に対してハッシュ化を行うため、速度は期待できません。 ●crypt関数 暗号化にはcrypt関数を利用します。crypt関数は引数としてソルトとキーの格 納されたアドレスをとり、ハッシュの先頭3文字が「$1$」で始まるときはMD5で、 それ以外のときはDESでエンコードします。また、crypt関数を利用するには-lcr yptオプションが必要であり、次のようなマクロとインクルードを行わなければな りません。 ----- #define _XOPEN_SOURCE #include