[-]=======================================================================[-] Wizard Bible vol.31 (2007,2,5) [-]=======================================================================[-] x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x ---- 第0章:目次 --- x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x ○第1章:FLASHプレーヤーの改造 金床 著 ○第2章:はじめてのハッキング 〜プログラミングの基礎〜 Defolos 著 ○第3章:ハニーポットを作ろう(連載第11回) Narusase 著 ○第4章:OpenGLを利用した3次元プログラミング入門(前編) Kenji Aiko 著 ○第5章:OpenGLを利用した3次元プログラミング入門(後編) Kenji Aiko 著 ○第6章:基礎暗号学講座 〜 第7回 〜 IPUSIRON 著 ○第7章:お知らせ ○第8章:著者プロフィール x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x --- 第1章: FLASHプレーヤーの改造 --- 著者:金床 x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x ■0x01.) はじめに  攻撃者がDNSサーバーの設定変更をウェブページ上で動作するJavaScriptやJav aアプレット、FLASHファイルなどと連携して行うことによりセキュリティ制限を 突破する攻撃手法がAnti-DNS Pinningである(この呼び名が定着するかどうかは わからないが、今の時点ではこのように呼んでおこう)。この攻撃によって、特 にFLASHの場合には大きな被害が発生するおそれがある。インチキ英語で記事とデ モを公開しているので、こちらの攻撃については次のURLを参照のこと。 http://www.jumperz.net/index.php?i=2&a=3&b=3  FLASHには以前からXMLSocketというネットワークアクセス機能が備わっていた のだが、最新版(9以降)のFLASHプレーヤーではさらに強力なSocketクラスが登 場した。このクラスを使用することでウェブページに埋め込まれたFLASHファイル は完全なTCPクライアントとして機能することが可能となった。  「FLASHにSocketの機能なんか必要ないだろう。いったいどこの誰が使うんだ? 」と思っていたら、なんとVNCのFLASH実装なども登場している。そのうちFLASHで 実装されたメーラーや、しまいにはFLASH上で動作するウェブブラウザなんかも登 場するかもしれない。何にせよ、シェアを伸ばし「インストールされていて当た り前」となったFLASHが、この時点でこのようにネットワークアクセス機能を強化 することは恐怖である。  Anti-DNS PinningとFLASHを組み合わせた攻撃は恐ろしいものだ。ここで、対策 としてFLASHプレーヤーをアンインストールしてしまえば話は簡単である。しかし 例えばYouTubeのような便利なサービスが使えなくなってしまうことを考えると、 アンインストールは現実的でない。特にネットワーク管理者がユーザに対し「危 険なのでFLASHプレーヤーは禁止します」と強制することは大きな反発を呼ぶだろ う。  ではどうするべきか。従来のFLASHが持つアニメーションやストリーミングの機 能は活かしつつ、SocketクラスやXMLSocketクラスが行う独自のTCPレベルのアク セスのみを禁止できないだろうか。FLASHプレーヤーにそのような設定項目が用意 されていればベストであるのだが、どうやらAdobe様は用意してくれていないよう である。そこで、強引にバイナリファイルの書き換えによってこれを解決するこ とにする。 ■0x02.) FLASHプレーヤーの正体  Windowsの場合、FLASHの本体はNPSWF32.dllやFlash9b.ocxのようなファイルと なっている。Firefoxの場合はpluginsというディレクトリ内に、IEの場合には「 C:\WINNT\system32\Macromed\Flash」などのディレクトリ内に存在する。ウェブ ブラウザを一度終了し、これらのファイルをバイナリエディタで編集する。そし てウェブブラウザを再起動する。  IEが使用するocxファイルは読みとり属性がついており単純に編集が行えないケ ースがある。この場合は次のような手順で作業を行う。 1:ocxファイルの名前を(何にでもよいので)変更する 2:ocxファイルを同じディレクトリ内でコピーする 3:コピー先のファイルの読みとり属性を外す 4:ファイルを編集する 5:コピー先のファイルの名前をオリジナルのocxファイルのもの(Flash9b.ocxなど)に変更する  改造は次のように行えばよい。なお、以下で示す改造はあくまで一例であり、 別の方法でも同じ効果をあげることは可能であるだろう。  ここではWindowsのAPIのひとつであるconnect()の呼び出しに注目することにす る。このAPIはソケットプログラミングにおいてTCPの接続を行う際に利用される ものだ(ActionScriptにもconnect()が存在するが、これとは別のものであること に注意すること)。FLASHも例外ではなく、Socketクラスなどを利用してTCP接続 を行う際には内部でこのAPIを呼び出している。 ■0x03.) OllyDbgで解析  connect()を呼び出している位置をOllyDbgを用いて特定する。OllyDbgでNPSWF 32.dllを開くと、loaddll.exeを使ってデバッグ可能な状態にすることができる。 CPUウィンドウでCtrl+Nを押し、そこからconnect()を探すことにする。しかしこ こではなぜかWSOCK32.dll内のAPIは「WSOCK32.#10」のように表示されてしまい、 直接「connect」というキーワードで探すことはできない(理由はよくわからない。 誰か教えてください)。そのため、connectはWSOCK32あたりのDLLに存在する、と いう予備知識が必要だ。  適当に「WSOCK32.#10」などを選択してEnterキーを押すと、リファレンスが表 示される。ここで#10はrecvfromであることがわかる。ここで表示されたrecvfro mの行を選択しさらにEnterキーを押すと、NPSWF32.dllのアドレス3018BAE2付近に CPUウィンドウの表示が移動する。ここにWinsock系APIのリストがずらりと書かれ ており、その中からconnectを見つけることができる。  CPUウィンドウ上でコメント欄にWS2_32.connectと書かれた行を選択し、右クリ ックから「Find reference to」->「Selected command」を選択すると、connect を呼び出している箇所が特定できる。筆者の環境では300B49A5と300B4A78の2箇所 だ。 ■0x04.) connect()の呼び出しを潰す  connect()の呼び出しは次のようになっている。 ----- 300B49A5 |. E8 50710D00 CALL -----  呼び出しは「E8 50 71 0D 00」の5バイトで行われているので、これをすべてN OPで潰してしまえばよい。…と思ったら、これでは実行される際に不正終了して しまう。これはおそらくAPIを呼び出す前にスタックに引数が積まれているので、 こちらを正しく処理する必要があるのだろう。  connectの引数は3つあり、確かにcallの直前付近でいろいろpushしているのが わかる。それらのpush命令を潰す方法も考えられるが、ここではその方法ではな く、popを3回繰り返し、スタックに入っている余分なデータを取り除くことにす る。pop eaxは0x58となるので、3バイトあれば3つの引数をすべて取り除くことが できる。ここでは潰す命令が5バイトあるので、2バイトの余裕を持って書き換え を行うことができる。つまり書き換え後は 58 58 58 90 90 となる。これによっ てconnect()の呼び出しは行われないことになる。  この命令に続いてtext eax, eaxが行われることからもわかるとおり、connect ()を呼び出した後、FLASHはその接続が成功したかどうかを戻り値から判断する。 connect()は接続に成功した場合は0を返す。命令を書き換えた結果、ここでEAXに はpopした値が入っているのだが、都合がよいことに、これは(connectの呼び出 しでは第1引数が0でないので)0ではない。そのため、FLASHはconnect()が失敗し た、つまりTCPの接続ができなかったと判断して処理を続行する。つまり単にサー バーが落ちていたりする場合と同様の処理が進むことになり、FLASHファイルの実 行パターンとして不自然でない状態を保つことができるのだ。TCPの機能のみを禁 止する方法としては非常にスマートだといえるだろう。  DLLの場合は2箇所、OCXの場合も同様に2箇所をこのような方法で潰せばよい。 以下に筆者の環境での該当箇所を示す。 ----- DLL 300B49A5 E8 50710D00 CALL 300B4A78 E8 7D700D00 CALL ----- ----- OCX 300C6979 FF15 BC361A30 CALL DWORD PTR DS:[<&WSOCK32.#4>] 300C6BA2 FF15 BC361A30 CALL DWORD PTR DS:[<&WSOCK32.#4>] -----  OCXの場合は潰す対象は6バイトになるので、「58 58 58 90 90 90」と書き換え ればよい。 ■0x05.) HTTPアクセスには影響しない  connect()を潰してしまうとYouTubeも見ることができなくなりそうなものだが、 実際には問題なく動画が再生される。これはYouTubeでは動画の取得にHTTPでのア クセスが使われており、かつFLASHプレーヤーはHTTPのアクセスについてはconne ct()よりも少しレベルの高いAPI(おそらくWinInetなどと呼ばれるもの)を利用 しているからではないかと考えられる。あるいはウェブブラウザの機能を使って いる可能性もある。この点については詳しくは調べていない。いずれにせよFLAS HプレーヤーのHTTPレベルのネットワークアクセス機能を邪魔することはない。 ■0x06.) まとめ  このように、バイナリファイルを直接改造することで、FLASHプレーヤーのTCP レベルのネットワークアクセス機能のみを禁止することができた。この方法を使 えばAnti-DNS Pinning攻撃を恐れることなく、YouTubeなどを楽しむことができる。 FirefoxなどにはFLASHの動作を制限するプラグインなどもありそうだが、このテ クニックはIEやFirefox、Operaなどの主要なウェブブラウザで共通して使うこと ができる点ですぐれているといえるだろう。 x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x --- 第2章: はじめてのハッキング 〜プログラミングの基礎〜 --- 著者:Defolos x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x ■0x01.) はじめに  前回に引き続き、初学者のためのハッキング技術の解説を行います。今回は基 礎知識の確認としまして、ハッカーの必須知識であるプログラミングの基礎につ いて解説します。個々のプログラミング言語の文法はWizard Bibleの読者の方々 は私よりもよほど精通していらっしゃると予想されますので、文法よりも一般的 かつ重要な概念を確認することに主軸を置きました。  これからの予定は、次回にも引き続き基礎知識の確認としてハードウェアの基 礎知識を確認し、その次の回でバッファオーバフローの仕組みと実践を解説する 予定です。 ■0x02.) プログラミング  プログラミングとはコンピュータに与える命令を記述することです。ハッキン グの技術にはなくてはならない知識であり、コンピュータを知るうえでも重要な 分野です。プログラミングというと難しそうなイメージがあるかもしれませんが、 概念自体は普段の人間生活で自然に活用しているものです。例えばカップラーメ ンを作る場合を考えてください。おそらくほとんどの人は次の手順に従ってカッ プラーメンを作ると思います。 1:カップラーメンのふたを取りはずす 2:お湯を用意する 3:お湯をカップラーメンに注ぐ 4:3分立ったかどうかを判断する 5:もし3分たってなかったならしばらく待つ  このような手順はれっきとしたプログラムの考え方です。プログラムの基礎と 題して解説している、後述の技術を、例としてカップラーメン作成など、身近な 物事と対比して考えてもらえれば、いかにプログラミングが身近なものであるか がご理解いただけると思います。 ■0x03.) アルゴリズムとデータ  プログラムは大きく分けて、2つの部分からなっています。ひとつはデータをど のような手順で加工し、問題を解くかを記述した部分です。これはアルゴリズム (algorithm)と呼ばれます。もうひとつは加工対象となるデータを記述した部分 です。これらの概念も生活のなかでは非常に一般的なものです。例えば私たちは 「りんごを食べる」という行為を行います。この例の場合、「食べる」という行 為がアルゴリズムであり「りんごを」という部分がアルゴリズムの対象となるデ ータです。先述のカップラーメンの例で考えるなら、「カップラーメン」や「お 湯」がデータであり、「注ぎ、観測し、待つ」という一連のカップラーメン作成 行為がアルゴリズムであると言えます。  アルゴリズムの語源ははっきりとしてはいませんが、9世紀のバグダットで活躍 した数学者アル・フワーリズミー(al-Khwarizmi)が語源だと考えられています。 やはり数学者の名前が語源になっているだけあり、多くは数学的な問題解決手順 がアルゴリズムと呼ばれます。 ■0x04.) コンピュータとプログラムの関係  私たちは日本語や英語など、様々な言語を理解できます。コンピュータも言語 を理解することはできますが、コンピュータが理解できる言語は私たちが普段使 っている言語とは大きく異なります。  現在のコンピュータは皆さんがご存知のように2進数、つまり0か1しか理解でき ません。電気的に強い電流が流れたら0、弱い電流が流れた場合は1といったよう に、2つの状態しか理解できません。当然ですが、人間が理解できる言語で命令を 与えてもコンピュータは理解できません。コンピュータが理解できるのは2つの値 だけですので、コンピュータに命令を与える時はこの0と1の組み合わせで命令を 記述します。これは機械語と呼ばれます。次に機械語の例を挙げます。 ----- 1011000000000001 1011100001001100 -----  上記のような0と1の羅列が延々続きます。これをみて理解しやすいと思う方は 稀でしょう。機械語はコンピュータが理解できる唯一の言語ではありますが、私 たちは機械語以外にも多くの言語を理解できます。その中にはもっと理解しやす い言語がたくさんありますので、機械語は非常にわかりにくいように感じます。  昔はこの0と1だけで構成された機械語を直接人間が記述し、コンピュータに命 令を与えていましたが、これは大変非効率です。コンピュータが登場した初期の ころはトルグ式スイッチ(http://www.otax.co.jp/item/if/m.html)で0と1を打 ち込んでいましたが、2進数は桁上がりが頻発するため桁数が長くなり、結果的に 大変な労力をようすることになります。そこで桁数を少なくするため2進数を16進 数で表す方法がとられました。16進数で上記の例を表すと次のようになります。 ----- B0 01 B8 4C -----  2進数のときよりもスマートに記述できます。しかし、16進数で表現しても見た 目が簡単になるだけで2進数と同じです。結局はCPUのために符号化された記号を 人間が読み取るというところに無理があるのです。次に登場したのが、2進数の機 械語に1対1で対応したアルファベットでプログラムを記述し、それをプログラミ ング後に機械語に変換する方法です。このアルファベットで記述する言語をアセ ンブリ言語といいます。アセンブリ言語で上記の機械語を記述すると次のように なります。 ----- MOV AL, 0x01 MOV CL, 0x4C -----  MOVはMobileの略で「移動」という意味を持ちます。ALはレジスタと呼ばれる一 時的な記憶領域です。0x01は16進数で表された数字です。MOVの意味が移動なので、 機械語を知らなくても「ALに0x01を移動させる」という意味が読み取れると思い ます。  アセンブリ言語は機械語に比べれば人が理解しやすい言語といえます。機械語 と1対1で対応しているため機械語への変換は容易に実現できますが、簡単な処理 でもCPUが用意している複数の命令を組み合わせて実現しなければなりません。 「ALの値を3倍しBLに代入する」という処理はアセンブリ言語では次のようになり ます。 ----- ADD AL, AL ADD AL, AL MOV BL, AL -----  簡単な処理であるにもかかわらず3命令も使用します。私たちの感覚では「BL = AL * 3」のように記述したいと思うでしょう。そこで現在では「BL = AL * 3」 のように、人間がより簡単に理解できる言語でプログラムを記述し、それを機械 語に変換するソフトウェアに入力して機械語を出力します。このソフトウェアの ことをコンパイラといいます。 +------------------------+ +--------------------+ | 人間が理解できる言語で |----------[変換]--------→| 機械語に変換される | | プログラムを記述 | | | +------------------------+ +--------------------+  英語ができない日本人がアメリカで本を出版したいと思ったとき、英語を学ん でから英語で本を書くのは非効率です。普通は本の内容を日本語で記述し、それ を翻訳者に頼んで英語に翻訳してもらい、それを出版します。下図を参照しても らいますと、コンピュータのプログラムを記述する場合となんら変わりないこと がわかると思います。 +------------------------+ +--------------------+ | 日本語で本の内容を記述 |----------[翻訳]--------→| 英語に翻訳される | | | | | +------------------------+ +--------------------+  翻訳者は両方の言語に堪能でなければなりませんが、やはり母国語の方がうま く扱えますし、後から覚えた言葉は母国語より不得意な場合が多いです。コンパ イラも同じで、両方の言葉を完璧に使えるわけではありません。コンパイラもソ フトウェアですので、機械語を母国語とします。そしてコンパイラが理解できる 言語も比較的母国語に近い、コンピュータ専用の言語だけです。  機械の理解できる機械語に近い言語は低級言語と呼ばれ、人が理解しやすい言 語は高級言語と呼ばれます。低級・高級とは性能の良い悪いではなく、より詳し いところまでプログラマが制御できるかどうかです。低級言語の代表例はアセン ブリ言語であり、高級言語として有名なものにC言語やBASICなどがあります。 ■0x05.) コンパイルの手順  コンパイル(Compile)とはコンパイラによって行われる、先述の例で挙げたよ うに翻訳のような行為です。人間基準に書かれた命令を機械基準で書かれた命令 へ変換することです。人間基準に書かれた命令のことをソースコードと呼びます。  C言語のコンパイルは次のような手順を経て完了します。コンパイルとは下図に あるようにソースコードを変換し、オブジェクトコードを生成する行為までを指 します。オブジェクトコードはソースコードを機械語に変換しただけのもので、 これだけではまだ実行はできません。実行可能な形式にするにはコンパイルの他 にリンクと言う作業が必要になります。リンク作業はリンカという独立したプロ グラムによって行われますが、多くのコンパイラはリンカも含められて配布され ているため、コンパイルと同時にリンクも行います。ですので実行が可能なロー ドモジュールの生成が可能です。 +------------+ |ソースコード| +-----+------+ | | ←プリプロセス---[文字列の調整] | +--------------------+ |調整済みソースコード| +-----+--------------+ +---[字句解析] | | ↓ | ←コンパイル----------+---[構文解析] | | ↓ +-----+------------+ +---[意味解析] |オブジェクトコード| | ↓ +-----+------------+ +---[最適化] | | ←リンク------[他のオブジェクトコード等の結合] | +-----+----------+ |ロードモジュール| +----------------+ ●字句解析  ソースコードを字句ごとに区切り、使われている字句を明らかにします。例え ば、「a+b-cd」という部分は「a」,「+」,「b」,「-」,「cd」という5つの字句に 分解されます。コンパイラの用語では、この基本単位をトークン(token)と呼び ます。C言語のソースコードで具体的な例をみてみましょう。次のようなソースコ ードを字句解析します。 ----- while(count <= x){ count++; } -----  これはC言語のソースコードの一部です。ソースコードの意味はわからなくても 結構です。字句解析の結果、次のように11個のトークンに分けられます。 ・while ・( ・count ・<= ・x ・) ・{ ・count ・++ ・; ・}  ソースコードにおかしな字句が含まれているなどのエラーはここで検出されま す。 ●構文解析  文法をチェックします。字句解析で切り出したトークンを、構文規則に基づい て導出木に構成する過程が構文解析です。文法エラーはここで検出されます。 ●意味解析  構文のチェックでは誤りかどうか判断できない部分をチェックします。例えば 「c = a + b;」という命令は構文はエラーになりませんが、aがchar型でbがfloa t型であった場合、演算対象の型がそれぞれ違いますからエラーになります。意味 としてみた場合に間違えているかどうかで判断します。 ●最適化  不要な命令の省略やより高速な命令への置き換えなどを行います。簡単な例で は「5+5+5+5」という4命令を「5*4」という1命令に置き換えるような処理のこと です。近年のコンパイラは非常に高性能な最適化ルーチンを搭載しており、並み の人間が最適化を行うよりも高度な最適化を行える場合もあるようです。 ■0x06.) C言語  C言語は1972年にAT&Tベル研究所のカーニハン(B.W.Kernighan)とリッチー( D.M.Richie)によって開発されたプログラミング言語です。非常に汎用的な言語 で、組み込みシステムからOSの記述まで様々なところで利用されています。機械 語に比べて人が理解しやすい形式で記述できるため、開発効率は高いですがコン ピュータはC言語を直接理解することはできません。先述のようにコンパイラを通 して機械語に変換します。  現在では、C言語はプログラミング言語で最も有名な言語であり、ハッカーが熟 知しておくべき言語のひとつとなっています。Wizard Bibleの読者の方は私より よほどC言語に熟達していると思われますので、ここではC言語の特徴や知ってお くべき最低限の解説を行い、細かなC言語の仕様については割愛します。 ●C言語の特徴  C言語は記述方法が簡単で、表現に制約が少ないという点が最も特徴的といえる でしょう。システム記述用という背景から移植性にも優れ、構造化プログラミン グがしやすい点も大きな特徴です。その他にも演算子・データ構造・制御構造を 豊富に備えており、高級言語でありながら低水準言語に近いビット操作も行えま す。  C言語は多くの技術者が自分たちが書きやすいように仕様を変えてきたため、方 言のような派生した書き方が無数に存在しました。これは表現の多様化という見 解からは利点となりますが、はじめてC言語にふれる人にとっては混乱を招く原因 になりかねません。現在では1989年に機能が改良・拡張された標準規格がANSIに よって制定され、ANSI-Cとして広まっています。ここでもC言語の規格はANSI-Cに 沿った文法で解説します。  一般的にC言語にはエラーを自動で処理する機能はありません。エラーが発生し た場合の処理はプログラマーが自分で考え、自分で実装しなければなりません。 ●サンプルコード  実際にC言語で簡単なプログラムを書いてみましょう。次に解説するプログラム は初めて作成するC言語プログラムの定番です。テキストエディタで以下のコード を打ち込んでください。改行やスペースの挿入は適当にしてもらって結構ですが、 改行は単語の途中等ではしないようにしてください。先の説明で出てきた言葉を 使うと、トークンの途中で改行を入れることはできません。また、ソースコード 中には全角文字を含めることはできません。全角文字を使うときは「"」で囲むか、 コメントアウトしなければなりません。  入力できたらhello.cという名前で保存してください。 ----- hello.c /**********************************/ /* 2006-12-13 Defolos hello.c */ /**********************************/ #include int main (){ printf("Hello hackers!\n"); return 0; } -----  このレポートではLinux上での作業を想定しています。Linuxには標準でC言語の コンパイラであるgccがインストールされていますので、コンパイルするには次の ようにコマンドを入力します。 ----- defolos@glazheim:~$ gcc -o hello.exe hello.c -----  gccのoオプションはコンパイルによって生成される実行形式のファイルの名前 を変更するオプションです。oオプションを省略するとコンパイル後の実行形式フ ァイル名は指定できず、自動的にa.outあるいはa.exeという名前になります。こ こではhello.exeという名前に変更しています。最後に指定されているhello.cは 元となるソースコードを指定します。  コンパイルとはソースコードを翻訳し、オブジェクトコードを生成する行為の ことをいいますが、gccは自動的にリンクまで行いますので実行可能なファイルが 生成されます。コンパイルによって生成された実行可能ファイルを実行すると次 のようになります。 ----- defolos@glazheim:~$ ./hello.exe Hello hackers! -----  実行すると画面に「Hello hackers!」と表示されました。上記のサンプルプロ グラムは「Hello hackers!」と表示するプログラムでしたので、予期した動作で す。プログラム名の先頭に「./」という記号がついていますが、これはカレント ディレクトリを意味する記号です。Linuxはセキュリティを考慮した結果、システ ムに登録されていないプログラムは全てディレクトリを指定して実行する必要が あります。 ●プリプロセッサについて  「/* Comment */:は、「/*」と「*/」で囲まれた部分をコメントとします。つ まり、注釈として人が読むための部分で、コンピュータには見えない部分です。 同じように// Comment のように「//」より右から改行までをコメントとしますが、 こちらはC++で定義されているコメントですからC言語環境ではエラーになること もあります。コメントは入れ子にすることはできません。例えば次のようなコメ ントの書き方はエラーになります。 ----- /* コメント1 /* コメント2 */ */ -----  コメント2が入れ子になっています。コンパイラによっては入れ子のコメントを 解釈するコンパイラも存在しますが、コメントの入れ子は控えるように気をつけ てください。プログラミングを行っていると、デバッグのときなど上記のように コメントを含むソースコードの一部を全部無視したい場合がでてきます。このよ うな場合はコメントを入れ子にするかわりに次のようにすることでコンパイル時 にソースコードの一部を無視することができます。 ----- #ifdef DEBUG /* コメント2 */ #endif -----  コメントを無視して考えると、上記のサンプルコードは次のようになります。 今後はこのコードを用いて解説します。 ----- #include int main (){ printf("Hello hackers!\n"); return 0; } -----  C言語ではコンパイルの過程で、最もはじめにプリプロセッサにソースコードを 渡します。プリプロセッサは渡されたソースコードの文字列調整を行います。具 体的にはコメントの削除、改行のスペースへの置き換え、複数のスペースをひと つにまとめる、文字列を定義したほかの文字列に置き換えるなどの前処理を行い ます。プリプロセッサで文字列調整が行われたソースはコンパイラに戻され、コ ンパイルが続行されます。プリプロセッサもコンパイラとリンカのように独立し たプログラムですが、gccはプリプロセッサも自動的に通してコンパイルを行いま す。  プリプロセッサで特別に処理される命令は先頭に「#」がついたものです。サン プルコードの1行目には「#include 」という行があります。includeと いう命令はプリプロセッサでは「ファイルの埋め込み」を意味する命令です。つ まり、「#include 」という命令は「この場所にstdio.hというファイル の内容を展開する」という意味になります。stdio.hは表示・読み込み処理命令を 扱うときに必要となるファイルで、画面に文字を表示させるときやキーボードか ら入力を読み込むときに必要になります。後述するprintfという命令は画面に文 字を表示する命令ですので、このstdio.hが必要です。  プリプロセッサは改行をスペースに置き換えてしまいますので、1行の終わりは 「;」で識別することになります。そのため、命令の後に「;」を忘れますとコン パイル時にエラーが発生します。 ●関数  関数とは、ある値を入力すると加工して違う値を出力するもののことです。た とえば、りんごを入れると中で何やら加工してアップルパイを出してくれるよう な箱を思い浮かべてください。アップルパイの作り方を知らなくても、材料を入 れればアップルパイが出てきます。このような仕組みのことを関数と呼びます。  関数は数学などでよく出てきますが、プログラムの関数と数学の関数はまった く別のものです。ただ動作が似ているのでこのような仕組みのことを数学用語で あった「関数」と呼んでいるだけです。ただし、数学用語を用いているだけあっ て、りんごの例を数学的に考えることができます。りんごをx、アップルパイをy とおきます。アップルパイ製造ボックスをf()で表現するなら、f(x) = yと表すこ とができます。数学の教科書などでよく出てくるような形となりましたが、これ はアップルパイ製造ボックスの中にx(りんご)を入力「f(x)」するとy(アップ ルパイ)が出力されるということを表しています。 x:りんご=入力値 ↓ +------------------+ | f() |:アップルパイ製造ボックス=関数 +------------------+ ↓ y:アップルパイ=出力値  サンプルコードの5行目には「printf ("Hello hackers!\n")」という命令があ ります。先述の説明ではこれは文字を画面に表示する命令だと解説しましたが、 それは正確にいえば誤りです。本来画面への出力というのはよりハードウェアに 近い処理が必要となるため、1行やそこらの命令では到底記述できません。  実は「printf("Hello hackers!\n")」というのは関数です。"Hello hackers!\ n"という文字列をprintf()という関数に入力値として入力し、出力値は画面への 表示という形で返されます。画面へ文字を出力する仕組みを知らなくても、材料 を入れれば結果が出てきます。  仕組みを知らなくても結果が出てくるということには大きな利点があります。 画面に文字を表示するという処理は非常に複雑な仕組みが関係して文字を表示し ています(実際には私は仕組みを知りません)。これをブラックボックスとして、 表示したい文字を渡せば画面に表示してくれるように隠蔽すれば、すべてのプロ グラマーがハードウェアに近い複雑な処理を知る必要がなくなり開発効率が向上 します。 "Hello hackers!\n":入力値 ↓ +------------------+ | printf() |:関数(内部の仕組みは知らなくてよい) +------------------+ ↓ Hello hackers!:出力値  関数は処理を小分けするのにも便利です。世の中の仕事は、どんな大きな仕事 であっても小さな仕事の集まりです。小さな仕事を細かく見すぎると全体を把握 できなくなりますが、大まかな内容に分けてトップダウン的に仕事を考えると全 体を見失うことなく大きな仕事を小分けできます。  例えば、A社に自社で販売している商品の販売契約をとるという仕事があったと します。これ自体は非常に大きな仕事です。しかし、よく見るとこれはいくつか の仕事の集まりで構成されています。 +------------契約をとる-----------------+ | | | ・上司に相談する | | ・A社にアポイントメントをとる | | ・プレゼンテーションの資料作成 | | ・契約書の準備 | | ・A社へ訪問 | | ・プレゼンテーションを行う | | ・契約 | | | +------------[仕事達成]-----------------+  どうやってA社にアポイントメントをとるかといった細かい方法はこの時点では わかりません。しかし、全体としてどういった流れで仕事を行えばよいのかを把 握することができます。小分けした仕事を関数として扱えば、細かい方法を考え ずに、全体の仕事を遂行するために必要なサブルーチン(小分けした仕事)がど ういうものか把握できます。さらにA社にアポイントメントをとるというサブルー チンを見ていくと次のようなサブルーチンが必要になります。 +------A社にアポイントメントをとる------+ | | | ・A社の電話番号を調べる | | ・電話をかける | | ・用件を伝える | | ・場所と日時を決める | | ・電話を切る | | | +------------[仕事達成]-----------------+  このままさらに細部まで小分けしていけばA社とアポイントメントをとる方法は 明らかになります。関数の概念を用いれば、大きな仕事であっても全体を見逃す ことなく細部の処理を考えることができます。  プログラミングにおいて関数化は非常に重要な概念であり、効率的に開発する のには必須の考え方です。通常ならひとつの関数は内部でさらに細かい仕事に分 けられるため60行以内に収まります。 ●ポインタ  ポインタはC言語で特につまずきやすい鬼門として有名です。  変数というのはプログラムで利用するデータを格納しておく箱のようなもので す。プログラム内で宣言し、利用している変数は全てコンピュータ上のどこか( 正解はメモリ内のどこか)に配置されています。その場所自体のことをアドレス といいます。ここで駅のロッカーを考えてください。ちょうどロッカーは箱状に なっていて内部に荷物を格納しますので、変数のようなものだと考えることがで きます。ロッカーには1番から順番にロッカー番号が振られていて、その番号があ るおかげで私たちはどのロッカーを借りたのか探すことができます。 +--------+--------+--------+--------+--------+--------+ | 1 | 2 | 3 | 4 | 5 | 6 | | | | | | | | +--------+--------+--------+--------+--------+--------+ | 7 | 8 | 9 | 10 | 11 | 12 | | | | | | | | +--------+--------+--------+--------+--------+--------+  7番ロッカーを借りたとしますと、私たちは7番という数値だけ覚えておけばロ ッカー内の荷物を出し入れすることができます。ロッカーの例ではロッカー番号 がアドレスという概念になります。  ポインタはアドレスを格納するための変数です。ポインタを解説するに当たり、 変数の宣言時にどのようにメモリ(ロッカーと置き換えてもらって結構です)に 変数のための領域が確保されるのかを見てみましょう。例えば、変数int test = 30はメモリ上に次のように確保されます。 番地 [メモリ] 1 +---------+ | | 2 +---------+ ! ! 100 . . | | 101 +---------+ | 30 |←test 102 +---------+ ! !  この例ではメモリ101番地をtestと名づけ、その番地に30を格納しています。t estと名づけることでアドレス番号を指定しなくても、testという文字列で指定で きるようになったわけです。このように番地に別名をつけるのはアセンブラでラ ベルにあたるものだと思います。ポインタの部分がわかりにくいと感じましたら、 先にアセンブリの解説を読んだうえでもう一度ポインタの解説をお読みください。  この例で変数testというものは101番地であると定義されています。このtestと いうラベルのついた番地を他の変数に格納する仕組みをポインタといいます。ポ インタも変数の一種ですから当然メモリの番地の一画に確保されているわけです が、この番地は特別な番地に確保されます。  ポインタの宣言、利用は次のように行います。 ----- int main (void){ int test = 0; /* 変数testの宣言 */ int *pointer; /* ポインタの宣言 */ int temp = 0; /* 103番地に確保されるものとする */ pointer = &test; /* testのアドレスを格納 */ *pointer = 2600; /* 解説は後述 */ temp = *pointer + 1; /* 解説は後述 */ return 0; } -----  変数の前に*をつけることでポインタだと宣言します。pointer = &test;でpoi nterにtestのアドレスを格納します。 番地 [メモリ] 1 +---------+ ! ! 100 . . | | 101 +---------+ | 0 |←test 102 +---------+ | | 103 +---------+ | 0 |←temp +---------+ ! ! 900 . . | | 901 +---------+ | 101 |←pointer(内容は変数testのアドレス) +---------+  ポインタを使ったデータのアクセスには*をつけます。*pointerで、pointerに 格納されているアドレスの中身を表します。それ故に*pointer = 2600;で「poin terに格納されているアドレスの中身を2600で上書きする」という命令になります。 番地 [メモリ] 1 +---------+ ! ! 100 . . | | 101 +---------+ | 2600 |←test 102 +---------+ | | 103 +---------+ | 0 |←temp +---------+ ! ! 900 . . | | 901 +---------+ | 101 |←pointer (内容は変数testのアドレス) +---------+  temp = *pointer + 1;は、pointerに格納されている値(ここではtestのアドレ スである101)に1を足すという命令になります。それによってtempに格納される 値は102になります。 番地 [メモリ] 1 +---------+ ! ! 100 . . | | 101 +---------+ | 2600 |←test 102 +---------+ | | 103 +---------+ | 102 |←temp +---------+ ! ! 900 . . | | 901 +---------+ | 101 |←pointer (内容は変数testのアドレス) +---------+ ○参考 ・初心者のためのポイント学習C言語(http://www9.plala.or.jp/sgwr-t/) ・Wizard Bible vol.22(http://wizardbible.org/22/22.txt)  ポインタで特に理解しておくべき点は、プログラム中のデータは変数に格納さ れ、その変数はメモリ上のどこかに必ず配置されるという点、メモリは区画分け されてデータを格納しており、アドレスを用いてそのデータにアクセスできると いう点の2点です。これらの知識はハードウェアの基礎を理解するのに役立ち、ア センブリやほかの高級言語の理解を助けます。また、ハッキング手法を理解する 大前提となります。 ■0x07.) アセンブリ言語  アセンブリ言語は先述のように機械語命令と一対一で対応した低級言語です。 機械語の代わりにニモニックと呼ばれるアルファベット形式の命令を使ってプロ グラミングします。機械語と一対一で命令が対応しているので、機械語と同レベ ルのきめの細かいプログラミングが可能であり、なおかつ機械語よりも簡単にプ ログラミングを行うことができます。  C言語などの高級言語の出現、ハードウェア性能の飛躍によってアセンブリ言語 は過去の産物ととられがちになりましたが、プログラムは全て一度アセンブリに 変換されたうえで機械語に置き換えられます。プログラムを学んでいくうえでは 決して無視できない言語です。私はアセンブリ言語は特にハッカーがC言語以上に 精通しておくべき言語だと考えています。 ●アセンブリ言語の種類  アセンブリ言語は記述の仕方によっていくつかの種類に分けられます。現在主 に使われている種類を次に列挙します。 ○MASM  MASM(Microsoft Macro Assembler)はマイクロソフト社製のアセンブリ言語で す。元はインテル社のASM86というアセンブラを起源とし、インテル社のASM(ア センブラ)と互換性があるアセンブラとして作られました。Windows環境下でプロ グラミングができ、記述方法も簡単です。 ○NASM  NASM(Netwide Assembler)はケンブリッジ大学のSimon Tathamによって開発さ れたMASMと互換性のある8086CPU用のアセンブリ言語です。Windows以外にもUNIX で利用できます。 ○GAS  GAS(GNU Assembler)はDean ElsnerおよびJay Fenlasonが作成したアセンブリ 言語で、x86アーキテクチャで動作します。GNUが開発を行っており、gccでアセン ブルできます。 ○CASL  基本情報技術者試験で出題されるプログラミング言語であり、COMETと呼ばれる 仮想コンピュータで動作するアセンブリ言語です。学習用言語としての性質が強 く、エミュレータを除いて実際のコンピュータ上で動くプログラムを作成するこ とはできません。  このレポートではGASを使って解説します。理由はgccでコンパイルが可能であ り、プログラマーがよくお世話になるデバッガGDBがリエンジニアリングで吐き出 すコードがGASだからです。 ●サンプルコード  次にGASアセンブリのサンプルコードを示します。このプログラムは「Hello W orld」を画面に表示するプログラムです。 ----- sample.s .data msg: .string "hello world\n" len: 12 .text .global main main: movl $4, %eax movl $1, %ebx movl $msg, %ecx movl $len, %edx int $0x80 ret -----  アセンブリでは変数は「.data」と書かれた部分から「.text」と書かれた部分 までの間で宣言します。正確には変数ではなくラベルという概念です。msgという 変数はASCII文字列でhello world\nという内容を格納した変数と扱えます。「.d ata」と書かれた部分はデータセグメントと呼ばれるデータ格納用のメモリ領域に 確保されます。セグメントの詳細については次回解説しますので、ここでは変数 は「.data」から「.text」までの間で宣言しなければならないと覚えておいてく ださい。  ラベルはメモリ番号に別名をつけることです。ロッカーの例では、7番ロッカー と呼ぶかわりに「鈴木のロッカー」と呼びかえるようなものです。別名をつける ことで、番号で呼ぶよりも何のためのロッカーなのかが明確になりました。msgの 宣言でメモリが次のようになります。 番地 [メモリ] 100 . . | | 101 +---------+ | 103 |←msgと別名をつけた 102 +---------+ | | 103 +---------+ | H |←文字列の先頭アドレス 104 +---------+ | e | 105 +---------+ ! l !  プログラムのコード自体は「main:」以降に記述します。アセンブリのプログラ ミングではOSが提供するシステムコールを利用して様々な処理を行います。画面 に文字を表示する処理やファイルの内容を読み込むなどの処理はシステムコール を介して行われます。システムコールとは関数のようなもので、OSが提供する機 能をユーザが利用しやすいようなインタフェースとしたものです。たとえば、OS が文字を表示する仕組みはわからなくとも定められた値を設定してシステムコー ルを呼べばOSが文字を表示してくれます。システムコールにはそれぞれ番号が割 り振られており、文字を出力するwriteシステムコールは4番になっています。Li nuxのシステムコール番号の対応表は/usr/src/linux-2.4.18/include/asm/unist d.hに保存されています。次にunistd.hの一部を挙げます。 ----- /usr/src/linux-2.4.18/include/asm/unistd.h #ifndef _ASM_I386_UNISTD_H_ #define _ASM_I386_UNISTD_H_ /* * This file contains the system call numbers. */ #define __NR_exit 1 #define __NR_fork 2 #define __NR_read 3 #define __NR_write 4 #define __NR_open 5 #define __NR_close 6 #define __NR_waitpid 7 #define __NR_creat 8 #define __NR_link 9 #define __NR_unlink 10 #define __NR_execve 11 #define __NR_chdir 12 …(略)… -----  システムコールを利用するには、eaxに利用したいシステムコール番号を指定し、 ebxにそのシステムコールが要求する第1引数を、ecxに第2引数を設定し、その後 int $0x80を実行して割り込みを発生させます。eaxやebxはレジスタと呼ばれる高 速な記憶領域をあらわしていますが、変数のようなものだと思っていただければ 結構です。 +-----------------------+---------------+---------------+---------------+ | eax | ebx | ecx | edx | +-----------------------+---------------+---------------+---------------+ | システムコール番号 | 第1引数 | 第2引数 | 第3引数 | +-----------------------+---------------+---------------+---------------+  Manpage(http://www.linux.or.jp/JM/html/LDP_man-pages/man2/write.2.html) でwriteシステムコールを検索すると、書式は次のようになっています。 ----- write(int fd, const void *buf, size_t count) -----  上記より第1引数にはファイルディスクリプタを指定し、第2引数には文字列が 格納されているアドレスの先頭、第3引数は出力する文字の数であることがわかり ます。標準出力はファイルディスクリプタ1番と定義されていますので、次のよう に設定して割り込みを発生させればよいことになります。msgやlenは自動的にア ドレスが渡されることになります。msgのアドレスには文字列が格納されている先 頭アドレスが格納されています。 +-------+-------+-------+-------+ | eax | ebx | ecx | edx | +-------+-------+-------+-------+ | 4 | 1 | msg | len | +-------+-------+-------+-------+  割り込みが発生した後はOSが提供するシステムコールに処理が移行し、画面に 文字が表示されます。システムコールは関数であり、このとき文字列のアドレス や出力する文字の長さなどはスタックを用いて受け渡されます(スタックの詳細 については次回を参照)。割り込みはレジスタに必要な引数がセットできたこと をOSに伝え、システムコールへ処理を移行させるための合図です。  今後のアセンブリプログラミングにおいてもシステムコールを多用して必要な 処理を行っていくことになります。 ●命令  ソースコード中の「movl $4, %eax」という命令を例にとって解説します。mov lの部分が命令で「〜を〜に移動させる」という意味を持ち、$4および%eaxが命令 に関係するデータです。$4は4という数字自体を現しており、%eaxはeaxレジスタ を表しています。「$」は数字や文字列を表し、「%」はレジスタを表す記号と思 ってもらえれば結構です。  主に命令の表記の仕方には2つの方法があります。ひとつはIntel形式と呼ばれ る記述方法で、もうひとつはAT&T形式と呼ばれる記述方法です。前者はMASMやNA SMで採用されている記述方式で、後者はGASに採用されています。この2つの方式 の違いはごく簡単なもので、命令の後に続けるデータの順番が逆になるだけです。 例えば「mov a b」のような命令は、Intel形式では「aにbを代入」と解釈されま すが、AT&T形式では「aをbに代入」と解釈されます。これだけの違いであり、ア センブリ言語の種類によってどちらか一方の固定ですので、どちらの記述方法を 採用しているか知っていれば、特に難しいものではありません。  ここではGASを使っていますので、AT&T形式で解釈します。つまり、「eaxレジ スタに4を代入する」という命令であることがわかります。同様に、「movl $1, %ebx」は「ebxレジスタに1を代入する」という命令です。少し毛色が違うのは「 movl $msg, %ecx」という命令です。$msgというのは数字ではなく、.dataのとこ ろで定義したmsgという配列(正確に言えばアドレス)に宣言された文字列を表し ています。つまり、「ebxレジスタにmsg配列の先頭アドレスを代入する」という 命令と等価であるといえます。  次の「int $0x80」のint命令(interrupt)とは割り込みを発生させる命令で す。変数をここで呼び出すことをOSに通知するシグナルのようなもので、0x80番 シグナルは先述のシステムコール割り込みの発生を表しています。ここでシステ ムコール番号4番のwriteシステムコールが呼ばれることになり、画面の文字列を 表示します。  最後の「ret」は、ここでプログラムが終わりであることを表す特殊な命令です。 基本的にはプログラムの終わりにこの命令を配置することになります。  少し駆け足でサンプルコードの実行される様子を見てきましたが、ここで理解 しておいてほしいところは実際のアセンブリプログラミングの雰囲気と次の2点で す。 ・アセンブリ言語は単純な命令しか持ち合わせていない点 ・高度な処理はシステムコールを利用する点  アセンブリプログラミングの知識は第3回以降の解説で必ず使います。具体的に はシェルコードの開発でアセンブリプログラミングの応用技術を使います。この 解説では文法については触れていませんので、よく分からなかったという方や文 法を知らないという方は他の書籍を参考に知識の補充をお願いします。私のちゃ ちな解説よりもよほど洗練された解説をされている書籍は多いと思いますので、 文法の解説は割愛します。 ■0x08.) 参考文献 ・「Hacking:美しき策謀」 Jon Erickson著 村上 雅章訳 ISBN4-87311-230-3  http://www.oreilly.co.jp/books/4873112303/ ・「ハッキング対策マニュアル」ISBN4-7973-2145-8 ・「セキュリティ夜話 バッファオーバーフロー(BO)系列 (1)Aleph Oneによ るスタック破壊の楽しみと恩恵」  http://www.asahi-net.or.jp/~vp5m-snd/sec/tech/Phrack49-14.html ・オータックス株式会社  http://www.otax.co.jp/item/if/m.html ・初心者のためのポイント学習C言語  http://www9.plala.or.jp/sgwr-t/ ■0x09.) さいごに  今回は前回に引き続き、前提知識の確認を行いました。ハッキングにおいて特 に本質となるプログラミングを重点にC言語とアセンブリ言語について解説をしま した。次回はハードウェアについての基礎部分を解説し、前提知識の確認を終え ます。まだ、いかにもハッキングといった内容の解説は出てきませんが、前提と なる知識を詰めることがハッキングの理解を助けるのだと考えています。  それでは、またお会いしましょう。 x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x --- 第3章: ハニーポットを作ろう(連載第11回) --- 著者:Narusase x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x ■0x01.) はじめに  前回はSnortとPostgreSQLのインストールと設定について解説しました。Snort のログをDB(データベース)に格納すると軽く触れましたが、ログの中身につい てはまったく触れませんでした。動作させるだけで、監視の結果を分析しないの では意味がありません。  そこで今回はDBに格納されたログを見やすい形で表示してくれるソフトウェア であるACIDのインストールについて解説していきたいと思います。 ■0x02.) Apache2 + PHP + gdのインストール  ACIDを使用するためには、Snortより多くのパッケージをインストールする必要 があります。まずはaptで導入できるパッケージをインストールします。ところで、 Apache2ではなくApacheでもおそらく問題ありませんが、今回はApacheをアンイン ストールした上でApache2を使用することにします。また、マルチスレッドで動か すと一部のパッケージでエラーがでるためApache2のバイナリへのリンクを変更し ます。 ----- # apt-get remove apache # apt-get install apache2 php php-pgsql php-apache2 gd # rm -f /etc/alternatives/apache2 # ln -s /usr/sbin/apache2.prefork* /etc/alternatives/apache2 -----  次にApache2の設定を変更して、Apache2を起動します。 ----- # vi /etc/apache2/conf/apache2.conf ----- ----- 編集前 LanguagePriority en da nl et fr de el it ja kr no pl pt pt-br ltz ca es sv tw ----- ↓jaを先頭に持ってくる ----- 編集後 LanguagePriority ja en da nl et fr de el it kr no pl pt pt-br ltz ca es sv tw ----- ----- 編集前 AddDefaultCharset ISO-8859-1 ----- ↓jisをデフォルトにする ----- 編集後 AddDefaultCharset ISO-2022-JP ----- ■0x03.) その他のパッケージのインストール  ここからはどんどん必要なパッケージを入れていきます。基本的にtar.gzを解 凍しコピーしていくだけですので特に問題は起こらないはずです。 ●phplotのインストール ----- # cd /usr/local/src # wget http://downloads.sourceforge.net/phplot/phplot-5.0rc2.tar.gz # tar xvzf phplot-5.0rc2.tar.gz # cp -R phplot /var/www/html/ ----- ●ADOdbのインストール ----- # cd /usr/local/src # wget http://downloads.sourceforge.net/adodb/adodb493a.tgz # tar xvzf adodb493a.tgz # cp -R adodb /var/www/html/ ----- ●ACIDのインストール ----- # cd /usr/local/src # wget http://www.andrew.cmu.edu/user/rdanyliw/snort/acid-0.9.6b23.tar.gz # tar xvzf acid-0.9.6b23.tar.gz # cp -R acid /var/www/html/ ----- ■0x04.) ACIDの設定  必要なパッケージを入れ終わったので、次は設定に入ります。必要な変更がい くつもあるので変更点だけ列挙します。 ----- # vi /var/www/html/acid/acid_conf.php -----  編集内容は下記を参考にしてください。 ----- 編集前 $DBlib_path = ""; $DBtype = "MySQL"; $alert_dbname = "snort_log"; $alert_host = "localhost"; $alert_port = ""; $alert_user = "root"; $alert_password = "mypassword"; $ChartLib_path = ""; ----- ↓編集 ----- 編集後 $DBlib_path = "/var/www/html/adodb"; $DBtype = "postgres"; $alert_dbname = "snort"; $alert_host = "localhost"; $alert_port = ""; $alert_user = "snort"; $alert_password = "snort"; $ChartLib_path = "/var/www/html/phplot"; ----- ■0x05.) ACID用のPostgreSQLの設定  次はPostgreSQLでACIDを使うための設定を行います。この作業は、ACIDがPost greSQLの最新版では廃止されている型を使っているために、最新版のPostgreSQL では必須の作業となります。編集を忘れた場合、データベースが変な形でできて しまうため面倒なことになってしまいますので気をつけてください。 1:まずは、テーブルの作成に利用するSQLファイルから編集します。 ----- # vi /var/www/html/acid/create_acid_tbls_pgsql.sql -----  「DATETIME」となっている部分を「TIMESTAMP」に変更します。計4個所あるは ずです。 2:次は、DBのセットアップを行うPHPファイルを編集します。 ----- # vi /var/www/html/acid/acid_db_setup.php -----  「DATETIME」となっている部分を「TIMESTAMP」に変更します。計10個所あるは ずです。 3:最後に書き換えたSQLファイルをつかってDBに必要なテーブルを作成するSQL文 を発行します。 ----- # sudo -u snort psql snort < /var/www/html/acid/create_acid_tbls_pgsql.sql ----- 4:これで設定作業は終了です。 ■0x06.) ACIDの動作確認  では、早速ACIDの動作確認をしてみます。次のURLにアクセスしてみてください (IPアドレスは自分のサーバーのものを指定する)。 http://192.168.1.1/acid/acid_main.php  アクセスができ、行頭に「Analysis Console for Intrusion Databases」とい う文字が表示されればACIDがうまく動作していることが確認されました。 ■0x07.) Snortの動作確認  Snortの動作確認にはnmapを使って、インターネット側からのPCで次のように実 行します。ポートスキャンができるアプリケーションであれば、nmap以外でも構 いません。 ------ # nmap -sT [Snortが動作しているIPアドレス] ------  実行終了後にACIDにアクセスし、「Unique Alerts:」の横の数字をクリックす ると、アラートのリストが表示されます。その中に「TCP Portscan」、「BLEEDI NG-EDGE SCAN NMAP」などの文字列があればポートスキャンされたことを意味しま す。表示されない場合は、監視するNICに関する設定などを変更してみてください。 監視するNICは/etc/sysconfig/snortあたりに設定があったはずです。 ■0x08.) おわりに  今回はSnortのログ分析ツールであるACIDのインストールと設定について解説し ました。次回はTripwireかnepentesについて解説したいと思います。 x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x --- 第4章: OpenGLを利用した3次元プログラミング入門(前編) --- 著者:Kenji Aiko x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x ■0x01.) はじめに  PS3(Play Station 3)やWiiといった昨今のゲーム機では、3次元空間を再現し たゲームが多数発売されている。もはや現在のゲームは3次元なくしてはありえな い。しかし、ファミコンのスーパーマリオブラザーズが大好きな筆者としては、 これは大変嘆かわしい事実である。  筆者はスーパーマリオブラザーズが大好きである。もうかれこれ10年以上プレ イし続けている。自慢ではないが、筆者はスーパーマリオブラザーズを6分台でク リアすることができる。自己最速は6分ジャストである。ちなみに、1年ほど前の 世界記録は5分17秒だったと思う。これは当時理論値と呼ばれていた数値で、これ 以上超えることはできないと思われていたが、現在は5分ジャストくらいでクリア されている映像があったような気がする。マリオプレイヤー(略してマリラー) はまだまだ進化し続けているのだ!  そもそも5分台になると、まず死ぬことは許されない。さらに、ほぼすべてのマ ップをBダッシュで通過しなければならない。さらに、ドカンを駆使して、最短距 離を走りぬける必要がある。余計なプレイは一切排除し、ただ最短コースを最短 の距離で通過することのみに神経を集中させる。  ただし、初心者の方がいきなり5分台に挑戦するのは無謀だろう。初心者の方は まずは10分クリアを目標にするとよい。10分クリアは意外と簡単である。覚える べきことはひとつで、1-1、1-2、4-1、4-2、8-1、8-2、8-3、8-4という最短コー スの進み方を覚えればよい。これだけで、10分クリアは目前である。まずは、8- 1まで進むのに、3〜4分くらいでいけるようになれば上出来である。4分で8-1に到 達すれば、残りの4コースを6分、つまり、1コース約90秒(1分30秒)で進めばよ いことになる。これはかなり楽である。10分クリアの重要なポイントとしては、 8-1までは決して死なないこと、そして、なるべく早く8-1に到達することにある。 つまり、勝負は8-1までにかかってる。8-1に到達したら、今度は一転して、安定 したプレイを心がける。無理なアクションはなるべくせず、負けないマリオ、死 なないマリオに徹する。仮に1度くらい死んだとしても、まだ余裕はある。落ち着 いてプレイすれば間違いなく10分クリアを遂げることができるだろう。  10分クリアが当たり前にできるようになったら、次は7分30秒クリアを目標にす る。これはかなり難しいが、できないことはない。まず、8-1までは、ほぼすべて Bダッシュで突破する。1-1はすべてBダッシュで行き、かつ、ドカンを使いショー トカットを行う。1-2はブロックを壊して上へ進みダッシュで最後のワープゾーン まで進む。4-1はすべてBダッシュでクリアする。4-2は豆の木の部分が少し難しい が、なるべく早く進み8-1へのワープソーンに到達する。ここまでで約2分30秒。 そして、残り5分で、8ステージをクリアしなければならない。ここからが10分ク リアとはかなり異なる。実質1ステージ1分ちょいでクリアしなければならないた め、かなりシビアなプレイが要求される。死ぬことは許されないし、かなりアク ティブなプレイをしなければならない。すべてBダッシュで突破する必要はないが、 かなりの無理をして進めていかなければならないだろう。8-3はハンマーブロスが 多数出現するため難易度は高めだが、意外とBダッシュで突破できやすいコースな ので、ここで時間を稼ぐのも手だ。ただし、8ステージは全コースに渡って手を抜 くことが許されないので、安全プレイはできない。  7分30秒クリアが当たり前にできるようになったら、いよいよ5分台の領域に挑 戦する権利が与えられる。しかし、ここからのチャレンジは長く険しいものにな るため、かなり難しい。まず、現段階において、全ルートをBダッシュでクリアで きるコースを列挙する。1-1、4-1の2つは確実にクリアできていて欲しい。また、 1-2も、上のルートを通らずに全Bダッシュクリアを実現してほしい。4-2も豆の木 を出して速攻で上るというテクニックを身につけていてほしい。とりあえず、こ こまでは最低限必要なテクニックだ。そして問題はここからだ。いかにして8ステ ージをBダッシュで突破できるか。これにすべてがかかっている。8ステージまで は最速でいけるが、8ステージが難しい。8ステージだけを練習したいという方は、 適当なところで無限1UPをして、8ステージまで進むのがよいだろう。また一度ク リアしたら、次からはステージが選択できるため、それを利用してもよい。  とにかく、ここからは、8ステージを延々とプレイすることになる。何千プレイ、 何万プレイとチャレンジを繰り返す必要があるだろう。  そして、8ステージをほぼBダッシュでクリアできるようになったとき、あなた はついに、世界記録に挑戦する技術を身につけたことになる。ぜひとも頑張って もらいたい。 ■0x02.) さいごに  スーパーマリオブラザーズを極めたら、次はスーパーマリオブラザーズ2が待っ ている。2は1と比べて、難易度が高めであり、最速クリアも難しい。しかし、そ の分手応えもあり、極めるにはもってこいのソフトである。基本的にこの2つのソ フトだけで20年は遊べる。さらにスーパーマリオブラザーズ3というものもあるが、 これは1や2と比べると、ダッシュルーチンやジャンプアルゴリズムが大幅に異な るため、別のゲームとしてプレイすると良いだろう。  3次元のゲームだけでなく、2次元のゲームもなかなか面白いことが分かってい ただけただろうか。これを機会にぜひともスーパーマリオブラザーズを極めてほ しいと思う。  さいごにOpenGLを利用したプログラムを以下に示す。  http://ruffnex.oc.to/kenji/src/xi.cpp  では、また会う日まで。 x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x --- 第5章: OpenGLを利用した3次元プログラミング入門(後編) --- 著者:Kenji Aiko x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x ■0x01.) はじめに  「OpenGLを利用した3次元プログラミング入門(前編)」では、スーパーマリオ ブラザーズの話をした。よって、後編ではスーパーマリオブラザーズ2の話をしよ うと思う。スーパーマリオブラザーズ2は、初代よりもかなり難易度が高めであり、 クリアすること自体も大変難しい。しかし、筆者はスーパーマリオブラザーズ2も 大好きである。もうかれこれ8年以上プレイし続けている。自慢ではないが、筆者 はスーパーマリオブラザーズ2を……………。  と、これ以上続けると、さすがに読者の方からお怒りの言葉をいただけそうな ので、この辺りでタイトル通り、OpenGLによる3次元プログラミングをやりたいと 思う。 ■0x02.) OpenGLとは  OpenGLとは、Silicon Graphics社が中心となって開発した、グラフィック関連 の処理を担ってくれるプログラミングインターフェースである。グラフィック関 連のインターフェースには有名なものとしてDirectXなどがあるが、DirectXとは 違い、OpenGLはハードウェアやOSに依存しない形に改良されているため、同じコ ードでWindows上でもLinux上でも動作させることができる。  公式Webページは「http://www.opengl.org/」である。OpenGLの実体はDLLとヘ ッダファイルであり、一般的なプログラムを作成するときにライブラリファイル をリンクさせることで、OpenGLが提供するAPI(関数群)を利用することができる。  そして、今回のサンプルプログラムは以下である。  http://ruffnex.oc.to/kenji/src/xi.cpp  ちなみに、このテキストでは、OpenGLに関する基本的なことを解説していない 。OpenGLに関する入門サイトは次のWebサイトがお勧めである。もし分からなけれ ばここを参照してほしい。 ・「GLUTによる「手抜き」OpenGL入門」 (http://www.wakayama-u.ac.jp/~tokoi/opengl/libglut.html) ■0x03.) 球体と立方体  2次元平面において、任意の円を描画するのに必要な情報は「円の中点」と「半 径」である(図1)。 (図1:http://ruffnex.oc.to/kenji/gl/0.png)2次元平面上の円  これは3次元空間においても同じである。3次元空間の場合は球体となるが、球 体の中心点の座標と、その球体の半径を得ることで、3次元空間に任意の球体を決 定できる。  そして、正方形とは、各点が2次元平面に描かれた円上に存在するもっとも大き な長方形である。同じく、立方体とは、各点が3次元空間に描かれた球体の中に納 まるもっとも大きな直方体であり、各頂点は球体の表面に接触する。よって「立 方体の中心点から頂点への距離」は、「球体の半径」と等しいことになる。つま り「傾き(角度)」を考えなければ、任意の球体の決定は、任意の立方体の決定 となる。  これらの理由から、3次元空間における立方体は、中心点の座標と、中心点から 頂点への距離のみで表すことが可能であることが分かる。ただ、OpenGLで立方体 を描画する場合、各頂点を指定する順番がややこしい問題となってくるので、サ ンプルプログラムでは、立方体の情報を、中心点の座標と頂点への距離ではなく、 「中心点の座標」と「基点となる頂点の座標」で示している。  また、実際に3次元空間に立方体を描画するためには、立方体の8つの頂点を指 定する必要がある。よって、立方体の中心点から、この8つの頂点を計算する。 (図2:http://ruffnex.oc.to/kenji/gl/1.png)立方体  図2は、1辺が1の長さを持つ立方体である。1辺が1であるため、この立方体の中 心点の座標は(0.5, 0.5, 0.5)に存在することが分かる。よって、この中心点(0. 5, 0.5, 0.5)から8つの頂点を求める方法を考える。これは至って簡単である。す べての頂点は、中心点から、(0.5, 0.5, 0.5)の距離に存在する。よって、中心点 にその距離を加算することで求められる。 頂点G: (x, y, z) = (0.5, 0.5, 0.5) + ( 0.5, 0.5, 0.5) = (1.0, 1.0, 1.0) 頂点H: (x, y, z) = (0.5, 0.5, 0.5) + ( 0.5, 0.5, -0.5) = (1.0, 1.0, 0.0) 頂点F: (x, y, z) = (0.5, 0.5, 0.5) + ( 0.5, -0.5, 0.5) = (1.0, 0.0, 1.0) 頂点H: (x, y, z) = (0.5, 0.5, 0.5) + (-0.5, 0.5, 0.5) = (0.0, 1.0, 1.0) 頂点B: (x, y, z) = (0.5, 0.5, 0.5) + ( 0.5, -0.5, -0.5) = (1.0, 0.0, 0.0) 頂点E: (x, y, z) = (0.5, 0.5, 0.5) + (-0.5, -0.5, 0.5) = (0.0, 0.0, 1.0) 頂点D: (x, y, z) = (0.5, 0.5, 0.5) + (-0.5, 0.5, -0.5) = (0.0, 1.0, 0.0) 頂点A: (x, y, z) = (0.5, 0.5, 0.5) + (-0.5, -0.5, -0.5) = (0.0, 0.0, 0.0)  3次元空間の中に任意の1点と基点となる1点を決定すれば、立方体を描画できる。 ■0x04.) 回転  傾き(角度)を考えないのならば、「中心点の座標」と「中心点から頂点まで の距離」だけで立方体の描画を行うことができる。しかし、立方体に傾きを取り 入れると、「中心点の座標」「中心点から頂点までの距離」の他にもうひとつ「 回転の角度」が必要になる。 (図3:http://ruffnex.oc.to/kenji/gl/2.png)角度の演算  (a1, b1)の点を立方体の中心点とし、立方体の頂点(x1. y1)を、角度Q分だけ回 転させたのが頂点(x2, y2)だ(図3)。頂点(x1, y1)は、立方体の中心点に対して、 45度の角度を持っている状態であり、それからQ度だけ回転させるということは、 それぞれの頂点に対して、次の関係が成り立つ。 (現在の角度 + Q) = 回転角度  そして、回転角度から、頂点の位置を決定する計算式は、円の半径をL(エル) とすると、次のようになる。 (x2, y2) = (a1 + L * cos(現在の角度 + Q), b1 + L * sin(現在の角度 + Q))  中心点を軸にして、立方体の8つの各頂点に上記の演算を加えることで、傾いた 状態の立方体を描画することができる。ただし、立方体の右上の頂点に対しては 現在の角度が45度だが、他の頂点では、現在の角度がそれぞれ、135度、225度、 315度となる。よって、それぞれの頂点に対して現在の角度を指定しておく必要が ある。  上記の計算式から「中心点の座標」と「中心点から頂点までの距離」そして「 回転角度」で、任意の立方体を3次元空間に描画できることが分かる。ただし、3 次元空間の場合、回転角度は2次元である。  球体の表面の任意の1点は、(x, y)の2つの角度(つまり2次元空間と同じ)で表 すことができる。つまり、最終的には、「中心点の座標」と「中心点から頂点ま での距離」、そして、「2次元の回転角度」が必要となる。ただし、サンプルプロ グラムでは、分かりやすさを重視するために、回転角度を1次元としている。よっ て、1次元方向への回転にしか対応していない。 ■0x05.) 中心点の移動  立方体が、ある頂点を軸に円運動を行う場合の立方体の中心点の移動軌跡を調 べる。立方体だと分かりにくいので、2次元の正方形を利用して解説する。 (図4:http://ruffnex.oc.to/kenji/gl/3.png)中心点の移動  (a1, b1)の点を立方体の中心点とする。この状態で、点oを中心として、サイコ ロのように立方体を転がすと、立方体の中心点は、点oを中心とした半径√2(x/2 )の円運動を行うことが分かる。これにより、中心点の移動は次の計算式で表すこ とができる。 (a, b) = (o1 + √2(x/2) * cos(r), o2 + √2(x/2) * sin(r))  点(a, b)は、点oを中心とした半径√2(x/2)の円上の任意の座標である。上記の 式に任意の角度rを与えることによって、この円上の任意の座標(a, b)を求めるこ とができる。  ただし、図4より、点(a1, b1)は点oに対して、あらかじめ45度の角度に位置し ている状態なので、それから90度移動した位置が、立方体をサイコロのように移 動した後の位置(a2, b2)となる。このような動作から、(a2, b2)を求める計算式 を次に示す。実際にはこのような計算式を用いることになるだろう。 (a2, b2) = (o1 + √2(x/2) * cos(45 + Q), o2 + √2(x/2) * sin(45 + Q))  また、図4を見ても分かる通り、最初の角度が45度であり、最後の角度が135度 であることから、Qは(45 < r <= 135)の範囲で変動することになる。  つまり、サイコロ移動時のプログラムは次の計算処理を繰り返すことになる。 (a, b) = (o1 + √2(x/2) * cos(45 + 1), o2 + √2(x/2) * sin(45 + 1)) (a, b) = (o1 + √2(x/2) * cos(45 + 2), o2 + √2(x/2) * sin(45 + 2)) (a, b) = (o1 + √2(x/2) * cos(45 + 3), o2 + √2(x/2) * sin(45 + 3)) ... ... ... (a, b) = (o1 + √2(x/2) * cos(45 + 89), o2 + √2(x/2) * sin(45 + 89)) (a, b) = (o1 + √2(x/2) * cos(45 + 90), o2 + √2(x/2) * sin(45 + 90))  そして、その時々の(a, b)の座標が、立方体の中心点となる。その中心点を元 に、立方体の各頂点を計算し描画すれば、位置だけを模倣したサイコロ移動が実 現できる。この移動に関しての詳しい動作は、サンプルプログラムを実行し、上 下キーにて移動を行って確認して欲しい。 ■0x06.) サイコロ移動  立方体をサイコロのように移動させるには、位置を移動した後、任意の角度を 立方体に与えて描画しなければならない。例えば、立方体の中心点をQ分だけ移動 したら、立方体の各頂点もまた、Q分だけ傾かなければならない(図5、図6参照)。 (図5:http://ruffnex.oc.to/kenji/gl/4.png)中心点の移動 (図6:http://ruffnex.oc.to/kenji/gl/5.png)立方体の回転  図5では、最初に中心点を移動させ、そこに立方体を移動している。中心点は角 度Q分だけ移動している。そして次に、図6では、同じQ分だけ、立方体を回転させ る。立方体の各頂点をQ分だけ回転させることで、最終的に、頂点oを中心として 立方体全体を回転させたように見える。  つまり、中心点の移動と、立方体そのものの回転を、Q分だけ行うことで、サイ コロ移動を実現しているわけである。この動作については、サンプルプログラム を実行し、左右のキー入力で立方体を動かすことで確認することができる。 ■0x07.) サンプルプログラムの概要  最後にサンプルプログラムで定義している関数の簡単な解説を行う。ソースコ ードの先頭から順番に関数を見ていくことにする。 ----- キーボード入力に関する関数 int inputdata(int in); void spkeyboard(int key, int x, int y); -----  まずは、キーボード入力に関する関数が定義されている。spkeyboardはスペシ ャルキー入力を取得する関数で、main関数内でglutSpecialFunc関数にて登録され ている。inputdata関数は現在のキー入力情報を保持する関数である。 ----- 角度を変換する関数 GLdouble DegToRad(GLdouble Deg); GLdouble RadToDeg(GLdouble Rad); -----  これらは角度を変換する関数群である。角度の表記は、DegreeとRadianがある ため、それらを相互に変換するために作成した。DegToRad関数はDegreeからRadi anへ、RadToDeg関数はRadianからDegreeへ変換する。 ----- 3次元座標に対する演算処理 void Copy3d(GLdouble *dest, GLdouble *src); GLdouble *Add3d(GLdouble *a, GLdouble *b); GLdouble *Sub3d(GLdouble *a, GLdouble *b); -----  これらは3次元座標に対する演算処理を行う関数群である。座標配列に対し、C opy3d関数は代入、Add3d関数は加算、Sub3d関数は減算を、それぞれ行う。 ----- 立方体の生成と描画を行う関数 GLdouble *Add3da(GLdouble *a, GLdouble x, GLdouble y, GLdouble z); void DrawCube(GLdouble **vertex); GLdouble *RotatePoint(GLdouble *o, GLdouble x, GLdouble r, int flag); void RotatePoints(GLdouble **vertex, int *num, GLdouble *o1, GLdouble *o2, GLdouble x, GLdouble r, int flag); void MakeCube(GLdouble **vertex, GLdouble *center, GLdouble *corner); void RotateCube(GLdouble **vertex, GLdouble *center, GLdouble *corner, GLdouble *r, int flag); -----  これらは立方体の生成と描画を行う関数郡である。Add3da関数はAdd3d関数の改 造版であり、実質的な動作は変わらない。DrawCube関数は、ディスプレイに立方 体を描画する。RotatePointとRotatePointsは、それぞれ回転を扱う関数であるが、 RotatePoint関数がひとつの頂点に対して処理を行うのに対し、RotatePointsは立 方体全体に対して処理を行う。ちなみに、RotatePointはRotatePointsから呼び出 されている。  MakeCubeは、実際に立方体を生成する関数であり、RotateCubeは、生成された 立方体に回転を与える関数である。 ----- 立方体の中心点の移動を行う関数 GLdouble *OperationXi(int direct, GLdouble *center, GLdouble *corner, GLdouble r); -----  OperationXiは、立方体の中心点の移動を行う関数である。あくまでも中心点に 対してのみであり、立方体には関わらない。 ----- ディスプレイへの描画関数 void display(void); -----  display関数はディスプレイへの描画を受け持つ。glutDisplayFunc関数にて登 録されている。 ----- アクションを待っている時に処理する関数 void sleepf(float intv) void idle(void); -----  idle関数にはシステムがアクションを待っている時に処理するコードを記述す る。glutIdleFunc関数にて登録されている。sleepf関数は、処理のウェイトを行 っている。 ----- リサイズ処理 void resize(int w, int h); -----  resize関数にはウィンドウがリサイズされた時に呼びだされる処理を記述して いる。glutReshapeFunc関数にて登録されている。 ----- エントリーポイント&初期化関数 void init(void); int main(int argc, char *argv[]); -----  main関数とinit関数ではシステムの初期化を行っている。init関数はmain関数 から呼び出される。 ■0x08.) さいごに  アルゴリズムの基本的な部分はほぼ解説したが、もし詳細な部分を知りたい場 合は、サンプルプログラムのソースコードを参照してもらいたい。理論として理 解しているのと、実際に実装するのとではやはり違いがあるので、ソースコード も正確で分かりやすく書くように心がけた。また、不必要な部分はなるべく省い ているため、約500行程度の収まっており、読みやすさを保つために、コメントも なるべく多くつけている。ぜひとも読んでもらいたい。  では、また会う日まで。 x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x --- 第6章: 基礎暗号学講座 〜 第7回 〜 --- 著者:IPUSIRON x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x ■0x01.) はじめに  前回は共通鍵暗号と共に使われるMAC(Message Authentication Code)という 暗号技術について解説しました。このMACを使うことで、メッセージの正当性を保 障することができます。  今回は公開鍵暗号を理解するうえで必要な数学について解説します。といって も定義の連続ばかりでは萎えると思いますので、直観的な意味の定義を示します。 その後で、実際に暗号を実装する上で役に立つ(かもしれない)考え方について 解説します。 ■0x02.) 群・環・体の直観的定義  大学の数学科では、群・環・体という概念について半年〜1年を通じて学ぶと思 います。これらの概念は非常に重要で、化学・物理学・情報学などを理解する上 でも便利なものです。ところが定義に登場する条件が多く、慣れるまで混乱する でしょう。そこで今回は直観的な意味だけを解説します。  ここで覚えることは次の3つだけです。 ・群:加算・減算を自由にできる世界 ・環:加算・減算・乗算を自由にできる世界 ・体:加算・減算・乗算・除算を自由にできる世界  「自由にできる」という言葉について少し解説しておきます。「加算が自由に できる」というときは、対象の世界から2つ値a,bを取り出して、それを足し算し た結果c(=a+b)が対象の世界に収まっているということを意味します。  具体的な例を出して考えてみます。整数の世界{…,-2,-1,0,1,2,…}を考えてく ださい。この整数の世界から適当に2つ選択します。ここではa=-2,b=10とします。 次にa+bを計算します。これをcとしましょう。cはc=a+b=(-2)+10=8と計算できま す。このc=8は整数の世界のものです。このように適当に2つ選択したとき、必ず 元の世界に含まれる(これを「演算が閉じている」と表現する)ときに、この世 界は群と呼びます。  群は減算についても言及していますが、減算は加算と同じと考えることができ ます。なぜなら、減算はマイナスの数値の加算と考えられるからです。実際に整 数の世界が減算で閉じていることを調べてみてください。実際に手を動かして納 得することが、群・環・体の理解の近道だと思います。  次に環とは群の性質を満たしつつ、さらに乗法について閉じている世界のこと です。  具体的な例として1桁の2進数の世界、即ちmod 2の世界{0,1}について考えてみ ます。この世界の加法としてXOR演算、乗法としてAND演算と定義しておきます。 XOR演算・AND演算について覚えているでしょうか。ちょっと復習しておきましょ う。 ○XOR演算 0 XOR 0=0 1 XOR 0=1 0 XOR 1=1 1 XOR 1=0  これは普通の足し算をして、位が上がっても1桁目だけに注目していると考える とイメージしやすいでしょう(私の場合は同じもの同士を足したら0になると覚え ています)。XORは○の中にプラスを入れた記号で記述されます。WBのテキストベ ースでは表示できないため、+で表記しています。2進数の場面で+が出てきたら、 それはXOR演算だと思ってもらって構わないです。 ○AND演算 0 AND 0=0 1 AND 0=0 1 AND 1=0 1 AND 1=1  これは1同士をAND演算するとき以外はいつも0です。ANDは「かつ」と同じ意味 とイメージするとよいと思います。  それではmod 2の世界{0,1}が環であることを数値例で確かめてみます。まず{0 ,1}(単に0または1の2つの選択肢しかない)の世界から2つ選択します。ここでは a=0,b=1とします。このときc= a XOR b = 0 XOR 1 =1となります。このcはもちろ ん{0,1}の世界に収まっています。またd= a AND b = 0 AND 1 =0となります。こ のdも{0,1}の世界に収まっています。よって1桁の2進数の世界は環であることが わかります。  最後に体について解説します。これは環の性質に加えて、さらに除算が閉じて いる世界のことです。思いつくでしょうか。もっとも単純なものとしては実数の 集合があります。加算・減算・乗算が閉じていることは明らかです。実際に数値 例で確かめてもよいでしょう。もっとスマートな考え方としては、上記の議論で 整数の世界はすでに群(環にもなっている)であることを確かめているので、そ れを利用してもよいでしょう。整数の世界は、実数の世界の中に含まれているか らです。それでは問題の除算はどうでしょうか。実際に数値例で確かめてみます。 まず実数の世界から適当に2つ選択します。ここではa=1/3,b=-2とします。割り算 してe=a/bを計算すると、e=a/b=(1/3)÷(-2)=-(1/6)となります。このeは実数の 世界に収まっています。どのように2つ選んだときでも実数の世界に収まるので( これは証明しない)、体ということになります。  他の例を考えると、2進数の世界(桁数に制限なし)も体となります。これは各 自の課題とします。この体はGF(2)と書きます。この書き方は今回のWBで登場する ので覚えておいてください。  群→環→体と考えていくと、段々とそういう世界は少なくなっていきます。つ まり「群であるが、体ではない」世界などがあるということです。整数の世界や 自然数の世界は群・環ですが、体ではありません。割り算をしてみると、必ずし も整数とはならないからです。  暗号の世界では特に環が重要です。加算と乗算の間に面白い関係が潜んでいて、 それが色々なことに応用できるからです。詳細についてはここでは解説しません。 暗号について学ぶうちに自然と気付くことでしょう。 ■0x03.) 多項式に関する直観的定義  今回は多項式の演算についての話なので、まず多項式というのがどういうもの かを知っておかなければなりません。そこで多項式に関する用語についても直観 的定義を解説しておきます。 ・GF(2)上の多項式:係数がGF(2)に属する多項式を「GF(2)上の多項式」といいま す。これをGF(2)[x]と表記します。 例:0・x^3+1・x^2+0・x+1=x^2+1はGF(2)上の多項式のひとつ。係数だけに注目 すると0101という4ビット列になる。つまり4ビットのメモリで扱えるということ になるわけだ。 ・n次:多項式の次数がnという意味。 例1:多項式:x^3+x+1⇒次数:3次 例2:定数⇒次数:0次 ・既約:これ以上分解できないという意味。 例1:x^3+1は既約。 例2:x^2-1(∈GF(2)[x])は既約でない。なぜならx^2-1=x^2+1=(x+1)^2と分解で きる。 例3:x^64+x^4+x^3+x+1、x^128+x^7+x^2+x+1、x^256+x^16+x^5+x^2+1はすべて既 約。証明は省く。  GF(2)上の多項式が既約とは、係数がmod 2の範囲においてこれ以上因数分解で きないことを意味します。 ■0x04.) 拡大体GF(2^n)  GF(2)上のn次既約多項式f(u)を任意に固定します。このときGF(2)上の任意の多 項式a(u)(∈GF(2))をf(u)で割ってみます。割った結果の答え(割られる数)を q(u)、余りをr(u)と書くことにします。このときa(u),f(u),q(u),r(u)の4つの関 係は次のひとつの式に書き表されます。 a(u)=f(u)q(u)+r(u)  小さい数値で考えてみると、この式は成り立つことがわかります。これは多項 式でも同様な関係式が成り立つのです(本当は数学的に証明が必要だが、事実だ け知っておけば十分)。例えば、10(a(u)に対応)を2(f(u)に対応)で割ると、 答え4(q(u)に対応)、余り2(r(u)に対応)となる。つまり、10=2×4+2という 関係式が成り立つはずです。  この余りの全体の集合は要素数が2^n個であり(なぜならばr(n)はn-1次であり、 係数だけに注目すると{0,1}^nの2進ビット列で決定されるから)、体となります (証明は省く)。この体はGF(2^n)と記述されます。体の世界から新しい体の世界 を作ることができたので、拡大体と呼ばれるものの一種です。割る数であるf(u) の次数はn次であったので、余りの次数はn-1次以下になります。そこで、余りa( u)は次のように書けます。 a(u)=a_(n-1)・u^(n-1)+…+a1・u+a0  これは係数がGF(2)の要素であるn-1次多項式ですが、係数だけに注目してGF(2) 上の長さn(=係数がn個という意味)のベクトルに捉えることもできます。 (a_(n-1),a_(n-2),…,a1,a0) ∈{0,1}^n ■0x05.) 多項式の加算  GF(2^n)の2つの要素a,bの加算は、単純に係数をXOR演算すればよいだけです。  例えば、次数3の多項式が2つあって、それを加算したときを考えてみます。+と 表記しているところはXOR演算であることに注意してください。 (a3・x^3+a2・x^2+a1・x+a0)+(b3・x^3+b2・x^2+b1・x+b0) =(a3+b3)・x^3+(a2+b2)・x^2+(a1+b1)・x+(a0+b1)  3次多項式同士を加算しても次数が上がったりせず、係数だけに注目するので、 ベクトル表記で考えるとすっきりします。 (a3,a2,a1,a0)+(b3,b2,b1,b0)=(a3+b3,a2+b2,a1+b1,a0+b0) ■0x06.) 多項式の乗算 1:GF(2^n)の2つの要素a,bの乗算を考えてみます。まずa,bを次のように定義しま す。ここでuに関する多項式なのでa(u)などのように表記しました。 a(u)=a_(n-1)・u^(n-1)+…+a1・u+a0 b(u)=b_(n-1)・u^(n-1)+…+b1・u+b0 2:次にそれらの積c(u)=a(u)b(u)を求めます。係数はもちろんmod 2で考えます。 3:最後にc(u)を既約多項式f(u)で割った余りを求めます。これがGF(2^n)の世界 の積a・bになります。  なぜ最後にこのような変な処理を行うのかというと、掛け算した結果GF(2^n)の 世界、つまりn次の(係数は2進数の)多項式の世界に収めるためです。ピンと来 なければ、拡大体GF(2^n)の乗算はこういう操作をすることが決まっていると無理 やり納得するというのもありでしょう。 ●uを掛ける  まずuをa(u)(127次の多項式とする)に掛ける操作を考えます。即ちb(u)=uと いう単純な例の場合です。  既約多項式としてf(u)=u^128+u^7+u^2+u+1を固定します。 c(u) =a(u)b(u) =a(u)・u =(a127・u^127+…+a1・u+a0)・u = a127・u^128+…+a1・u^2+a0・u  ベクトル表記にするとわかりやすいかもしれません。 (a127,a126,…,a1,a0) ↓uを掛けた (a128,a127,…,a0,0)  ベクトルの各成分がひとつだけずれたのです。これは1ビット左シフトされたこ とを意味します。aを1ビット左シフトすることを「a<<1」と定義することにしま す。<<が逆になれば右シフトを意味します。1は1ビットという意味です。  話を戻します。uを掛けた結果、最大次数の係数はa127が0か1かによって場合分 けします。 [1]a127=0のとき a(u)=a126・u^126+…+a1・u+a0となるので、 c(u) =a(u)・u =a127・u^127+…+a1・u^2+a0・u =(a126,…,a1,a0) =(a<<1) [2]a127=1のとき c(u) =u^128+a126・u^127+…+a1・u^2+a0・u =(1,a126,…,a1,a0,0) =(u^128)+(a<<1)  一見するとこれは汚い結果のように見えますが、そうではありません。1ビット 左シフト部分はよいとして、u^128のところに注目してください。どこかで見覚え はないでしょうか? そうです。既約多項式としてf(u)=u^128+u^7+u^2+u+1を考 えていました。法u^128+u^7+u^2+u+1の世界で考えると、u^128というのは次のよ うに変形できます。 u^128 (mod u^128+u^7+u^2+u+1) =-u^7-u^2-u-1 (∵u^128+u^7+u^2+u+1=0) =u^7+u^2+u+1 (∵各係数はGF(2)なので、-1=1 (mod 2))  よって、(u^128)+(a<<1)は1ビット左シフトしてから、u^7+u^2+u+1を足すとい うことになります。加算は係数同士のXOR演算だと説明しました。u^7+u^2+u+1を 2進数にすると、0…010000111(「0…0」部分は0が120桁)=0^(120)10000111の ようになります。  ゆえに、次が成り立ちます。 a(u)・u =a<<1([1]のとき) or (u^128)+(a<<1)([2]のとき)  これはGF(2)[x]において、uを掛けるというのは、1ビット左シフトするか、1ビ ット左シフトしてからXOR演算するということを意味します。これはコンピュータ と相性がよく、コンピュータ上で暗号技術を利用するときはこうした仕組みを利 用して設計されています。  乗算は左シフトでしたが、除算は右シフトすることになります。上記の議論に おけるuを掛けたところを、u^(-1)を掛けると考えて議論を進めていけば、理解で きると思います。これは各自の課題としておきます。 ■0x07.) おわりに  今回の話題は暗号の話というよりは情報数学の話でした。暗号の実装に興味の ある方は知っておくといつかは役に立つかもしれません。暗号の理論だけに興味 ある人は今回の話題が理解できなくても全然大丈夫だったりします。  来月からはやっと皆が大好きな(?)公開鍵暗号系について入りたいと思いま す。  ではまた来月に会いましょう。 x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x --- 第7章:お知らせ --- 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 ---- 第8章:著者プロフィール --- x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x ■金床 ●Job: プログラマー ●Web: http://guardian.jumperz.net/, http://www.jumperz.net/ ●Mail: anvil@jumperz.net ●Comment:  前号のプロフィールでイプロム先生もおっしゃっていましたが、アウトプット は大事です。そう、セイカブツです。また、たぶんHもとさんがおっしゃたものだ と思いますが、「情報は発信する人に集まる」という言葉があります。いい言葉 ですね。これは間違いなく真実です。ということで、ここを読んでいる最近くす ぶり気味のあなた、是非次号WBへの投稿をお願いします。 ●2006年印象に残った本:  いい意味で印象に残った本は少ないというか、今の時点でぱっと思いつくもの がないですね。  …ていうかホントはあるんだけど「お前そんな本読んでるのか!」と言われそ うなのばかりなのでスルーしておきます。  悪い意味で印象に残った本は数冊あります。特に名誉(ry ■Defolos ●Job: Student ●Web: http://ruffnex.oc.to/defolos/ ●Mail: defolos@ruffnex.oc.to ●Team(Group): none ●Comment:  最近ラテン語がマイブームです。日本語とは本質的に異なった、非日常な言語 であるという点に強い魅力を感じますね。今のところ入門書を一通り読み終わり、 『クマのプーさん』のラテン語訳を読んでいます。いつかはVulgata(聖書のラテ ン語訳)を読めるように、日々精進したいと思います。 (プ、プログラミングもちゃんとやるつもりです・・・最近できてないですが) ■Narusase ●Job: Student ●Web: (裏)雑学の博物館(http://k-o-m.hp.infoseek.co.jp/) Narusaseの日記 -ハニポってどうよ?(仮)-(http://d.hatena.ne.jp/narusase/) ●Mail: narusase@mcn.ne.jp ●Team(Group): N/A ●Comment:  こんにちわ、Narusase(ナルサス)です。  色々と、仕事の方が忙しく連載をまた中断しそうになりあわてて締め切り当日 に書いていたりします(笑)。  さて、今回はSnort関係のソフトウェアACIDについて書きました。ACIDはDBを利 用するため結構重いので、もしかすると旧式のPCだとちょっと使いにくいかも知 れません。  サイトのほうはまあ最近全然更新してませんが、ヘタレな文章と未熟な技術、 ヘボいプログラムを紹介するサイトということで、暇があったらあら探しでもし てみてください。誤植とかミスとかはBBSにでも書いてくだされば、こっそり修正 しときます(笑)。ブログの方はほぼ毎日更新していて、技術ネタから投資ネタ、 どうでもいい独り言などあんまり役に立たない情報をそろえてます。 ●去年読んで印象に残った本:『金持ち父さん、貧乏父さん』  去年読んだ本と言いつつ実際に初めて読んだのは2年前だったりしますが、たま に目を通しているということで・・・。この本を最初に読んだときは、なかなか結論 を言わないといらいらしてしまいましたが、結論が出てくる最後のほうでは「お お、なるほど〜〜」と納得できる結論を出してくれました。  まあ、その結論がどんなのだったかは秘密ですが、自分の投資という考え方を 180度変えてしてしまったという意味では、かなりの良書かと思います。  皆さんも一度読んでみてはいかがでしょうか。 ■Kenji Aiko ●Job: Reverse Engineer ●Web: http://ruffnex.oc.to/kenji/ ●Mail: kenji@ruffnex.oc.to ●Team(Group): N/A ●Comment:  今回のテキストは、「ですます調」ではなく「である調」で書いてみましたが、 いかがだったでしょうか。実は「である調」でのテキストは初めてなので、もし かしたらおかしなところがあるかもしれません。今後はどちらの方式も使い分け られるようになりたいと思います。  ちなみに今回の「前編」「後編」に関しては、「ネタ」として受け取ってもら えると有難いです(^^;。ただ、マリオは本当に好きです。というか、本気で6分台 でクリアできます。というか、一時期、本気で世界記録に挑もうとしたことがあ ります。マリオ4に関しては、世界記録に7秒及ばないというところまで行ったの ですが、残念ながらその後さらに世界記録が更新され、あきらめてしまいました。 ●去年読んで印象に残った本:『30日でできる! OS自作入門』  この本は本当に面白かったです。いろんな意味で思い出に残っています。 ■IPUSIRON ●Job:Student ●Web:http://akademeia.info/ ●Mail:ipusiron@gmail.com ●Team(Group):N/A ●Comment:  今年になって就活で忙しい日々を送っております。この歳になってあれですが、 新卒カードが使える最後のチャンスだと思っています。早く内定もらって、開放 されたいです。 ●去年読んで印象に残った本:『墨攻』  孔子・孫子・老子・韓非子などと同時代に登場した墨子に焦点を当てた話です。 2万の敵兵から、たった一人の墨子が城を守るという内容です。孫子が攻めの教え なら、墨子は守りの教えといえます。グロも少し入っていますが、比較的万人向 きです。主要登場人物は少ないので、歴史が苦手でも普通に読めるはずです(三 国志とか戦国時代の話は似たような名前が多く、慣れないと混乱することが多く、 それが苦手意識を作る要因のひとつとなっている)。2月から映画も公開されまし たが、漫画版のほうが面白かったです。原作は漫画版とまったく異なる結末とい うことなので、近いうちに読んでみるつもりです。