[-]=======================================================================[-] Wizard Bible vol.48 (2009,10,6) [-]=======================================================================[-] x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x ---- 第0章:目次 --- x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x ○第1章: ダビングできねーし!! 嶋崎 聡 著 ○第2章: Intel x86命令の構造 version 2 〜 x86簡易ディスアセンブラの作成 大原まひる 著 ○第3章: レイヴパーティーの現状と2次元児童ポルノ規制の類似点 ローリングクレイドル 著 ○第4章: 基礎暗号学講座・第23回 〜コミットメントスキーム〜 IPUSIRON 著 ○第5章: お知らせ ○第6章: 著者プロフィール x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x --- 第1章: ダビングできねーし!! --- 著者:嶋崎 聡 x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x ■0x01.) はじめまして  WBを読んでいるみなさま、はじめまして。2009/09に発売する「クラッカーの教 科書」を書きました、嶋崎と申します。今回、IPUSIRONさんとまどさんに「WBの 紙面、ちょっとあげるから、宣伝したらいいよ」と許可が出ましたので駄文では ありますが、簡単な自己紹介がてら書かせていただきました。よろしくお願いし ます。 ■0x02.) ぼくのかんがえたさいきょうのくらっかー  「クラッカーの教科書」という大それたタイトルをつけていただいた本を書く くらいなので、「お前は相当なやつなんだろうな!」と思っている方もいると思 います。  しかし、あの本には「もうこれさえあれば大丈夫な魔法のツール(笑)」とか「 これ以上ないくらいすごいテクニック公開(笑)」とか「この方法で俺はナンパに 100%成功し続けています!」みたいなことは書かれていません。  自分ですごいと思ったところは「ねずみさんに書いてもらった」ことでしょう か。  それだけでも読んでもらう価値はあるんじゃないかと思います。  そして、今回はここに書く機会をいただきましたので、過去自分がどんなきっ かけから解析なんてものをはじめたのか、ということを書いてみたいと思います。 興味ねーよって人もいるかとは思いますが、なにかの暇つぶしに読んでください。 ■0x03.) 003.ダビングできねーし!!  今でこそ、ハードディスクが100GBなんてのも珍しくない、むしろ、少ない部類 に入る時代になりました。うすっぺらーい小さいカードの中に4GBとか入っちゃう 世の中です。  しかし、私がPCというものを知った頃は記録媒体に「カセットテープ」でした。 カセットテープにプログラムを「セーブ」していたころです。読み込みは「ロー ド」です。  CLOADとかCSAVEとか書いていた頃です。  世の中は、DOSなんてものはなくて、N-BASICとかN60-BASICとかN88-BASICとか …。Microsoft BASICの亜種が国内メーカーの手によって量産されていた時代です。 雑誌に載ったプログラムリストを打ち込んで、間違いを探し、テープに保存。そ ういうことを繰り返してコレクションを増やす毎日でした。  いや、むしろ、打ち込み途中のものでも頻繁にセーブしないままに「これで動 くかな?」とか実行しようものなら、画面は起動時の画面に逆戻り、とか、よく あった話です。それだけで数時間の苦労は消えちゃったりして。  そんな感じで60分テープに何本もソフトを入れて持ち歩くことができた時代で す。いまならUSBメモリにたくさん拡張子.imgとか付けて、エミュレータ本体と一 緒に持ち歩けるのにね。  当時小学生の私は本屋に行って、「ラジオの製作」とかああいう本を買おうか なと思っていました。はんだごて握ってみたかったから。でも、目的の本は存在 せず、代わりになんかおもしろそうなタイトルが書いてある本があったんです。 工学社からでてる「I/O」でした。初めて買ったときは、APPLE][の将棋盤だった 気がする。「将棋」じゃなくて「将棋盤」なのがみそですよ。APPLE][を将棋盤に 見立てて、人間二人で将棋するの。それでも当時はすごいことだったんです。  で、その本に載っているリストであるとか広告見て、「パーコンがあれば、こ んなことができるんだなーすげーなー!」とか思っていたんです。当時はマイコ ンかパーコンです。パソコンなんてしゃれた呼び方になったのは80年中盤以降だ ったかと。  その本と出会ってから数年経ったある日、家から結構離れている国鉄駅近くの デパートに「マイコン売り場」なるものができたというのを知り、ちょっと見に 行きました。  「パラダイスっていうのはこういうものか」っていうくらい雑誌でしか見たこ とないPCが陳列されているのを見て興奮したものです。どういうきっかけか覚え てないですけど、何度か通っているうち、店員さんと仲良くなり、他のガキ共は 注意されているのを見るのに自分だけ注意されないなんていうPCを自由に使える 不思議な環境が手に入りました。  それからは、店員さんに頼まれて雑誌のダンプリスト打ち込んでみたり、同じ ようにPC使いたそうにしているやつも仲間に入れてソフトの交換やってみたりし ていたんですが、ある日こんな話が出ました。 「このソフト、ダビングできないんだけど」  その頃には、雑誌のテープサービスだけでなく、ショップが委託品なのかなん かわかりませんが、そのショップのブランドとしてソフトを売っていたり(99っ て書いてあるソフトが結構あった)今で言うソフトハウスみたいな感じで、趣味の 延長で作られたソフトが売られはじめていました。  で、ソフトウェアが商品になり始めた頃で、それまでは単純にダビングデッキ でコピーできていたものがマスターのボリュームに低周波をかけたように音量が ゆれていたんです。(VCAにLFOをかけたような感じといえばいいのかな…)  小さいだけならば音量を上げればいいし、大きいだけならば下げればいい。だ けど、それが周期的に来るとなれば手で調節するわけにもいかないわけです。  さて、困った。どうしましょう?とその売り場のバイトだったTさんに相談する と「じゃあ、おもしろい店があるから一緒に行こう」と言われ、渋谷へ行きまし た。  かすかな記憶では、その店は今じゃsで始まる量販店のあのお店なんですが、貸 しソフト屋だったので、多分違うと思います。そして、そのお店で「テープコピ ーツール」というジャンルのソフトに出会いました。  テープをコピーするツール。文字通り、そのまんまですね。  どういう原理かと言えば、そのツールを実行するとテープの内容を一旦メモリ に読み込みます。で、新しいテープにその内容を保存します。たったそれだけ。  ただ、これが相当画期的だったのは、CLOAD/CSAVEといったBASICの機能は使わ ず、ローダーと呼ばれる読み込み用プログラムを使っているような特殊フォーマ ットのものでもメモリに読み込める内容ならば、コピーができたんです。これは すごいと中坊の頭でもわかりました。ダビングしなくてもコピーできるんじゃん。 ま、中坊ならそんなもんです。 ■0x04.) フロッピーディスクのすごいとこ  テープの速度に満足できなくなった頃にちょうど小遣いで買えるくらいのフロ ッピーディスクが出てきました。10枚で5,000円くらい。これなら買える!と思い ました。今なら、5,000円あればハードディスク買えるけど。  まあ、それはさておき、周りにやっと追いついたなか、私のPC環境もフロッピ ーディスクに移っていきます。  PC-80S31って知っていますか?NECがPC-8001用(後にPC-8801用にも)に出してい たフロッピーディスクドライブです(PC-8031というでかい箱のバージョンアップ 版)  この中にはフロッピーディスクコントローラ(FDC)ってのが載っていてディス クの読み書き用のプログラムが動いています。これはNECのPC系と同じCPUでした。  PC-88シリーズと同時期に人気のあった機種にFM-8/FM-7という富士通の出して いたPCがあります。こちらにもフロッピーディスクドライブがあり、こちらはま た違うCPUが載っていました。  この頃にはもう数々のソフトハウスができソフトウェアは、商品として流通し ていましたので、コピーされると売り上げが減る→プロテクトかければいいんじ ゃね?という流れで、結構すごいプロテクトが施されていました。  しかし…、こういうある種の壁ができるとそれを壊したがる人はいるもので、 先ほどのテープコピーツール以上におもしろいツールがたくさんでていました( 時期的にはフロッピーディスクのコピーツールのほうが先でしょう。その当時PC -6001を使っていた私にとっては、テープコピーツールのほうが重要だったんです …)。  フロッピーディスクのコピーツールにはPC-8801/PC-8001の環境で動くものだけ でも ・BabyMaker ・FileMaster ・RATS&STAR ・EXPERT88 ・WIZARD88 ・アインシュタイン など、複数のものがありました。  拡張ポートに入れるボードに可変抵抗が付いていて、それを回して回転数を変 更するなんていうものすごいものもありましたが…、そこまでしてコピーしてい た人がいるのかどうかは疑問です。  フルオートでコピー→チェッカーつぶすためのパッチを適用するタイプという 流れになっていき、貸しソフト屋→疑似貸しソフト屋(定価で販売→定価の8割で 買い取りなど)という商売の流れとも相まって話題になっていましたね。  定期的に発売したソフト用のパッチを送ってくれるサービスなんかをやってい るソフトハウスもありました。  その他に「サークル」と称して、コピーソフトを配っている人たちもいました が、今そんなことやったら、確実に起訴されますので、絶対にやめてくださいね。 雑誌のメンバー募集とかに「リスト送ります」なんて書いていたところは、確実 にこれでした。  この辺のプロテクトに関しては、デュプリ屋さん(ゲームのマスターディスク から実際の商品用にディスクをコピーして、パッケージにいれて出荷状態にして くれる業者さん)のプロテクト開発部隊のみなさんの技術により、実に様々な方 法が考案されました。  フロッピーディスクのフォーマットに一工夫して ・読み取るタイミングによって読み出されるデータが違うことを利用する ・基準になる穴を複数用意されていることで通常の読み出しとは違うデータになる ・1セクタの長さやセクタ間の隙間の長さを変えて通常とは違うタイミングで読み込む などといった「そこまでやるのか…」的なものを施してみたり、  チェッカーの方に ・チェックが通らなかったときに何度も再起動を繰り返す ・チェックが通りませんでしたよ的なメッセージを流す ・ふつーに遊べているはずなのに最後の最後で「コピーするな」とゲームが終わる  なんていう、ちょっとした遊び要素が入ってしまって「どうなるのか知りたい」 人たちにとっては格好のネタになったわけです。  この頃は、TheBASIC(技術評論社)などでもこの手のプロテクトのネタを扱って いて、読んでいるこちらが「ほんとに大丈夫なのかな?」と心配になるくらいで した。ある意味「バックアップ活用テクニック」よりトンガっていたと思います。  その後、「Hacker」(確か、漫画ゴラク増刊)なんて雑誌もありましたが、こち らはもう少し時期が後なだけに扱う内容はソフトだった気がします。SPT-HACKさ んの記事が読みたくて買っていました。MSXに関する記事は特におもしろかったで す。 ■0x05.) MSXというプラットフォーム  MSX/MSX2というのを知っている方はどれくらいいるでしょうか。エミュレータ のfMSXなら知っているって方は多いでしょうね。  今までで一番いいと思ったPCはなんですか?と聞かれれば、PC-6001な私がその 後いろいろとお世話になったのは、なんといってもMSXでした。  解像度も貧弱、メモリ容量も貧弱。だけど、いろいろと楽しい環境です。スプ ライトが使えるし、VDPもいろいろと便利に使えるのでプログラムをするには最高 でしょう。  でも、MSXでもやっぱりフロッピーディスクのプロテクトは存在していました。 ただ、この頃になると「単純にコピーできなければいいよ」という妥協があった のか、DOSコールのセクタ読み出しを呼び出して、それが読めるか読めないかとい う単純なものくらいしか見たことがありません。  実際にそのプロテクトフォーマットを自分のソフトに施したときもプログラム を数行追加するだけでOKだったので楽なことこのうえなかったのと同時にチェッ カーに何かをいれるという楽しみがなかったので、物足りなかったのも事実です。  VDP(ビデオディスプレイプロセッサー/映像周りの管理をするチップ)やPSG( プログラマブルサウンドジェネレータ/音源チップ)の操作などを本格的に覚えた のはこの環境があったからですし、その部分はその後ゲーム機であるとか遊技機 などのハードウェアが関連することが多い環境のプログラムにも役に立ちました (ソフト屋なのでだいぶ適当ではありますが、タイミングチャートの読み方とか 覚えられたのはこれがあったから)。 ■0x06.) 解析ふたたび  時代は一気に飛びますが…。世の中インターネットの時代になります。  といっても、パソコン通信(今で言う@nifty(NIFTY-Serve)とかBIGLOBE(PC -VAN))の頃にメールにドメイン名が付けられるようになったよ!とかrimnetの uucpサービスでfjとか読めるんだよ!っていうところよりは、ちょっとあとです。  知人の会社にスペースを借り、WEBサイトなんていうものを作ったりもしていた ころ、MSXつながりで親しかった人に誘われ、転職しました。  その当時在籍していた会社では、紆余曲折あったため、所属していた部署が本 社とは別の場所にありました。独立部隊には変な監視もないのもあり、割とやり たい放題できたわけです。  最初にやったのは、自分たち用のファイルサーバーを建てました。Linuxは0.99 の頃に自宅のPCにいれてだいぶめんどくさかったので、FreeBSDを入れ(それでも めんどうだった)、Apacheを動かし、Sambaを入れ。Perlでスクリプトを書いて、 弁当の注文をまとめるスクリプトなんていうのを書いていました。  ただ、回線自体はISDNなんていう貧弱なものだったので10数人が同時につなぐ と大変なことになってしまうため、外に出て行く方は人のいない時間帯。それほ ど見るところもありませんでしたから、それだけで充分だったんです。  しばらくして、本社のあるビルを移転するからお前らもこっちに合流しろとい うお達しがありまして、部署丸ごと本体に合流しました。そこには憧れの(笑) 1.5Mbps専用線(当時は、テレホーダイの頃です)が手に入るやいなや、私の中の インターネットは始まりました(意味がわかりませんね、すいません)。  同じフロアにいた連中は「ぁゃιぃわーるど」とかを見るのが好きなようでし たが、私の方はと言えば…見つけたのは「シリアル集」ですよ。kurareさんの離 乳食もこの頃だったでしょうかね。  そこから、いろんなページを探していくのも楽しかったのですが、「なんかめ んどくせえなあ」が口癖な私としては、「んじゃ、自分でやればいいじゃん」と なり、ほんとに適当にデバッガで中身を見ていった結果をToHeartサーバーに借り た掲示板に掲載していきました。あと金さん掲示板ですよ。あそこもすごかった。  で、当時情報なんてほとんどないし、特定の掲示板に集中していたんです。も う名前忘れちゃったけど、パスワード知らないと入れない掲示板なんていうのも ありました。  そこでFCJの方々が定期的に来ては解析依頼に応えて結果を載せてくれる、みた いなことも行われていたのを知ったのはもうちょい後ですえ。  しばらくそういうことをやっているとCARJのLogyaさんという人からメールが来 ました。Logyaさんは、いろんな掲示板を巡回してそれこそ掲示板のLOGをまとめ てくれていた方です。なにやら、CARJの中に「なんかおもろいことやっている人 がいるよ」という話をしていただいたそうで、良かったらCARJ掲示板見に来ない? みたいな内容でした。  他の人たちが何やっているのか知りたくて仕方なかったので、早速行ってみま した。  もうここから、のめり込むのは速かったです。ねずみさん、だっ!さんと知り 合ったのもこの頃です。  FCJのかわら版さん、苦楽屋さん、鍵屋さん、H.Kさん、CARJのmoguraさん、kaz 99くん、Logyaさんなどお世話になった方は数知れず。  ある程度やったなーと思っていた頃から後は仕事の忙しさなどもあり、飲み会 には行くけど、ほとんど表舞台にでることはなくなりました。裏方でなんかやっ ている方が自分にあっているとも思いますし。  ですから、今さら今回のような本を書くことは本当にためらわれました。しか し、なんとなーく、ほんとに「なんとなく」ですが、せっかくの機会だし、昔自 分が苦労していたころに考えていた内容を書けるならそれもいいかなと思い、ま とめてみました。  技術的な部分は、本当に初歩の初歩です。ただ、あまり簡単な話ばかりでは手 応えがないかなと思ったので、kernelに近い部分に関してねずみさんに協力を仰 ぎました。  おかげで簡単すぎることのない本ができたと思います。立ち読みでもいいから、 一度読んでいただけたらありがたいです。  最後まで読んでいただいて、ありがとうございました。 x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x --- 第1章: Intel x86命令の構造 version 2 〜 x86簡易ディスアセンブラの作成 --- 著者:大原まひる x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x ■0x01.) はじめに  Wizard Bible 27で書いた内容の続きです。簡易なディスアセンブラを作成する ところまでやってしまいます。  僕の住んでいる世界では自動解析とか、解析結果の視覚化とかブームのようで、 それに伴ったディスアセンブラの利用とか作成もまた話題に上っているようです。  時代を先取りしすぎてWB27で書いたことは見向きもされなかったのですが、よ うやく時代が追いついてきた気がしたので、ちょこっとバージョンアップしてみ ました。 注: ブームといっても僕の住んでいる世界の話ですから一般の世界がどうなのか 分かりません。 ■0x02.) Intel x86命令フォーマット  これからIntel x86アーキテクチャの命令フォーマットについて解説していきま すが、この項を読むに当たってはインテルから提供されている「IA-32 インテル アーキテクチャ ソフトウェア デベロッパーズ マニュアル」を参考にするのがい いでしょう。 Intel 日本語技術資料: http://www.intel.com/jp/download/index.htm#ia32 ●基本構造  Intel x86の命令はその命令を構成する数値を分解していくと次の構造になって います。それぞれの意味については後から説明します。 |Prefix|Opcode|ModR/M|SIB|Displacement|Immediate| (図)http://wizardbible.org/48/image/instruction_structure.png  命令を構成する各要素が取りうる長さは次のようになります。 | 要素 | 長さ(bytes) | |--------------+-------------| | Prefix | 0,1,2,3,4 | | Opcode | 1,2,3 | | ModR/M | 0,1 | | SIB | 0,1 | | Displacement | 0,1,2,4 | | Immediate | 0,1,2,4 |  単純に計算すると一つの命令の取りうる長さは1バイトから15バイトの間になる と分かります。  命令を構成する各要素について見ていきます。 ●Prefixの分類  prefixは4つグループに分けられます。 - Group 1 :: リピート(Repeat Prefix),ロック(Lock Prefix) F3h,F2h,F0h - Group 2 :: セグメント(Segment Prefix),分岐ヒント(Branch Hint Prefix) 2Eh,36h,3Eh,26h,64h,65h,2Eh,3Eh - Group 3 :: オペランドサイズ(Operand Size Prefix) 66h - Group 4 :: アドレスサイズ(Address Size Prefix) 67h  各命令はこれらのグループからひとつずつプリフィックスを使うことができま す。プリフィックスなしのときも含めて、各グループからひとつずつなら使って も使わなくてもいいので、プリフィックスの長さが0-4の間になるわけです。  各グループの出てくる順番は決まっていません。 ○Group 1 - Repeat Prefix, Lock Prefix  REP、REPNEがそれぞれF3hとF2hで表されるリピートプリフィックスです。  通常ストリング命令と組み合わせて使われます。たとえばLODSD命令はADhなの で "REP LODSD", "REPNE LODSD"は次のようになります。 | LODSD | AD | | REP LODSD | F3AD | | REPNE LODSD | F2AD |  LockはF0hで表され、マルチプロセッサ環境での共有メモリの排他的使用のため に使 われます。 ○Group 2 - Segment Prefix, Branch Hint Prefix  DOSなどの16ビット環境でのアセンブリ言語プログラミングの経験があればセグ メントは基本かつ重要な概念ですが、32ビットWindowsのflatな環境で普通のソフ トウェアを作るのにはほとんど気にする必要がありません。  例えば、DOSではデータとコードをデータセグメントDS、コードセグメントCSに わけ、メモリ上のコードのアドレスを指すには"CS:"を頭につけてアドレスを指定、 データを指すには"DS:"を頭につけてアドレスを指定するといった感じで使ってい ました。同じ7777hでもDS:7777hとCS:7777hでは別の場所を指すことになります。  WindowsではCSやDSを直接使うようなことはないですが、FSで指定されるセグメ ントが、そのスレッドの重要な情報を格納していたりするので、システムレベル の解析などではよく出てきます。  それぞれのセグメントプリフィックスには次の表の値が対応しています。 | CS | 2Eh | | SS | 36h | | DS | 3Eh | | ES | 26h | | FS | 64h | | GS | 65h |  通常、デフォルトのセグメントはDSとなっていて、DS以外のセグメントを使い たいときにセグメントプリフィックスを命令のプレフィックス領域に配置します。 例:Segment Prefix | MOV EAX, DWORD [EAX] | 8B00 | | MOV EAX, DWORD CS:[EAX] | 2E 8B00 | ○Group 3 - Operand Size Prefix  Windowsの32ビット環境なら32ビットオペランドがデフォルトで使用されます。 16ビットオペランドを使いたいときにはオペランドサイズプリフィックスを付加 する必要があります。66hがオペランドサイズプリフィックスを表します。 例:Operand Size Prefix | MOV EAX,EAX | 89C0 | | MOV AX,AX | 66 89C0 | ○Group 4 - Address Size Prefix  Operand Size Prefixと同様で、デフォルトのアドレッシングモードを変更する のに使われます。67hがアドレスサイズプリフィックスを表します。 例:Address Size Prefix | MOV EAX,DWORD DS:[EAX] | 8B00 | | MOV EAX,DWORD DS:[BX+SI] | 67 8B00 | ●Opcode  オペコードは命令の機能を決める柱となる部分です。この領域は1から3バイト の長さになっています(すべてのオペコードの表はインテルのマニュアルに詳し く載っていますので、それを参考にしてください)。  基本的にはこの領域で命令の種類と命令が使うレジスタやメモリが決まります。  x86の命令のなかでもっとも短いものは1バイトで表されます。1バイトで命令が 完結するものの代表としてNOP命令があります。アセンブリ言語にそれほど詳しく なくてもNOPは90hだと知っている人も多いはずです。  "PUSH EAX"という命令も1バイトで表すことができます。50hがこれに対応して います。他のPUSH命令は次の表のようになっています。 | PUSH EAX | 50h | | PUSH ECX | 51h | | PUSH EDX | 52h | | PUSH EBX | 53h | | PUSH ESP | 54h | | PUSH EBP | 55h | | PUSH ESI | 56h | | PUSH EDI | 57h | これらを2進数に直すと次のようになります。 | PUSH EAX | 01010 000 | | PUSH ECX | 01010 001 | | PUSH EDX | 01010 010 | | PUSH EBX | 01010 011 | | PUSH ESP | 01010 100 | | PUSH EBP | 01010 101 | | PUSH ESI | 01010 110 | | PUSH EDI | 01010 111 |  先頭の5ビットでPUSH命令を表し、続く3ビットでレジスタを指定すると見るこ とができます。つまり"PUSH reg"=>"01010reg"と考えることができます。  実はx86命令では3ビットでのレジスタの指定方法が決められています。 | reg | 8bits | 16bits | 32bits | |-----+-------+--------+--------| | 000 | AL | AX | EAX | | 001 | CL | CX | ECX | | 010 | DL | DX | EDX | | 011 | BL | BX | EBX | | 100 | AH | SP | ESP | | 101 | CH | BP | EBP | | 110 | DH | SI | ESI | | 111 | BH | DI | EDI |  この決まりを使って簡単に表すことができる命令を挙げておきます。 | INC reg | 01000reg | | DEC reg | 01001reg | | PUSH reg | 01010reg | | POP reg | 01011reg | | XCHG EAX, reg | 10010reg |  例えば次のようになります。 : INC EAX => 01000 000 => 40h : INC ECX => 01000 001 => 41h : XCHG EAX,EAX => 10010 000 => 90h : XCHG EAX,ECX => 10010 001 => 91h  "XCHG EAX,EAX"に注目してください。90hになっています。さっき見たNOPと同 じです。つまり、NOP命令の「何もしない」動作の正体が"XCHG EAX,EAX"というこ とが分かります。そもそもNOP命令は"XCHG EAX,EAX"の別名として定義されている だけです。  次にもう少し複雑な例を見てみます。 : 89C1h => 10001001 11000001 => MOV ECX,EAX  構造を分解すると次のようになります。 | instruction | d | w | | Mod | Reg1 | Reg2 | |-------------+---+---+---+-----+------+------| | 100010 | 0 | 1 | | 11 | 000 | 001 | - instruction :: 命令を表す部分 - d :: d=0のとき REG2,REG1 の順番。d=1のとき REG1, REG2 の順番。 - w :: 32ビット環境で、w=0 のとき8ビットモード、w=1 のとき32ビットモード 16ビット環境で、w=0 のとき8ビットモード、w=1 のとき16ビットモード  上の例で2バイト目はModR/Mという領域です。ModR/Mはオペランドの型を決定す る領域で、Mod=11のときには続く2つの3ビットは共にレジスタであることを意味 しています。ModR/Mについては後で解説します。  "MOV ECX,EAX" (100010 0 1 11 000 001)をd=1にすると、"MOV EAX,ECX"(100010 1 1 11 000 001)となります。  dの状態によりReg1とReg2が入れ替わることから、同じ命令を表す2通りの方法 が考えられます。 : MOV EDI,EAX => 100010 1 1 11 111 000 => 8B F8 : MOV EDI,EAX => 100010 0 1 11 000 111 => 89 C7  つまりdのビットを反転させると同時にReg1とReg2を入れ替えれば同じ命令にな りま す。  次にwについて見てみます。  "MOV ECX,EAX"の例で、w=0として8ビットモードにすると次のように、続くレジ スタが8ビットレジスタになります。 :100010 0 0 11 000 001 => MOV CL,AL  このMOV命令と同じ型で使われる命令には以下のようなものがあります。 | OR | 000010dw | | AND | 001000dw | | SUB | 001010dw | | XOR | 001100dw | | CMP | 001110dw | | ADD | 100000dw | | MOV | 100010dw | ●ModR/M  ModR/M という領域について詳しく見てみます。  ModR/M は命令がどのような型のオペランドを使用するかを指定する領域です。 以下のような構造になっていて、Modが2ビット、Reg/Opcodeが3ビット、R/Mが3ビ ットで構成されています。 | Mod | Reg/Opcode | R/M | | bb | bbb | bbb |  オペコードには1つのオペランドをとるものも2つのオペランドをとるものもあ ります。1つのオペランドだけを必要とするとき、Reg/Opcodeの部分で、命令の種 類が決まります。 : NOT EAX => F7 D0 => 11110111 11 010 000 : MUL EAX => F7 E0 => 11110111 11 100 000 : DIV EAX => F7 F0 => 11110111 11 110 000  上のようにReg/Opcode領域がことなるだけで3つの異なる命令になります。  2つのオペランドを必要とする命令ではReg/Opcodeがレジスタを表します。 : CMP EDX,EAX => 39 D0 => 00111001 11 010 000  010がReg/Opcode領域で、010に対応するレジスタEDXを表しています。  次にR/Mの領域について見てみます。  R/MはMod部分により意味が変わってきます。 | Mod | 意味 | |-----+------------------------------------------------------------------------------| | 00 | メモリアドレス => [EAX] | | 01 | 1バイトのディスプレイメントを伴ったメモリアドレス => [EAX+11h] | | 10 | 1ダブルワードのディスプレイスメントを伴ったメモリアドレス => [EAX+11111111h] | | 11 | レジスタ => EAX |  次の表がModR/Mの組み合わせです。 (図)http://wizardbible.org/48/image/modrm.png  この中で00 101のところはレジスタは使用されずにModR/Mの後にDWORD値がくる ことになります。  dispというところはディスプレイスメントを伴ったアドレスの指定になります。 これについては後から解説します。  [-][-]で表されている 00 100, 01 100, 10 100のところはModR/Mの後にSIBが 続きます。 ●SIB  SIBはScale、Index、Baseの略で、次のような構造になっています。 | Scale | Index | Base | | bb | bbb | bbb |  たとえばアドレスの指定で[EBP+EAX*2]となっているとき、EBPがBase(ベースレ ジスタ)、EAXがIndex(インデックスレジスタ)、2がScaleと呼ばれるものになって います。  Scaleは次のように、2のScale乗が実際に対応する値になります。 : 00 => 2^0 = 1 : 01 => 2^1 = 2 : 10 => 2^2 = 4 : 11 => 2^3 = 8  Indexはレジスタを3ビットで表します。  BaseもIndexと同じく3ビットでレジスタを表します。  いくつか例を挙げると次のようになります。 | SIB | | |------------+-------------| | 00 000 001 | [1*EAX+ECX] | | 01 001 010 | [2*ECX+EDX] | | 10 010 111 | [4*EDX+EBX] | | 11 000 011 | [8*EAX+EBX] | ●Displacement  ModR/MでModが01または10のときにはディスプレイスメントを伴ったアドレスの 指定になります。ディスプレイスメントは [EBP+EAX+12345678h] のようなメモリ 指定をしたときの 12345678h の部分になります。 : MOV EDI,[EBP+12345678h] => 8B BD 78563412 | 100010 | 1 | 1 | 10 | 111 | 101 | 12345678h | | MOV r32,r/m32 | d=>REG1 REG2 | w=>32bit | Mod | Reg/Opcode=>EDI | R/M=>EBP | Displacement | ●Immediate  即値を表す領域です。  たとえば、05hは"ADD EAX,imm32"を表し、05hに続いて即値を指定することにな ります。 : 05 78 56 34 12 => ADD EAX,12345678h ■0x03.) ディスアセンブラの実装の手法  ここまでの知識があれば、汎用命令についての基本的なディスアセンブラを作 ることができます。  インテルの「IA-32 アーキテクチャ ソフトウェア デベロッパーズ マニュアル」 の中巻の最後に「オペコードマップ」と「命令フォーマットおよびエンコーディ ング」という項目があります。ここにどの値にどの命令が対応付けされているの かが書かれています。命令の取りうるオペランドもオペコードマップから分かり ます。  ディスアセンブラのもっとも重要な機能は命令を構成する各フィールドを分解 することです。つまり、プリフィックス、オペコード、ModR/M、SIB、ディスプレ イスメント、即値といったフィールドの有無とその長さを取得することが核とな ります。  これさえできれば、各フィールドを細かく読み取っていくだけです。フィール ドが分割されていれば、面倒ではありますが、個々の命令をアセンブリ言語の書 式に変換するのは簡単に実装できます。プログラム中で使うにしても各フィール ドの内容を分割して取得し、そこから必要な情報を導き出していくことになりま す。  ここではフィールドを分割し、1 つの命令の長さを算出するディスアセンブラ (Length Disassemblerなどと呼ばれる)の実装について説明していきます。 ●プリフィックス解析  各命令は最大4バイトのプリフィックスを持ちます。  プリフィックス部分は可変長なので、これを解析しないと主となる処理を決め るオペコードが何バイト目からはじまるかが分かりません。また、オペランドサ イズプリフィックスとアドレスサイズプリフィックスが存在すればオペコードに 続く領域のサイズが変更されるため、どのプリフィックスがあるのかを調べて、 保存しておかないといけません。  プリフィックスも他の命令と同じオペコードマップを構成する要素のひとつな のでオペコードマップを参照して、プリフィックスなのかどうかを確かめること にします。  インテルの「IA-32 アーキテクチャ ソフトウェア デベロッパーズ マニュアル」 の中巻の「オペコードマップ」と「命令フォーマットおよびエンコーディング」 を元に書き出すと次のようになります(以下のプログラムはすべてC++)。 ----- /* opcode map */ unsigned char op_tbl[256] = { /* 00h */ C_MODRM /* add Eb,Gb */ /* 01h */, C_MODRM /* add Ev,Gv */ /* 02h */, C_MODRM /* add Gb,Eb */ .... /* 63h */, C_MODRM /* arpl Ew,Gw */ /* 64h */, C_PREFIX /* Prefix Group 2 : Segment Prefix: FS */ /* 65h */, C_PREFIX /* Prefix Group 2 : Segment Prefix: GS */ /* 66h */, C_PREFIX /* Prefix Group 3 : Operand Size Prefix */ /* 67h */, C_PREFIX /* Prefix Group 4 : Address Size Prefix */ /* 68h */, C_IMM32 /* push imm32 */ .... -----  各命令の解析に必要なフラグをセットしてあります。プリフィックス命令には C_PREFIX、他のものに関してはオペコードのあとにModRMが続くとか、即値が続く とかの情報です。  解析対象となるバイト列から1バイトを取り出して、オペコードテーブルから対 応するフラグを取り出します。  フラグがC_PREFIXならプリフィックスのGroup 1からGroup 4のいずれかという ことを表しています。 - Group 1 :: リピート(Repeat Prefix),ロック(Lock Prefix) F3h,F2h,F0h - Group 2 :: セグメント(Segment Prefix),分岐ヒント(Branch Hint Prefix) 2Eh,36h,3Eh,26h,64h,65h,2Eh,3Eh - Group 3 :: オペランドサイズ(Operand Size Prefix) 66h - Group 4 :: アドレスサイズ(Address Size Prefix) 67h  プリフィックスは各グループで最大1個だけつけられるので、プリフィックスの 数の合計は0から4個になります。最初の1バイトがプリフィックスなら次の1バイ トもプリフィックスの可能性があるので、プリフィックスが続く限り先頭から4バ イトまでは次の1バイトもプリフィックスなのかチェックすることになります。  解析した結果は、構造体にまとめて保存します。xxx_prefix_pはbool型でその プリフィックスがあるかどうかを表しています。prefix_lengthにはプリフィック スの合計サイズを保持しています。 ----- typedef struct _dsminfo{ unsigned char length; // 命令のトータルの長さ // 各プリフィックスの有無 bool repeat_lock_prefix_p; bool segment_branchhint_prefix_p; bool operand_size_prefix_p; bool address_size_prefix_p; // プリフィックスの合計の長さ unsigned char prefix_length; ..... -----  コードは次のようになります。 ----- op_tbl_flags = op_tbl[inst]; while(op_tbl_flags == C_PREFIX){ switch (inst){ /* repeat prefix */ case 0xF3: case 0xF2: case 0xF0: dsm->repeat_lock_prefix_p=true; break; /* segment prefix */ case 0x2E: case 0x36: case 0x3E: case 0x26: case 0x64: case 0x65: dsm->segment_branchhint_prefix_p=true; break; /* operand size prefix */ case 0x66: dsm->operand_size_prefix_p=true; break; /* address size prefix */ case 0x67: dsm->address_size_prefix_p=true; break; }; dsm->length++; pos++; inst=*pos; op_tbl_flags=op_tbl[inst]; if(dsm->length == 4){ break; }; }; /* while - prefix */ dsm->prefix_length=dsm->length; /* end of prefix scan */ dsm->length++; -----  これでプリフィックス部の解析が終了しました。  プリフィックス部の解析の次は命令の実際の処理を決定するオペコード部の解 析に移ります。 ●2バイトオペコード  1バイトの表せる範囲は256個ではCPUの命令のすべてをカバーできません。そこ で0Fhをエスケープオペコードとして別のオペコードテーブルを参照するようにな っています。これが2バイトオペコードです。  ここでは必須の汎用命令にのみ対応できるようにしています。  オペコードテーブルの0FhにC_ESCAPEというフラグを立てておき、2バイトオペ コードを表すオペコードテーブルop_tbl2 []を定義しておきます。 ----- unsigned char op_tbl2[256] = { /* 01h */ C_UNKNOWN /* 02h */, C_UNKNOWN /* 03h */, C_UNKNOWN .... -----  これを解析する部分は命令を表す部分をひとつずつらして、参照するテーブルを op_tbl2 []にするだけです。 ----- /**************************** * TWO bytes(ESCAPE) opecode ****************************/ if (op_tbl_flags == C_ESCAPE){ pos++; inst=*pos; op_tbl_flags=op_tbl2[inst]; dsm->length++; dsm->two_bytes_opcode_p = true; }; ----- ●未実装の命令  オペコードテーブルはすべてうまってるわけではなく予約領域として置いてあ る部分もあります。そのような領域にはオペコードテーブルでC_UNKNOWNというフ ラグを立てておいてエラーを返すようにします。  また、仕様では定義されていても、自分が作るディスアセンブラにはまだ解析 できるようにしていないという部分にもC_UNKNOWNというフラグを立ててエラーを 返すようにしています。 ----- /************************* * UNKNOWN *************************/ if (op_tbl_flags == C_UNKNOWN){ dsm->length=0; return dsm->length; }; ----- ●1バイト命令  次に、もっとも単純な1バイトで完結する命令を解析します。NOPやINT3命令な どが対象となります。  これらは、それ以降に何も続かないので解析は簡単に終わります。  1バイト命令にはC_SIZE1というフラグを立てておき、これを処理する部分を作 ります。 ----- /*********************** * ONE byte Instruction ************************/ if (op_tbl_flags == C_SIZE1) { pos++; return dsm->length; }; -----  長さを1増加させればそれで解析終了となります。 ●ModR/Mの解析  次にModR/Mを持つ命令の処理をします。C_MODRMというフラグが立っている場合 にここで処理を行います。  まず、Mod,Reg/Op,R/Mの3つの領域に分けて考えます。  ディスプレイスメントとSIBのチェックをします。どちらもMODが00,01,10,11の 場合で分けて、さらにR/Mの場合分けで絞り込んで決定できます。ここではディス プレイスメントのチェックとSIBのチェックを別のブロックにします。  ディスプレイスメントのチェックでは、アドレスサイズプリフィックスの有無も チェックする必要があります。これによってサイズが2バイトなのか4バイトなのか も決定されます。 ----- /************************** * MODRM **************************/ if (op_tbl_flags & C_MODRM){ pos++; /* pos point to MODRM byte */ inst=*pos; dsm->length++; /* modrm byte */ /* check MODRM for displacement */ switch (inst & MODRM_MOD_MASK){ case MODRM_MOD00: if((inst & MODRM_RM_MASK) == 0x05){ /* Mod:00 RM:101 == disp32 */ dsm->displacement_size = dsm->address_size_prefix_p ? 2 : 4; dsm->length += dsm->displacement_size; }; break; case MODRM_MOD01: dsm->displacement_size = 1; dsm->length += dsm->displacement_size; break; case MODRM_MOD10: dsm->displacement_size = dsm->address_size_prefix_p ? 2 : 4; dsm->length += dsm->displacement_size; break; }; /* end modrm field check for disp*/ /* check MODRM for sib */ if((inst&MODRM_MOD_MASK) != MODRM_MOD11){ if((inst & MODRM_RM_MASK) == 0x04){ /* RM: 100 == SIB */ dsm->sib_p = true; dsm->length++; }; }; /* end modrm check for sib */ } /* MODRM */ ----- ●即値の解析  次に即値を取る命令の解析です。C_IMM8,C_IMM32,C_IMM16がそれぞれ8,32,16ビ ットの即値を取る命令のフラグです。ただし、C_IMM32に関してはプリフィックス の影響を受けて32,16ビットのどちらかになります。  それぞれ、即値の長さが決定されれば、その分だけlengthを増加させれば終わ りです。 ----- /******************** * IMM ********************/ if(op_tbl_flags & C_IMM8){ dsm->length++; dsm->c_imm8_size++; }; if(op_tbl_flags & C_IMM32){ if(dsm->operand_size_prefix_p){ dsm->length+=2; dsm->c_imm32_size=2; }else if(dsm->address_size_prefix_p && !(op_tbl_flags & C_REL)){ dsm->length+=2; dsm->c_imm32_size=2; } else{ dsm->length+=4; dsm->c_imm32_size=4; } } if(op_tbl_flags & C_IMM16){ dsm->length+=2; dsm->c_imm16_size=2; } /* end of IMM */ ----- ■0x04.) 高機能なディスアセンブラへ  ここまで、ディスアセンブラの骨格を示しましたが、これは不完全なものなの で、まだまだ改良の余地はあります。対応する命令を増やしたり、特殊な場合の 処理を追加したりする必要があります。インテルのマニュアルを見ながら行うこ とになりますが、もう少しまとまったわかりやすいものとしてSandpile.orgのIA -32のページやx86asm.netのx86 Referenceのページが役に立ちます。わかりやす い表をメインに構成されたレファレンスになっているので、ディスアセンブラの 実装するときに参照すると便利です。 - Sandpile.org IA-32 :: http://www.sandpile.org/ia32/index.htm - x86asm.net reference :: http://ref.x86asm.net/ ●ソースコード ----- disasm.h /* * File: disasm.h * * - dsminfo structure * - opcode table */ #pragma pack(push) #pragma pack(1) /* * struct dsminfo */ typedef struct _dsminfo{ unsigned char length; // length // prefix bool repeat_lock_prefix_p; bool segment_branchhint_prefix_p; bool operand_size_prefix_p; bool address_size_prefix_p; unsigned char prefix_length; // displacement size unsigned char displacement_size; /* * displacement size: * 0== no displacement * 1== 1 byte * 2== 2 bytes * 4== 4 bytes */ bool sib_p; /* followed by SIB */ unsigned char c_imm8_size; /* 0 == no C_IMM8 1 == 1 byte 2 == 2 bytes */ unsigned char c_imm32_size; /* 0 == no C_IMM32 2 == 2 bytes 4 == 4 bytes */ unsigned char c_imm16_size; /* 0 == no C_IMM16 2 == 2 bytes */ bool two_bytes_opcode_p; } dsminfo, *pdsminfo; /* flags */ #define C_UNKNOWN 0x00 /* not implemented */ #define C_PREFIX 0x01 /* Prefix */ #define C_SIZE1 0x02 /* One byte instruction */ #define C_MODRM 0x04 /* have ModRM */ #define C_IMM8 0x08 /* 8 bits imm */ #define C_IMM16 0x10 /* 16 bits imm */ #define C_IMM32 0x20 /* 32 bits imm */ #define C_REL 0x40 /* relative jmp */ #define C_ESCAPE 0x80 /* escape byte for next byte */ /* ModR/M Mod Reg/Op R/M 00 000 000 */ #define MODRM_MOD_MASK 0xc0 /* Mod field mask: ModRM: 11 000 000 */ #define MODRM_RM_MASK 0x07 /* RM field mask: ModRM: 00 000 111 */ #define MODRM_MOD00 0 /* MOD 0b00 */ #define MODRM_MOD01 1 /* MOD 0b01 */ #define MODRM_MOD10 2 /* MOD 0b10 */ #define MODRM_MOD11 3 /* MOD 0b11 */ /* opcode map */ unsigned char op_tbl[256] = { /* 00h */ C_MODRM /* add Eb,Gb */ /* 01h */, C_MODRM /* add Ev,Gv */ /* 02h */, C_MODRM /* add Gb,Eb */ /* 03h */, C_MODRM /* add Gv,Ev */ /* 04h */, C_IMM8 /* add al,imm8 */ /* 05h */, C_IMM32 /* add eax,imm32 */ /* 06h */, C_SIZE1 /* push es */ /* 07h */, C_SIZE1 /* pop es */ /* 08h */, C_MODRM /* or Eb,Gb */ /* 09h */, C_MODRM /* or Ev,Gv */ /* 0Ah */, C_MODRM /* or Gb,Eb */ /* 0Bh */, C_MODRM /* or Gv,Ev */ /* 0Ch */, C_IMM8 /* or al,imm8 */ /* 0Dh */, C_IMM32 /* or eax,imm32 */ /* 0Eh */, C_SIZE1 /* push cs */ /* 0Fh */, C_ESCAPE /* 0x0F => */ /* 10h */, C_MODRM /* adc Eb,Gb */ /* 11h */, C_MODRM /* 12h */, C_MODRM /* 13h */, C_MODRM /* 14h */, C_IMM8 /* 15h */, C_IMM32 /* 16h */, C_SIZE1 /* push ss */ /* 17h */, C_SIZE1 /* pop ss */ /* 18h */, C_MODRM /* sbb Eb,Gb */ /* 19h */, C_MODRM /* 1Ah */, C_MODRM /* 1Bh */, C_MODRM /* 1Ch */, C_IMM8 /* 1Dh */, C_IMM32 /* 1Eh */, C_SIZE1 /* push ds */ /* 1Fh */, C_SIZE1 /* pop ds */ /* 20h */, C_MODRM /* and Eb,Gb */ /* 21h */, C_MODRM /* 22h */, C_MODRM /* 23h */, C_MODRM /* 24h */, C_IMM8 /* 25h */, C_IMM32 /* 26h */, C_PREFIX /* Prefix Group 2 : Segment Prefix: ES */ /* 27h */, C_SIZE1 /* daa */ /* 28h */, C_MODRM /* sub Eb,Gb*/ /* 29h */, C_MODRM /* 2Ah */, C_MODRM /* 2Bh */, C_MODRM /* 2Ch */, C_IMM8 /* 2Dh */, C_IMM32 /* 2Eh */, C_PREFIX /* Prefix Group 2 : Segment Prefix: CS */ /* 2Fh */, C_SIZE1 /* das */ /* 30h */, C_MODRM /* xor Eb,Gb */ /* 31h */, C_MODRM /* 32h */, C_MODRM /* 33h */, C_MODRM /* 34h */, C_IMM8 /* 35h */, C_IMM32 /* 36h */, C_PREFIX /* Prefix Group 2 : Segment Prefix: SS */ /* 37h */, C_SIZE1 /* AAA */ /* 38h */, C_MODRM /* cmp Eb,Gb */ /* 39h */, C_MODRM /* 3Ah */, C_MODRM /* 3Bh */, C_MODRM /* 3Ch */, C_IMM8 /* 3Dh */, C_IMM32 /* 3Eh */, C_PREFIX /* Preefix Group 2 : Segment Prefix: DS */ /* 3Fh */, C_SIZE1 /* aas */ /* 40h */, C_SIZE1 /* inc reg */ /* 41h */, C_SIZE1 /* 42h */, C_SIZE1 /* 43h */, C_SIZE1 /* 44h */, C_SIZE1 /* 45h */, C_SIZE1 /* 46h */, C_SIZE1 /* 47h */, C_SIZE1 /* 48h */, C_SIZE1 /* dec reg */ /* 49h */, C_SIZE1 /* 4Ah */, C_SIZE1 /* 4Bh */, C_SIZE1 /* 4Ch */, C_SIZE1 /* 4Dh */, C_SIZE1 /* 4Eh */, C_SIZE1 /* 4Fh */, C_SIZE1 /* 50h */, C_SIZE1 /* push reg * /* 51h */, C_SIZE1 /* 52h */, C_SIZE1 /* 53h */, C_SIZE1 /* 54h */, C_SIZE1 /* 55h */, C_SIZE1 /* 56h */, C_SIZE1 /* 57h */, C_SIZE1 /* 58h */, C_SIZE1 /* pop reg */ /* 59h */, C_SIZE1 /* 5Ah */, C_SIZE1 /* 5Bh */, C_SIZE1 /* 5Ch */, C_SIZE1 /* 5Dh */, C_SIZE1 /* 5Eh */, C_SIZE1 /* 5Fh */, C_SIZE1 /* 60h */, C_SIZE1 /* pushad */ /* 61h */, C_SIZE1 /* popad */ /* 62h */, C_MODRM /* bound Gv, Ma */ /* 63h */, C_MODRM /* arpl Ew,Gw */ /* 64h */, C_PREFIX /* Prefix Group 2 : Segment Prefix: FS */ /* 65h */, C_PREFIX /* Prefix Group 2 : Segment Prefix: GS */ /* 66h */, C_PREFIX /* Prefix Group 3 : Operand Size Prefix */ /* 67h */, C_PREFIX /* Prefix Group 4 : Address Size Prefix */ /* 68h */, C_IMM32 /* push imm32 */ /* 69h */, C_MODRM+C_IMM32 /* imul Gv Ev imm32 */ /* 6Ah */, C_IMM8 /* push imm8 */ /* 6Bh */, C_MODRM+C_IMM8 /* imul Gv,Ev,imm8 */ /* 6Ch */, C_SIZE1 /* insb */ /* 6Dh */, C_SIZE1 /* insd */ /* 6Eh */, C_SIZE1 /* outsb */ /* 6Fh */, C_SIZE1 /* outsd */ /* 70h */, C_IMM8+C_REL /* jcc imm8 */ /* 71h */, C_IMM8+C_REL /* 72h */, C_IMM8+C_REL /* 73h */, C_IMM8+C_REL /* 74h */, C_IMM8+C_REL /* 75h */, C_IMM8+C_REL /* 76h */, C_IMM8+C_REL /* 77h */, C_IMM8+C_REL /* 78h */, C_IMM8+C_REL /* 79h */, C_IMM8+C_REL /* 7Ah */, C_IMM8+C_REL /* 7Bh */, C_IMM8+C_REL /* 7Ch */, C_IMM8+C_REL /* 7Dh */, C_IMM8+C_REL /* 7Eh */, C_IMM8+C_REL /* 7Fh */, C_IMM8+C_REL /* end of jcc imm8 */ /* 80h */, C_MODRM+C_IMM8 /* add or adc sbb and sub xor cmp / Eb,Ib */ /* 81h */, C_MODRM+C_IMM32/* add or adc sbb and sub xor cmp / Ev,Iv */ /* 82h */, C_MODRM+C_IMM8/* add or adc sbb and sub xor cmp / Eb,Ib */ /* 83h */, C_MODRM+C_IMM8/* add or adc sbb and sub xor cmp / Ev,Ib */ /* 84h */, C_MODRM /* test Eb,Gb */ /* 85h */, C_MODRM /* test Ev,Gv */ /* 86h */, C_MODRM /* xchg Eb,Gb */ /* 87h */, C_MODRM /* xchg Ev,Gv */ /* 88h */, C_MODRM /* mov Eb,Gb */ /* 89h */, C_MODRM /* mov Ev,Gv */ /* 8Ah */, C_MODRM /* mov Gb,Eb */ /* 8Bh */, C_MODRM /* mov Gv,Ev */ /* 8Ch */, C_MODRM /* mov Ew,Sw */ /* 8Dh */, C_MODRM /* lea Gv,M */ /* 8Eh */, C_MODRM /* mov Sw,Ew */ /* 8Fh */, C_MODRM /* pop Ev */ /* 90h */, C_SIZE1 /* nop / xchg eax, reg */ /* 91h */, C_SIZE1 /* xchg eax, reg */ /* 92h */, C_SIZE1 /* xchg eax, reg */ /* 93h */, C_SIZE1 /* 94h */, C_SIZE1 /* 95h */, C_SIZE1 /* 96h */, C_SIZE1 /* 97h */, C_SIZE1 /* 98h */, C_SIZE1 /* cbw/cwde */ /* 99h */, C_SIZE1 /* cwd/cdq */ /* 9Ah */, C_IMM32+C_IMM16 /* far call */ /* 9Bh */, C_SIZE1 /* wait/fwait */ /* 9Ch */, C_SIZE1 /* pushfd */ /* 9Dh */, C_SIZE1 /* popfd */ /* 9Eh */, C_SIZE1 /* sahf */ /* 9Fh */, C_SIZE1 /* lahf */ /* A0h */, C_IMM32 /* mov al, [imm32] */ /* A1h */, C_IMM32 /* mov eax, [imm32] */ /* A2h */, C_IMM32 /* mov [imm32], al */ /* A3h */, C_IMM32 /* mov [imm32], eax */ /* A4h */, C_SIZE1 /* movsb */ /* A5h */, C_SIZE1 /* movsd */ /* A6h */, C_SIZE1 /* cmpsb */ /* A7h */, C_SIZE1 /* cmpsd */ /* A8h */, C_IMM8 /* test al,imm8 */ /* A9h */, C_IMM32 /* test eax,imm32 */ /* AAh */, C_SIZE1 /* stosb */ /* ABh */, C_SIZE1 /* stosd */ /* ACh */, C_SIZE1 /* lodsb */ /* ADh */, C_SIZE1 /* lodsw */ /* AEh */, C_SIZE1 /* scasb */ /* AFh */, C_SIZE1 /* scasd */ /* B0h */, C_IMM8 /* mov al,imm8 (alt encoding) */ /* B1h */, C_IMM8 /* mov cl,imm8 */ /* B2h */, C_IMM8 /* mov dl,imm8 */ /* B3h */, C_IMM8 /* mov bl,imm8 */ /* B4h */, C_IMM8 /* mov ah,imm8 */ /* B5h */, C_IMM8 /* mov ch,imm8 */ /* B6h */, C_IMM8 /* mov dh,imm8 */ /* B7h */, C_IMM8 /* mov bh,imm8 */ /* B8h */, C_IMM32 /* mov eax,imm32 */ /* B9h */, C_IMM32 /* mov ecx,imm32 */ /* BAh */, C_IMM32 /* mov edx,imm32 */ /* BBh */, C_IMM32 /* mov ebx,imm32 */ /* BCh */, C_IMM32 /* BDh */, C_IMM32 /* BEh */, C_IMM32 /* BFh */, C_IMM32 /* mov edi,imm32 */ /* C0h */, C_MODRM+C_IMM8 /* rol,ror,rcl,rcr,shl/sal,shr,sar Eb,imm8 */ /* C1h */, C_MODRM+C_IMM8 /* rol,ror,rcl,rcr,shl/sal,shr,sar Ev,imm8 */ /* C2h */, C_IMM16 /* ret imm16 */ /* C3h */, C_SIZE1 /* ret */ /* C4h */, C_MODRM /* les Gv,Mp*/ /* C5h */, C_MODRM /* lds Gv,Mp */ /* C6h */, C_MODRM+C_IMM8 /* mov Eb,imm8 */ /* C7h */, C_MODRM+C_IMM32 /* mov Ev,imm32 */ /* C8h */, C_IMM8+C_IMM16 /* enter Iw, Ib */ /* C9h */, C_SIZE1 /* leave */ /* CAh */, C_IMM16 /* retf Iw*/ /* CBh */, C_SIZE1 /* retf */ /* CCh */, C_SIZE1 /* int3 */ /* CDh */, C_IMM8 /* int Ib */ /* CEh */, C_SIZE1 /* into */ /* CFh */, C_SIZE1 /* iret */ /* D0h */, C_MODRM /* rol,ror,rcl,rcr,shl/sal,shr,sar Eb,1 */ /* D1h */, C_MODRM /* rol,ror,rcl,rcr,shl/sal,shr,sar Ev,1 */ /* D2h */, C_MODRM /* rol,ror,rcl,rcr,shl/sal,shr,sar Eb,cl */ /* D3h */, C_MODRM /* rol,ror,rcl,rcr,shl/sal,shr,sar Ev,cl */ /* D4h */, C_IMM8 /* aam imm8 */ /* D5h */, C_IMM8 /* aad imm8 */ /* D6h */, C_SIZE1 /* salc */ /* D7h */, C_SIZE1 /* xlat */ /* D8h */, C_MODRM /* FPU -- modrm */ /* D9h */, C_MODRM /* DAh */, C_MODRM /* DBh */, C_MODRM /* DCh */, C_MODRM /* DDh */, C_MODRM /* DEh */, C_MODRM /* DFh */, C_MODRM /* end of FPU */ /* E0h */, C_IMM8+C_REL /* loopne/loopnz imm8 */ /* E1h */, C_IMM8+C_REL /* loope/loopz imm8 */ /* E2h */, C_IMM8+C_REL /* loop imm8 */ /* E3h */, C_IMM8+C_REL /* jecxz imm8 */ /* E4h */, C_IMM8 /* in al,imm8 */ /* E5h */, C_IMM8 /* in eax,imm8 */ /* E6h */, C_IMM8 /* out imm8,al */ /* E7h */, C_IMM8 /* out imm8,eax */ /* E8h */, C_IMM32+C_REL /* call imm32 */ /* E9h */, C_IMM32+C_REL /* jmp imm32 (near) */ /* EAh */, C_IMM32+C_IMM16 /* jmp far imm16 (far) */ /* EBh */, C_IMM8 /* jmp imm8 (short) */ /* ECh */, C_SIZE1 /* in al,dx */ /* EDh */, C_SIZE1 /* in eax,dx */ /* EEh */, C_SIZE1 /* out dx,al */ /* EFh */, C_SIZE1 /* out dx,eax */ /* F0h */, C_PREFIX /* Prefix Group 1 - Lock Prefix: LOCK */ /* F1h */, C_SIZE1 /* ICEBP (INT1 - ICE Break Point) */ /* F2h */, C_PREFIX /* Prefix Group 1 - Repeat Prefix: REPNE */ /* F3h */, C_PREFIX /* Prefix Group 1 - Repeat Prefix: REP/REPE */ /* F4h */, C_SIZE1 /* hlt */ /* F5h */, C_SIZE1 /* cmc */ /* F6h */, C_MODRM+C_IMM8 /* test not neg mul imul div idiv */ /* F7h */, C_MODRM+C_IMM32 /* test not neg mul imul div idiv */ /* F8h */, C_SIZE1 /* clc */ /* F9h */, C_SIZE1 /* stc */ /* FAh */, C_SIZE1 /* cli */ /* FBh */, C_SIZE1 /* sti */ /* FCh */, C_SIZE1 /* cld */ /* FDh */, C_SIZE1 /* std */ /* FEh */, C_MODRM /* inc/dec */ /* FFh */, C_MODRM /* inc/dec */ }; /************************************/ unsigned char op_tbl2[256] = { /* 01h */ C_UNKNOWN /* 02h */, C_UNKNOWN /* 03h */, C_UNKNOWN /* 04h */, C_UNKNOWN /* 05h */, C_UNKNOWN /* 06h */, C_UNKNOWN /* 07h */, C_UNKNOWN /* 08h */, C_UNKNOWN /* 09h */, C_UNKNOWN /* 0Ah */, C_UNKNOWN /* 0Bh */, C_UNKNOWN /* 0Ch */, C_UNKNOWN /* 0Dh */, C_UNKNOWN /* 0Eh */, C_UNKNOWN /* 0Fh */, C_UNKNOWN /* 10h */, C_UNKNOWN /* 11h */, C_UNKNOWN /* 12h */, C_UNKNOWN /* 13h */, C_UNKNOWN /* 14h */, C_UNKNOWN /* 15h */, C_UNKNOWN /* 16h */, C_UNKNOWN /* 17h */, C_UNKNOWN /* 18h */, C_UNKNOWN /* 19h */, C_UNKNOWN /* 1Ah */, C_UNKNOWN /* 1Bh */, C_UNKNOWN /* 1Ch */, C_UNKNOWN /* 1Dh */, C_UNKNOWN /* 1Eh */, C_UNKNOWN /* 1Fh */, C_UNKNOWN /* 20h */, C_MODRM /* mov Rd,Cd (mov reg,crx) */ /* 21h */, C_MODRM /* mov Rd,Dd (mov reg,drx) */ /* 22h */, C_MODRM /* mov Cd,Rd (mov crx,reg) */ /* 23h */, C_MODRM /* mov Dd,Rd (mov drx,reg) */ /* 24h */, C_UNKNOWN /* 25h */, C_UNKNOWN /* 26h */, C_UNKNOWN /* 27h */, C_UNKNOWN /* 28h */, C_UNKNOWN /* 29h */, C_UNKNOWN /* 2Ah */, C_UNKNOWN /* 2Bh */, C_UNKNOWN /* 2Ch */, C_UNKNOWN /* 2Dh */, C_UNKNOWN /* 2Eh */, C_UNKNOWN /* 2Fh */, C_UNKNOWN /* 30h */, C_SIZE1 /* wrmsr */ /* 31h */, C_SIZE1 /* rdtsc */ /* 32h */, C_SIZE1 /* rdmsr */ /* 33h */, C_SIZE1 /* rdpmc */ /* 34h */, C_SIZE1 /* sysenter */ /* 35h */, C_SIZE1 /* sysexit */ /* 36h */, C_UNKNOWN /* 37h */, C_UNKNOWN /* 38h */, C_UNKNOWN /* 39h */, C_UNKNOWN /* 3Ah */, C_UNKNOWN /* 3Bh */, C_UNKNOWN /* 3Ch */, C_UNKNOWN /* 3Dh */, C_UNKNOWN /* 3Eh */, C_UNKNOWN /* 3Fh */, C_UNKNOWN /* 40h */, C_UNKNOWN /* 41h */, C_UNKNOWN /* 42h */, C_UNKNOWN /* 43h */, C_UNKNOWN /* 44h */, C_UNKNOWN /* 45h */, C_UNKNOWN /* 46h */, C_UNKNOWN /* 47h */, C_UNKNOWN /* 48h */, C_UNKNOWN /* 49h */, C_UNKNOWN /* 4Ah */, C_UNKNOWN /* 4Bh */, C_UNKNOWN /* 4Ch */, C_UNKNOWN /* 4Dh */, C_UNKNOWN /* 4Eh */, C_UNKNOWN /* 4Fh */, C_UNKNOWN /* 50h */, C_UNKNOWN /* 51h */, C_UNKNOWN /* 52h */, C_UNKNOWN /* 53h */, C_UNKNOWN /* 54h */, C_UNKNOWN /* 55h */, C_UNKNOWN /* 56h */, C_UNKNOWN /* 57h */, C_UNKNOWN /* 58h */, C_UNKNOWN /* 59h */, C_UNKNOWN /* 5Ah */, C_UNKNOWN /* 5Bh */, C_UNKNOWN /* 5Ch */, C_UNKNOWN /* 5Dh */, C_UNKNOWN /* 5Eh */, C_UNKNOWN /* 5Fh */, C_UNKNOWN /* 60h */, C_UNKNOWN /* 61h */, C_UNKNOWN /* 62h */, C_UNKNOWN /* 63h */, C_UNKNOWN /* 64h */, C_UNKNOWN /* 65h */, C_UNKNOWN /* 66h */, C_UNKNOWN /* 67h */, C_UNKNOWN /* 68h */, C_UNKNOWN /* 69h */, C_UNKNOWN /* 6Ah */, C_UNKNOWN /* 6Bh */, C_UNKNOWN /* 6Ch */, C_UNKNOWN /* 6Dh */, C_UNKNOWN /* 6Eh */, C_UNKNOWN /* 6Fh */, C_UNKNOWN /* 70h */, C_UNKNOWN /* 71h */, C_UNKNOWN /* 72h */, C_UNKNOWN /* 73h */, C_UNKNOWN /* 74h */, C_UNKNOWN /* 75h */, C_UNKNOWN /* 76h */, C_UNKNOWN /* 77h */, C_UNKNOWN /* 78h */, C_UNKNOWN /* 79h */, C_UNKNOWN /* 7Ah */, C_UNKNOWN /* 7Bh */, C_UNKNOWN /* 7Ch */, C_UNKNOWN /* 7Dh */, C_UNKNOWN /* 7Eh */, C_UNKNOWN /* 7Fh */, C_UNKNOWN /* 80h */, C_IMM32 /* jcc imm32 */ /* 81h */, C_IMM32 /* 82h */, C_IMM32 /* 83h */, C_IMM32 /* 84h */, C_IMM32 /* 85h */, C_IMM32 /* 86h */, C_IMM32 /* 87h */, C_IMM32 /* 88h */, C_IMM32 /* 89h */, C_IMM32 /* 8Ah */, C_IMM32 /* 8Bh */, C_IMM32 /* 8Ch */, C_IMM32 /* 8Dh */, C_IMM32 /* 8Eh */, C_IMM32 /* 8Fh */, C_IMM32 /* end: jcc imm32 */ /* 90h */, C_UNKNOWN /* 91h */, C_UNKNOWN /* 92h */, C_UNKNOWN /* 93h */, C_UNKNOWN /* 94h */, C_UNKNOWN /* 95h */, C_UNKNOWN /* 96h */, C_UNKNOWN /* 97h */, C_UNKNOWN /* 98h */, C_UNKNOWN /* 99h */, C_UNKNOWN /* 9Ah */, C_UNKNOWN /* 9Bh */, C_UNKNOWN /* 9Ch */, C_UNKNOWN /* 9Dh */, C_UNKNOWN /* 9Eh */, C_UNKNOWN /* 9Fh */, C_UNKNOWN /* A0h */, C_SIZE1 /* push fs */ /* A1h */, C_SIZE1 /* pop fs */ /* A2h */, C_SIZE1 /* cpuid */ /* A3h */, C_MODRM /* bt Ev,Gv */ /* A4h */, C_UNKNOWN /* A5h */, C_UNKNOWN /* A6h */, C_UNKNOWN /* A7h */, C_UNKNOWN /* A8h */, C_SIZE1 /* push gs */ /* A9h */, C_SIZE1 /* pop gs */ /* AAh */, C_UNKNOWN /* ABh */, C_UNKNOWN /* ACh */, C_UNKNOWN /* ADh */, C_UNKNOWN /* AEh */, C_UNKNOWN /* AFh */, C_MODRM /* imul Gv,Ev */ /* B0h */, C_MODRM /* cmpxchg Eb,Gb */ /* B1h */, C_MODRM /* cmpxchg Ev,Gv */ /* B2h */, C_UNKNOWN /* B3h */, C_MODRM /* btr Ev,Gv */ /* B4h */, C_UNKNOWN /* B5h */, C_UNKNOWN /* B6h */, C_MODRM /* movzx Gv,Eb */ /* B7h */, C_MODRM /* movzx Gv,Ew */ /* B8h */, C_UNKNOWN /* B9h */, C_UNKNOWN /* BAh */, C_MODRM+C_IMM8 /* bt/bts/btr/btc Ev,imm8 */ /* BBh */, C_MODRM /* BTC Ev,Gv */ /* BCh */, C_MODRM /* BSF Gv,Ev */ /* BDh */, C_MODRM /* BSR Gv,Ev */ /* BEh */, C_MODRM /* movsx Gv,Eb */ /* BFh */, C_MODRM /* movsx Gv,Ew */ /* C0h */, C_UNKNOWN /* C1h */, C_UNKNOWN /* C2h */, C_UNKNOWN /* C3h */, C_UNKNOWN /* C4h */, C_UNKNOWN /* C5h */, C_UNKNOWN /* C6h */, C_UNKNOWN /* C7h */, C_UNKNOWN /* C8h */, C_SIZE1 /* bswap reg */ /* C9h */, C_SIZE1 /* CAh */, C_SIZE1 /* CBh */, C_SIZE1 /* CCh */, C_SIZE1 /* CDh */, C_SIZE1 /* CEh */, C_SIZE1 /* CFh */, C_SIZE1 /* end: bswap reg */ /* D0h */, C_UNKNOWN /* D1h */, C_UNKNOWN /* D2h */, C_UNKNOWN /* D3h */, C_UNKNOWN /* D4h */, C_UNKNOWN /* D5h */, C_UNKNOWN /* D6h */, C_UNKNOWN /* D7h */, C_UNKNOWN /* D8h */, C_UNKNOWN /* D9h */, C_UNKNOWN /* DAh */, C_UNKNOWN /* DBh */, C_UNKNOWN /* DCh */, C_UNKNOWN /* DDh */, C_UNKNOWN /* DEh */, C_UNKNOWN /* DFh */, C_UNKNOWN /* E0h */, C_UNKNOWN /* E1h */, C_UNKNOWN /* E2h */, C_UNKNOWN /* E3h */, C_UNKNOWN /* E4h */, C_UNKNOWN /* E5h */, C_UNKNOWN /* E6h */, C_UNKNOWN /* E7h */, C_UNKNOWN /* E8h */, C_UNKNOWN /* E9h */, C_UNKNOWN /* EAh */, C_UNKNOWN /* EBh */, C_UNKNOWN /* ECh */, C_UNKNOWN /* EDh */, C_UNKNOWN /* EEh */, C_UNKNOWN /* EFh */, C_UNKNOWN /* F0h */, C_UNKNOWN /* F1h */, C_UNKNOWN /* F2h */, C_UNKNOWN /* F3h */, C_UNKNOWN /* F4h */, C_UNKNOWN /* F5h */, C_UNKNOWN /* F6h */, C_UNKNOWN /* F7h */, C_UNKNOWN /* F8h */, C_UNKNOWN /* F9h */, C_UNKNOWN /* FAh */, C_UNKNOWN /* FBh */, C_UNKNOWN /* FCh */, C_UNKNOWN /* FDh */, C_UNKNOWN /* FEh */, C_UNKNOWN /* FFh */, C_UNKNOWN }; #pragma pack(pop) ----- ----- disasm.cpp /* IA32 32bits mode specific length disassembler */ #include #include #include "disasm.h" /* opcode table */ /* Func: int disasm() @params: inst_start: ディスアセンブルする命令 dsm : ディスアセンブルの結果を格納する構造体 @return: length: */ int disasm(unsigned char* inst_start, dsminfo* dsm) { unsigned char inst; unsigned char* pos; unsigned char op_tbl_flags; memset(dsm,0,sizeof(dsminfo)); pos = inst_start; inst = *pos; /************** * prefix の解析 **************/ op_tbl_flags = op_tbl[inst]; while(op_tbl_flags == C_PREFIX){ switch (inst){ /* repeat prefix */ case 0xF3: case 0xF2: case 0xF0: dsm->repeat_lock_prefix_p=true; break; /* segment prefix */ case 0x2E: case 0x36: case 0x3E: case 0x26: case 0x64: case 0x65: dsm->segment_branchhint_prefix_p=true; break; /* operand size prefix */ case 0x66: dsm->operand_size_prefix_p=true; break; /* address size prefix */ case 0x67: dsm->address_size_prefix_p=true; break; }; dsm->length++; pos++; inst=*pos; op_tbl_flags=op_tbl[inst]; if(dsm->length == 4){ break; }; }; /* while - prefix */ dsm->prefix_length=dsm->length; /* end of prefix scan */ dsm->length++; /**************************** * TWO bytes(ESCAPE) opecode ****************************/ if (op_tbl_flags == C_ESCAPE){ pos++; inst=*pos; op_tbl_flags=op_tbl2[inst]; dsm->length++; dsm->two_bytes_opcode_p = true; }; /************************* * UNKNOWN *************************/ if (op_tbl_flags == C_UNKNOWN){ dsm->length=0; return dsm->length; }; /*********************** * ONE byte Instruction ************************/ if (op_tbl_flags == C_SIZE1) { pos++; return dsm->length; }; /************************** * MODRM **************************/ if (op_tbl_flags & C_MODRM){ pos++; /* pos point to MODRM byte */ inst=*pos; dsm->length++; /* modrm byte */ /* check MODRM for displacement */ switch (inst & MODRM_MOD_MASK){ case MODRM_MOD00: if((inst & MODRM_RM_MASK) == 0x05){ /* Mod:00 RM:101 == disp32 */ dsm->displacement_size = dsm->address_size_prefix_p ? 2 : 4; dsm->length += dsm->displacement_size; }; break; case MODRM_MOD01: dsm->displacement_size = 1; dsm->length += dsm->displacement_size; break; case MODRM_MOD10: dsm->displacement_size = dsm->address_size_prefix_p ? 2 : 4; dsm->length += dsm->displacement_size; break; }; /* end modrm field check for disp*/ /* check MODRM for sib */ if((inst&MODRM_MOD_MASK) != MODRM_MOD11){ if((inst & MODRM_RM_MASK) == 0x04){ /* RM: 100 == SIB */ dsm->sib_p = true; dsm->length++; }; }; /* end modrm check for sib */ } /* MODRM */ /******************** * IMM ********************/ if(op_tbl_flags & C_IMM8){ dsm->length++; dsm->c_imm8_size++; }; if(op_tbl_flags & C_IMM32){ if(dsm->operand_size_prefix_p){ dsm->length+=2; dsm->c_imm32_size=2; }else if(dsm->address_size_prefix_p && !(op_tbl_flags & C_REL)){ dsm->length+=2; dsm->c_imm32_size=2; } else{ dsm->length+=4; dsm->c_imm32_size=4; } } if(op_tbl_flags & C_IMM16){ dsm->length+=2; dsm->c_imm16_size=2; } /* end of IMM */ return dsm->length; }; void display(dsminfo dsm) { printf("Length: %d\n", dsm.length); printf("Prefix: Rep Seg Ope Adr\n"); printf(" %3d %3d %3d %3d\n", dsm.repeat_lock_prefix_p, dsm.segment_branchhint_prefix_p, dsm.operand_size_prefix_p, dsm.address_size_prefix_p); printf("Prefix length: %d\n",dsm.prefix_length); printf("Displacement Length: %d\n", dsm.displacement_size); printf("SIB? : %3d\n", dsm.sib_p); printf("2-byte Opcode?: %d\n",dsm.two_bytes_opcode_p); printf("imm8: %d\n", dsm.c_imm8_size); printf("imm16: %d\n", dsm.c_imm16_size); printf("imm32: %d\n", dsm.c_imm32_size); }; int main(int argc, char* argv[]) { dsminfo dsm; // unsigned char instdata[]= {0x50}; // unsigned char instdata[]= {0x08,0xc0}; unsigned char instdata[]= { // 0x66,0x05,0x08,0x00 0x81,0xc6,0x08,0x00,0x00,0x00,0x00 }; disasm(instdata, &dsm); display(dsm); return 0; }; ----- x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x --- 第3章: レイヴパーティーの現状と2次元児童ポルノ規制の類似点 --- 著者:ローリングクレイドル x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x ■0x01.) 現場で見たレイヴパーティーの姿  のりピー騒動やら何やらで、すっかり「ドラッグ乱用の温床」「クズの集まり」 というイメージが定着したレイヴパーティー。要は公園やキャンプ場などの野外 でトランス等の音楽を大音量で流し、参加者が踊り狂うというもので、80年代 のヨーロッパで発祥したものが日本にも入ってきて今でも続いている。  レイヴにもトランスにも全く関心がなかった筆者ですが、1年ほど前からレイ ヴに興味を持ち、レイヴにスタッフとして参加したり、機材レンタルの手伝いな どで他のパーティーをのぞいたりしたことで、現場レベルでの実態が分かってき た。  まずドラッグ関連については、蔓延しているという認識はあながち間違っては いない。あるレイヴパーティーでは、DJブースに大麻入りクッキーが置き忘れ られるという珍事も目撃したことから、参加者のみならずDJの中にもドラッグ 使用者はいると思われる。参加者にしても、壁に向かって話しかけている奴、ひ たすらコインを積み重ねて崩しては笑っている奴、ドラッグで酔い潰れて痴漢に 乳を揉まれまくっていても気付かない女性など、おかしな人達をたくさん見掛け た。  とはいえ、参加者にしてもDJにしてもドラッグ使用者はほんの一部であり、 普通に遊びに行って踊っているだけならば、ドラッグ等の犯罪とかかわることは ない。ドラッグ使用者にも話を聞いたが、ほとんどが自分でドラッグを用意して 行ったり、自分から売人に接触したりしていた。  レイヴがあろうとなかろうと、彼らは似たようなイベントで自ら進んでドラッ グを使用するであろうし、レイヴという文化が悪いのではなく犯罪に手を染める 人間が悪いだけである。  しかし、レイヴにドラッグ使用者や売人が集まりやすいのは事実で、これはレ イヴという文化が発祥の時点でドラッグと切っても切れない関係にあったことが 大きい。押尾学事件で注目されたMDMAは、レイヴ御用達のドラッグとして知 られている。レイヴに慣れ親しんだ者ほど、創成期のレイヴにあこがれ、「ドラ ッグを使ってこそのレイヴ」と考えているフシがある。ただし、これもロックや パンクにドラッグがつきものだったのと一緒で、レイヴだから特別にどうという 話ではない。  もちろん、そういった環境にあるレイヴを社会的に問題視するのは正しい判断 である。しかし、若者文化とドラッグの関係は今に始まったことではない。クラ ブが流行する以前の90年代はディスコで同じようにドラッグが蔓延していたし、 もっとさかのぼれば現在のレイヴパーティーに眉をひそめている団塊世代もハイ ミナール(催眠・抗痙攣薬)を使ったパーティーをやっていたし、60〜70年 代当時の野外音楽イベントでも大麻は蔓延していたと聞く。  つまりは、多少の形が変わっただけで以前からの若者文化と同じであり、そこ にドラッグ等の犯罪がかかわってくるのも変わらない。そういった文化が問題視 されるのも歴史の繰り返しであり、程よく叩かれて沈静化し、また形を変えた文 化が盛り上がるだけなのだ。エジプトの古文書に「最近の若い者は…」と書かれ ていたというエピソードのように、叩く方にしても叩かれる方にしても、人類の 進歩のなさが感じられるだけである。 ■0x02.) レイヴへの風当たり  レイヴ開催に対する風当たりが思った以上に強いことも実感した。とにかくイ メージが悪く、ドラッグの問題だけでなく、ヤンキーが酔ってケンカをしたり、 器物破損したり、割れたビンなどのゴミを放置したりと、「パーティーでの恥は かき捨て」と考えている連中が多い。  そんなことが積み重ねられ、レイヴパーティーに会場を貸さない公園やキャン プ場が増えている。パーティーの聖地と呼ばれる「代々木公園」は、最近になっ て音楽イベントへの貸出しを実質的に受け付けなくなった。もちろん、正当な理 由なく自治体管理の公園が一般市民への貸し出しを断ることは問題があるので、 音楽イベントができないくらいの音量制限を利用規約に盛り込むという形だ。  これは、住民からの騒音苦情があったからとレイヴ主催者側に説明されている が、あるレイヴ主催団体が聞き込み調査したところ、地元の町内会や住民からの 目立った苦情はない。  実際に強く苦情を出しているのは、公園の近くにあるNHKと代々木体育館の 前でやっている「コルテオ」(シルク・ドゥ・ソレイユのサーカス)であること が判明した。NHKやコルテオの苦情を無視するべきだとは言わないが、たった 2つの営利団体からの苦情で、一般の貸し出し希望者を締め出すという対応には 疑問を抱かざるを得ない。  では、代々木公園でダンスイベントや音楽イベントが本当になくなったのかと いえば、そうではない。  公園の規約が変わってすぐに、韓国のダンスグループ「ビッグバン」のフリー ライブが開催され、ファン8000人(主催者発表)が押し掛けている。一般の レイヴイベントであれば、多くても客は300人くらいのもの。  ステージも特別に改造してあり、スピーカーも大型で規約の音量制限を守って いるとは思えず、どう考えても一般のレイヴより公園の一般利用者や住民にとっ て迷惑だと思われる。それだけでなく、ダンスイベントでも企業のバックアップ がある商業イベントは開催が続いている。  大きな企業の後ろ盾があると役所的に断りづらいし、大きなイベントならば客 が地元に金を落とす。フジロックなどの野外フェスでも薬物使用者がいるのは周 知の事実だが、あれは宿泊費や飲食代など客が地元に多額の金を落としていくた め、地元から歓迎される形で開催される。こちらの場合は、野外フェスを迷惑に 感じている一部の一般住民の声は無視に近い扱いをされている。  一般の人達が主催するダンスイベントは、そんな後ろ盾がないから、公園側と したら断っても後腐れがないし、集まるのは金のない若者ばかりだから地元に金 も落ちない。結局は、一般人主催のレイヴなどに貸し出しても「メリットがない」 という理由が主であろう。  これは代々木公園だけでなく、都内の公園などではほとんどがレイヴパーティ への貸し出し禁止の方向になりつつある。利用規約を変える方法もあれば、急に 使用料を倍以上に値上げしたところもあり、ほとんどが正直に「貸し出し禁止」 とは言わない。自分たちに非がないように利用を断る方法を考えることに関して は、感心させられるものがある。  それだけに止まらず、一部の自治体(岐阜県関市)では市営キャンプ場にレイ ヴ貸し出し禁止を通達した。これは常識的に考えれば問題があるように思えるが、 世論の後押しを獲得していれば反対の声は起きにくいために可能なのである。 ■0x03.) 2次元児童ポルノ規制との類似点  上記の問題が何かに似ているなと思ったら、児童ポルノの2次元規制の話に似 ていると気付いた。  2次元規制の話は普通に考えればバカバカしい話である。しかし、ロリマンガ や凌辱物の2次元ポルノを愛好している者が性犯罪に走るケースがマスコミ等で 問題視され、世間的にロリマンガ愛好者=犯罪者予備軍というイメージが強くな っている。全く無関係のように見えて、構造的にはレイヴの薬物問題のイメージ と非常に似ている。  もちろん、ロリマンガ愛好者で犯罪に走るのは一握りの者だし、それは犯罪者 が悪いのであって2次元作品のせいではない。そういった者は、ロリマンガや凌 辱物作品があろうとなかろうと別のきっかけで犯罪に走るのだろうが、世間的に は犯罪者も単なる愛好者も「自分の知らないところでよく分からないことをして いる気持ち悪い存在」として同じである。  レイヴパーティーに集う者への世間のイメージも同じである。  ロリコン作品があるから犯罪が起きるのだという考え方、レイヴがあるから薬 物が蔓延するという考え方、どちらも問題の本質をはき違えている。無理解から くる報道の鵜呑みにより、世間的な偏ったイメージが形成され、法律的に問題が あるのではないかと思われる規制が検討される状況も似ている。同時に、これは 主催者や出版社、レイヴ参加者、ロリマンガ愛好者が世間からのイメージに無頓 着だったことが事態を悪化させたという点も共通している。  また、2007年に都立産業貿易センターが「アブノーマルカーニバル」とい う名称のエロ同人誌即売会に対し、貸し出し拒否を通知したということがあった。 筆者は某誌での記事執筆のため、同センターを運営する東京都中小企業振興公社 に取材をしたことがある。  応対していただいた担当者は「新聞報道では『貸し出し拒否』となっています が、それは間違いで断ってはいません。条例に触れる可能性があるのではないか と主催者側に確認したところ、相手方が自主的に辞退しました」と主張していた。  しかし、条例うんぬんの問題であればコミケのように自主規制的な対策を講じ ればいいだけで、単に確認された程度で告知済みのイベントを急に取りやめると は思えない。  これはレイヴの貸し出し禁止と同じで、自治体管理の施設が明確な理由なしに 一般市民の利用を断るということには問題があり、実質的には強制であっても「 自主的に辞退した」という形にしたいわけである。  自分は即売会の主催者にも取材したが、驚くことに「記事を掲載した読売新聞 からは、当方に取材依頼がありませんでした」と言われた。  こうなると、報道で管理者側の言い分ばかりが強調され、主催者側の言い分は 無いものとして扱われてしまう。さらにマスコミ的な誇張した表現も入り、世間 からのイメージはさらに悪くなる。  2次元エロ業界でもレイヴでも、世間に迷惑を掛けないようにやっている真面 目な人々はいるのだが、そういった人々の声が大手マスコミで紹介されることは ない。どちらも擁護すれば「お前もロリコンか」「お前も薬物をやっているのだ ろう」と言われ、表立った場所で擁護する者も少ない。  これでは状況は悪化することはあっても、改善することは難しいだろう。  世間からの白眼視に耐えながら自分たちの愛する文化を守ろうとする人々を応 援したいと思うと同時に、こうやって文化が創造されては無理解によって潰され ていくのは、延々と続いていく人間の避けられない業なのかとも思う。  さらにいえば、長いスパンで考えれば世間からの抑圧は、文化を発展させてい くために必要なことなのかもしれない。  そういったことを踏まえながら、世間から異常な批判を受ける二つの文化に今 後も注目していきたい。 x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x --- 第4章: 基礎暗号学講座・第23回 〜コミットメントスキーム〜 --- 著者:IPUSIRON x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x x0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0xx0xXx0x ■0x01.) はじめに  WB43〜WB47までは平方剰余という数学的概念や平方剰余仮定に基づく暗号技術 を紹介した。今回はまったく違った方向性の暗号技術を紹介するので、前回まで の記事が読みにくくてよくわからなかった場合でも今回の記事は読めると思う。  今回の記事の後半では離散対数問題の困難性について言及しているので、必要 に応じてWB33を復習してもらいたい。 ■0x02.) コミットメントスキームとは  今回取り上げるコミットメントスキーム(commitment scheme)は暗号技術のひ とつである。様々な暗号技術が存在する中で、コミットメントスキームは複雑な 暗号技術を構成するときの道具の中で最も基本的なもののひとつという立場にあ る。つまり、縁の下の力持ちのような存在といえるでしょう。  コミットメントスキームの仕組みを直観的に言うと「ある値を約束しておいて、 ある時点以降その値を明かす」という暗号技術のことである(「コミットメント」 とは元々「約束」「委託」という意味を持つ)。あまりにも直観的すぎて逆にわ かりにくいかもしれないので、コミットメントスキームにおけるやり取りをもう 少し具体的に見ていく。 m ↓ -------------- -------------- | S | | R | | r←R | | | | c=Com(m;r) | c | | | |----------->| | | | | | COMMITフェーズ ======================================================= | | m,r | | REVEALフェーズ | |----------->| ? | | | | c=Com(m,r) | | | |If 一致 then| | | | output m, | | | |else | | | | abort. | -------------- -------------- ↓ m  まず送信者Sと受信者Rがいて、この2者がコミットメントスキームを行うとする。 ここで、Comは一種の暗号化関数のようなもので、公開されているものとする。  このときSがメッセージmをRに対して約束したいとする。するとSは乱数rを選択 し、c=Com(m;r)を計算する。この記号はComという関数にmとrを代入したと考えて もらってよい。このcは暗号化関数の出力結果なのである意味暗号文のようなもの である。このcをRに送信する。ここまでをCOMMITフェーズという。  次に、ある時点以降になると、Sはm,rをRに送信する。Sは今受け取ったm,rから Com(m;r)を計算し、その結果がCOMMITフェーズで受け取ったcと一致するかどうか を検証する。もし一致すればmを出力し、そうでなければ停止する。ある時点から ここまでをREVEALフェーズという。  COMMITフェーズが終わってから、いきなりREVEALフェーズに入ってもコミット メントスキームとしては問題ないが、実用上まったく意味がない。一般的には何 らかの別の仕事が終わってから、REVEALフェーズに入って、m,rがRに投げられる。  最終的にREVEALフェーズが終われば、S,Rの両者がmを知ることができた。つま り、約束した値mできちんと共有されたことが保障されるわけである。  ちなみに、ここで具体的に示したやり取りはあくまで非対話型のコミットメン トスキームの話である。非対話型とは通信のやり取りが一方通行のものである。 非対話型に対して対話型というものもあるが、これは通信のやり取りが双方向の ものである。  対話型のコミットメントスキームも存在するが、ここでは単純な非対話型なコ ミットメントスキームの仕組みを紹介した。なお、対話型のコミットメントスキ ームも同様にして定義できる。 ■0x03.) コミットメントスキームの応用例  このコミットメントスキームの応用例として、仕事の発注先を決定する入札シ ステムを考えた。この入札システムには以下のルールが設けられているとする。 (1) 入札者は入札値を隠した状態で、発注者に預ける。 (2) 入札者は何回も入札できるが、最終的に一番高い入札値のみが自分の入札値 として認識される。 (3) 入札値は期日まで伏せられており、他の入札者だけでなく仕事の発注者にも わからないものとする(なぜならば発注者が入札値を知ってしまったら、懇意の 入札値の低い相手に対して、「あなたは今最高入札値ではないから、入札値を○ 円の額よりも上げる必要がある」と助言してしまうかもしれない。こうすること で、懇意の入札者が最終的に落札できてしまうことになってしまう。これでは公 平なシステムではない)。 (4) 期日を越えると入札値の比較が行われて、入札値が一番高い入札者が仕事を 引き受けることができる。  この入札システムは一種の匿名オークションのようなものと言えるだろう。で は、この入札システムを実現するためにはどうしたらよいだろうか?  例えば、公開鍵暗号方式を素朴に用いてこの入札システムを実現できるか考え てみる。入札者は公開鍵暗号方式の暗号化アルゴリズムを用いて(暗号化アルゴ リズムに入札値と受信者の公開鍵を入力する)、入札値を暗号化する。この暗号 化された入札値を発注者に送信する。他の入札者がこの通信を盗聴したとしても、 暗号化されているので入札値が漏れて不利になることはない。しかし、発注者は 自分の秘密鍵と用いて、いつでも暗号文を復号できてしまう。これはルール(3)に 反しているので、公開鍵暗号方式を素朴に使った方法ではこの入札システムを実 現できない。  次に、共通鍵暗号方式を素朴に用いてこの入札システムを実現できるか考えて みる。入札者は入札値を共通鍵(ただしまだ発注者とは共有していない)で暗号 化する。そして、入札の期日後に、入札者は入札値(=平文)と共通鍵を発注者 に送信する。この仕組みのときに、不正な入札者は入札期日時に、暗号化に利用 した入札値と共通鍵の組を正直に送るとは限らない。例えば、他の入札者が発注 者に入札値と共通鍵の組を送信しているので、それを盗聴することで、ライバル 入札者の入札値を知ることができる。その入札値よりも自分の入札値が小さけれ ば、なんとかライバル入札者の入札値よりも高い入札をしたように、発注者を騙 したい。そこで、共通鍵暗号方式の復号アルゴリズムに自社の入札値の暗号文と 適当な共通鍵を入力する。すると、対応する平文が出力される。この平文の値が ライバル入札者の入札値よりも高ければ、復号アルゴリズムの入力で利用した共 通鍵とその出力結果を発注者に送信すればよい。もし、そうでなければまた別の 共通鍵を生成して、それを利用して同様のことを行えばよい。何回か繰り返せば、 落札を決定付けるような平文を得ることができるだろう。  特に共通鍵暗号方式がバーナム暗号のように暗号化アルゴリズムが平文と共通 鍵のXOR演算のように単純だった場合は、上記のようなことをせずともライバル落 札者の落札値に+1した値(なぜこの値を採用したのかというと、最も安い値段で 自社が落札できるから)を自分の落札値にしてしまうことは簡単である。「(自 社が送信しておいた落札値の暗号文)=(ライバル落札者の落札値に+1した値) XOR(つじつまを合わせるための共通鍵)」を満たすような共通鍵を計算すればよ い。そのためには単に「(自社が送信しておいた落札値の暗号文)XOR(ライバル 落札者の落札値に+1した値)」を計算しればすむ。  よって、共通鍵暗号方式を素朴に用いてしまうと、入札者が不正できてしまう のである。  以上をまとめると、素朴に公開鍵暗号方式や共通鍵暗号方式を利用して、この 匿名オークションは参加者全員が安心して使うことができないことがわかった( 上記で考えたような素朴な方法以外ではあるかもしれない)。つまり、誰かが有 利になってしまい、フェアな取引が成立しないということになる。結局、全員が 安心して使えるような入札システムを実現するにはどうしたらよいだろうか。  その解決方法のひとつとして、コミットメントスキームを採用すればよさそう である。 ■0x04.) コミットメントスキームの定義  コミットメントスキームは次の2つの性質(安全性)を必ず持つ。  1つ目が秘匿性(hiding)である。  これはCOMMITフェーズにおいて、cからmの情報が(部分情報でさえも)漏れて いないということである。即ち、任意の確率的多項式アルゴリズムがCom(m;r)と Com(m';r')が識別できない(m≠m'またはr≠r')。  入札システムの例で言うと、COMMITフェーズにおいては発注者は入札値を知る ことは不可能ということである。  2つ目が束縛性(binding)である。  これはREVEALフェーズにおいて、約束(コミット)した値であるm以外を送って も、検証式が成り立たないため、受信者は検知できる。即ち、任意の確率的多項 式時間アルゴリズムがc=Com(m;r)=Com(m';r')を満たす(c,(m,r),(m',r'))を生成 できない(ただし、m≠m')。  入札システムの例で言うと、COMMITフェーズにおいて1億円で約束しておいたの に、REVEALフェーズにおいて1億5千万円で受理させようとしてもできないという ことである。  この2つの性質があれば、0x02で紹介した匿名システムを安全に実現できる。  秘匿性は受信者の力を制限するものであり、束縛性は送信者の力を制限するも のである。送信者と受信者の両者の力のバランスを取るという考え方は安全な暗 号プロトコルを実現するために重要である。互いに牽制しあいつつ、満たすべき サービスを実現するのである。  暗号化の安全性の世界では、送受信者とは別の第三者が暗号文を盗聴し、その 対応する平文が漏れないことが議論の対象となる。一方、暗号プロトコルの世界 では、敵が第三者とは限らず、送信者・受信者のどちらかが敵である可能性があ るのである。プロトコルの仕様通りに動く限りは敵であってもサービスをきちん と提供できていなければならない。つまり、暗号プロトコルを構築するときは敵 が存在したとしても、サービスを実現しつつ、サービスの不正をできない仕組み になっている必要があるのである。コミットメントスキームの場合も同様である (プロトコルを強調するときはコミットメントプロトコルという)。 ■0x05.) Pedersen's scheme  コミットメントスキームの具体例として、Pedersen's schemeを紹介する。この スキームは離散対数ベースのコミットメントスキームである。  記号の定義をしておく。  p,qを素数(ただし、q|p-1)とする。gはg^q≡1 mod pを満たす値とする。Com (m;r):=g^m・h^rとする。  まずPedersen's schemeを実行する準備として、次の手順を行う。 1:sをZ_q^*からランダムに選択する。 2:h=g^sを計算する。 3:(p,q,g,h)を送信者Sと受信者Rの両者に対する公開情報(CRSという)とする。  その後で、SとRは次のようなやり取りをする。 1:CRSの(p,q,g,h)はS,Rに入力される。 2:Sはm(∈Z_q)をコミットしたいとする。このとき、Z_q^*からrをランダムに 選択し、c=Com(m;r)=g^m・h^r mod qを計算する。この計算結果のcをRに送信する。  ここまでがCOMMITフェーズである。 3:REVEALフェーズでは、Sがm,rをRに送信する。 4:RはCOMMITフェーズで得たcと、REVEALフェーズで得たm,rを使って、c=Com(m;r) (即ち、c≡g^m・h^r mod q)という検証式が成り立つかどうかを検証する。もし 成り立てばmを出力し、そうでなければ終了する。  以上がPedersen's schemeのS,Rのやり取りになる。  補足になるが、CRSは信頼できる第三者がS,Rに送信してもよいし、公開掲示板 と考えてもよい。  準備で生成したgはmod pの世界で位数がqの値である。  CRSとして、(p,q,g)が与えられるということは、位数がqの乗法群G(≦Z_p^*) が共有されているのと同じである。 ■0x06.) Pedersen's schemeの安全性  それではPedersen's schemeがコミットメントスキームあることを確かめる。 コミットメントスキームあるための必要条件が秘匿性と束縛性であったので、こ の2つの性質を満たすことを確認できればよい。  まず秘匿性を持つことを確認する。  Pedersen's schemeのコミットメント情報はc=g^m・h^r=g^(m+sr)である(sはg ,hの離散対数、即ちs=log_g(h))。ここでrはZ_q^*上から一様ランダムに選ばれ ているので、cはG上を一様分布している。  仮に、秘匿性を破ろうとする敵が無限の能力(指数時間の計算が可能)を持っ ていたとする。すると離散対数問題を破ることができるので、gの肩のm+sr mod q を知ることができる。しかし、rがわからないので、mを確定できない。つまり、 秘匿性を持つ。  無限の能力を持つ敵であっても秘匿性を維持できるので、完全な秘匿性(perf ect hiding)を持つという。  次に束縛性を持つことを確認する。  いつもの帰着法を用いる。束縛性を破る敵Aが存在するとする。このときAの入 力は(g,h,p,q)、Aの出力はc=g^m0・h^r0=g^m1・h^r1を満たす(c,(m0,r0),(m1,r1)) の組である。Aを利用して、離散対数問題を解くアルゴリズムBが構成できればよ い。  Bには(g,h,p)を入力とする。Bはq|p-1を満たすqを選び、Aに(g,h,p,q)を入力す る。すると、Aはc=g^m0・h^r0=g^m1・h^r1を満たす(c,(m0,r0),(m1,r1))が出力さ れる。Bはこの情報を利用して、(r1-r0)/(m0-m1) mod qを計算して、計算結果を 出力する。  h=g^{(r1-r0)/(m0-m1) mod q} mod pを満たすため、Bの出力はg,hの離散対数と なっている。つまり、離散対数問題を解くアルゴリズムが構成できた。この事実 は、確率的多項式時間アルゴリズムは離散対数問題を解くことが困難であること に矛盾する。ゆえに、Aは存在しない。  ゆえに、束縛性を持つ。Aは確率的多項式時間アルゴリズムであったので、厳密 には離散対数問題が困難という仮定の下で、計算量的な束縛性(computationally binding)を持つと言える。  以上によって、Pedersen's schemeはコミットメントスキームであることが確認 できた。 ■0x07.) Pedersen's schemeを利用した入札システム  コミットメントスキームであるPedersen's schemeを利用すれば、参加者全員が フェアである入札システムを本当に実現できるだろうか?結論から言えば、まだ 実現できないのである。  敵が別の送信者や受信者に成りすますという攻撃がある。コミットメントスキ ームのやり取りの場合で言えば、敵Aが送信者Sに対して受信者Rになりすましたり、 Rに対してはSとしてなりすますといった攻撃である。このような攻撃を中間者攻 撃という。  中間者攻撃を行う敵を想定した場合(実は中間者攻撃ができない普通の敵であ っても十分)、Pedersen's schemeを利用した入札システムは敵が安全性を破って しまう。 m ↓ -------------- -------------- ------------------- | S | | A | | R | | r←R | | | | | | c=Com(m;r) | c | | | | | |----------->| c^*=c×g | c^* | | | | | |----------->| | | | | | | | ========================================================================== | | m,r | | | | | |----------->| | | | | | | m^*=m+1 | | | | | | r^*=r | m^*,r^* | | | | | |----------->| ? | | | | | |c^*=Com(m^*,r^*) | | | | | | 必ず一致 | -------------- -------------- ------------------- ↓ m^*  ライバル入札者が送信する入札値の暗号文c=Com(m;r)の計算結果のcを敵Aが盗 聴する。そして、c^*=c×g mod pを計算し、その計算結果c^*を発注者に送信する。  そして、入札締め切り後、ライバル入札者は発注者に(m,r)を送信する。Aはそ れを盗聴し、m^*=m+1 mod q,r^*=rとし、発注者に(m^*,r^*)を送信する。  すると、Aは必ずライバル入札者よりもたった1円高い入札値で必ず落札できる。 つまり、敵が必ず落札できるということは、入札システムとして安全ではない。 ■0x08.) 中間者攻撃と頑強性  中間者攻撃に対しても耐性がある入札システムにするためには、コミットメン トスキームに新たにどのような安全性を追加すればよいだろうか。  中間者攻撃における攻撃とは、mと関係のあるm^*を生成し、それで受信者に受 理させること、即ち検証式を成り立たせることである(Pedersen's schemeに対す る中間者攻撃ではm^*=m+1という関係を持つ)。つまり、中間者攻撃に対して安全 であるためには、cやmを受け取っても、c^*やm^*を生成するのに有効に働かない ことである。つまり、mはm^*と関係がないということである。この中間者攻撃に 対する安全性は頑強【がんきょう】性(Non-Malleability:NM)という。  公開鍵暗号方式の安全性にもNM(IND≦NM。INDよりも強い安全性という意味) というものがあったが、直観的にはそのコミットメントスキーム版だと思えばよ い。  頑強性を満たすコミットメントスキームとして、Pass,Rosenの衝突困難なハッ シュ関数族が存在するという仮定に基づくコミットメントスキームや、Damgard, Nielsenのp-部分群仮定に基づくコミットメントスキーム(複数の送受信者が参加 する状況における頑強性を満たす。これをコンカレントな頑強性という)などが 知られている。  コンカレントな頑強性を持つコミットメントスキームを使えば、安全な入札シ ステムを実現できる。 ■0x09.) 終わりに  今回はコミットメントスキームの最もよく知られたPedersen's schemeを紹介し た。また、提供するサービスによってはPedersen's schemeの満たす性質だけでは 不十分であることを示した。  次回はコミットメントスキームの別の応用例であるコイン投げプロトコルか、 別のコミットメントスキーム(今回は離散対数ベースだったので、次回はQR仮定 に基づくものがよさそう)を紹介したい。 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://d.hatena.ne.jp/sato_c/ ●Mail: motosumi64@gmail.com ●Comment:  一時期のAndroid熱も若干冷めては来ましたが、それはネタがないからであり、 何かおもしろそうなネタを探さなくてはと思う今日この頃です。  でも、Java自体の勉強ももっと必要だと作っていて痛感したのでその辺含めて やっていこうと思っているところです。Javaの参考書、なにがイイやらわからん から余計です。  プログラムの解析ってのは、実際のところプログラムのデバッグと言い換える と身近なものだし、実際にプログラム見てて難しいところなんていうのは、ある 程度、数を読んでいれば、自然と似てるものに気がつくものなんですよっていう のを書きたかった本です。「クラッカーの教科書」ってタイトルに名前負けして なければいいんですが。 ●お勧めのゲームのソフト:  自他共に認めるモンハンキ○ガイなので、モンハン。しかも、3。  P2Gのほうが良かったとか言う話も聞くけど、やっぱ新しいモンスターはどいつ もこいつも動きその他いいですよ。中途半端な制限の中でカツカツになって作っ てるんじゃなくて環境変えて1から作っただけあって、イイできになってます。  キャラの髪型にイイ感じのがなかったので、そこだけはP2Gのやつも入れて欲し かったなーってくらいでしょうかね。 ■大原まひる (muffin) ●Job: 自称プロサーファー(ネット) ●Web: なし ●Mail: mfnvir@gmail.com ●Comment:  Common Lispとアセンブリ言語に興味あります。「Lispいいよ」と主張し続けて 早10年。近年のLispブームでようやく時代がLispに追いついた。  次はアセンブリ言語ブームのためにウイルスのブリブリな本を執筆中。執筆開 始して早3年。きっと7年後にはブームがきます。  7年後に出る本の話は置いておいて、「クラッカーの教科書」という本が出たみ たいで読んでいるところ。途中まで読んで思ったことを以下に列挙します。 - 著者がすごい - 内容はすごくわかりやすい - 思考の過程が細かく書かれていていい  僕が開発する自動解析ツールの参考資料にすることにしました。  クラッカーの思考過程を極限までに分解していく。分類してパターンを見出す。 一つ上のレベルへの抽象化を行う。そのレベルでのパターンを見出し、さらに上 のレベルへ抽象化を行う。これがまさにあれなんです。解析の核となるアセンブ リ言語に人工知能を得意とするCommon Lispが融合するのです。  僕の好きな2つの言語を融合させるわけです。7年後にウイルス本が完成してか ら開発に取りかかるので、その10年後、つまり今から17年後には公開できるはず です。 ●お勧めのゲームのソフト名:  なし。ゲーム機持ってない。テレビも持ってない。 ■ローリングクレイドル ●Job: ライター ●Web: http://yellowteardrops.web.fc2.com/ ●Mail: rollingcradle666@gmail.com ●Comment:  某アングラ編集者さんに誘われ、初めて記事を執筆させてもらいました。ニュ ースサイト運営とインターネットの話題を扱う雑誌連載をしております。  完全な文系人間のため、WBに執筆していいものかと悩みましたが、図々しくも 少し毛色の違う記事を書かせていただきました。  今回の記事への感想や、レイヴ関連、インターネットの話題、サブカル系マン ガ、芸能、アングラ関連での執筆依頼などがありましたら、気軽にメールをくだ さい。 ●お勧めのゲームのソフト名  もうゲーム機すら持っていないほどゲームから離れてしまってますが、携帯電 話で「探偵神宮寺三郎」シリーズをやっています。ファミコン時代から好きなシ リーズでしたが、こういうベタな推理物ゲームは少ないので、雰囲気を楽しんで ます。  目デカの萌え美少女より、洋子さんの方がエロいし素敵です。  あとプロレスファンに絶対お勧めなのは、PC-98やPCエンジンなどで出ていた女 子プロレスゲーム「レッスルエンジェルス」でしょうか。プロレスなのにカード ゲームという時点で異色なのですが、シリーズ3作目は団体運営シミュレーショ ンとなっており、マッチメイクや新人育成、選手引き抜き、海外団体との提携な どができます。興行場所を全国の実在の会場から選ぶことができるのですが、最 初は後楽園ホールや地方の体育館で始め、横浜文体や今はなき月寒グリーンドー ムを満員にし、最終的には東京ドームや福岡ドームに打って出るという熱い内容 になってます。  最近になって新作も出たようですが、いい評判を聞きません…。 ■IPUSIRON ●Job: プログラマー ●Web: http://akademeia.info ●Mail: ipusiron@gmail.com ●Comment:  今回は『クラッカーの教科書』の感想を書こうと思います。個人的には第3章が ためになりました。第3章はOllyDebugを使ってcrackmeを解析するというストーリ ーになります。しかし、いきなりOllyDebugの便利な機能を使うのでなく、デバッ ガ一般の標準的な機能によって解析を行い、その後で別のアプローチとして便利 な機能によって解析を行うという解説になっています。この点が非常によいと思 いました。なぜならば便利な機能の方法だけを習得してしまうと、原理の部分が おざなりになってしまうし、もしOllyDebugがない場合に対処できなくなってしま うからです。  私はまだ3章の途中までしか読んでいなのでこれ以上言えませんが、おそらく解 析(リバースエンジニアリングではない)に興味がある人には勉強になると思い ます。 ●お勧めのゲームのソフト:  最近はオンラインプレイが面白いゲームがたくさん出ていますが、どんなにゲ ームシステムがよくてもオンライン対戦をやっている人の絶対数が少なくなって くると面白さも半減してきます。例えば、CoD4はとてもよくできているのですが、 もう2年ぐらい経つとオンラインの参加数が数千人に減っていたりします。  それに比べてHalo3は人が少ない時間帯であっても5万人ぐらいはいます。多い ときだと数十万人です。Halo3:ODSTが発売されたばかりなので新規の人も増えた のかもしれません(Halo3ユーザーとODSTユーザー同士で対戦可能)。Halo3なら 結構安くなっているはずなので、まだやったことない人にはお勧めします。