Hackers' Dream 優勝してしまいました
意外にも。というわけで今回はここまでの経緯について。
イベントを教えてもらう
私は PacSec 2010 にスピーカーとして参加した。PacSec の終了後に飲み会があったのだが、そのときに韓国人グループと話をしていたのだ。今回スピーカーとして参加した韓国人は 3 人 (2 セッション; Vangelis, ChakYi and Externalist) で、さらに韓国で開催されるカンファレンスである POC のスタッフである Kancho 氏もいっしょだった。ブログで話をしたように、PacSec のプレゼンで、私は韓国におけるハッカーシーンといえるものを見たくなっていた。どのような話の流れでそうなったのか忘れたが、POC でリバースエンジニアリングのコンテストがあるよ!と。興味深かったので、参加してみると彼らに話したことを覚えている。
韓国 POC のサイトを開くと、すぐに答えは見つかった。(厳密にはリバースエンジニアリングだけではないものの、) Hackers' Dream というコンテストだ。興味深かったのはその日程。普通のハッキング関連コンテストは 1〜3 日で終わってしまうのが普通な気がしていたのだが、これは 11/22〜29、8 日間という長丁場。これは参加するしかないと決め込んだ。*1そして興味深いのは、問題の形式は決まった鍵を見つけ出せば OK なだけではなく、問題を解く過程まで含めてレポートを提出しなければならないという点だ。これはおそらく、問題の作成者や主催者によって審査される。これも結果的には吉と出た気がする。
イベント参加
Day 1
「!?」
問題ファイルをダウンロードした瞬間私はおののいた。厳密には、問題ファイルをダウンロードした瞬間におののいた Kaspersky に表示した情報を見て私もおののいた。「実在の脆弱性が使われている!?」
そう、本当に、本物の、脆弱性が使われているのだ。問題ファイルを見た限り脆弱性は二個で、パッチ状況を調べてみると…
- IE に関連する脆弱性 (CVE-2010-3962)
- IE6〜IE8 に影響
- コンテスト参加時点で未修正
- ただし PoC、Metasploit などで攻撃手法は既知。
- Adobe Reader に関連する脆弱性 (CVE-2010-3654)
ただし後で調べてわかったことだが、シェルコードの有害さは打ち消されている。(元々 Drive-by-Download をやる悪意あるペイロードっぽかったのが、パッチにより無害化されていたり。) またセキュリティをちゃんとやっている人間ならば、簡単には引っかからないようにもなっている。(例えば、DEP や ASLR の回避といったテクニックは最近当たり前のように使われているが、これらシェルコードの半分では半ば意図的に使用されていない。もう半分は脆弱性そのものの性質によって ASLR 回避の必要こそないが、同じ性質によって DEP 回避がほぼ不可能という代物。)
問題は 4 問あり、それぞれについてレポートを書く必要がある。
- Application (PDF; 壊れた PDF ファイルを修正し、シェルコードが何をするのか調べる。)
- Mobile (APK; 悪意ある Android アプリを調べる。)
- Packet (PCAP; 攻撃真っ最中のパケットから、攻撃の種類を特定し、さらに攻撃の「開始」「終了時間」も特定する。)
- Web (HTML; JavaScript の難読化を解き、IE の脆弱性を突く exploit を調べる。)
この日は Mobile を真っ先に解いてしまい、Web もその日のうちに解く。
Web の問題には罠があるかもと思ってシェルコードやペイロードの奥底まで解析をしてみたが、何もなかった☆
Day 2
本格的なパケット解析は初めてだったが、Packet 問題における攻撃の種類はいち早く特定 (ただしこの時点では答えが不十分。) しかしこれだけではまだ半分。Packet のもう半分が解けない。同時進行で Web 問題のボーナスポイントを得るため、最近有償アップグレードした VMware Workstation を総動員して、IE の脆弱性を徹底的にいじめる。Application は読み始めをしただけだが、PDF のファイルフォーマットが基本的にテキストだということがわかって一安心。これでイチから知らないフォーマットを解析する問題だったら諦めていたかも。(いや、実際 Packet でそうなったけどね。)
Day 3
Packet を後回しにする方向にして、Application から先に解く。様々な部分が壊れていることを疑ったが、実際にはバイナリエディタを使ってできる程度の修正ですべて有効な PDF になることが判明。JavaScript はかなり読みにくいが、それでもシェルコードにまで到達する。Web に使われるシェルコードと違って結構解析に苦労するも、これがどのような種類の攻撃コードか、ということまではある程度理解する。
Day 4
静的解析。細かい部分までの追跡を行い、コードのありとあらゆる動作を明らかにした。これで解いていない問題は Packet のみに。
少なくとも良いところまで行けるという確信を得る。
Day 5
苦難の日々のはじまりはじまり。
Packet 問題に関しては、攻撃の「種類を特定する」部分について、Ethernet / MAC フレームを見れば一目瞭然ということに気がつく。しかし、残りがわからない。
間違ったファイル (wrong files) を集め、パスワードを取得せよ。そして、攻撃の開始と終了時間を明らかにせよ。
ここからして、明らかにパケットキャプチャ中の SYN flood 攻撃が示す時間は攻撃の本質を明らかにしていないと推測 (SYN flood の途中でキャプチャが終わっているので、少なくとも終了時間を推測することが不可能。) 様々な部分を探すが良い結果は得られず。Transfer-Encoding が chunked なテキストに仕様上挟まる 16 進数のテキストがヒントかもと勘違いしたり、あるいは SYN flood のポート番号に規則性を見出すも答えは得られず。そうするうちに体調を崩してしまった。
Day 6
回復中…
Day 7
私には (Forensics の) 才能がないのかもと諦めかけたその 11 分後*2、決定的な証拠っぽいものを掴みとる。ふつう、Web ブラウズをしている最中の HTTP リクエストのほとんどには、Referer ヘッダがついてくる。というのも、リンクをクリックする、画像や CSS を読み取るといった行動においてはそれがついてくるからだ。つかないのは、「手動での URL 入力」「お気に入り」「動的コンテンツ」「怪しいファイル」くらいだと当たりをつけて、次の Wireshark フィルタを適用する。
http.request && !http.referer
ビンゴ!HTTP リクエストをほとんど手動で解析できるくらいに減らせた。しかもこの中に、HTML ファイルと URL には記述されているのにパスワードつき ZIP ファイルが送り返されているモノがあるぞ?となれば…
ここから、Packet の完全解析完了までは早かった。あとはレポートをちゃんとまとめることと、ボーナスポイントを限界まで稼ぐことだけだ。
Day 8
日本語に訳しながら英語の明らかな間違いを修正する。(某所で公開しているレポートはそのときに書いたものだ。) 最後にボーナスポイントのための 2 コンフィギュレーションを試し、レポートに書き加え、提出。これが 21:00 ぐらい。もう結果に賭けるしかない。
結果発表
そして昨日 (2010/12/2)、結果発表があった。結果は優勝。他の追随を許さない勢いで。
名前 (チーム) | Application | Mobile | Packet | Web | 合計 |
Tsukasa Ooi | 86 | 90 | 100 | 91 | 367 |
Jae-ryoung, Seong-hyun | 64 | 95 | 85 | 80 | 324 |
Jo Hyun-ho | 42 | 97 | 95 | 88 | 322 |
これを見る限り、勝負を分けたのは Application だったようだ。Mobile を除いてすべての問題で上位よりさらに高い点数を獲得できた。
考察
Application は、シェルコードの解析が比較的難しいものだったことが明暗を分けた理由かもしれない。あるいは PDF を修復しなかったとか。Mobile の点数が低いのは納得。真っ先に解いて、レポートの作成もその…サボったのだ。Packet は意外。完全解答は意外と難しかったか?Web もなんとか。ボーナスポイントチャンスであるこの問題は他の上位陣もなかなか良い点数を取っている。
このコンテストは、いわゆる「早解き」が問われない。つまり早解きが苦手でも、洞察と解析の深いスキルさえあれば優勝できるようになっているものと理解した。スピードがなくてもパワーさえあれば、というヤツだね。今回私は迂回することが多かったけど。というのも、実在するシェルコードの、実在する Heap Splay を解析するというのはなかなか楽しかったのだ。実際の脆弱性には色々なテクニックが内在しているということも。
これから
というわけで、副賞として POC 2010 にタダで入れる (ふだんは $400 する) ので、韓国に行ってきます。*3新型 MacBook Air も受け取れる*4ということで、次からは Mac が主要開発環境になっているということも…まだそれはないか。
Hackers' Dream 参加しました。
後日レポートをアップする予定です。(本文そのものはブログには貼りません。念のため。)
問題は 4 問あり、そのうちの 3 問ではリバースエンジニアリングが必須です。8 日という長丁場なので、全問正解することは最低必須だと考えていました。そこで取り掛かったのが、ボーナスポイント。全部横並びならボーナスポイントで勝てるぐらいに揃えておこうとしました。
特に Web 問題のボーナス問題。
今回これで最高点を取るため、様々な環境を立ち上げて試しました。IE の脆弱性というのは厳密に言えば mshtml.dll のバージョンに依存するため、違ったバージョンの mshtml.dll を「どうやって」集めるかがポイントでした。結局試したのはユニークなもので、次のバージョンのものでした。(バージョン辞書順)
- 6.0.2600.0
- 6.0.2800.1106
- 6.0.2900.2180
- 6.0.2900.3698
- 6.0.2900.5969
- 6.0.2900.6003
- 6.0.2900.6036
- 6.0.3790.0
- 6.0.3790.630
- 6.0.3790.1830
- 6.0.3790.2643
- 6.0.3790.3304
- 6.0.3790.3959
- 6.0.3790.4470
- 6.0.3790.4772
- 7.0.5730.13
- 7.0.6000.16386
- 7.0.6000.17080
- 7.0.6000.17092
- 7.0.6001.18000
- 8.0.6001.18702
- 8.0.6001.18939
- 8.0.6001.18975
この 23 種類。この脆弱性特有の性質で、mshtml.dll のバージョンがほんの少し違うだけでかなり違う結果が得られるという事実に驚き、また感激。今回のコンテストは実在の脆弱性を扱う問題が幾つかあったので、実際の脆弱性が「何を」やっているかが垣間見れたという点が良かったと感じる。
私の目から見た PacSec 2010 (2)
時系列に並べずにアトランダムに記述するという方針変更。まぁ大まかには時系列どおりにいきたいところだけど。
トレンドの変化、時代の変化、参加者の変化
今年の PacSec は 1 日チケットが購入可能になったのと同時に、昨年は明確でなかったジャンルの区分が行われた印象がある。1日目は技術的な話題が少なめ、というより、一般向けのトレンドな話題について。2日目は技術的かつ若干深遠な応用も含むものについて。―といったように、両日の違いはかなり鮮明なものになった。ただ、それでこのカンファレンスの魅力が薄れたわけではない。今回の内容は、それぞれの内容についてより踏み込んだと考えている。
ただ、参加者の方は私が観る限り昨年より少なくなってしまっている。1〜2割ほど? ただその代わりに外国人の方をよく見かけた気がする。(気がするだけかもしれないけど。もし正しかったとしたら、日本人が相対的に減ってしまったことになる。) 両日には参加者の数にも違いが現れ、2日目の方が若干 (特に日本人の) 参加者が多かったように感じる。これについてはある程度合理的な説明が得られる。高い料金を支払ってまでセキュリティについて深い知識を得たいと考える人なら、やはり技術的議論メインの 2日目を目当てにするだろう。実はこのブログエントリを書く過程で各年の PacSec 参加者に関する主催者側資料に当たることができたが、「減った」といっても全体の参加者は明らかに 100 名程度いたように感じたし、まだまだ開催する余裕はあると言えばあるのかもしれない。
これは発表を終えてからの印象なのだが、参加者が少し減ってしまった以上に、今回の私の内容に「食いついてくれる」人は多かったように感じる。*1参加者の技術的なレベルは下がっていない上に、私の発表も応用範囲が広く、かなり興味を持ってもらえる内容で、発表そのものもなんとか安定して行えたのが影響しているのだと思う。
スライド
思いっきり typo あるし、果ては図の 1 個に関してはそのまま日本語になってしまっていた。やってしまった、がそこにツッコまれることはなかった。またスライド製作途中、徹夜のせいでテンションが若干上がってしまい、スライドに (無駄に) エルシャダイネタ*2を仕込んでしまった。今では反省しているが、そこに突っ込むにはベストだったということもまた言える。
PacSec Day 1 : 電源がないっ!
PacSec 2010 がはじまって…最初に気づいたこと。電源がない…。もしかして以前から電源は勝手に取り回すようになってた? かどうかはさておき、最初に座った場所 (最後尾、韓国人メンバーが同席) からの電源確保は無理そうだった。仕方なくスマートフォンで tsuda ることにした…が、タッチによる文字入力の遅さはさすがに否み難い。あまり有用なツイートをすることができなかった。
1日目の昼以降と2日目はなんとか電源確保に成功し、ある程度の量はツイートに変換できた。それでも昨年の PacSec 2009 で精力的に tsuda っていた方には遠く及ばず。あの人達のモチベーションはどこから来ているんだ、と不思議に思う一幕。
PacSec Day 0 Party : 買い物?
韓国人グループとの話の中で 「?」が頭の上に飛び出した*3のが、唐突な「ベビー用品」に関する質問。どうも家族のためにベビー用品を買いに行きたいらしい。(外国人の方が日本の電化製品などを購入していくというのはよく聞く話だが、この人達の場合も同様らしい。なんか Day 1 の終了後には秋葉原にも行ったっていうし。)
PacSec Day 0 Party : 翻訳 (続き)
AVTokyo でも話した [twitter:@security4all] はかなりの日本好きだ。そればかりか、なんとスライドの大部分を自分で日本語に訳してしまったらしい。ただしここには彼なりの秘訣がある。ほとんどのスライドの要素は「単語」だけで表現してしまい、あとはスピーチで補うのだ。*4同時通訳が大変そうだと他人なりに思った。
PacSec Day 1 : 体力の限界
今回、私は発表に関して秘密兵器を準備して来た。Android タブレットである。タブレットに発表用原稿をあらかじめ入れておき、詰まったときはこれを読み上げることでカバーするという作戦だ。発想は悪くない。しかし、原稿を作るのにもそれなりの時間を消費してしまい、PacSec Day 1 に最悪な体調を持ち越すハメになってしまった。なんとか全員の発表を聞けたものの、今考えればそのまま倒れこんでいてもおかしくなかったかもしれない。さて、この秘密兵器タブレットがどう活躍したかについては…次回以降。
PacSec Day 1 : 発表
今回は Tweet が少なめだったので、内容を多めに補完。ただしスライドが公開されていないものもあり、一部しか理解していないものもある。
POC 主催者 - Vangelis : "ある経験と日本のセキュリティコミュニティへのアドバイス" ([twitter:@vangelis_at_POC])
この前の日に話した (前回参照) Kancho もスタッフとして参加する POC の主催者である Vangelis による発表。実は Kancho もスピーカーだと勘違いしていたが、そうではなかったらしい。まぁそれは置いておこう。彼の話は、特に日本人、もっと言えば、日本のハッカーコミュニティに焦点を当てている。正直この発表は「技術的」ではないし、お世辞にもスムーズに進んだ発表でもなかった、しかし、私にとってはこのプレゼンは PacSec 2010 の中では最も記憶に残ったものと言えるだろう。
日本人から見ても日本の「ハッカーコミュニティ」と呼べるものはわずかしかない。Vangeris がはせがわようすけ ([twitter:@hasegawayosuke]) 氏の言葉を引用したように、ほとんどの「ハッカー」は個人でひっそりと活動しているようだ。スピーチからは少し外れるが、日本人グループがアンダーグラウンドのハッカーをやっているという話もほとんど聞かない。*5日本人で活動している研究家ならそのままやり過ごしてしまいそうな話題だが、韓国から見ると、それ以上に見えてしまうらしい。
韓国にほぼ特有なハッカーコミュニティの特徴は、ハッカーの「正当な活動」が社会に十分に認知され、なおかつハッカーやハッカーコミュニティに対して政府の厚い支援があるということだ。これは、韓国においてブロードバンドなどを含む IT が他国を上回るペースで普及していった*6のと同時に、他国からのサイバー攻撃も集中して受けることになり、政府や社会の情報セキュリティに対する関心が極めて高いことが理由として挙げられる。*7
そう、この話が昨日の「ひとりでやっているのか?」という質問につながるわけだ。もちろんグループにもデメリットはある。しかし個人だけ、なおかつ成り行きまかせでやっていた場合、れっきとした研究や成果が葬り去られてしまうリスクも極めて高くなってしまうのだ。*8
彼が訴えたかったことは簡単には「日本人による、日本の(ハッカー|ハッカーコミュニティ)の育成」とまとめることができる。まだやるべきことは多いらしい。あ、そういえば発表の中で面白かった一幕、「日本人が主催するハッカーカンファレンスを開催すべきだ。」という部分があった。PacSec はカナダ企業が主催するカンファレンスで、「彼らが去っちゃったら日本のハッカーカンファレンスがなくなっちゃうからね」と Vangelis が言ったら、「なくならないよ!」と PacSec 主催者の Dragos。Dragos も日本のセキュリティ業界における事情 (日本のエンジニアの事情が見えてこない etc.) から PacSec を主催することを決めた人でもあるし、ツッコまずにはいられなかったのだろう。
ただ―訴える内容というのは、やはり日本人からすれば現状難しい部分というのは多い。昼食中もこの発表に関しての話題に少し参加したが、若干ネガティブな印象も受けた。日本のセキュリティ業界は終わってると堂々と喋ってたメンバーの横で色々話を聞いていたけど、それも正論なんだよなぁ。
ベルギー,BruCON 主催者 - Benny Ketelslegers : "ハッキング-コミュニティ: ヨーロッパのセキュリティコミュニティの過去と現在" ([twitter:@security4all])
そう、AVTokyo でも喋っていたあの人だ。
この人の発表はヨーロッパにおけるハッカーシーンの紹介など。27C3 や自身の主催するカンファレンスである BruCON など、例を多めにわかりやすく紹介。
(*** すみません、後で追記します。***)
Microsoft Malware Protection Center - Jeff Williams : "Stuxの板挟み"
PacSec 2009 に来ていた方のような気がする。後で確認すると、昨年の飲み会でよく喋った方であった。名刺を交換していたのでアドレス帳に残っていた。
今回の話題は、最近ニュースでもよく出るようになった "Stuxnet" の全貌について。技術的な話題も多めだが、全体としてはニュース以上のものをより詳しく解説したもののようだ。
もちろん Stuxnet の特徴として挙げられることは、その複雑さだ。複数段階の攻撃を経て、Siemens 製ソフトウェアを乗っ取ろうとする。
もうひとつの特徴は、複数のゼロデイを使用したこと。Stuxnet が使用した脆弱性は幾つかあって、まだ未パッチのもの*9も含まれる。その中でも主要な役割を果たしているのが Windows に存在する 2 つの脆弱性だ。ひとつは一躍有名になった*10 Windows の LNK ファイルに関する脆弱性。もうひとつは、Windows のプリンタスプーラーサービスに存在する脆弱性。特定のファイル名で「印刷」を行うと、そのファイルが自動的に「実行」されてしまうという*11恐ろしいものだ。
Stuxnet の解析を阻むのは複雑さだけではない。このマルウェアは権限を慎重に (複数段階のチェックを加えながら) 昇格させ、最終的に WinCC ソフトウェアへの完全なコントロールを取得する。この過程でアンチウイルスソフト、仮想マシン、サンドボックスなどによる干渉を受けたと判断した場合、それ以上の行動は何一つせずに静かに終了する。
さらに Stuxnet がもつ rootkit は、「正当な」証明書によって署名されているということも問題になった。これはエフセキュアブログの記事が詳しいが、結論としてこれらの証明書は正当な会社*12から「窃盗」されたということがわかっている。証明書が窃盗されたのなら、それを無効化すれば良いではないかというのが大勢の意見で、事実私もそう考えていた。しかし実際にはあまり助けにならないこともあるらしい。というのも、Windows のバージョンによっては証明書の無効化が適切に行われていたとしても、警告なしにドライバをインストールできてしまうからだ。*13
そこから背景にあったものは…と話は続くのだが、意識が朦朧としていたせいかその部分の記憶がほとんどない。ここは大人しくスライドを待つことにする。
University of Luxembourg - Philipp Weinmann : "隠された復讐の女神: エンベッド・コントローラーにバックドアを仕込む" ([twitter:@esizkur])
なんというか一言で言わせてください。「良くも悪くも Thinkpad 最強説?」
Thinkpad の中にあるマイクロチップ、組み込みコントローラ*14は LAN 経由でコマンドを送ることができ、それによって BIOS の内容やコントローラ自身のファームウェアまで書き換えてしまうことが可能。この部分を悪意あるものに書き換えた Thinkpad は、タイプしたキーやその他の有益な情報を外部に送信することができる。
ただし、マルウェア自身が占有できる書き換え可能領域はそれほど多く無いが、情報を圧縮することで数時間分のキータイプ (?) を記録し、それを送信することが可能。
…などなど。
"パネルディスカッション"
当日もらった予定表でも TBA のままで何なのだと思っていたが、オンデマンドにパネラーを決めるという前代未聞のシステムだとのこと。
実はパネルディスカッションが開始される直前、私にパネルディスカッションに入ってくれないかと ([twitter:@gohsuket] 氏に) 頼まれたが、断っている。*15というわけで、なぜか [twitter:@tessy_jp] さんが連れて行かれた。ここでインタプリタ (同時通訳用) なしで聞いてたことがアダになる。これまでのセッションは「発表」ということから英語だけでも「聞きやすい」のでなんとか聞けていたが、早口気味のディスカッションは難しい。(英語の訛りが酷いわけではないのだが、速さでついていけない。) 話題については…「一般人にどうセキュリティの現在を教えるか」という部分からボットネットに関する話題、セキュリティ業界に関する話題 (?) に移っていったが、あまりよく聞けていない。ボットネットを「乗っ取って」クリーンにすることの是非についての話になったとき、誰かが "never" という言葉を口にしたのが少し印象的。どんな理由があろうと、コンピュータネットワークを乗っ取ることは良い考えではないという風に解釈。
PacSec Day 1 : 記者会見
記者会見に臨んだ記者は朝日新聞の方と [twitter:@sen_u] 氏を含む Hacker Japan 関連の人たち。私の分はそれなりに無難に話せた。が機転が利かず、ちょっとした喩え話とかで分かりやすく説明する計画がパァである。Dragos は日本「特有」の環境について質問を受けていて、日本はある部分ではものすごく進んでいるのに、一方ものすごく遅れている部分もある、というアンバランスな環境だという説明をしていたのが印象的か。
PacSec Day 1 : レセプションディナー
去年は 2 日を通して体調が悪かったため、レセプションディナーで話した人数もある程度限られていたが、今回は色々なところを回って話をしたりあるいはそれを聞いたりすることに成功。私の (PacSec でないそれ以前の、ブログでは旧アカウントに載せていた) 成果について見てくださっていた方もいて、本当に色々な話ができた。体調が悪いのはどこへやら。*16
思い出そうとするだけでも記憶がグルグルする。色々なコトが高エントロピーで記憶されていることで、少し混乱してしまうのかも。
PacSec Day 1 after
本当は原稿の完成度を少し上げようと思っていたのだが、疲労感からして遅く寝ると発表当日に酷いことになることは分かりきっているので、意図的に早く切り上げた。相当の疲れが溜まっているだろうし、強めの栄養ドリンク、カロリーメイト、レッドブルの基本三点セットを購入し、深い眠りについた。このことが今回功を奏したといってもいい。
*1:質疑応答の時間に質問してくれる方はいなかったのだが、その後に色々具体的な話について聞かれることが多かったのだ。これについては次回以降。
*2:JIT コンパイルしたコードについて、「そんなやり方で大丈夫か?」「問題ない。」さらに効率的なコード生成のために「一番良いエンコーディングを頼む。」までセットで。
*3:まるで MGS シリーズのように!
*4:AVTokyo で彼の発表を見ている方なら知っているとおり、もちろんトルーパーがスライドの至るところに登場する。
*5:本当にわずかしかいないのか、あるいは外国のハッカーチームと組んでいるか、のいずれかだろう。
*6:その大部分が Microsoft 製テクノロジである、というのはある意味笑えない話である。
*7:私はこれ以外にも、韓国の政治体制と経済規模が、急な政策の変更を行いやすい地盤となっていると推測した。もちろんこれは政情不安定というデメリットも産んでしまうが、情報セキュリティに関してだけ言えばプラスに働いたと言えるだろう。
*8:私がこの話題に関して (時には過剰に) アウトプットを重視し、未完成にも関わらず PacSec 2010 の発表に応募したのには、この理由もある。精神異常者一人きりに任せてこの話題を忘れさせてしまうより、マトモな公開資料の形で残しておきたかったのだ。
*9:私のノート PC にも見つかってしまった!
*10:Stuxnet が初出ではない! これについては Jeff が解説した。
*11:ここでは技術的概要を思いっきり省く。Jeff のプレゼンではもう少し詳しく解説された。
*12:ただしソフトウェアのための証明書は購入すらしていない。
*13:これは同じ例なのか定かではないが、x86 版においてはサービス操作系の API を使用することにより、任意の非署名ドライバを警告抜きにロードすることができる。x86 版においてドライバや rootkit 開発は、通常その手段を使うからね…。
*14:具体的な名前はメモするのを忘れた。
*15:流石に、日本と世界をつなぐセキュリティカンファレンスで、どっちも知らない (業界で働いてすらいないし、その事情さえ見えていない) 私が入ったらダメでしょ。
*16:もちろん体調がよくなっているわけではないことは分かっている。痩せ我慢では 2 日目はもちそうにない。
私の目から見た PacSec 2010 (1)
なんで自分語りばかりのエントリに星がついたのか謎だが、今回からマトモな話題です。
AVTokyo 2010 (昼の部)
会場の場所がわからず、BS ホールではなく「本社まで」行ってしまった。往復 1.5km の無駄足だった。とりあえず遅刻しながらも昼の部会場まで到着。(白夜書房の親切な社員の方に道を教えてもらいました。) 席のとなりには [twitter:@yasulib] と [twitter:@ichirin2501] という三鷹病*1メンバー。どうも両者とも CTF に夢中なようだ。*2
これに関しては、やはり CTF に関する話題が圧倒的に多かった。というよりかなりの豪華メンバー。個人的な CTF への興味は最近高まってきているが、これらのセッションは CTF に対してさらに興味を高めることになった。個人的にツボだったのは次の二箇所か。
- (福森さん? の発表において) CTF 会場で頒布される USB メモリには autorun.inf とともにマルウェアたんまり。マヌケにも Windows をそのまま使うような阿呆は Wall of sheep に晒されても文句言えないということか。
- (愛甲さんの発表において) CTF 1 位のまま終了かと思いきや、「1 時間延長します☺」
あとは休憩時間とかの合間に [twitter:@ichirin2501] に私が「三鷹」にたどりつく途中の方法を教えてみた。これは key が何かという部分を無視するだけでもここまで到達できるという例で、面白く見てもらえた。これはネットエージェントの問題 (第二問) なのだが…
- 最初の 6 バイトの分布が明らかに偏っていて、しかも 3 バイト毎の構造が見えるので、UTF-8 文字列を疑う。
- しかし、このままでは UTF-8 文字列としては解釈できない。*3
- そこでこのバイト列の本質を隠しているのが xor 暗号であったと仮定して、少なくとも最初の 6 バイトに関しては 0x60〜0x6f というバイト*4で暗号化されたと考えれば、ピッタリ正規の UTF-8 文字列になる。*5
- 同じように考えると、最後のほうは数字または ASCII 記号かもしれない。
- しかし、"key" が何を示しているかがわからず、つい最近まで「三鷹」に辿りつけず。SHA-1 でググればよかったと後悔。
という具合。
あとは白夜書房の販売ブースで面白そうな本を見つけたのでこれも買ってみたり。
終了後、私はホテルにトランクいっぱいの荷物を下ろすために早めに離脱。直前に予約したホテル (御茶ノ水駅付近) はなかなか快適だった。
AVTokyo 2010 (本体)
実のところ、ロフトで開催される AVTokyo に参加するのは初めてだ。ロフトに来るのは初めてなのにどこかで見たと思ったら、多分ニコ生で放送されてた何かの番組がここ使ってたと思い出す。
セッションについてはこんな感じ。(AV! とかはきっと別の人がまとめてくれてるはず…!)
はせがわようすけ : "Internet Explorer exSpoilt Milk codes"
IE には未修正の脆弱性が(ry(ry というお話。このへんの話は "ブラックハットジャパンその後" で話しておられた話題とほぼ同じだったので割愛。ただ、質疑応答や余談がなかなか面白かった。MSFT の中の人に "なんでこんなに脆弱性を探してくれるんだw" と圧迫面接 (?) を受けたりとかしたらしい。
TAKESAKO : "no-alnum x86 programming"
x86 で任意コードの実行をたった 7 種の文字 (英数字以外でしかもエスケープされにくい文字のみ) で実行できたぜというお話。少ない文字でシェルコードを書くというのは "HACKING: 美しき策謀" (isbn:4873112303) にも載っていた話だが、これは英数字と一部記号で 10 種。対してこちらは printable な記号のみ 7 文字と優っている。質疑応答では長谷川氏と変態度 (JavaScript の場合任意コードを記号 6 種で書ける。) について競いあうなどかなり面白い話だった。
[twitter:@security4all] : "2010年のダメダメセキュリティ"
PacSec 2010 の発表者でもある [twitter:@security4all] こと Benny 氏だが、今回の話題は PacSec 2010 の発表とは全く異なる内容。セキュリティにおいても、特に人的ミスが原因の事例についてのおさらいというなかなか (バイナリ漬けの私にとっては) 新鮮な話題。例として、最近話題の Stuxnet は、工場などの制御ソフトウェアである WinCC に対して「デフォルトパスワード」でログインしようとするのだが… Siemens (WinCC の開発元) はこのデフォルトパスワードを「変えるな」と言っていたらしい。そのおかげで多数の WinCC ベースのシステムが危険に晒されうるという結果に。
ChakYi & Externalist : "Code Injection for Nintendo Wii"
この人達も PacSec 2010 の発表者。内容は PacSec 2010 における発表のダイジェスト版と言っていいかも。(ただし Externalist はこの時点で日本に来れなかった。PacSec 2010 には参加してらっしゃったと記憶している。)
海賊版を実行出来る状態というのは、「認証されていないすべて」を実行できる状態であるのと等価であるのと同時に、マルウェアを簡単にインストールできる状態にあるというのと等価である。彼らの発表は実践的なデモが多いのが特徴で、DS に Metasploit 移植版をインストールしてハッキングステーションにする、Wii の海賊版にウイルスを混ぜ込み、ゲームがちゃんと動いているにも関わらずバックグラウンドでホームネットワークに侵入する*6などなど。
昔 PSP 用ゲームソフトの海賊版に「実行したらシステムファイルを破壊して二度と起動しなくなる」罠が入ってた (しかもそれが主に Share ネットワークで氾濫してた) ことがあったが、これはゲームのバイナリそのもの (BOOT.BIN、中身は ELF ファイル) を破壊してそこにトロイの木馬を上書きしていた。それと比べると、彼らの発表内容はかなり進化している。
もちろんだが、これは DS や Wii の問題ではない。ネットワークエコシステムの問題でもあり、また全く対策ができないというわけでもない。
彼らの締めの言葉は、"海賊版の実行は自己責任で!"
wakatono : "Drive by Download攻撃定点観測"
私が知らない方…かと思いきや、去年 AVTokyo 2009 の発表後に質問をされてた方で、しかもその後の飲み会でも色々喋ってた方だったことを思い出した…というより、この後の飲み会で教えてもらった。Drive by Download 攻撃の具体的な内容について、特定の 1 サイトについて観測を行ったとのこと。印象的だったのは、
- いつも攻撃された iframe が存在するわけではない (一時的に戻されているときがある。)
- ダウンロード先のサイトは刻々と変化し、しかもドメインのトレンドも観測期間中に変化していった。
ということ。
あとはオフレコ。
面白い話題であったことだけは確かだが、バラすと大変なことになりそうなモノも含まれるので割愛。でも "愛奴&愛花 テヘッ☆" の発表はオフレコじゃなくても良いような気がするんだけどな〜。
AVTokyo その後飲み会
23〜「29時」という凄い日程の飲み会。去年の飲み会は割と早い段階で (少なくとも二次会は) 終わってたので、今回はかなり濃い内容について話せた。
- 仮想マシンについて色々とか、
- セキュキャン参加者のアウトプットとか、
- 海外とのつながりについてとか、
- うさぎについてとか、
とにかくたくさんの話題が出た。
飲み会の場所は新宿近く、対してホテルは御茶ノ水。タクシーで帰れない距離ではないが金がもったいないので、意地でも起きて始発まで間を持たせることにした。ノート PC で色々しながら喋っていたのだが、飲み会終了間際に―― AC アダプターが (ピンクがかった赤色の) 火花を吹いて壊れるという大変なことに。*7まぁそれはともかく無事に飲み会も終了したので、ホテルに帰った途端スイッチが切れたように眠るのであった。
AVTokyo〜PacSec
とにかく英語版スライドを完成させなければならない。日本語版も若干の修正を加える必要がある。というわけで、起きても気は抜けない。というか、締切りはとっくに過ぎている。(日本語と英語両方のスライドを出せる場合にはスライド提出期限はかなり遅めなのだが、それすら通り越してしまったのだ。) しかし AC アダプターは壊れてしまっているので、先に秋葉原 (御茶ノ水からであれば徒歩で行ける) でアダプターを買ってから作業をすることになった。そこから徹夜して、8 日の朝にスライドを両言語とも完成させることができた…が、なぜか正常に PDF 変換できない!具体的には、PrimoPDF を使って正常に PDF を吐き出すことができなかったのだ。家の同一環境 (と思い込んでいる) では吐き出せたのに。色々設定を変えてもうまくいかない。PowerPoint 付属の PDF 出力はフォントがラスタライズされた上にファイルサイズがメール添付できる限度を超えてしまう。Adobe Acrobat の体験版を急遽 (ホテルの遅いネットワークで数時間かけて) ダウンロードし、正常に PDF にできたのが昼過ぎ。
あとは私の泊まっていたホテルは外出して鍵を預けているかどうかでルームクリーニングをするか否か決めているらしく、私が部屋にいる限り部屋は掃除されない。というわけで通りすがりのスタッフの方に部屋のタオル交換だけをお願いした。ご迷惑をおかけした…。
翌日―― 11/9 がこのホテルのチェックアウト日なのだが、チェックアウトしてから PacSec スタッフ側で予約されているホテルのチェックインまでかなり時間がある。…しかし、ぶっちゃけどこに行くのにも苦労する。APEC による厳戒態勢のおかげで、駅のコインロッカーは軒並み封鎖されている。*8結局渋谷駅前で暇つぶしをするしかない。*9まぁ時間さえ潰せれば迷うことはそれ以外ほとんどなく、前回同じホテルを利用していただけにすんなりとホテルに入ることができた。
PacSec 直前の飲み会
この飲み会は PacSec の前日にあり、顔合わせをする良い機会となる。ホテルの待ち合わせ時点で少なくとも 5 人のスピーカーと顔を合わせ、かなり色々な話題について話した。*10去年から英語の「勉強」はほとんどしていないものの、話は聞けるようになったしある程度話せるようにもなった。(時々脳内ですごい誤訳をやらかすことがあるけど。) 横にいたのが POC*11 の韓国人スタッフである Kancho*12 氏。彼と話したことがすごく印象的であったのだが、なぜ「印象的」であったのかは PacSec の発表当日にわかることになる…。
自己紹介の過程で聞かれたのは、「あなた (私のこと) は個人で――ひとりでやっているのか?」ということだった。答えは Yes。企業で働いているわけではないし、チームメンバーと一緒に活動をしているわけでもないのだ。もちろん sutegoma2 のメンバーでもない。彼は言った。「誰かと一緒にやるべきだよ。なぜかというと…ひとりでやっているというのは…ある意味弱いってことだからね。」この言葉自体は当たり前に聞こえるのだが…話すときの言い方に、それ以外の何かが見え隠れしているような気がしたのだ。
途中で PacSec のスライド翻訳担当 (のひとり?) である櫻井さんも合流。聞いたところ、彼が翻訳に参加したのは、当時の PacSec におけるスライド翻訳の「酷さ」があったそうなのだ。当時の翻訳は主にプロの翻訳者に任せっきりだったそうなのだが、文脈を無視した翻訳 (例えば、そのままでないとマズい設定ファイルの内容を翻訳してしまったりとか。) などなどの問題があり、参加することになったのだとか。
その後も色々な話に華を咲かせた…。
次回予告
次は PacSec 1 日目について話せれば良いと思う。分量が足りなければ 2 日目の一部も追加する方向で。
*1:突然 xor 暗号や UTF-8 を暴きだしたりあるいは突然三鷹と言い出したり果ては実際に三鷹市に行ってしまう病気のこと。
*2:私の場合、30 分でバッテリー切れするノート PC では勝負にならないと判断した。
*3:ビットシーケンスが UTF-8 のものと「逆」になっている。
*4:ASCII では小文字の英字に相当する部分だ。
*5:2,3,5,6バイト目は 0x70〜0x7f で暗号化されていてもつじつまが合うため、ますます英小文字の疑いが濃厚に。
*6:そう、家庭のネットワークにつながっているということは、そこに対して攻撃も可能だということだ。ルーターなどのファイヤーウォールは既に (海賊版を自身が実行することによって) 突破されているわけだからね。
*7:非公式の充電器は怖い。とくに安い中国製は、と思い知らされました。
*8:その割にはゴミ箱は使えたりとか中途半端である。
*9:私の隣で待ち合わせをしていたであろうオタクっぽい人が職質を受けていた。会場から離れていてもこれだけの厳戒態勢なのだ。
*10:余談のひとつだと、「ハックを漢字であらわすと何になる?」と聞かれて、日本人スタッフのひとりである金森さんと一緒に悩んでみたりとか。
*11:Power of Community カンファレンス。韓国で開催される最大級のセキュリティ系イベント。彼らのウェブサイトは http://www.powerofcommunity.net/
*12:日本語だと凄い危ないという…w
私の目から見た PacSec 2010 (0)
今回は PacSec 以前の話となります。自分語り多めどころか全部そうです。
まずは前回 (PacSec 2009) 直後から。
前回も、私は PacSec において発表させてもらった。話題はライブメモリフォレンジックを妨害するための rootkit という、ものすごくマイナーなネタだ。これは Shadow Paging モドキ (←ここは重要。本当の Shadow Paging と使って仮想化支援機能を必要としない。) を使ってメモリの内容をフォレンジックソフトウェアから隠し、正常な取得と、それに依存する解析を妨害するという話だ。
PacSec の前後には、主催者、スタッフ、スピーカ、また一部の参加者を含めた飲み会があったりする。私が参加したのは直前と直後の二回だ。
当時私は学校を中退したままこれといった職を持っていなかった。(今もそうなのだが。) これを知った (主催者である Dragos を含む!) 一部の方が私をセキュリティ専門のチームに紹介するという話になっていった。実のところ、そこでのことは高揚感で一部が曖昧になっている。(その時泥酔していたのもその理由のひとつだ。)
AD/HD
同時に、私は精神に問題を抱えていたようだ。精神科の通院によって全く問題のないところまで回復し、当時も薬の量はおまじない程度だった。しかし―――精神の状態が極めて良くなっても、そして PacSec が終わってしばらくしても、物事に対する集中力だけは回復せず…ロクにプログラムを書くことすらできなくなっていった。このままでは仕事を紹介してもらっても役立てそうにないと、Dragos らにお断りのメールを送ったのは苦い思い出だ。
しばらくして、その症状が注意欠陥多動性障害 (ADHD; AD/HD) によってもたらされるものとそっくりなことに気がついた。これは完治 (あるいは寛解) させる方法こそ見つかっていないものの、適切な投薬さえ受ければ症状をかなり抑えることができる先天性の発達障害だ。しかし、この「適切な投薬」というのが曲者だ。しばらく前まで、AD/HD のための主要な薬はリタリンであった。脳の機能を活性化させ、集中力などの障害を抑えるように働くらしい。しかしこの薬は、依存性の問題などが取りざたされてから AD/HD への適用 (正確には、AD/HD と併発することの多いうつ病への適用) が取り消されてしまった。
ではそれ以外のチョイスは? 2010 年現在、日本で AD/HD に対する適用があるのは次の 2 つだ。
このうちコンサータは禁止されたリタリンと同一の成分を含む (どころか、コンサータはリタリンと同成分の徐放薬である。) ため処方できる医師が限られており、しかも 18 歳以上への適切な処方はできないようだ。ストラテラは 18 歳以上は適用外であるものの処方は容易であり、当時私の選択はこれしかなかった。しかしストラテラという薬に関してあまり良い印象はない。最初は集中力に大してある程度効果を発揮したものの… 3 週間程度で耐性のためか効果を失い、極端な抑鬱症状で回復していた精神を極端に揺さぶることになってしまった。
諦めて数ヶ月し、これ以上引き伸ばしはできない、そういうとき、県外の医師を見つけた。もちろん成人に対してコンサータの処方をするとは公式に謳っているわけではないが、是非もなく私は飛びついた。これで駄目ならセキュリティ分野を諦めて、単なるニートとして過ごすか、あるいは××することすら考えた。
診断ではいくつかの質問をされた。加えて医師は母親に、私に関する生育歴、また出生時の事故や病気がなかったかなどを聞いた。診断結果は――アスペルガー症候群 (診断名には含まれないが、AD/HD との併発)。コンサータの処方も可能とのことだった。投薬の結果は今のところ良好といえる。ストラテラのような酷い副作用はなく、(それでも喉が乾くなどの副作用はある。有名な副作用が食欲の減退と体重減少だが、私の場合抱え続けていたストレスから開放されたせいか、体重は逆に微増した。) ほんの少しずつだがプログラムの実装ができるようになっていった。
PacSec 2010 へ
それなら、去年から思い浮かべていたアレを実現に移すときだ。実は AVTokyo 2009 の資料 (仮想化に関連するモノ) に、その断片がある。読み取ったメモリ内容などを保存して、プログラムのすべての動作を再現するという、いわゆるトレーサだ。あの後実現手段を必死に考えて、より良い手段―― PacSec 2010 の発表におけるものとほぼ同じ ――にまで到達していた。これを応用すれば、1MB/s のトレースでプログラムの全部をキャプチャすることも夢ではない。
形は見えている。実装の手段も手の内にある。それで実装しなければ何なのか。
念の為に言っておくと、コンサータを摂取したとしてもスーパーマンになれるわけではない。あくまで集中力を適切に出すことを「助ける」だけだ。プログラムを長く書いていなかったことによる不慣れさと、自分の怠け癖のおかげで苦労こそしたものの、実装と論文の形が見えてきた。実のところ、論文は実装がほとんどマイクロベンチマークのみという状態で提出したのだが、数値シミュレーションによる結果を掲載することで説得力を高める努力をした。
PacSec 2010 通過の知らせがくるのはかなり遅く、10月5日だった。ぶっちゃけ諦めかけていたところへの突然の通過の知らに、深夜 3 時だったにも関わらず思わず声を出して驚いた。
それでも、実装が進むのは遅い。ずっと前からデモを行うための最低限の機能を実装することを目標に安全性の大部分を切り捨てたにも関わらず、ライブデモを PacSec 会場で行うことは絶望的という状況。…ならライブデモなしで十分面白くしようと、プレゼンはそれなりに凝らして作った。しかし東京に出発するまでに英語版の方を完成させることができず、AVTokyo 終了後から翻訳を徹夜でやるというスケジュール的に厳しいモノとなった。(誰だよライブデモさえなければ余裕とか言ってたのは ←お前だ)
(続く ― 次は AVTokyo 当日〜 PacSec 前日まで。)
PacSec 2010 で発表してきました。
去年の別のネタ (アンチフォレンジック) に比べれば噛むことも少なく、全体としては安定した発表になった。(それが「良い」かどうかは別として。)
さて、今回の発表は "Record and Replay" に関する VMM の設計技術に関する部分。つまりどのように VMM を実装することができるか、そのオーバーヘッドはどうなのかという点に関して焦点を当てたものとなっている。残念だったのは、そこまでに十分なデモをできるほどにトレーサが完成しなかったという点。完全に学術論文の読み上げだけじゃねぇかとツッコまれても文句言えません、割とマジで。
ベンチマーク
今回の発表においては、若干ではあるがマイクロベンチマークの結果を載せている。どんなコードを実行したんだ!とかそもそも比較対象がわからないとかはそもそもが (VMM の特性を図るための [しかも洗練されていない]) マイクロベンチマークだったのでご容赦を。
実装からして私はなんとなく予想していたのだが、"Record and Replay" を実装した VMM のうち、トレースを取得する部分固有のオーバーヘッドはわずかであった。つまり、最適化はある程度阻害される可能性こそあるものの、VMM が速ければトレースもほぼそれだけ速くなる。
「未定義」の範囲は?
「未定義」の EFLAGS の値について、実際にはどのような挙動になっているのか、という質問を後から頂いた。会場でも話したのだが、ここでも参考のために掲載。
「未定義」というのには色々幅があって、乱数が格納されてもおかしくないし、定数になったり、結果の一部になったり、あるいは実際にはほかの予測しやすい結果だったりする。実は、最近の Intel および AMD のプロセッサにおいては、これらの「未定義」の部分は「変化しない」とみなせる。Intel 製のプロセッサにおいて本来の意味での「不定値」を持っていたのは Pentium 4 までで、Core 以降はこの部分の予測不能さはほぼ失われている。
そう、実は私が話した「EFLAGS の遅延評価」というのは、機会さえあれば真っ先に外しても良い部分なのだ。――もちろんそれに対応する (例えばこのような手法で保存した、ということを宣言する) メタデータをきちんと保存したと仮定した場合の話だが。私がこれにこだわったのは、「(プロセッサの長期的なモデルの変化など) 長期間の保存に耐えうる情報を残す」という前提があるためで、それが難しくなり、なおかつ後からでも (超越演算命令のように、内部を補完し辛いものではなく) 容易に補完が可能であるのなら仕方なかろう。
反響
色々な方と喋ったことのうち、多かったのは次のようなことだ。
- 役に立ちそう。
- もう少し具体的な内容が見れるとよかった。
後者については謝るしかないのだが、前者については私も同じことを思っていて、しかも「なぜこれが今になって埋れているのか」と憤慨すらしている。というのも、基礎となる学術論文は 8 年前に、しかもれっきとしたセキュリティ分野である「Intrusion Analysis (侵入解析)」をテーマとして発表されているにもかかわらず、セキュリティ分野に対する応用をほぼ発見することができなかったためだ。
これについては、当時の計算量がこれを動かすのに現実的ではなかったという可能性とか、あるいは実装の難しさなどがあるのではないか、という話になった。
次回予告
次回以降、私から見た PacSec 2010 をダイジェストでお送りします。
プリプロセッサで型名を自動整形 (C/C++ 両対応)
C++ と C で同じ内容の型を定義したいときがある。しかも、C++ ではちゃんと名前空間に入れて、さらに C では名前空間に対応するユニークな名前で修飾しておきたい場合とかも。というわけでこれに対応するためのマクロを Boost.Preprocessor を使って書いてみよう。
その前に、このマクロを使って書いたサンプルのヘッダファイルの一部がこんな感じ。(nvm は単なるプログラムの内部名称。)
/** (前略) **/ #define nvm_ccompat_namespace (nvm, (kernel, NVM_CCOMPAT_NAMESPACE_TAIL)) #include <nvm-fix/ccompat/namespace_begin.hpp> /* { */ typedef struct NVM_CCOMPAT_TYPE_DECL_TAG(sample_t) { /* .... */ } NVM_CCOMPAT_TYPE_DECL(sample_t); typedef struct NVM_CCOMPAT_TYPE_DECL_TAG(sample2_t) { /* .... */ NVM_CCOMPAT_TYPE(sample_t) mem; } NVM_CCOMPAT_TYPE_DECL(sample2_t); #include <nvm-fix/ccompat/namespace_end.hpp> /* } */ /** (後略) **/
実装はかなり好みに左右される。前もってヘッダをインクルードした上でマクロ宣言を使っても良いのだが、ここで定義した nvm_ccompat_namespace の後片付けをフレームワーク側ですることを考慮し、このように namespace_begin.hpp と namespace_end.hpp の 2 つで囲う実装になっている。
マクロは自動的に後片付けされる上にそもそもソースコード側でマクロを使わないために作ったヘッダなので、これらの生成された型を使用するには C と C++ 各々の自然な名前を使用する。
/* 使用法 : C++ の場合 using namespace による省略も使えるが、 名前空間に配置されていることを確認するために明示的な記述をした。 */ #include <nvm/sample.hpp> void sample(nvm::kernel::sample2_t value) { nvm::kernel::sample_t m = value.mem; }
/* 使用法 : C の場合 */ #include <nvm/sample.hpp> void sample(nvm_kernel_sample2_t value) { nvm_kernel_sample_t m = value.mem; }
見てわかるとおり、C++ においては名前空間内に修飾されない型が配置されるのに対して、C では名前空間に対応する名前 (この場合 nvm_kernel_) で修飾を受けた型名を使うことになる。
マクロ展開された結果はおおむね次の通り。(空白、改行などは一部分かりやすいように改変している。)
/** (前略) **/ namespace nvm { namespace kernel { typedef struct TAG_sample_t { /* .... */ } sample_t; typedef struct TAG_sample2_t { /* .... */ ::nvm::kernel::sample_t mem; } sample2_t; }} /** (後略) **/
/** (前略) **/ typedef struct TAG_nvm_kernel_sample_t { /* .... */ } nvm_kernel_sample_t; typedef struct TAG_nvm_kernel_sample2_t { /* .... */ nvm_kernel_sample_t mem; } nvm_kernel_sample2_t; /** (後略) **/
では、これをどのように実装しているかを見てみよう。
実装
勘の良い人なら (#define nvm_ccompat_namespace の宣言で) わかるように、これは Boost.Preprocessor の list 機能を使っている。勘違いされがちなのだが、Boost は必ずしも C++ 向けのライブラリではない。特に Boost.Preprocessor は、標準準拠の C コンパイラならすべての機能を使うことができる。
nvm_ccompat_namespace の宣言で使っているデータ構造は Boost.Preprocessor では list と呼ばれるデータ構造だ。*1このデータ構造を、プリプロセッサを使って弄り倒してみる。
では namespace_begin.hpp の方を見ていこう。
list の使用宣言
#define NVM_CCOMPAT_NAMESPACE_TAIL BOOST_PP_NIL #include <boost/preprocessor/list.hpp>
NVM_CCOMPAT_NAMESPACE_TAIL は単に名前付けのルールを統一するためのものだ。実際のところ、マクロは展開される (使用する) 場所で実際に展開されるため、namespace_begin.hpp や
名前空間スコープ
次に、スコープを定義しよう。
#ifdef __cplusplus /* C++ のみ */ #define NVM_CCOMPAT_NAMESPACE_BEGIN_I(r,data,elem) namespace elem { BOOST_PP_LIST_FOR_EACH(NVM_CCOMPAT_NAMESPACE_BEGIN_I,:,nvm_ccompat_namespace) #undef NVM_CCOMPAT_NAMESPACE_BEGIN_I #endif
ここでは C++ に限り名前空間を展開する。ここで、あらかじめ定義されていたマクロである nvm_ccompat_namespace がリストとして評価、さらに各要素がマクロ展開される。言うまでもないけど、C 言語の場合は __cplusplus の定義に阻まれてこの場所は空白に展開される。
BOOST_PP_LIST_FOR_EACH(NVM_CCOMPAT_NAMESPACE_BEGIN_I,:,nvm_ccompat_namespace) >> BOOST_PP_LIST_FOR_EACH(NVM_CCOMPAT_NAMESPACE_BEGIN_I,:,(nvm, (kernel, BOOST_PP_NIL))) >> NVM_CCOMPAT_NAMESPACE_BEGIN_I(nvm) NVM_CCOMPAT_NAMESPACE_BEGIN_I(kernel) >> namespace nvm { namespace kernel {
型の定義名と使用名
型に関しては単純な定義ルールを採用しても良いのだが、名前空間に関連する混乱を避けるため、次のルールに従う。
- 宣言時 (NVM_CCOMPAT_TYPE_DECL マクロで定義)
- 使用時 (NVM_CCOMPAT_TYPE マクロで定義)
この両方を満たすため、2 つのマクロを使用することに。まずは宣言時、NVM_CCOMPAT_TYPE_DECL マクロから。
#ifdef __cplusplus /* C++ の場合 */ #define NVM_CCOMPAT_TYPE_DECL_I #define NVM_CCOMPAT_TYPE_DECL(clsname) clsname #else /* C 言語の場合 */ #define NVM_CCOMPAT_TYPE_DECL_I(d,data,elem) elem##_ #define NVM_CCOMPAT_TYPE_DECL(clsname) BOOST_PP_CAT(BOOST_PP_LIST_CAT(BOOST_PP_LIST_TRANSFORM(NVM_CCOMPAT_TYPE_DECL_I,:,nvm_ccompat_namespace)),clsname) #endif
ここでは C 言語のほうが (名前空間をプレフィックスとして付加するために) 複雑な実装になっている。
C++ のほうは単純。clsname を clsname と展開するだけ。ここでは C/C++ 両言語で全く同じマクロを定義し、後で #undef するため、ダミーのマクロ定義も含んでおこう。
C 言語の方は、プリプロセッサレベルで次のように動作する。
- 名前空間リストの各要素を、最後に _(アンダースコア) が付くように設定する。(BOOST_PP_LIST_TRANSFORM)
- リストの全要素を 1 つの識別子として連結する。(BOOST_PP_LIST_CAT)
- 最後に、clsname を連結する。(BOOST_PP_CAT)
具体的な展開の内容は次のようになる。
BOOST_PP_CAT(BOOST_PP_LIST_CAT(BOOST_PP_LIST_TRANSFORM(NVM_CCOMPAT_TYPE_DECL_I,:,nvm_ccompat_namespace)),sample_t) >> BOOST_PP_CAT(BOOST_PP_LIST_CAT(BOOST_PP_LIST_TRANSFORM(NVM_CCOMPAT_TYPE_DECL_I,:,(nvm, (kernel, BOOST_PP_NIL)))),sample_t) >> BOOST_PP_CAT(BOOST_PP_LIST_CAT((NVM_CCOMPAT_TYPE_DECL_I(nvm), (NVM_CCOMPAT_TYPE_DECL_I(kernel), BOOST_PP_NIL))),sample_t) >> BOOST_PP_CAT(BOOST_PP_LIST_CAT((nvm_, (kernel_, BOOST_PP_NIL))),sample_t) >> BOOST_PP_CAT(nvm_##kernel_,sample_t) >> BOOST_PP_CAT(nvm_kernel_,sample_t) >> nvm_kernel_sample_t
リファレンスを片手に読むと、順番にリストや識別子が変形していることがわかるだろう。
さて次は使用時の型名だ。こちらはさほど難しくはない。
#ifdef __cplusplus /* C++ の場合 */ #define NVM_CCOMPAT_TYPE_I(d,data,elem) ::elem #define NVM_CCOMPAT_TYPE(clsname) BOOST_PP_LIST_FOR_EACH(NVM_CCOMPAT_TYPE_I,:,nvm_ccompat_namespace)::clsname #else /* C 言語の場合 */ #define NVM_CCOMPAT_TYPE_I #define NVM_CCOMPAT_TYPE(clsname) NVM_CCOMPAT_TYPE_DECL(clsname) #endif
C 言語版は宣言時の型名をそのまま使えるのでそこへのリダイレクト。C++ においては、BOOST_PP_LIST_FOR_EACH を使って、次のように展開している。
BOOST_PP_LIST_FOR_EACH(NVM_CCOMPAT_TYPE_I,:,nvm_ccompat_namespace)::sample_t >> BOOST_PP_LIST_FOR_EACH(NVM_CCOMPAT_TYPE_I,:,(nvm, (kernel, BOOST_PP_NIL)))::sample_t >> NVM_CCOMPAT_TYPE_I(nvm) NVM_CCOMPAT_TYPE_I(kernel) ::sample_t >> ::nvm ::kernel ::sample_t >> ::nvm::kernel::sample_t (←マクロ展開ではなく、C++ 言語における型名の解釈)
BOOST_PP_CAT 系を使っていないのは、これらは識別子を連結するためにしか使えず、また C++ の "::" は演算子であるため、自動的に、かつ適切に区切られるから。
構造体タグ
上では、今まで定義しなかったマクロが 1 つだけ使われている。NVM_CCOMPAT_TYPE_DECL_TAG(clsname) だ。これは無名構造体になることを避けるための構造体タグを名付けるためのユーティリティマクロであり、次のように定義される。
/* 両言語共通 */ #define NVM_CCOMPAT_TYPE_DECL_TAG(clsname) BOOST_PP_CAT(TAG_,NVM_CCOMPAT_TYPE_DECL(clsname))
これだけで OK。
namespace_end.hpp
namespace_end.hpp の実装は極めて単純だ。ここではソースコードの一部をそのまま貼り付ける。
#ifdef __cplusplus #define NVM_CCOMPAT_NAMESPACE_END_I(r,data,elem) } BOOST_PP_LIST_FOR_EACH(NVM_CCOMPAT_NAMESPACE_END_I,:,nvm_ccompat_namespace) #undef NVM_CCOMPAT_NAMESPACE_END_I #endif #undef NVM_CCOMPAT_TYPE #undef NVM_CCOMPAT_TYPE_I #undef NVM_CCOMPAT_TYPE_DECL #undef NVM_CCOMPAT_TYPE_DECL_I #undef NVM_CCOMPAT_TYPE_DECL_TAG #undef NVM_CCOMPAT_NAMESPACE_TAIL #undef nvm_ccompat_namespace
名前空間スコープを終了させるのは開始するものと使用するマクロの内容が異なるだけ。それ以外は、namespace_begin.hpp で定義されたマクロ等を #undef するだけと単純そのもの。実際には namespace_begin.hpp、namespace_end.hpp ともに幾つかの安全策を施しているが、ここでは省略する。
まとめ
ここまでやってもこれを使う機会があまりない (内部構造体を外にだすこと自体が少ない) のは残念だが、見た目としては非常に面白いものに仕上がった。Boost.Preprocessor の力も再確認できたことだし、今回はこれで満足。