[-]=======================================================================[-] Wizard Bible vol.33 (2007,5,8) [-]=======================================================================[-] x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x ---- 第0章:目次 --- x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x ○第1章:DNSを使った攻撃 金床 著 ○第2章:「リバースエンジニアリングまつり」レポート eagle0wl 著 ○第3章:UnhandledExceptionFilter()を使ったアンチデバッギング手法 sourcerian 著 ○第4章:基礎暗号学講座 〜 第9回 〜 IPUSIRON 著 ○第5章:お知らせ ○第6章:著者プロフィール x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x --- 第1章: DNSを使った攻撃 --- 著者:金床 x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x ■0x01.) はじめに  Anti-DNS Pinningについて某所でプレゼンなどをやらせてもらってきたが、こ こに来てやっと用語の整理ができてきたので、簡単にまとめてみたい。今になっ てプレゼン資料を見てみると「オイ違うだろソレ」という点が出てくるのでまっ たく困ったものである。  ということで、「Anti-DNS Pinning」でググると上位に出てくるあの資料は参 考程度扱いでお願いします。プレゼンをきいてくれたみなさんスミマセン(;´Д`)アセアセ ■0x02.) DNS Spoofing  つまり最終的に行われる攻撃は「Anti-DNS Pinning」ではなく「DNS Spoofing」 なのである。  …といきなり書いても意味がわからないと思うので、簡単に説明する。  まず、本稿中でのみ使用する「プログラム」というオレ用語を定義しておく。 「プログラム」とは ・JavaScript ・FLASH ・Javaアプレット ・LiveConnect(のJava)  などの、一般的なウェブブラウザが備えている「ネットワークアクセス能力を 持つ」機能のことである。これらはイヴ(攻撃者のこと)のウェブページに含ま れており、罠のページを踏んでしまったあわれなアリス(ターゲットのユーザの こと)のウェブブラウザ上で稼働する。  プログラムが持つネットワークアクセス機能には、それぞれにセキュリティ制 限が備わっている。この制限は「Same Origin Policy」とよばれる。  JavaScriptの場合には同じドメインに所属するページの内容しか読めない(他 のドメインのページを開くことはできる)。また、XHRはダウンロード元のホスト にしか接続できない。  FLASHのSocketクラスはダウンロード元のホストにしか接続できない(特殊な設 定によって明示的に許可している他のホストには接続できる)。  JavaアプレットやLiveConnectのJavaはダウンロード元のホストにしか接続でき ない。  このような制限がなければ、アリスのウェブブラウザを踏み台にイントラネッ トをスキャンしたり、スパムメールを送信したり、Exploitコードを打ち込んだり、 他のサイトにDoS攻撃を仕掛けたり、とやりたい放題になってしまうのだ。  しかし「セキュリティ=いたちごっこ」の定理にしたがい、この制限を突破する 手法が考え出されたのである。それがDNS Spoofingだ。 ■0x03.) DNS Spoofing  ちなみにDNSを悪用する攻撃には色々な種類が存在し、そのうちいくつかは「D NS Spoofing」と呼ばれる。つまり「DNS Spoofing」という用語は複数の意味を持 つので、その点についてはご了承願いたい。「オレが知っているDNS Spoofingは そんなヤツじゃなかった」とか言わないように。  プログラムに対するDNS Spoofingは、だいたい次のようなイメージで行われる。 某プレゼン資料より引用する。 ・ まず罠のページが読み込まれる ・ このとき名前解決が行われる ・ 短いTTL(数秒)を持つDNSレコードを返す ・ 少し経ってからプログラムがダウンロード元のホストへ接続を試みる ・ 2度目の名前解決が行われる ・ 攻撃者のDNSサーバーは偽のIPアドレス(127.0.0.1 192.168.0.1など)を返す ・ 同一のホスト名なので接続は許可される ・ (;´Д`)エー  このように、イヴが持つドメインはイヴがDNSサーバーを自由に操ることができ るため、ウェブアプリケーションと連動して設定を変更することでSame Origin Policyが破られてしまうのである。この攻撃をDNS Spoofingと呼ぶ。 ■0x04.) 最新の攻撃手法?  さてあなたは0x03で述べた攻撃(DNS Spoofing)を知っていただろうか。筆者 はつい5ヶ月くらい前(2006年末)まで知らなかった。あまり話題にならなかった 気がするので、「コレ、最新の攻撃手法でしょ?」と考えてしまうかもしれない。 だがしかし… http://www.cs.princeton.edu/sip/news/sun-02-22-96.html  この記事を読んで欲しい。驚くべきことに、なんと1996年に書かれたものなの だ!  細かい点で若干異なる点がある(短いTTLを使うわけではなく、最初から2つの IPアドレスを返してしまうようだ)が、基本的なコンセプトはまるで同じである。 1996年、つまり11年前である。筆者が最初のコンピュータを買ったのは1997年だ ったように記憶しているので、何というかとてつもない昔のことのように感じて しまう。  この記事はSunのJavaアプレットの実装について述べたもので、どうやら某プレ ゼン資料に「Sunのエンジニアはこの攻撃を予期していた!」とか書いてあるのは 真っ赤なウソだったようである。JVMが超頑固にキャッシュをPinningするのはこ のように指摘されたせいであったようだ。  筆者がこの攻撃を「DNS Spoofing」とよぶことにした大きな理由のひとつはこ の記事でそのようによばれているからである(また、用語の使われ方も納得がい くからだ)。 ■0x05.) DNS Pinning  ということで、この攻撃は11年前から知られていたのである。そして、Sunはこ の脆弱性(?)に対してきちんと対応を行った。その方法は「一度名前解決したら、 その結果を(JVMの起動中は)永遠にキャッシュする」という極端なものである。 このように名前解決した結果を(DNSプロトコルのTTLを無視して)アプリケーシ ョンが独自にキャッシュしておくことを「DNS Pinning」とよぶ。この用語はMoz illaの開発者の間などで使われるようになったようだ。  つまり「DNS Pinning = Anti-DNS Spoofing」なのである。…ナルホド(゜д゜) ! ■0x06.) Anti-DNS Pinning  DNS Pinningの実装にはいくつかパターンがある。先述したようにJVMはこの中 でも最右翼の「一度名前解決したらそれを永遠にキャッシュする」という実装を 選んでいる。一度決めたら2度と言うことを変えない、超ガンコ親父を想像してもら うとよいだろう。  一方でIEやFirefox、Operaなどの主要ブラウザは「DNS Pinningするが、アクセ スが失敗するようだったら再度名前解決する」という実装を選んでいる。これは ダイナミックDNSによって運営されているウェブサイトなどを強く意識しているも のと思われる。そしてこの事実によってDNS Spoofing攻撃が可能になるのでは、 とセキュリティコミュニティに伝えたのがマーティソであり、彼はウェブサーバーを停 止するかファイアウォールでアクセスをブロックすることで2度目の名前解決が発 生する事実を突き止めたのである(といっても、おそらくウェブブラウザの開発 者に言わせれば「それは仕様です」ということになると思われる)。  このようにDNS Pinningの状態を破ることが「Anti-DNS Pinning」なのである。  実際の攻撃の際には、Anti-DNS Pinningによって2度目の名前解決を行わせ、結 果としてDNS Spoofing攻撃が行われることになるのである。  …ナルホド(゜д゜) !!! ■0x07.) FLASH  Adobeは(というかマクロメディアは)あまりやる気がないというか単に知らな かっただけなのか、DNS Pinningを一切行わない。つまり11年前の手法で普通にD NS Spoofingできる。しかしこれは必ずしもFLASHの脆弱性ではなく、DNSプロトコ ルそのものの問題という意見もあるだろう。ちなみに筆者はこれはDNSプロトコル の問題だと考えている。 ■0x08.) まとめ  年末からしばらくAnti-DNS Pinningネタのデモ制作などに明け暮れていたのだ が、最初にウェブブラウザを調べ、その後Javaを調べ、最後にFLASHを調べたせい で、用語について混乱してしまっていた。実際にはもっとも原始的なのがFLASHで、 ウェブブラウザやJavaアプレットなどは一歩先の対策を行っていたのである。筆 者が先述した1996年の記事をしらなかったことが混乱の最大の原因なのだが…。  ということで、ここでの簡単なまとめは ・DNS Spoofingは11年前からある攻撃だが、FLASHには今の時点でも有効 ・DNS Pinningはその対策であり、ウェブブラウザやJavaアプレットが実装してい る ・Anti-DNS Pinningは最新の攻撃手法であり、DNS Pinningを破る可能性がある  ということになる。現在執筆中の某書籍にてさらに詳しく説明を行っているの で、楽しみにして頂きたい。 x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x --- 第2章: 「リバースエンジニアリングまつり」レポート --- 著者:eagle0wl x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x ■0x01.) はじめに  セキュリティに関連する技術としては、いまひとつ知名度の低い「リバースエ ンジニアリング」。国内でこの技術を主題にしたワークショップが開催されると 聞きつけ、筆者も参加してきました。詳細は以下のリンクから。 ・カーネギーメロン大学セキュリティ・ワークショップ 「情報セキュリティのためのリバースエンジニアリング」 http://www.cmuj.jp/070409workshop/index.html  このワークショップは、カーネギーメロン大学日本校の武田圭史教授の音頭に より話が持ち上がり、去る4月9日に開催されました。リバースエンジニアリング というトピックでこのような催しが行われること自体、非常に画期的な試みで、 このような場を設けて下さった武田教授に本当に感謝いたします。  今回のワークショップですが、事前受付開始と共に応募が殺到して2日足らずで 定員を迎えるという、通常では有り得ない盛り上がりを見せていました。事実、 会場でも130名がすし詰め状態で、かなり蒸し暑かったです(笑)。講演も5コマ というなかなかハードなスケジュールでしたが、最後まで興味深く聞くことがで きました。  筆者の周りでは「行きたかったけどすでに締め切られていた」「行ってきてレ ポートして欲しい」との声も多く聞かれました。事実、ワークショップ中でも「 資料だけでも欲しい、という問い合わせが相次いでいました」との発言があった ことから、相当関心が高まってきているように感じます。そこで、今回ワークシ ョップに参加することができた者の責務として(?)、僭越ながらレポートをし たためる次第です。  なお、表題にもなっている「リバースエンジニアリングまつり」の由来ですが、 武田教授さんのblogにありますように、企画段階の仮名(?)から来ています。 http://motivate.jp/archives/2007/03/post_119.html ■0x02.) 会場の雰囲気  今回は4月9日(月)開催でしたが、平日であるのは仕方ないとしても、学生に とっては参加しづらい日取りだったように思います。筆者は開始30分前に到着し ましたが、すでに半分近くの席が埋まっていました。最終的に会場は満員。出席 者は130人を超えるほどで、非常に暑苦しかったです(笑)。会場には、Wizard Bibleでお馴染みの方など、セキュリティ界隈で見聞きする方を多数お見かけしま した。セキュリティの世界は狭いと感じた次第であります。と書いておきながら、 筆者はセキュリティ業界の人間では無かった(過去形)ので、そのほとんどの方 とは初対面でした(参加していた金床先生が紹介して下さりました)。こういう 場でコネクションが生まれ出すのはなんとも嬉しいことです。  先ほど示しましたワークショップ詳細ページに、ワークショップの写真が数点 ありますので、ほんの少しですが会場の雰囲気を味わえるのではないかと思いま す。激しくどうでもいいですが、筆者の後ろ姿が映っている写真があります(笑)。 ■0x03.) 全体の感想  今回は、リバースエンジニアリングを題材にした初の試みは第一回目というこ とでイントロダクション的な発表が多かったように思います。したがって、深く 踏み込んだ発表はほとんどなかったように思います。また、準備期間が短かった のか、発表内容が著しく被っていたりしていました。でも今回は一回目です。今 後の動きに期待大です。 ■0x04.) リバースエンジニアリングの現状と課題  初めは武田教授による「リバースエンジニアリングの現状と課題」と題した、 リバースエンジニアリングのイントロダクション的な内容でした。リバースエン ジニアリングとは何か、その目的とは、解析手法・解析妨害手法、今後の動向な どの解説が行われましたが、比較的ゆるい内容だったなという印象です。ただ、 筆者はソフトウェアクラッキングから入った、ある意味イレギュラーな人種なの で、「不正な目的ではない」(笑)利用事例については改めて考えさせられると ころがあったのも事実です。  そもそも、リバースエンジニアリングは何を目的として行うものかを次に記し ます。 ・ウイルス・ワーム・マルウェアなどの解析による対抗策の検討 ・バックドア・個人情報の送信など、本来の仕様にはない動作の発見・解析 ・ソフトウェアの脆弱性の発見・解析 ・(OpenOfficeなど)既存ソフトウェアとの互換性確保のための解析 ・競合製品(EPSONが開発したPC-98互換機など)の開発 ・DRMといった著作権保護機構の回避 ・ゲーム改造 ・exploitなどの不正なソフトウェアの開発のための解析  リバースエンジニアリングに関する具体的な研究事例としては、次が挙げられ ます。 ・プログラムの復元(デコンパイル) ・プロトコルの解析 ・P2Pアプリケーションなどの解析(国内はWinny,Share。海外はSkypeなど) ・暗号化コードの解読 ・マルウェア解析の自動化 ・脆弱性解析の自動化 ・プログラムの難読化 ・Fuzzing  Fuzzingとはアタックベクタ(プログラムの入力)に対して、ブルートフォース 的に様々な入力値を生成・投入させ、エラーを故意に引き起こす手法を指します。  また、国内ではほとんど見られないですが、学術的なカンファレンス・アドホ ックな研究会は、海外では適時開催されているそうです。情報セキュリティ・ソ フトウェア工学の一分野として取り上げられることが多いですが、リバースエン ジニアリング主体のカンファレンスとして、カナダ・モントリオールで開催され るREcon(http://recon.cx/)などが知られています。ハッカーカンファレンスに おいては、脆弱性検査を中心とする発表が常時行われていることは、WB読者であ ればご存じだと思います。 ■0x05.) リバースエンジニアリングによる脆弱性監査  2番目は、お馴染みeEye Digital Securityの鵜飼さんの発表でした。鵜飼さん のそれは、毎回技術的に高度なものが多いのですが、前半の発表は「eEye Secur ity Forum / Autumn 2006」のものとほとんど同じでした(汗)。 ・セキュリティ・プロフェッショナルのためのリバースエンジニアリング http://www.scs.co.jp/event/2006/1027_eeye/  しかし後半は、実際の脆弱性解析事例として、アニメーションカーソルの処理 におけるバッファオーバーフローと、Windows LSASSのリモートバッファオーバー フローの2件を題材にして、実際に脆弱性を発見するプロセスを紹介していました。 ・Windows ANI File Parsing Buffer Overflow http://research.eeye.com/html/advisories/published/AD20050111.html ・Windows Local Security Authority Service Remote Buffer Overflow http://research.eeye.com/html/advisories/published/AD20040413C.html  アニメーションカーソルの脆弱性というと、つい最近Microsoftが対策パッチを 緊急リリースしていましたが、それとは別物です(鵜飼さん曰く、偶然タイムリ ーな話題になったとのこと)。 ・Microsoft、aniファイル脆弱性対策パッチを4日にリリース http://slashdot.jp/security/article.pl?sid=07/04/02/098253  しかしながらこの0-dayは、今回紹介する事例に置ける脆弱性と同様のコードが 他所にも存在していたために引き起こされたものとのことです(本当にタイムリ ーですね)。  後半の発表は、バイナリエディタのバイナリ表示、WinDBGのデバッグ画面、ID A Proの逆アセンブルリストのスクリーンショットが連続する、技術寄りでレポー トしにくい発表なので(笑)、本レポートでは割愛させて頂きます。 ■0x06.) マルウェアのリバースエンジニアリング  続いて”世界のホシザワ”こと星澤裕二さんによる発表です。本人曰く、短い 時間しか与えられていないと思っていたようで、プレゼンの内容も割と初歩レベ ルでボリュームも控えめでした。が、星澤さんが本気出して資料作ったらとんで もないことになることは確実なので(苦笑)、まあアリなのではないかなと…。  星澤さんはコンピュータウイルスなどのマルウェアが専門なので、マルウェア の機能や目的の調査、マルウェアを検出するシグネチャの作成、そしてマルウェ ア開発者の意図を探るためにリバースエンジニアリングを行っています。ここで 重要なのは、「マルウェアの解析には時間をかけることができない」ということ です。つまり、解析を行っている間にも感染被害は次々と発生するため、他のリ バースエンジニアリングとは異なり、とにかく「時間との勝負」解析時間の短縮 が重要課題になります。さらに近年のマルウェアは、いわゆるパッカーや難読化 ・アンチデバッグなどといった、自身を解析されにくくするテクニックが用いら れているため、人手による解析だとどうしても時間がかかってしまいます。その ため、近年のマルウェア解析においては、その解析・発表までの作業がかなり自 動化されているようです。もちろん自動化にも限界がありますので、手作業によ る解析も行われますが、検出するためのシグネチャ作成が第一であることを考え ると、非常に合理的といいますか当然の流れであるように思います。  補足になりますが、星澤さんが所属するセキュアブレインでは、2007年3月から ”全自動かつ高速にマルウェアの解析と駆除ツールの生成を行う”「SecureBrai n Zero-Hour Response System」を販売しています。 http://www.securebrain.co.jp/news/070312_zhr.html  マルウェアのリバースエンジニアリングは「詳細な動作など得なければならな い情報が多いため、時間と手間がかかる」とのことで、ノウハウが固まっていな いことからも「経験と慣れが必要」とも。さらに「OSやネットワーク・プログラ ミング言語などの幅広い知識が必要不可欠」だそうです。筆者も気が向いたとき にコンピュータウイルスを解析する(フリをする)ことがありますが、マルウェ アはOSなどの動作に強く関連している性質上、幅広い知識が要求され、しかもコ ード自体が危険なものであるため、安易にそれを実行するわけにもいかず、さら に(一般にウイルスはコードサイズが小さいとはいえ)詳細な動作を知るために はコードを幅広く精査しなければならないため、モノによっては時間と手間がか かってしまいます(単に私のスキルが低いだけかもしれませんが…)。  前述しましたが、ほとんどのマルウェアは「パッカー」と呼ばれる実行可能フ ァイル専用の圧縮・暗号化ツールが用いられているため、リバースエンジニアリ ングを行うには、逆の処理を行うアンパックという作業が必要になります。星澤 さん曰く「近年のボットはその9割以上がパックされており、国産であれば、いわ ゆるワンクリックウェアも9割以上がパックされている。また、パッカーは150種 類以上存在するが、実際に使われているパッカーは10%程度」とのことです。こ こで星澤さんは150種類以上、と仰りましたが、その性質上、同一パッカーのバー ジョン違いであったとしてもパック手法がバージョン毎に毎回異なる(=互換性 がない)ため、それらを別カウントとすると、その種類はさらに膨大なものにな るものではないかと推測できます。  しかしながら、パッカーの暗号化を解除し、元の実行ファイルを復元すること のできる「アンパッカー」も有志の手で多数作られているはずです。それに関し て星澤さんは「アンパッカーも250〜300種類以上があるが、それで得られる実行 ファイルは不完全なものが多い、例えばコマンドボタンが正しく復元されてない ケースもある」と仰っています。  さらに、マルウェア特有のトピックとして、ポリモフィック・メタモフィック 技術があります。両者とも、自分自身を組み替えることでアンチウイルスによる 検出を困難にする技術です。両者の違いについては割愛しますが、自分自身を組 み替えるといっても必ずオリジナルのコードはあるはずです。ただ、星澤さん曰 く「アンチウイルス的(検出)にはある程度対抗技術は確立しているが、解析の 手間に関しては負荷が増大する」とのことで、マルウェア対策に関しては、今後 かなり厳しい戦いを強いられるのでは、と思った次第。 ■0x07.) ソフトウェア製品開発・提供者から見たリバースエンジニアリング  すこし視点が変わって、脆弱性発見のためにリバースエンジニアリングされる 立場にあるマイクロソフトの中の人である、セキュリティレスポンスマネージャ の小野寺さんによる発表でした。小野寺さんは非常にユーモアのある方で、話が 一番面白く会場からの笑いが絶えませんでした。というのも、最初の掴みで次の ようなやり取りがあったので、堅苦しい雰囲気だった会場が一気に解れました。 小野寺さん「会場の中で、Microsoft Office製品をデバッガに読み込ませたこと のある方、挙手願います」 (鵜飼さんをはじめとする少数から手が上がる) 小野寺さん「はい、手を挙げて下さった方はマイクロソフトの使用許諾契約に違 反していますね」(会場笑)  まず前提条件としてマイクロソフト製品は、使用許諾契約書にあるとおり、リ バースエンジニアリングを許可していません。リバースエンジニアリングの定義 として、「Microsoft エンカルタ」(MSの中の方らしいですね)のリバースエン ジニアリングの定義を引用しています。 ----- 【競合する他社の】新製品や過去の製造プロセスなどを分解・分析し、その性能 ・構造などを読みとり、それを新製品などに応用する技術。(【】は筆者) -----  ここで、小野寺さんは【競合する他社の】を強調して説明していました。これ は、リバースエンジニアリングすべてが禁止だという意味ではなく、自社製品に 対するリバースエンジニアリングは(当然だが)認められ、自分(自社)以外が 権利を有するものについてのそれは認められない、という意味で話しを進めてい るからですね。  小野寺さん曰く「ソフトウェアには企業秘密がたくさんあるため、リバースエ ンジニアリングを制限したい。しかし、自社製品に関しては開発・サポートを円 滑に進めるためにリバースエンジニアリングが必要」とのことで、リバースエン ジニアリングには(法律的に)安全なものとそうでないものがあるとのこと。  例えば、マルウェアの解析において、小野寺さんは「著作権などは一般のアプ リケーションと同じ扱いであるが、開発者不詳ということになっているため、リ バースエンジニアリングしたところで開発者が権利を主張することはないので問 題ないだろう」との見解を提示していました(ここでマイクロソフトの公式見解 ではないことを強調)。  脆弱性の解析については「グレーゾーン、製品解析とは異なり、脆弱性解析の ような、本来起こりえないことになっている”不思議な挙動”によるアプリケー ションの影響を解析するのであれば、問題ないのでは」とコメントしてました( ここで再度マイクロソフトの公式見解ではないことを強調)。これに関しては様 々な見解があるように思いますが「脆弱性解析」に関して言えば、グレーゾーン であっても公共の利益に適うので有れば許容されるのでは、との印象を受けまし た。しかし、本件は(少なくとも国内においては)明文化はされておらず、それ が開発者・リバースエンジニアの判断を迷わせる一因ではないかと思っています。  また、リバースエンジニアリングの阻止(アンチデバッグ・アンチクラック) についても「.NET Framework (CLI) 向けのバイナリなどは難読化しないとほぼ完 全なソースを復元できる」とのこと。.NET 向けのバイナリは非常に高い精度で復 元(デコンパイル)が可能ですが、「Reflactor for .NET」あたりが.NETデコン パイラとして有名ですね。また、「.NET主要コンポーネントは難読化が施されて いない」とも。 ・Reflactor for .NET http://www.aisto.com/roeder/dotnet/  余談ですが、Javaに関してもクラスファイルからのデコンパイルが容易です。 これに関しては『クラッキング・バイブル』を参考にして頂きたいと思います。  さらにWindows Vistaのみに搭載されている、「Protected Processes」という 機能についても紹介していました。これは、有り体に言えばWindows公認のRootk itのようなもので、カーネル(OS)レベルでプロセスを保護する機構で、デバッ ガのアタッチなどが不可能になる技術とのことです。使いようによっては危険な 機能となりうるので、Microsoftの認証が必要とのことでした。 ■0x08.) リバースエンジニアリングと情報セキュリティの法的問題  最後は、弁護士の高橋郁夫さんによるリバースエンジニアリングに関わる法律 に関する発表でした。リバースエンジニアリングに関する法律については、国内 と国外でその動向が大きく異なっています。特に国内に関してはリバースエンジ ニアリングに関しては明文化されておらず、事例も非常に少ないのが実情のよう です。  制定法の動向として、米国合衆国では DMCA(Digital Millenium Copyright A ct:デジタルミレニアム著作権法)が存在しており、著作権保護システムの無効 化を禁止する規定が存在しますが、一部例外が追加され、暗号研究・セキュリテ ィテストなどはその例外事項にあたるようです。さらに、アメリカにはUCITA(U niform Computer Information Transaction Act)という、リバースエンジニアリ ング禁止条項を正当化する法律も存在しているそうですが、規定も曖昧で、実際 に採用している州は少ないとのことです。  EUではEU Directive(Europian Communities Council Directive on the Lega l Protection of Computer Programs)という法律が存在し、その6条に逆コンパ イルの規定が存在し、9条2項に「逆コンパイルに関する6条に反するいかなる契約 内容も無効」との記載があるとのこと。つまりデコンパイルを法律で認めている 訳ですね。EUは進んでいますね(?)。  対して日本では、リバースエンジニアリングに関しては、明文化はほとんどさ れておらず、判例も非常に少ないです。そのため「解釈」というレベルでしかな いのですが(日本の法制度の限界ですよね…)、ここで専門家の見解を聴くこと ができることは非常に貴重ではないかと思います。  高橋さんは「逆アセンブル・逆コンパイルという作業が、プログラムの複製と みなされ著作権侵害に該当するのか?」という問いかけを行いました。これに関 しては、学説の根拠は明確ではないものの、リバースエンジニアリングを認める 向きが大多数のようです。まず「逆コンパイルで得られたソースコード」の位置 づけとして、2通りの見解が存在するようです。 1) 本来のソースコードと、逆コンパイルで得られるソースコードは機械的には合 致しない→「翻訳」と同様の扱いであり、別個の表現とみなされるため、法律上 問題ない(という解釈) 2) 機械的にソースコードを作出することから、機械的な複製である→複製権侵害 となる。契約上の制限条項違反の際に刑事的制裁も可能となる(という解釈)  しかし、逆コンパイルが複製権を侵害するとしても、何らかの理由でリバース エンジニアリングが認められるケースが非常に多いようです。つまり、1)の見解 が正になる、ということでしょうか。その認められる理由として、 ・いかなる「複製」に権利が及ぶものと解釈するべきではない ・先人の文化的所産を踏まえて新たなる創作活動を促進することは、法制度の趣 旨に適う ・新たな創作活動の作業過程における複製は許容される という見解が存在しているとのことで、前述しましたが「グレーゾーンであって も公共の利益に適うので有れば許容される」のではという解釈が適用されるよう です。それはそれで望ましいことなのですが、明文化されず解釈で乗り切る運用 は健全ではないと感じた次第です。 ■0x09.) パネルディスカッション  各パネリストによる発表後は、パネルディスカッション形式で参加者を含む討 論が行われました。中でも印象に残ったものをいくつか記していきたいと思いま す。 ※本稿はメモを元に起こしていますが、筆者の(超)解釈も少なからず含まれて います。その点ご容赦下さい。  「セキュリティ全体の利益を考慮すると、のんびりとしていられないケースが ある。作者不詳あるいは継続的なメンテナンスが行われていないWinny,Shareのよ うなソフトウェアの場合だと、リバースエンジニアリングせざるを得ないのでは ないか」という発言があり、それに続く形で、Shareのリバースエンジニアリング 禁止条項についてのツッコミもありました。 参考:Share EX2 の readme.txt に記載されている禁止事項 -------------------- 禁止事項 本ソフトウェアの販売。 インターネット上以外のメディアでの配布。 リバースエンジニアリング。 改造改編版の配布。 意図的なShareネットワークへの攻撃。 禁止事項に違反した場合、著作権者の了承を必要とせずに、任意の個人または団 体が禁止事項についての注意勧告、場合によっては法的措置を行えるものとしま す。 --------------------  続いて、「学校でソフトウェアの開発は教えてくれるが、解析・デバッグにつ いては教えてくれない」「リバースエンジニアリング技術の体系化、トレーニン グの場をどのようにして用意するべきかが課題だ」「攻撃者側は情報の共有がで きているが、防御側は情報の共有ができていないのでは?」「リバースエンジニ アリング技術はオープンではない。アメリカではオープンだが、国内においては 解析技術の蓄積がなされておらず、米国と日本の技術力の差は圧倒的」といった、 (国内における)教育と情報共有の不備に関する発言も目立ちました。特に、星 澤さんはワークショップ全体を通して、解析エンジニアの育成と情報共有の重要 性を何度も強調していたことが印象に残りました。  リバースエンジニアリングに対する誤解が、周知と普及の足枷になっているの ではという指摘も。「かつてtcpdumpを使うこと自体けしからんという風潮があっ たが、今現在リバースエンジニアリングにおいて同じことが起こっているのでは ないだろうか」とも。しかし、一番気になったのは「日本にもリバースエンジニ アリング系の資料はあるものの、クラック系が多い」「7〜8年前頃にソフトウェ アの不正利用が横行していたが、そのイメージを未だに引きずっているのではな いか?」「昔は攻撃などに使われていたことからアンダーグラウンドなイメージ が強い」「リバースエンジニアリングのイメージアップが必要ではないか」とい った意味合いの発言がみられました。これは確かにその通りであり、『クラッカ ー・プログラム大全』『クラッキング・バイブル』なんというストレートなタイ トルの書籍執筆に関わった者としては苦笑するしかありませんでした。しかし、 それを鵜飼さんも一緒になって言っているのもどうかと思いましたが…。 ■0x0A.) ワークショップ終了後  パネルディスカッションでは、参加者も発言できるようになっていたのですが、 ワークショップ終了後に個別に話したほうがいいと思い、突撃を敢行しました。 特に星澤さんとは長くお話しすることができましたが(ありがとうございました)、 そのやり取りの中で「脆弱性を公開したら、それを発見した人は評価されてポジ ションがよくなるけれども、リバースエンジニアリングにはそれがないのが問題 ではないか」といった印象的なコメントをいただくことができました。  リバースエンジニアリング技術に関する情報は、なかなか表に出てこないもの です。アンチデバッグ技術やパッカー・難読化技術などは、一言でいえば”手品” のようなもので、種明かしをすればそれでおしまいです。情報を隠すことが安全 性の向上につながるという構造上、情報はなかなか外に出て行かないものです。 HackにしてもKrackにしても、攻撃手法が編み出されたら、それに対する防御手法 も公開されていたちごっこ、という点では変わりません。しかし、脆弱性情報の 公開は一般に公共の利益に適うことですが、アンチデバッグ技術を公開したとこ ろで解析者側が損をするだけです。リバースエンジニアリングに関する情報はな かなか外に出て行かない、というのが現状のようです…(それでも数年前と比べ るとよくなってはいますが)。  鵜飼さんともお話しすることができましたが、名刺交換の後『クラッキング・ バイブルの中の人です』といった瞬間、鵜飼さんの微妙な笑顔を見ることができ た気がしました。非常にレアな経験だと思います(爆死)。 ■0x0B.) 最後に  リバースエンジニアリングというと日の目を見ない、どちらかといえば前向き ではない技術であるように捉えられる向きがありましたが、ここ最近になって徐 々に盛り上がりを見せています。P2Pソフトウェアやマルウェアのように、リバー スエンジニアリングする価値のあるソフトウェアが出てきていることも大きいよ うに思います。  今回のワークショップは、日本における閉塞的な風潮を打破するいい切っ掛け にもなったと思います。それは130人の席が2日で埋まったことや、資料だけでも いいから欲しい、という問い合わせが相次いでいたことからも明らかだと思いま す。ワークショップの最後で、武田さんが次回も開催したいと仰っていましたの で、武田さんの所に応援メールを送れば、第二回・第三回のワークショップが開 催されるかも知れませんよ。次回開催時はもちろん筆者も参加するつもりです。 x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x --- 第3章: UnhandledExceptionFilter()を使ったアンチデバッギング手法 --- 著者:sourcerian x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x ■0x01.) はじめに  前回「アンチデバッギングの話は終わりです」と書いておきながら性懲りもな くまたアンチデバッギングの話です。おまけでインポート関数呼び出しの隠蔽も 行っているので読んでみてください。前回は特定のデバッガがアタッチされてい ないと動作しない仕組みでしたが、今回はデバッガがアタッチされていると動作 しない仕組みとなります。 ■0x02.) UnhandledExceptionFilter()APIとSetUnhandledExceptionFilter()API  今回のアンチデバッギング手法の根幹となるのがUnhandledExceptionFilter() APIとSetUnhandledExceptionFilter()APIです。UnhandledExceptionFilter()API はアプリケーションエラーダイアログボックスを表示し、アンワインドを行って プロセスを終了させる関数です。基本的には構造化例外処理のフィルタ式の中で 使うAPIですが、明示的に呼び出すまでもなく、Cランタイムやカーネルが未処理 の例外を捕捉してUnhandledExceptionFilter()APIを呼び出します(Cランタイムの 場合は一部例外をシグナルに変換します)。アプリケーションエラーダイアログを 表示させたくなければSetErrorMode()APIを使うだけで十分ですが、デバッグ情報 の収集や独自のダイアログボックスを表示させたい場合はSetUnhandledExceptio nFilter()APIを使います。 ----- // フィルタ関数のポインタ型 typedef LONG (WINAPI *PTOP_LEVEL_EXCEPTION_FILTER)( struct _EXCEPTION_POINTERS *ExceptionInfo ); typedef PTOP_LEVEL_EXCEPTION_FILTER LPTOP_LEVEL_EXCEPTION_FILTER; // SetUnhandledExceptionFilter()の宣言 LPTOP_LEVEL_EXCEPTION_FILTER SetUnhandledExceptionFilter( LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter ); -----  SetUnhandledExceptionFilter()APIでフィルタ関数をセットするとUnhandledE xceptionFilter()関数はセットされたフィルタ関数を呼び出し、その戻り値によ って動作を変えます。 ・EXCEPTION_EXECUTE_HANDLER  プロセスを終了させる。 ・EXCEPTION_CONTINUE_EXECUTION  例外発生場所に戻って処理を続行させる。 ・EXCEPTION_CONTINUE_SEARCH  本来の動作(アプリケーションエラーダイアログの表示)を行う。  さて、ここからが今回の重要なところですが、UnhandledExceptionFilter()AP Iは、アプリケーションデバッガがアタッチされている場合にセットされたフィル タ関数を呼び出さないという仕様というかバグがあります。Windows95〜Windows Vistaまで一貫しているその動作はバグというより仕様としか思えませんが、Kno wledge Base Q173652(http://support.microsoft.com/kb/173652)では、バグと 書かれているのでバグなんでしょう。バグか仕様かはさておき、デバッグ時とそ うでない時に動作が違うものを利用すればデバッギング対策になるのは間違いあ りません。今回はこの動作の違いを利用してアンチデバッギングを実装します。 ■0x03.) SetUnhandledExceptionFilter()APIのサンプルコード  アンチデバッギングの実装に取り掛かる前にSetUnhandledExceptionFilter()A PIの使い方を見てみましょう。以下はアプリケーションエラーダイアログの代わ りにメッセージボックスで素っ気無いメッセージを表示して終了するサンプルで す。 ----- LONG WINAPI MyUnhandledExceptionFilter( PEXCEPTION_POINTERS pExceptPointers ) { MessageBox( NULL , "不正な処理を行ったため強制終了されます。" , "アプリケーションエラー" , MB_ICONEXCLAMATION ); return EXCEPTION_EXECUTE_HANDLER; // プロセスを終了させる } int main() { // フィルタ関数をセットする SetUnhandledExceptionFilter(MyUnhandledExceptionFilter); // アクセスバイオレーション例外が発生! *(int*)0 = 0; // 強制終了されるため実行されない printf("強制終了されるため実行されない\n"); } -----  一見、単純に見えるコードですが、水面下でいろいろと動いています。処理の 流れは次のようになります。 1:「*(int*)0 = 0;」でアクセスバイオレーション例外が発生。 2:Cランタイムがアクセスバイオレーション例外を捕捉してSIGSEGVシグナルに変 換し、シグナルハンドラを呼び出そうとするが、シグナルハンドラにSIG_DFLがセ ットされているためUnhandledExceptionFilter()APIを呼び出す。 3:UnhandledExceptionFilter()APIはSetUnhandledExceptionFilter()APIによっ てセットされたMyUnhandledExceptionFilter()関数を呼び出す。 4:MyUnhandledExceptionFilter()関数はメッセージボックスを表示して、EXCEP TION_EXECUTE_HANDLERを返す。 5:EXCEPTION_EXECUTE_HANDLERを戻されたUnhandledExceptionFilter()APIがプロ セスを強制終了する。  注意すべき点はステップ2ぐらいでしょうか。当たり前ですが、signal()関数で 例外に対応するシグナルのハンドラをセットしてある場合は、そのシグナルハン ドラが呼ばれてUnhandledExceptionFilter()APIは呼び出されません。signal()関 数を使っている場合は自前でUnhandledExceptionFilter()APIを呼び出したり、フ ィルタ関数で捕捉したい例外とシグナルの対応に気をつけるなどしてください。 なお、例外とシグナルの対応はCランタイムのソースのwinxfltr.cに定義されてい ます。次の対応表は参考程度にしてwinxfltr.cを確認してください。 ------------------------------------------- 例外 | シグナル ------------------------------------------- STATUS_ACCESS_VIOLATION | SIGSEGV STATUS_ILLEGAL_INSTRUCTION | SIGILL STATUS_PRIVILEGED_INSTRUCTION | SIGILL STATUS_FLOAT_DENORMAL_OPERAND | SIGFPE STATUS_FLOAT_DIVIDE_BY_ZERO | SIGFPE STATUS_FLOAT_INEXACT_RESULT | SIGFPE STATUS_FLOAT_INVALID_OPERATION | SIGFPE STATUS_FLOAT_OVERFLOW | SIGFPE STATUS_FLOAT_STACK_CHECK | SIGFPE STATUS_FLOAT_UNDERFLOW | SIGFPE ------------------------------------------- ■0x04.) アンチデバッギングの実装  前置きが長くなってしまいましたが、実際にアンチデバッギングの実装に取り 掛かりましょう。話を簡単にするために、デバッガがアタッチされていない場合 にメッセージボックスで"Hello world"を表示する例をとって説明していきます。  次はデバッガがアタッチされているとEIP(実行中のアドレス)がNULLになって続 行不可能な状態に陥るサンプルです。 ----- LONG WINAPI MyUnhandledExceptionFilter( PEXCEPTION_POINTERS pExceptPointers ) { if( pExceptPointers->ContextRecord->Eip == 0 ) { pExceptPointers->ContextRecord->Eip = (DWORD)MessageBoxA; return EXCEPTION_CONTINUE_EXECUTION; } else { return EXCEPTION_CONTINUE_SEARCH; } } static int (WINAPI * s_pMessageBoxA)(HWND, LPCSTR, LPCSTR, int) = NULL; int main() { SetUnhandledExceptionFilter(MyUnhandledExceptionFilter); s_pMessageBoxA(NULL, "world!", "Hello", MB_OK); return 0; } -----  main()関数ではSetUnhandledExceptionFilter()APIでフィルタ関数をセット後、 s_pMessageBoxA(メッセージボックスの関数ポインタ)を経由してAPI呼び出しを しようとしています。当然、s_pMessageBoxAにはNULLがセットされているのでこ の呼び出しは実行アドレスを0番地(NULL)に飛ばしてアクセスバイオレーション 例外を発生させる結果になります。ここからが重要な分岐点で、デバッガがアタ ッチされていなければフィルタ関数がその例外を受け取って実行アドレスをMess ageBoxA()APIのアドレスに飛ばしますが、デバッガがアタッチされている場合は 0番地に飛んだ時点で続行不可能な状態に陥ります(デバッガがEIPをMessageBox Aのアドレスに変更すれば話は別ですが)。  しかし、上記の方法ではもともとのソースに手を加える必要がある上、ソース コードの可読性が落ちてしまいます。そこらへんを何とかしてみたのが次のコー ドです。 ----- #ifndef _DEBUG #pragma comment(linker, "/ENTRY:EntryPoint") #define MAXIMPORTINDEX 2 static FARPROC s_rgImport[MAXIMPORTINDEX + 1]; __declspec(naked) LPCSTR WINAPI _imp__GetCommandLineA() { __asm { _emit 0x01 _emit 0x00 _emit 0x00 _emit 0x00 } } __declspec(naked) int WINAPI _imp__MessageBoxA( HWND hWnd , LPCTSTR lpText , LPCTSTR lpCaption , UINT uType ) { __asm { _emit 0x02 _emit 0x00 _emit 0x00 _emit 0x00 } } LONG WINAPI MyUnhandledExceptionFilter( PEXCEPTION_POINTERS pExceptPointers ) { DWORD Eip; Eip = pExceptPointers->ContextRecord->Eip; if( 1 <= Eip && Eip <= MAXIMPORTINDEX ) { pExceptPointers->ContextRecord->Eip = (DWORD)s_rgImport[Eip]; return EXCEPTION_CONTINUE_EXECUTION; } else { return EXCEPTION_CONTINUE_SEARCH; } } int EntryPoint(void) { extern int mainCRTStartup(void); HMODULE modKernel, modUser; modKernel = LoadLibrary("kernel32.dll"); s_rgImport[1] = GetProcAddress(modKernel, "GetCommandLineA"); modUser = LoadLibrary("user32.dll"); s_rgImport[2] = GetProcAddress(modUser, "MessageBoxA"); // フィルタ関数のセット SetUnhandledExceptionFilter(MyUnhandledExceptionFilter); return mainCRTStartup(); } #endif // #ifndef _DEBUG int main() { MessageBox(NULL, "world!", "Hello", MB_OK); return 0; } -----  かなりトリッキーなことをしていますが、何をしているかわかりますか?  まず、main()関数から見てみましょう。普通にMessageBox()APIを呼び出してい るだけですが、これでもデバッガがアタッチされていると正しく動かないように なっています。当然、その仕組みはmain()より上にあります。main()がすっきり した代わりにSetUnhandledExceptionFilter()APIを呼び出している部分はEntryP oint()関数に移りました。EntryPoint()関数はリストの冒頭にある ----- #pragma comment(linker, "/ENTRY:EntryPoint") ----- という文でCランタイムスタートアップルーチンに代わってプログラムエントリポ イントになります。本来ならリンカによってプログラムエントリポイントとなり プログラムのロード後に呼び出されるCランタイムスタートアップルーチンは、E ntryPoint()関数内の ----- return mainCRTStartup(); ----- という式で手動で呼び出されることになります。mainCRTStartup()はCランタイム の初期化後にmain()関数を呼び出すCランタイムスタートアップルーチンそのもの です。Cランタイムスタートアップルーチンはmain()関数やWinMain()関数によっ てリンクされる関数が異なりますので以下のリストを参考に自分のプログラムを 修正してください。 --------------------------------------------------------------- アプリケーションの開始関数 | Cランタイムスタートアップルーチン --------------------------------------------------------------- main() | mainCRTStartup() wmain() | wmainCRTStartup() WinMain() | WinMainCRTStartup() wWinMain() | wWinMainCRTStartup() ---------------------------------------------------------------  EntryPoint()関数の定義によって、Cランタイムスタートアップルーチンが呼び 出される前にフィルタ関数のセットを行っている、ということになります。Entr yPoint()関数では他にも今回のコアとも言える処理をしています。FARPROCの配列 であるs_rgImportのインデックス1と2にGetCommandLineA()APIとMessageBoxA()A PIのアドレスを格納しています。このインデックス値は重要なので覚えておいて ください。  今度はフィルタ関数であるMyUnhandledExceptionFilter()関数を見てみましょ う。実行アドレスを指すレジスタのEipが1〜MAXIMPORTINDEX(2)の間の場合は、E ipの値をインデックスにs_rgImportからアドレスを取り出して、Eipをそのアドレ スにセットする、ということをしています。つまりアドレス1番地または2番地に 飛んでしまった場合はGetCommandLineA()APIまたはMessageBoxA()APIのアドレス に飛ばす、ということをしています。  そして、アドレス1番地や2番地に飛ばす仕組みを提供しているのが以下のコー ドになります。 ----- __declspec(naked) LPCSTR WINAPI _imp__GetCommandLineA() { __asm { _emit 0x01 _emit 0x00 _emit 0x00 _emit 0x00 } } __declspec(naked) int WINAPI _imp__MessageBoxA( HWND hWnd , LPCTSTR lpText , LPCTSTR lpCaption , UINT uType ) { __asm { _emit 0x02 _emit 0x00 _emit 0x00 _emit 0x00 } } -----  __asmブロックの0x02と3つの0x00はジャンプさせるアドレスで、フィルタ関数 の中ではs_rgImport配列のインデックスになる値です。この定義が何故そうなる のかを理解するにはインポート関数がどのようにリンクされるか知らないといけ ないでしょう。変数名や関数名がコンパイラからリンカに渡される際に__declsp ec修飾子や呼び出し規約によって名前にアンダーバー(_)やアットマーク(@)がつ きます。 ・__declspec(import)修飾子  呼び出し規約より優先されて先頭に_imp__が付きます。 ・__stdcall(WINAPI/CALLBACK)  先頭にアンダースコア(_)が付き、末尾にアットマーク (@) が付き、その後ろ にパラメータ リストのバイト数が続きます。 ・__cdecl(既定値。C++ではextern "C")  先頭にアンダースコア(_)が付きます。 ・__fastcall  先頭と末尾にアットマーク(@)が付き、その後ろにパラメータリストのバイト数 が続きます。  上記を踏まえてMessageBoxA()APIがどのような名前でリンカに渡されるか考え てみましょう。次はWinUser.hに含まれるMessageBoxA()APIの宣言です。 ----- WINUSERAPI int WINAPI MessageBoxA( IN HWND hWnd, IN LPCSTR lpText, IN LPCSTR lpCaption, IN UINT uType); ----- ※WINUSERAPIはプリプロセッサにより__declspec(import)に変換されます。 ※WINAPIはプリプロセッサにより__stdcallに変換されます。  上記の宣言は__declspec(import)で_imp__MessageBoxAとなり、__stdcall呼び 出し規約と16バイトの引数によって__imp__MessageBoxA@16になります。ただし、 これは関数のプロトタイプ宣言ではなく、関数ポインタの宣言であることに注意 してください。インポート関数はIAT(インポートアドレステーブル)に含まれる 関数アドレスを参照して呼び出されるため、コンパイラはMessageBoxA()APIの呼 び出しを__imp__MessageBoxA@16関数ポインタを経由した関数呼び出しに変換し、 「__imp__MessageBoxA@16という関数ポインタがどこかにある筈だから探してきて リンクしてください」とリンカに指示するのです。__imp__MessageBoxA@16はuse r32.libインポートライブラリに含まれていて、リンクされる時にIATのエントリ のひとつとなります。  先ほどの_imp__MessageBoxA()関数の定義も__stdcall呼び出し規約と16バイト の引数によってMessageBoxAの宣言と全く同じ__imp__MessageBoxA@16という名前 でリンカに渡されます(実は引数の数さえあっていれば戻り値の型や引数の型は 何でもよい)。そしてリンカに渡されると、user32.libインポートライブラリに 含まれる__imp__MessageBoxA@16よりも優先してリンクされ、MessageBoxA()APIの アドレスを格納した関数ポインタとして利用されることになります。  つまり、リンカをだましてインポート関数のアドレスを定義している訳です。 その結果、main()内でのMessageBox()API呼び出しは本来ならIATのエントリを経 由して行われるはずが、まったく別の関数ポインタ(その値は0x00000002)を経 由するようになり、MessageBoxA()APIの呼び出しをしたはずなのにアドレス2番地 に飛んでしまう、ということになります。  なお、リンカをだましたことによってMessageBoxA用のIATエントリは作られま せん。そのためロード時に0x00000002がMessageBoxA()APIのアドレスで上書きさ れるようなことはありませんし、副産物として逆アセンブルされた時にMessageB oxA()APIの呼び出しを隠蔽することができます。  また、自分で作成したソースのみならず静的ライブラリが使用しているインポ ート関数にもこのトリックが使えます。GetCommandLineA()はCランタイムスター トアップルーチンが使用するAPIの一つですが、_imp__GetCommandLineAを定義し てリンカをだましています。  今回は、2つのAPIにしかこのトリックを使っていない上に関数ポインタの配列 で本来のアドレスを取得しているため、解除が比較的簡単でしょう。パフォーマ ンスが犠牲になりますが、関数ポインタの配列ではなく連想配列やswitch文で本 来のアドレスに飛ばすようにした上で、もっとたくさんのAPI呼び出しに今回のト リックを使うことで解除を行いにくくすることができます。ただし、API呼び出し のたびに例外が発生するこのコードはパフォーマンスを大きく低下させる点に注 意してください。GetMessage()APIなどループに組み込まれて頻繁に呼び出される ようなAPIにこのトリックを使うのはお薦めしません。  また、やりすぎてIATエントリがひとつもない実行可能ファイルにしてしまうと、 Windows2000/2000Serverで動作しなくなってしまう(ロードに失敗してしまう) ので、注意してください。ちなみにインポート関数呼び出しを隠蔽したいだけの 場合には同じ原理で以下のような手法が使えます。 ----- #ifndef _DEBUG #pragma comment(linker, "/ENTRY:EntryPoint") #pragma comment(linker, "/SECTION:.noimp,RW") #define IMPORT_WINAPI(RET,NAME,PARAM) \ __declspec(naked) RET WINAPI _imp__##NAME##PARAM \ { \ __asm { _emit ((__LINE__ >> 0) & 0xff) } \ __asm { _emit ((__LINE__ >> 8) & 0xff) } \ __asm { _emit ((__LINE__ >> 16) & 0xff) } \ __asm { _emit ((__LINE__ >> 24) & 0xff) } \ } #define BIND_API(HMOD,NAME) \ *(FARPROC*)_imp__##NAME = GetProcAddress((HMOD), #NAME) #pragma code_seg(push, ".noimp") IMPORT_WINAPI( LPCSTR,GetCommandLineA,() ) IMPORT_WINAPI( int,MessageBoxA,( HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType ) ) #pragma code_seg(pop) int EntryPoint() { extern int mainCRTStartup(void); HMODULE modKernel, modUser; modKernel = LoadLibrary("kernel32.dll"); modUser = LoadLibrary("user32.dll"); BIND_API(modKernel, GetCommandLineA); BIND_API(modUser, MessageBoxA); return mainCRTStartup(); } #endif // #ifndef _DEBUG int main() { MessageBox(NULL, "world!", "Hello", MB_OK); return 0; } -----  こちらはAPI呼び出しのたびに例外が発生するわけではないのでパフォーマンス を低下させることなくAPI呼び出しを隠蔽できます。少々特殊なマクロは使ってい ますが、説明はいらないでしょう。 ■0x05.) さいごに  前回と今回に共通していえることは「プロテクションの仕組みがばれても解除 が困難」ということです。プログラムの解析や改ざんを防ぐには「プロテクショ ンの仕組みがばれにくい」ものや「プロテクションの仕組みがばれても解除が困 難」なものを作るのが重要です。プロテクションを実装する場合は「仕組みがば れやすく解除が簡単なもの」にならないように注意してください。 x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x --- 第4章: 基礎暗号学講座 〜 第9回 〜 --- 著者:IPUSIRON x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x ■0x01.) はじめに  共通鍵暗号スキームでは、送信者と受信者が同じ秘密鍵を共有している必要が ありました。鍵を前もって相手に渡しておけばよいわけですが、これには当然限 界があります。インターネットのように遠隔地にいる人に安全に渡すのは困難で すし、鍵を変更するときにも不便です。また鍵を事前に共有できたとしても、暗 号文の通信相手が多くなるにつれて、管理しなければならない鍵の数が膨大にな ってしまいます。  この鍵配送問題を解決するための方法には、鍵センターを利用する方法、公開 鍵暗号スキームを利用する方法があります。  WB32では公開鍵暗号スキームを解説したので、復習ついでに、公開鍵暗号スキ ームを使った鍵配送について解説しておきます。公開鍵暗号スキームでは、暗号 文を作るときに自分の秘密鍵や公開鍵を一切使いません。送信先(受信者)の公 開鍵を用いて、平文を暗号化して、送信します。暗号文を受け取った受信者は自 分の秘密鍵で復号します。これが公開鍵暗号スキームでした。これを鍵配送に利 用するには、共通鍵を平文としてみてそれを暗号化して送ればよいことになりま す。  今回の記事の話題は、DH鍵配送方式という方法です。DH鍵配送方式を使うと、 共通鍵を暗号化して送るといった予備通信をせずに、いつ盗聴されているかわか らないような安全でないネットワーク(例えば、インターネットやLAN内)であっ ても共通鍵を共有することができてしまいます。 ■0x02.) DH鍵配送方式  DH鍵配送方式の「DH」とは、Diffie(ディフィー)とHellman(ヘルマン)の頭 文字です。それではDH鍵配送方式の定義を次に示します。原始元やZp^*のような 表記、合同式などの概念を使います。まだきちんと理解していない人はWB32を参 考にしてください。 [1]ネットワーク公開情報  ネットワーク全体で共通に使用する情報として、ランダムに生成された大きな 素数pとZp^*の原始元gが公開されていると仮定します。 [2]鍵生成アルゴリズム  Aliceは0≦a≦p-2となるaをランダムに選び、次のようにy_Aを計算します。 y_A=g^a (mod p)  次に、y_Aを公開鍵として公開し、aを秘密鍵として秘密に保持します。  また、Bobは0≦b≦p-2となるaをランダムに選び、次のようにy_Bを計算します。 y_B=g^b (mod p)  次に、y_Bを公開鍵として公開し、bを秘密鍵として秘密に保持します。 [3]鍵共有アルゴリズム  Aliceは、自分の秘密鍵aとボブの公開鍵y_Bを入力として、次のようにK_Aを計 算します。 K_A=(y_B)^a (mod p)  これがAliceの鍵となります。  また、Bobは、自分の秘密鍵bとAliceの公開鍵y_Aを入力として、次のようにK_B を計算します。 K_B=(y_A)^b (mod p)  これがBobの鍵となります。  以上のアルゴリズムの動きを画像にすると次のようになります(図1参照)。 (図1)http://s-akademeia.sakura.ne.jp/main/image9/K.jpg ■0x03.) DH鍵共有方式は本当に安全か?  まず確認すべきことは、鍵共有方式とは最終的に同じ鍵を共有できているとい うことなので、AliceとBobの両者が最終的に得た値K_AとK_Bは一致していること を確認しなければなりません。ここでK=g^ab mod pとおくと、K=K_A=K_Bとなりま す。このKがAliceとBobの2者間で共有できた鍵です。  次に確認すべきことは、通信路を盗聴しているアドバーサリーが共有鍵である Kを計算できないということです。Kを計算しようとする素直な方法は、y_A,y_Bか らa,bを特定して、g^ab mod pを計算するという方法です。gは公開情報ですが、 a,bは一様ランダムなので、g^aやg^bも一様に分布することになります。こういう 状況において、アドバーサリーはg^aやg^bからa,bを取り出すのは離散対数問題( 詳細はWB32)からできません。  Kを計算するもうひとつの方法は、DH鍵配送における公開情報であるp,g,y_A( =g^a mod p),y_B(=g^b mod p)から、K=g^ab mod pを求めようとするアプロ ーチです。この問題をDH問題といいます(図2参照)。アドバーサリーがDH問題を 解くことができないことを示せなければ、DH鍵共有は安全でないということにな ります。 (図2)http://s-akademeia.sakura.ne.jp/main/image9/dh.jpg ■0x04.) DH問題 vs 離散対数問題  公開情報から直接g^ab mod pを計算しなくても、a,bを計算してからg^ab mod p を計算できてしまえば、DH問題を解くことができます。つまり、0x03で呼べたこ との前者(離散対数問題)は、後者に含まれてしまっているわけです。よって、 離散対数問題が解けてしまえば、DH問題も解けてしまいます。しかし、その逆、 即ちDH問題が解ければ、離散対数問題も解けるかどうかはまだわかっていません。 DH問題は、離散対数問題よりもやさしい問題である可能性があるわけです。ただ し、暗号に使われているほとんどの群においては、離散対数問題とDH問題は計算 量理論の意味のおいて、等価だと信じられています。それと同時に、pが十分大き いときに、DH問題を解く効率的(多項式時間で解けること)なアルゴリズムは見 つかっていません。将来的にもそのようなアルゴリズムは作れないだろうという 仮定をDH仮定といいます。DH仮定は、離散対数仮定よりも要求することが大きい ので、より強い仮定となります。  以上のことをまとめれば、次のようになります。 ・離散対数問題が解ける⇒DH鍵共有方式は安全でない ・DH問題が解ける⇒DH鍵共有方式は安全でない ・離散対数問題が解ける⇒DH問題が解ける ・DH問題が解ける⇒離散対数問題が解けるとは限らない ・DH問題が解けない⇒DH鍵共有方式は安全 ■0x05.) DH問題とElGamal暗号の関係  ElGamal暗号はWB32で紹介した公開鍵暗号スキームの一種です。このElGamal暗 号の解読が離散対数問題と同程度に困難かどうかはわかっていません。すなわち、 アドバーサリーは離散対数である秘密鍵xを求める以外の方法で解読する可能性は あります。しかしながら、ElGamal暗号の安全性はDH問題の困難さと等価であるこ とがわかっています。これを定理として書くと次のようになります。 [定理] 「ElGamal暗号において、公開鍵pk=(p,g,y)および暗号文c=(c1,c2)から平文mを求 める効率的なアルゴリズムAが存在する」 ⇔「DH問題を解く効率的なアルゴリズムBが存在する」  証明には帰着法を用います。この証明アプローチでは暗号における証明可能安 全性の世界ではよく登場します。今回の証明を通じて帰着方のやり方をマスター してもらえたらと思います。理解するには、図を自分で実際に描いてみるのが効 果的です。アルゴリズムは入力と出力のセットになっているので、それを明確に しておくことがポイントです。 [1](⇒を示す)  ElGamal暗号を解読する任意のアルゴリズムAを利用して、DH問題を解くアルゴ リズムBを作ります。Aを内部で利用して、Bの入力と出力に合うように、内部で計 算できればよいことになります。次の図のようにアルゴリズムBを構成すれば、D H問題が解けたことになります(図3参照)。 (図3)http://s-akademeia.sakura.ne.jp/main/image9/dh_elgamal1.jpg  アルゴリズムは構成されましたが、確認すべきことはいくつかあります。  まず、Aの入力が正しいかどうかという点です(①)。Aから見てc=(c1,c2)=( g^r,R)はElGamalの暗号文となっているとします。ElGamal暗号の復号アルゴリズ ムでは次のような計算を復号します。 m=c2×c1^{p-1-x} mod p  c1=g^r、c2=Rを代入すると、R=mg^{xr}が成り立ちます。つまり、AはR=mg^{xr} を満たすような平文mは出力するということになります。  次に、Bの出力がDH問題を解いた結果であることを確認します(②)。BはR/mを 計算すれば、g^xrとなり、これを出力します。すると、ちょうど入力(p,g,g^x, g^r)に対して、きちんとDH問題を解いた結果であるg^xrを出力できています。 [2](←を示す)  今度は逆を示すので、帰着法も逆に考えます。DH問題を解く任意のアルゴリズ ムBを利用して、ElGamal暗号を解読するAを作ります。Bを内部で利用して、Aの入 力と出力に合うように、内部で計算できればよいことになります。次の図のよう にアルゴリズムAを構成すれば、ElGamal暗号が解けたことになります(図4参照)。 (図4)http://s-akademeia.sakura.ne.jp/main/image9/dh_elgamal2.jpg  アルゴリズムは構成されましたが、確認すべきことはいくつかあります。  まず、Aの入力が正しいかどうかという点です(①)。これはAの入力をそのま まBの入力にしてしまえばよいことになります。  次に、Aの出力がElGamal暗号を解いた結果であることを確認します(②)。Bは g^xrを出力するので、Aは{my^r}/g^(xr)を計算します。すると、次のように展開 できます。 {my^r}/g^(xr)=m(g^x)^r/g^(xr)={mg^(xr)}/g^(xr)=m  すると結局mが計算できるので、Bはこれを出力すれば、うまくElGamal暗号を解 いたことになります。 ■0x06.) おわりに  今回はあまり数学的な記述がなかったので、読みやすかったのではないでしょ うか。証明可能安全性の世界では、「ある仮定が真ならば、この暗号は安全であ る」というような議論をします。その議論の証明において、帰着法や背理法など が利用されます。背理法は数学をやったことがある人なら既知だと思います。一 方、帰着法は私自身暗号を学んで初めて触れたものなので、今回初めて聞いた人 も多いことでしょう。ポイントを理解すれば(証明をなぞることは)難しいもの ではないので、しっかり理解しておきましょう。  今回で10回となりましたが、全体として大体20回を考えていますので、ちょう ど半分を終えたことになります。次回は待ちに待ったRSA暗号の解説なのでお楽し みに。  それではまた来月に会いましょう。 x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x --- 第5章:お知らせ --- x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x ○Wizard Bible(http://wizardbible.org/)では随時、執筆ライターを募集して います。  扱う内容のテーマは広義での「under ground」です。例えばハッキングからサ リンガスの合成法などと幅広い内容を考えています。また特殊な職業や趣味を持 った方のレクチャーなども含まれます。  一回きりでも構いません。また必ず毎回連載する義務もありませんので、でき る範囲で構いません。気軽に声をかけてください。 ○Kenji AikoさんがQ&Aを作ってくれました。初めて参加する人でもわかりやすく 書かれていますので、参考にしてください。 http://wizardbible.org/wbQandA.html ○Wizard Bibleに参加希望の方は気軽にメール(ipusiron@gmail.com)ください。 x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x ---- 第6章:著者プロフィール --- x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x ■金床 ●Job: プログラマー ●Web: http://guardian.jumperz.net/, http://www.jumperz.net/ ●Mail: anvil@jumperz.net ●Comment:  いろんな人と(オフで)話をして驚くのが、みんな意外なほどにWizardBibleを 読んでいるということ。先月号なんて月光仮面ことtessyさんのおかげでフツーに セキュmemoからリンクされてたし、かなりの勢いで読者増加中なんではないでし ょうか。  …ということで「ROMはダメ」「情報を出さずに自分だけ欲しいというのは成り 立たない(クマーなひとの名言?)」という基本にのっとり、今これを読んでい るあなた、ぜひ次号から投稿をお願いします。といっても場所がWBである必要は なく、ブログなどで情報発信して頂けるだけでもうれしいのですが。日本には優 れた技術者がたくさんいるのに、情報発信する人がまだ一部なのは非常にいただ けません。とりあえず適当にハンドル名でもぶちあげて、気軽に投稿をお願いし ます。  某WebAppSec本ですが、どうやら数時間後に入稿第一弾を刷った見本が我が家に 到着するようで、非常にワクワクしているところです(昨日まどさんから電話が ありました)。現在手元の原稿の字数は34万文字弱で、そろそろ終わりが見えて きた感じです。山場だったSQLインジェクションの章が書き上がったので、後は残 しておいた小ネタ(HTTP Request Smugglingとか)を書いていきます。Apache2な んかも触ってみたりして、「おっ、2になってどんな新機能が?」とかググったら、 出てきた「Apache2の新機能」みたいな記事が2001年のだし(;´Д`)世間から取り 残され杉。バージョンアップが面倒なのでついつい古いのを使い続けてしまうの ですが…。ちなみにApache2はパフォーマンスはむちゃくちゃ速くなってますね。  あ、あと某MHN先生の本も進んでいるという噂をききました。非常に楽しみです ね。 ●携帯電話:  今回のお題のケータイですが、限りなく通話にしか使いません。メールを打っ ていると思うように打てずイライラしてしまうのでダメです。機種は古い京ポン ですが、そろそろいーぐる先生が使っていたキーがいっぱいあるやつにしようか とか思ってます。あと、iPhoneは興味あるので日本でも使えるようになってほす ぃ。  映像とかワンセグとかはまったく興味ないのですが、音楽大好き人間なので、 MP3プレーヤーと統合してしまいたいところ(現在は東芝のギガビートを使用中)。 電池の持ちや使い勝手などいろいろ調べてみたいところです。でも調べるのめん どくさいからついつい古いのを使い続けてしまうのですが…。 ■eagle0wl ●Job: Programmer / Reverse Engineer ●Web: http://www.mysys.org/eagle0wl/ (休止中・6月以降再開予定) ●Mail: masm0wl@hotmail.com ●Team(Group): backsection ●Comment:  皆様お久しぶりです。eagle0wlです。ご存じでない方は『クラッキング・バイ ブル』の中の人という認識で構いません。体調不良とモチベーションの喪失など で約半年前にウェブサイトを閉じましたが、その間に様々な出来事があり現在に 至ります。  休眠…というよりもモチベーションを失っている間にも、リバースエンジニア リングに対する流れが最近になって目まぐるしく変わってきており非常に驚いて います。それと共に、自分もうかうかしていられないと思うようになり、今回レ ポートをしたためた次第です(苦笑)。ウェブ上での活動もぼちぼち再開したい と思います。 ●携帯電話:  W-ZERO3[es]をメインに使っています。とはいえ全然使いこなせておらず、ウェ ブブラウズとぽけギコぐらいしか使っていません。USB接続でモデムとして使える のは結構ステキですね。満員電車の中でスタイラスペンを2回無くしているので、 念力でタッチできる機能が欲しいです(笑)。 ■sourcerian ●Job: オサーン ●mail:sourcerian@gmail.com ●Comment:  日本ファルコムの名作sorcerianを文字って命名しました。so[u]rcerianなので お間違い無きよう。ええ、おっさんですとも。 ●携帯電話:  GPSから移動速度を割り出して勝手にドライブモードになる機能が欲しい。フリ ーハンドフォンを買えって話ですかね? ■IPUSIRON ●Job:Student ●Web:http://akademeia.info/ ●Mail:ipusiron@gmail.com ●Team(Group):N/A ●Comment:  今さらながらDS買いました。でも、まだ家以外でプレイしたことがありません (汗)。 ●携帯電話:  j-phoneからvodafoneに切り替わった時期の携帯電話「J-SH53」という機種を使 っています。携帯電話に内蔵されているデジカメに不満が出てきたのと電源の調 子が悪いなどの理由から、新しい携帯を切り換えたいと願っていますが、LOVE定 額を継続できないため、仕方なく使い続けています。部屋では電波が入りにくい ため、専用の外部アンテナ利用していたりと大変です。vodafone機種の中で初め て(?)SDカードの抜き差し可能なタイプでしたが、付属していた8MBのSDカード のままです。1GBのmicroSDカードが1kちょいの時代に(笑)。  今後はもっと高機能な携帯電話が登場すると思いますが、個人的には手回しハ ンドル付き携帯電話が欲しいです。