第20回 コモンプラットホーム構想近況(Mac用移植者熱烈募集中:p)

12/4現在、コモンプラットホーム構想は着々と進みつつある。本当は、最初、夢物語のつもりだったのに、こんなに早くプロジェクトが進行するとは思わなかった。というのも、BMRのカーネルに仮想CPUのエミュレーションを採用し、その仮想CPU用のアセンブラとコンパイラ(C言語ライク)を実装し、あと各種ゲームのために必要となる部分(機種依存部)は有志のみんなで分担して、着々と進みつつある。

実は、やねうらおは、来年には家にWindowsNTとLinuxを導入しようと思っているので、そのへんで動作しないと痛い。そのへんで動作するかどうかは、wrapperの制作担当の手にかかっているわけだが、是非ともなんとかして欲しい。(とか、こんなところに書く奴)

一応、機種依存部分を完全に分離し、ゲーム自体は仮想CPUのコードで書いているので、誰でもゲーム本体の開発にも参加でき、かつ、BMRの移植されている機種であればどこででも動くという互換性を保つことが出来る。Linux用の機種依存部は、やねうらおが勉強用に作ろうと思っているが、まあ、ちんたらやねうらおなんかに任せてられっか〜という人がいれば、いくらでも交代しますんで(笑) あと、MAC用。なんか、BM98をマックに移植したいからソースコードくれ〜という人が、いままで数回いてたけど、BM98なんか移植するよりは、BMR移植するほうがよっぽど簡単だし、すっきりしてるし、常に最新版が走るし、汎用的だし、カッコイイ気がします。(なんかダレてるな〜この文章。最近、疲れぎみなんやね〜)

機種依存部は、

1.DirectSound
2.DirectDraw
3.DirectInput
4.FileAccess
5.MIDI Output
6.MIDI Input
7.JoyStick
8.CD再生がらみ
9.timerまわり

であります。仮に、CDの再生なら、

class CBMRCD : public CBMRcore {
static int getInfo(); // CDが利用可能であれば、その曲数を、利用不可であれば-1を返す。
static BOOL open(int track); // trackナンバーをopenする。成功したらtrue。
static BOOL play(); // openしたところを再生する。成功したらtrue。
static BOOL close(); // 再生中のを停止させる。再生終了時しているかどうかステータスを見てから
// 行なうこと!成功したらtrue。
static BOOL init(); // 初期化。CBMRcoreのvirtualメンバ。成功したらtrue
static BOOL terminate(); // 終了子。CBMRcoreのvirtualメンバ。成功したらtrue
static char* VersionInfo(); // ユニットのバージョン文字列を返す。(半角英数40文字程度)
// 実は、CBMRcoreのvirtualメンバ。
};

とゆー感じで、これだけ実装しておけば、OK。こんな感じで、機種依存部分だけ次々と移植すれば完成(のはず)。ちゅーことで、どなたかMac用って作りませんか?(とか言う奴)


第21回 ZIPファイルをcrackする(なんや?こんなん書いたらあかんのか?)

なんか、最近はアングラ系の大衆化が進み、ド素人でも裏系の掲示板に書き込みに来たりする。こんなところで言うのも何だが、昔は、裏系と言えば、ハッカーやクラッカーの温層であって、技術的にも世界で屈指の人たちが集まっていたわけだ。ハッカーゆうたら、それこそ神様みたいなもんでやね、Unixのソースコードなんか熟知してるから、それこそ欠陥なんかいろいろ知ってるわけよ。んで、そういうシステムの欠陥を利用して他のマシンに入り込んだ暁には、そこでパフォーマンスやらユーザー定義ファイルやらを調べて、ここをこうしなさいという処方箋までシステム管理者に提示して帰ってゆく親切なしとたちだったのよ。

それが、なんか、いまのハッカーって、ハッカーちゃうわ〜と思わんでもない。Win系のエロゲー交換のことしか頭になかったり、逆アセンブルすらろくにできない奴がいるし、それどころか、人の作ったプログラム使って、人の書いたマニュアル通りのハッキングしてるだけの奴もいるし、簡単なパスワードをハッキングするマクロが組めるだけのくせして、自分がすんげー高い技術を持ってるとか勘違いしている奴もいる。そいつらだって、言ってみれば、まだマシなほうで、まあ、下っ端ってきりがないほどレベルが低い。WinのエロゲーをCD−Rで朝から晩まで焼いてるだけのハッカーって、なんだか見ててなさけないずらよ〜。

そんなわけで、そんな状況に波紋を投げかけるべく、今回は、ZIP fileのパスワードをcrackする方法について述べる。どうでもいいことだが、crackとは、潰すことである。こういうの専門の人をクラッカーと呼ぶ。HackerとCrackerとはまったく別物であるという人もいるが、それは持っている思想や理念の違いであって、技術的な領域の違いからくるものではないと思う。Hackerも、crackぐらい出来なければならない。

まず、一言で言っておくが、ZIPパスワードというのは、基本的にcrackできない。何か期待して読んでた人、おめでとう〜、である。crackという言葉に花瓶(なんや?花いれる気か?!>ATOK11)に反応する人たちは、この文章の「crack」という単語をすべて「recovery」と置き換えてもらえれば結構。ちゅーか、やねうらおは、実際自分で自分のファイルにzip passwordをかけたのだが、そのpasswordを忘れたために必死こいてcrack(recoveryと読んでね!)した経験がある。しかし、出来ない。不可能に等しいのである。その理由を、これから述べる。

まず、ZIPのpasswordは、展開に使用しているのである。つまりは、passwordが一致しなければ、正常に展開できないのである。この点、ZIPを考えた人は、非常に偉い。展開してから、passwordが一致するかどうかを調べているのであれば、自前でZIPの展開ルーチンを書けばそれでOKなのだが、そうもいかない。

ZIPの有名なcrackソフト(何度も言うが、このcrackという文字はrecoveryと読むこと!)にAZPRというものがある。これは、Advanced Zip Password Recoveryとか何とか言う奴である。rarとzipをまとめてcrackするソフトもあったと思うが、知る限りまともなZIPのcrackツールはAZPRだけである。

こいつは、確か、パスワードを自動的に生成して、そのパスワードを用いて実際に解凍を行ない、そしてCRC(かな?)が一致するかどうかを調べて、一致しなければ次のパスワードにtryするというものである。検索は高速だが、時間は非常にかかる。アルファベットのみだとか、アルファベット大文字+数字のみの5文字以内だとか、そういった指定が出来るので、まだ救われる。

ところがそれでも20文字もあれば、アルファベット大文字だけとしても26^20通り、英数大文字、小文字なら、62^20通りもある。(log10 (62^20)=20 * 1.79 = 35.8桁もあるということだ。一秒間に1億通り調べたとしても、1兆年あっても終わらないということである) さらに、記号が入ってくれば、15文字程度でも、もう手の尽くしようがないだろう。

このように、ZIP Passwordというのは、非常に堅牢なのである。アホなプログラマの作るシェアウェアのパスワードチェックルーチンより数億倍はいい。あくまで、理論上は、である。本当は、ここからが真のハッカー(or クラッカー)の腕の見せ所なのだが、あいにくページの残りがもうないので、続きはまた後日にする。


第22回 スーパースカラー(Pentium 80000HMz)

その昔、祝一平(いまや、その筋の人しか知らんのかな〜)が、タコ足君などと言って、Z80を256個並べたらどうかなどと冗談とも本当ともとれるような構想を話していたが、そういうのは、やねうらおも考えたことがある。何と言っても、ハードは大の苦手なやねうらおなので、今回の話は、とてつもなく素人くさいミスを犯しているかも知れないが、ご容赦願いたい。

実際、並列処理でネックになるのは、CPU間の同期である。どのように処理を各CPUに割り振るかが難しい。また、メモリアクセスのタイミングも問題になる。共有メモリは必要だが、さすがに256個のCPUが共有するようなメモリを配置すると、よほどうまく管理しない限り、その共有メモリに対するアクセスが頻繁になりすぎて使いものにならない。

そこで、別の案を考えるわけである。結局、時間のかかるのは、画像処理や音声処理など限られていて、並列性の高いものばかりである。レイトレーシングやレンダリング、MPEG2の再生なども、並列性が極めて高い。

そこで、案1。

64Kbyte + 8x86 CPUを一対で1CPUモジュール(CPUのCはCentralのCのような気もするが、この際、細かいことにはこだわらない)とし、それを4096個ほど用意するのである。それぞれのモジュール間は独立しており、ひとつだけ親玉を用意する。こいつだけどのモジュール内のCPUをもlockをかけて眠らせることが出来て、かつ、眠らせている間にそのモジュールのメモリを読み書き込き出来るのである。こういう条件で、よーいどん!で仕事を振り分けてやららせればどうか?と考えるわけである。

これだけでも、とてつもないことが出来るような気がするのだが、ネックとなるのは、メモリが64Kしか自由にならないことである。テクスチャーマッピングでテクスチャーを張り付けようにも、そのテクスチャーは外部のメモリにあったりしては、どうしようもない。その手の分野で、並列性が有効になるためには、巨大なメモリとの共有が計れていなければならないというのが前提としてある。しかし、メモリっちゅーもんは、基本的にあるサイクルごとにぽつんとデータを一つずつ取り出すことしか出来ず、共有なんてことをした日には、メモリからのデータの読み出し待ちでず〜と待たされたりして、にっちもさっちもいかない。

そのへん、Intelはちびっと賢かった。MMX系の命令がこの問題に対するひとつの解答である。つまり、複数レジスタに対して、一括して同じオペレーションを行なえるようにする。こうすることで、単純な作業はずいぶんと速くなる。AMDのK2シリーズもパフォーマンスでは有名だが、設計思想としてはMMX系の命令を浮動小数点演算にまで拡張したに過ぎない。

しかし、その程度では納得できないやねえらお(誰がえらいねん?<タイプミス)は、何とかしてメモリを共有する手段はないかと考えるわけである。

だから、案2。もはや、CPUモジュール間で通信するしかない!

はあ?

と思われるかも知れないが、真剣である。先の、CPUモジュールで、外部のメモリが欲しいときは、どこそこのメモリむっちゃ欲しいねん〜と、近所のCPUモジュールに言って回るのである。もちろん、がむしゃらに言っては効率が悪いので、それぞれのモジュールは、ハイパーキューブ構造(立方体で、1つのモジュールが、前後左右上下の6つのモジュールと接続されていると考えよ)を採用する。こうすれば、4096個接続したとしても「どこそこのメモリ欲しいねん〜」から、平均15waitぐらいでもらってこれるような気がする。(<気がするってなんや?それくらい、しっかり計算せえよ...)

ええ?それじゃ、15分の1ぐらいでしか動かないのでは?と心配されるかも知れないが、そんな遠くのメモリが必要になるのは、頻繁にあるわけではないし、普段はローカルメモリに対して作業をしていて、外のメモリが欲しくなったら、まとめてパケットで送ってもらうような感じになるわけだから、本当に15分の1になるわけでもない。思うに、実際のところ1/3〜1/5でないかと。4096個あれば、仮に1/5になっても、通常の800倍の速度で処理が出来るわけであって、仮に、Pentium 100MHzクラスのCPUがその数あれば、Pentium 80000HMzの仕事が出来るわけである。(コンピュータのスピードの進歩の予測にムーア予測というのがあるが、そのへんからすると、技術的な大ブレークスルーがない限り、10年かけても到達しない速度だ)

そんなわけで、1つのモジュール := ローカルメモリ16K + 共有用メモリ16K + CPU + 共有メモリのデータをまわりのモジュールとやりとりするユニットという構成なんかがいいんでないかと思う。(いいんでないかとか言ったところで、絵に描いた餅みたいなものだが...)

あと、ハイパーキューブと言っても、それは論理上の話で、実際に多層基板にするわけではないし、それほどの集積度が必要なわけでもない。その気になればIntelの現在の技術で、十分ワンチップ化が期待出来ると思う。ロイヤリティよこせだのケチなことは言わないから、完成したら、ひとつ欲しい(笑) で、名前は、タコ足君に対抗して、イカ足君。足がタコよりは多そうだ。(謎)


第23回 Celeron300AMHzでいこう(聞くも涙、語るも涙のハードウェア物語)

今回は、息抜きに、ハードの話である。

なんか、パソコン触るのがイヤになることがある。やねうらおは、年に、5,6回、慈善事業で他人様のパソコンを組立てるのだが、2,3ヶ月組立てていないと、まったく新しいチップのことがわからなかったりする。組立の本ぐらい買えばいいのだが、やってわからなくなって、どうしようもなくなってからしか読まない(それも立ち読み)という極悪な人間だからして、よく失敗する。この歳になると、さすがに反省なんてしないし、頭のなかの「学習機能は有効にするか?」のオプションはいっつもOFFになっている。(んなもん自慢になるかいな...>わし)

そんなわけで、先日も、組立てを行なったのだが、こいつに採用したのが、いまハヤリらしいCeleron300AMHz。「さんびゃくエーメガヘルツ」と言われても、何が「さんびゃくエー」なのかちょっと理解しかねるのだが、「とにかくエー」んだろう。(なんのこっちゃ)

この「さんびゃくエー」君だが、旧Celeron300MHz(こっちはAは付かない)と違い、こいつだけL2キャッシュを内蔵してたりする。そのせいか、Pentium II用のマザーボードで起動時に誤認してくれたりする。そこまでは、まあよろしい。誤認するっちゅーことは、BIOSのプログラムに問題があるわけで、ホームページからちょこっとupdateするROM imageをダウンロードしてくれば済む。しかし、DLしてきたのは、良いが、それを実行するためには、フロッピーからMSDOSを立ち上げる必要がある。立ち上げるためには、そこまで正常に動作していなければならない。

ちょっと待て〜!本体起動時にCPUチェックのところで暴走しとんのに、MSDOSなんか立ちあがるかい!!だいたい、正常動作するCPUって、PentiumIIのことか〜。そんな価格性能比に誠意が見られへんCPUなんか、BIOSをアップデートするためだけに買えるか〜ゆうねん!!パケカ〜!!!そういや、昔、Aptivaの問題の多い音源とモデムと一体ものになっているカードで、Winodws98にアップグレードすると、モデムが認識しないんで、ホームページからモデムの修正ドライバを入手してくださいとかゆーのがあったが、モデムが認識しないよーになってしもて、動かへんのに、どないしてインターネットつなぐねん〜!!イテまうぞコラ〜!!とその時、思ったが、今回の衝撃は、その数百万倍は強かった。PentiumIIの333って、うちの仕入れが24800(なんや?裏でパソコンショップ経営しとったんか?>俺) 「さんびゃくエー」君より1万円以上高いではないか。パフォーマンスなんて、どっちもどっちやのに、んなもんのために1万円もよーださんがな。ど阿呆!これでは、何のために「さんびゃくエー」君を大量に仕入れたのかわからない。(えっ?大量に仕入れたんか?お前、慈善事業って上で書いてるやないか!>俺) 仕方ないんで、知り合いに頼んで、PentiumIIを借りることにした。

しかし、このP2BXAっちゅーマザーボードなのだけど、製造元がわからない。箱にURLも書いてない。サポートする気、あらへんのちゃうか〜?とか思うね。とりあえず、DOSパラの広告からリンクをたどり、なんとかホームページに到達できた。DOSパラの広告は、こういうときに便利である。(こういうときにしか使わんけど...)

ついでに、もう一つの方のマザーボードAX6Bは、AOpenが製造していて日本Acerが販売しているのだが、こいつ、製造元のAOpenからDLしたファイルでupdateしたら書き換えは無事終了したのだが、二度と起動しなくなった。見事に有償交換コースである。なんか噂では、販売元である日本AcerのHPにあるほうでupdateしないといけないとか聞いたが、真相は不明。そもそも、Celeron300AMHzの組立を行なっているショップがすべて、こんなことをしているのか疑問ではある。なんで製造元が不可で販売元が可なのかわからない。

ともかく、こいつらのせいで、休みが2日も潰れたのであった。

いや、それにしてもやね。CPUちゃんと認識せーへんって、サイテーでないか?どういう設計してるのか理解不能である。まあ、Intel側が悪い気もするが、本体がまったく立ち上がらずCPUチェックで止まるというのは、BIOSがしおしおな気もする。そもそも、新しいCPUが出るごとにマザーボードが変わるのはなんでやねん。いままで、前と同じマザーが使えた試しがないど〜。新しいCPU買うごとに実質、マザーボード買い換えなあかんし、なんか違うんでないかなー?という気がしなくもない。Intelが、そんなんやってるから、AMDとかcyrixの追随を許してまうんや。SLOT1とかで差別化を計っても仕方がない。男なら、Socket7で真っ向から勝負せえ!と言いたい。ついでに言えば、ベースクロックや電圧もしょっちゅう変更すな!男なら、黙って2.8V。これで決まりやろ?(何が決まりなんや、何が...)


第24回 DirectXプログラミング最大の罠その2(DirectSoundのバグ)

いまさらDirectXなんて腐ったテクノロジーについて語ることは何もないのだが、一応、糞々なDirectXプログラミングに一度でも関わった者として、その腐ったプログラミング環境について書き記し、あとに同じようなマイ糞ソフト犠牲者を出さないことは、当然の使命のように感じている。

とりあえず、今回は、DirectSoundである。

DirectSoundには、余計な関数が多すぎる。その割に、必要な関数がない。普通にゲームを作る上で欲しいのは、

HANDLE Load(char* filename);
int Play(HANDLE h);
int Stop(HANDLE h);
BOOL IsPlay(HANDLE h);
int SetVolume(HANDLE h);
int Release(HANDLE h);

の5つだけである。適当に統合して、3つぐらいにしても良い。要するに、ファイルを読み込んで、そのハンドルを取得して、それの再生だけ出来れば何も言うことはないのである。3D音響やバッファのロックなんて、出来なくていい。出来なくていいというか、別のやつでやればいい。コンポーネントは、最小限にすべきである。DirectSoundに何もかもをぶち込むなと言いたい。どうも、Windowsのデザイナはよほど頭が悪いのか、コンポーネントという概念を持っていない。いまになって、デバイスドライバにWDMを推奨して来ているが、それと同じことは、OS/2では6年も前にやってる。

話がそれるついでに、WDMについて簡単に述べるが、そもそも、こいつの正体というのはわかりやすく言えば、SCSIドライバを作るとき、SCSI汎用ルーチンのレイヤと、そのSCSIカード固有のプログラムを最小限にしたレイヤと2つのレイヤに分けるというものである。メーカーがサポートすべきは、後者だけで良いと。いままで、なぜそのようにしていなかったのか疑問だし、「最小限必要なものを固める」という発想だとか、「最小限度のプログラムだけで済むように」という配慮が欠けている。ついでに言えば、DirectXプログラミングには、「最低限度の勉強で済むように」という配慮も欠けている。

そんなわけで、DirectSoundについてなのだが、まず上のLoadというのに相当するものがない。もう、その時点で何考えてんのじゃ〜!死ねボケ〜!と言いたくなるのだが、そのへんは、以前に紹介したelのソースなりを参考にすればなんとかなる。DirectX SDKにはサンプルも添付されているから、それをぶっこ抜けば良い。

それはいいのだが、ステータスを得るための上のIsPlayに相当するGetStatusが、これまた信頼おけない。再生終了したかどうかの問い合わせをしたいだけなのだが、ハードウェアバッファで再生していると、再生が終了していないにもかかわらず、ハードウェアが嘘を付いて、「終わりました」と嘘の報告をするサウンドカードがあったりする。終わってないって!それって、ハードにデータ転送できただけっしょ?厳密に言えば、こういうサウンドカードのドライバは、ドライバの不都合であって、ドライバの製造メーカが悪いのだが、上に書いた通りWDM以前っちゅーのは、ドライバメーカ側の負担が尋常でなく、かつ、嘘だらけの技術文書がマイ糞ソフトから送られてくるので、にっちもさっちもいかないのが現状なのである。また、演奏は終わっているのに「終わってまちぇん」と嘘の報告をするサウンドカードもある。ほんとうにそのへんは微妙な話なのだが、ユーザーは、そのへん信頼してプログラムを書くしかない。しかし、いつまでたっても「およおよで、演奏が切れるバグなおしてください」とか書いてくる馬鹿ユーザー(ちゅーか知らんからしゃーないんやろけどね...)は、あとを立たないわけで、んなもん、知らんがなと言いたくなる。だいたいやね〜、あんたは、Office使ってて止まるごとに、マイクロソフトのサポートセンターに電話してんのかっちゅーの。不正なおよおよが発生しました、ハードウェアの製造元に連絡してくださいって出るごとに、ハードウェアの製造元、IBMやら富士通やらに電話してんのかっちゅーの。大手ソフトハウスに限って不都合などあるまいから、自分の使い方が悪いなどとあきらめることが出来るくせして、僕のような個人のプログラマには容赦なく、自分のハードについて製造元のホームページも調べようともせずにバグやバグやゆうてくんねんからなぁ〜。たまらんちゃ〜。IBMの糞Aptivaで、画面にチラつきがとかゆうて、んなもんわざとチラつかせるほうが難しいっちゅーねん。だいたい、IBMの旧マシンって、BIOSから何から何まで腐ってるだがや。こないだ知り合いのパソコンに8.4GBのHDを認識させようとしたら、2GBしか認識せずに、IBMのホームページからBIOSのupdateするやつをDLしてきたのだが、それでも4.3GBしか認識しない。「よんぎがさん家出事件」などとアホなことを言いながら帰ってきたのだが、IBM純正って、なんであんなに腐ってんのや〜。ちなみに、その8.4GBのHDDって、IBM純正なんやけどな〜。よっぽどAptivaを抹殺したいんか?>IBM

そんなこんなで、何も話せていないが、残りは次回まわしとする。


第25回 DirectXプログラミング最大の罠その3(DirectSoundのバグ) 99/4/1

毎度、毎度、WindowsだのDirectXだのをけちょんけちょんに言っているときもあるが、DirectXに関しては、心底嫌っているわけでもない。(どないやねん?>俺 だって乙女心は微妙なんよ...<誰が乙女やねん!)

そもそも、DirectSoundのようなミキシングルーチンを自前で用意するとなると、非常に大掛かりな作業であって、仕事でやったとしても、それだけで一年や二年潰れ兼ねないからである。Direct3Dなんか、二、三年は優に潰せるだろう。

実のところ、やねうらおも、その昔、Z80アセンブラ(アセンブラって、汗ばんだブラですか?という質問は却下 < 誰もしないって...)修行時代に、TUX吉村氏に密かにライバル意識を燃やし、おもちゃのような3Dルーチンを実装したりしたが、ちょっとしたルーチンなのに作るのに恐ろしく時間がかかった覚えがある。そのままハマると一年や二年、軽く飛んでなくなりそうなことが容易に想像できたやねうらおは、さっさと身を引いたのだ。

そうなのである。プログラマが、コンパイラを作る必要はないし(情報工学を専攻して工学博士になるんなら、一度ぐらいやっときなよとか思うけど)、3Dプログラマが、3Dルーチンを作る必要はない。ゲームプログラマが、ハードウェアの設計をする必要はないし、ピアニストがピアノを作る必要はない。ごくごく基本的なことなのだが、どうも当時のやねうらおには、そのへんが理解できていなかったらしく、おかげで野生のライオンのごとくだだっ広い野原をさ迷いつづけた結果、こんな規格外な人間になってしまったわけだ。(あまり喜べることではないような気がする)

ともかく。DirectSoundの二つ目の致命的な仕様について語る。

それは、サウンドバッファの確保をどこにするかということである。通例、サウンドボード側にサウンドバッファというものが存在して、CPUに負担をかけないためにも、ある程度、サウンドバッファが用意されており、「では、鳴りなちゃい」と命令すれば、そのサウンドバッファから音が再生されるメカニズムを採っている。

高価なサウンドボードほど、ボード内のサウンドバッファは多くある傾向にある。DirectSoundは、ディフォルトで、ボード側のサウンドバッファを利用しようとする。ところが、これが問題なのである。

ボード側のサウンドバッファを利用するということは、音量調整からミキシングまでボード側でやるということだ。ところで、サウンドバッファがあふれると、あふれた分をDirectSoundは、本体側のメモリに配置しようとするのだが、そうすると、ボード側に配置しているサウンドと、本体メモリに配置しているサウンドを同時再生のためミキシングするときはどうするのか?というか、どうなるのか?このへんをつつくと、非常にほこりが出てくる。ごほんごほんである。そんなわけで、このまわりのバグに悩まされつづけることになるのである。サウンドドライバ側が悪いと言えばそうなのだが、どうも、DirectSoundの仕様もまずい気がする。

そもそも、実メモリに配置している分だが、こいつはこいつで勝手にswapしやがる。メモリをswapされないようにlockしてしまう機構がWindowsには存在しないため、このようなひどいことになる。再生しようとした土壇場になって、ハードディスクにswapしたあとだとわかったところで、いまさらswapしてきても音の再生に間に合わね〜!!とかゆーことになるのである。(どうでもいいが、swapと言っても、夫婦交換することではない。また、SWAP×SWAP、略してスワスワなどとわけわからんことも言わないように。<お前しか言わねーよ!!)

解決策:

☆ サウンドバッファは、DirectSoundのオプションでボード側でなく、本体側のメモリに配置するようにする。

☆ バッファがswapしてしまわないように、あらかじめ音量を0にして、頭だけでも再生し、HDに待避していたものを実メモリに呼び戻すこと。

の2点だという結論に達した。ただし、じっくりと検証してないし、検証する環境もないので、そのへんはよくわからない。最近のマシンは、大量にメモリを搭載していたりするので、そのへんが問題になることはあまりないのかも知れない。ついでに、音量の調整だが、DirectSound自体、ボリュームを小さくすることは出来ても、大きく(増幅)することは出来ない。そこで、BM98では、マスターボリュームを無理やりいじりにいっていたわけだが、実は、DirectSound自体は、マスターボリュームの調整に対して、正常な音量で再生されることを保証していない(ようだ)。だから、ドライバ側のバグかと言えば微妙なところなのだが、Vaio等の、そのへん手抜きなドライバだと、DirectSoundBufferの構築時(かな?)に、一度マスターボリュームを参照しに行って、あとは、その相対でコントロールしていたりする。非常にまずい気がするのだが、そうなっているのだから仕方がない。そんなわけで、「音量を0にして再生」の部分、マスターボリュームでなく、DirectSound側のボリュームコントロールで行なうように変更しといてください>きくちゃん (って、こんなところで私信を書くな!!)

また、同様にボード側のバッファにまるごと格納して再生している場合も、マスターボリュームが変更されたからと言って、いまさら再生中のものに対してそのボリュームの変更を反映させることが出来なかったりする不幸なボードもあるので、ボード側のバッファに格納している場合も、マスターボリュームの変更に対応できないはずである。

そのへんを考えると、音声の転送コストやミキシングなんて、いまどきのCPUをもってすればどってことないんだから、完全にソフト側でやったほうがいいんでないの?というのが、やねうらおの率直な感想であって、そのへんDirectSoundの実装のありかた、仕様の不明確さについては疑問が残っていたりするのである。

そんなわけで、一番良い選択は、ユーザーにそのへん(バッファを本体メモリに確保するか、ボード側に確保するか)を選択させることなのかも知れないが、そういう結論になってしまうDirectSoundと向き合うとなんだかやるせない気持ちになる。


第26回 HOW TO CRACK(チンパンジーの花子ちゃんにも出来るプロテクトの外し方)99/4/2

やねうらおがZ80を愛用していた時代と違い、いまや、Winodws環境ならズブの素人であっても、Visual C++等で簡単にプログラムをトレース出来てしまう。

こういう環境ではcrackするのに、プログラミング技術はまったく必要がない。必要なのは勘と経験だけである。(言うまでもなく、crackと言えば、コピーチェックや、プロテクトチェック、パスワードチェック等を潰すことである)

crackというと花瓶に反応(なんちゅー変換するんじゃ!!)する人もいるが、ここで解説することは、自己防衛と救済のための単なる技術として受け止めてほしい。会社の仕事を家に持ち帰らないと納期に間に合わない、しかし家では会社に導入してあるCADはプロテクトチェックを行なっている為、家では動かなくて、このままでは会社に甚大なる被害を与えてしまう...など。

それでは、お手軽ご気楽にcrackする手順を簡単に説明する。

1.Visual C++を起動。ターゲット(実行ファイル)をその中にドラッグ&ドロップして、デバッグの開始。

2.そのターゲットがプロテクトに引っかかってエラーメッセージが表示される。(このパターンが一番crackしやすい)

3.そこでブレークさせ、コールスタックを表示。こいつが関数の呼び出し履歴みたいなものだからして、そいつの最後から2つ前か、3つ前あたりが非常に怪しい。よって、そこらへんを順番に潰してみる。(コールスタックは、帰り先のアドレスが積まれていくので、100番地からcallで呼び出されたとしたら、帰り先は、その次の101番地というように、次の命令番地を指していたりする。そのへんに気をつけてcallしている部分をnop(90h)に書き換えていけば良い。ただ、デバッガなのでコードを書き換えるには、バイナリエディタ等が必要)

そんなわけで、バイナリエディタを使わず、手軽にコードを書き換えるプログラムを作ったので、紹介する。(TABコードが潰れてしまっているのは勘弁してちょ...)

たまたまバイナリエディタが手元になかったので、Visual C++で30分ぐらいで作ったものであるからして、テキトーなのは勘弁して欲しい。コンパイルしたところ、20Kちょっとだったので、実行ファイルを配布するのにはちょうど良いと言えるだろう。

そんなわけで、手順としては、コールスタックを調べて、その呼び出し元のcall付近のバイトコードをメモって、callの部分のみを90hに置換するように指示してやれば完了である。慣れれば、10分ぐらいの作業である。

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// general cracker by yaneurao Feb.'99
#include <stdio.h>

const int searchz[]=
{ 0x50,0xe8,0x5a,0x06,0,0,0x83,0xc4,4,-1 };
// 検索するバイト列を設定。終了コードは、-1。

const int patchz[] =
{ 0x50,0x90,0x90,0x90,0x90,0x90,-1 };
// 置換するバイト列を設定。終了コードは、-1。
// 検索するバイト列と長さが異なっても良い。

char *filename = "target.dll"; // やっつけるファイル名

int main(void)
{
FILE *fp=fopen(filename,"rb+");
printf("General Cracker by yaneurao\n");
printf("Now Cracking %s ...",filename);

if(fp==NULL) {
printf("\nCan't Open %s \n",filename);
printf("push <return> key to exit\n");
getchar();
return 1;
}

for(int maxb=0;searchz[maxb]!=-1;maxb++) ;
for(int maxc=0;patchz[maxc]!=-1;maxc++) ;

int c;

int count = 0;
int num = 0;
while ((c=fgetc(fp))!=EOF){
if((num++ & 0x1FFFF) == 0x10000) printf(".");

if (searchz[count]==c) {
count++;
if (searchz[count]==-1){
// patch..
fseek(fp,-maxb,SEEK_CUR);
for(int i=0;i<maxc;i++){
fputc(patchz[i],fp);
}
printf("<patching!!>");
fflush(fp);
count = 0;
}
} else {
count=0;
}
}
fclose(fp);
printf("\n finished cracking!!\n");

printf("push <return> key to exit\n");
getchar();

return 0;
}
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

世の中には、強烈な暗号化を行ない、その暗号コードをもとに実行コードを展開している強力なプロテクトも存在するが、そういうのを無視すれば、だいたいこれで事足りる。

ハッカーやクラッカーの大衆化が進み、rarの解凍方法を知らない人や、CD-Rを焼くだけの人も出口のない迷宮の如きアングラをさ迷い続けていたりする。プロテクトひとつ外せなくて何がハッカーか!ハッカーはネットワークのみに生くるにあらず。右からプロテクトをかけられたなら、左の方から外しなさい。セイントテイルが駄目ならカードキャプターさくらにしなさい。鈴木あみがイヤなら、相川みさおにしなさい。どうも疲れてきたから、今日はこのへんで。(これ読んでる人のほうが疲れてんだろな〜。ごめんね〜)


第27回 ヒルベルト曲線を用いた誤差拡散法(世界で一番最初に考えたのは...)99/4/4

画像の減色変換は、データ圧縮の分野でますます重要になりつつある。フルカラーの絵を、8色でアナログパレット使用して、なるべく原画のイメージを損なわないように変換するとか、そういったものである。シェアウェアでは、OPTPiXなんかが有名である。

やねうらおも、ご多分に漏れず、いまから9年近く前に某SR麻雀をパソコンに移植するためにひたすら減色変換を研究していたことがある。

基本的に、誤差拡散法というのは、局所的なRGB値の和が変換前と変換後で等しくなるように変換するものである。そのためにはピクセルをスキャンして行き、誤差分だけ次のピクセルに持ち越して加算して行く必要がある。

イメージで言えば、

for(int y=start_y;y<end_y;++y)
 for(int x=start_x;x<end_x;++x)
  NewLayer.SetPixel(x,y,whatcolor(OldLayer.GetPixel(x,y)));
のようなスキャンループに対して、

COLOR whatcolor(COLOR c){
 static COLOR c_last(0,0,0); // 誤差
 COLOR RealColor = c_last + c; // 望まれるべき色
 COLOR c = SearchColor(RealColor); // 変換後のパレットの中でそれに一番近い色
 c_last -= c; // その差分を次回の誤差分としてstaticな変数に保持する
 return c.colorNo; // 変換後の色コード
}

のようなアナログパレットでの色決定ルーチンが存在するわけである。SearchColorは、まあ、いろいろ考えられるけれど、たとえば、R,G,Bそれぞれでの差の絶対値が一番小さくなるように選定するルーチンが一番簡単だ。

ここで問題となるのは、その誤差をどこに持ち越すかということである。明らかに、次にスキャンするピクセルに誤差は持ち越される。しかし、それは、隣接区域でなければ「局所なRGB値の和が変換前と変換後で等しくなる」という条件は満たせそうにない。(誤差拡散法をやめて、誤差の広がる範囲を限定して、なるべく近くのピクセルで帳尻を合わせるようなアルゴリズムも考えられるのだが、ここでは誤差拡散法にこだわってみたい) だとすれば、左上からテレビの走査線のように右下まで1ラインずつ辿って行くしかないのではないか?となるのだが、それが大きな間違いでそういうやり方では、誤差が縦縞になって出てきてしまう。

昔のフルカラーではないスキャナーなんかでも、この現象がときどき現れていた。というのも、スキャンするのに、コンデンサに電荷を蓄積して行き、敷居値になるごとに放電させるという方式で、まさに上のプログラムのstaticなc_last変数と同じ役割をコンデンサにさせていたからである。

そんなわけで、スキャン方向に関しては、テレビの走査線のような感じではなく、曲がりくねった線でかつ、平面全域を被覆するような曲線が望まれるわけである。それも、単純にプログラミングできることなら、なおさら良い。そんなことを言っているとき、当時、知り合いのnaz氏が「それならヒルベルト曲線を使えば良いのでは?」というようなことを言い始めた。(naz氏は、当時、某電波なんちゃら社のX68版のオールドクラシックゲームの移植を小遣い稼ぎにやっていた。やねうらおがこの世で唯一、敵と崇めるプログラマである。<なんで敵やねん...)

さっそく、やねうらおも試してみたのだが、なるほど、英リア寝具(なんちゅー変換するんや!!>ATOK11)は出ない。優秀な方法である。ただ、結局のところアナログパレットの決定するアルゴリズムのほうが減色変換では重要なのであって、ヒルベルト曲線を用いたからと言って、それほど大きな効果ではないような気もしないではない。

そんなわけで、このアルゴリズム自体は、お蔵入りしていたのだが、昨年ぐらい、どこぞの外国の論文に、この方法が載っているのを知った。(その後、Cマガにもそのアルゴリズムが紹介されていた)

うーん。そういうもんなんか。それなら、思いついたアイデアは、まっさきにインターネットで流して、私は10年前からその理論を提唱してましたとか言わんと損ではないのか(笑)

うーん。そんなわけで、気が向いたら近々、フリーの減色変換ツールを作るかも知れない。期待せずに待ってて。(そればっかし)


第28回 Bitmapフォーマットの内部構造について(Windowsなんでやねん物語)99/4/9

Windowsで標準的な画像フォーマットと言えば、Bitmapだろう。やねうらおは、最近、わけあってBitmapからDXFに変換するプログラムを作る必要があった。(DXFファイルについてはご存じない方もおられるだろうが、AutoCADのデータ形式である。CAD業界では、これが業界標準となっている)

WindowsでBitmap絡みって、ほとんど触ったことがないが、まあ、標準フォーマットなんだから読み込んでピクセルの色を調べるぐらい簡単だろうと思っていたのである。

ところが...読み込む関数が見あたらない。しばらく探す。LoadImageはリソース限定みたいなこと書いてあるし...。結局わからんので、人のプログラムを引っ張り出してきて調べる。あれ?LoadImageでLR_LOADFROMFILEでいけるの?ふーん。じゃあ、ピクセルの色を調べるには?

しばらく探しているとGetPixelなる関数が見つかったのだが、どうも、こいつは、DDBに対してであって、DIBに対してではないようである。根気よく探すが、見あたらない。もういい加減疲れてきたので、GetObjectでオブジェクト情報を得て、それを頼りに調べることにする。ところで、Bitmapの内部フォーマットってどこかにあるんだっけ?しばらく探すが、ヘッダーとなる部分の構造体については説明があるのだが、内部フォーマットについてはたいした説明がされていない。まー、データぐらいリニアに並んでるんだろうとか勝手に決めつけ、自分でGetPixelなる関数を作ったもののうまくいかない。そういや、昔、友達がそんなの調べてたぞ、とそれを掘り返して眺める。

そうそう。思い出した。

 データは、左下から、右上に向かって並んでいる。
 1ラインは、DWORD(4バイト)で繰り上げたバイト数になる。

そんなん、Visual C++のオンラインヘルプのどこにも書いてへんかったんちゃうん??うーん。勝手なことされたら困るなぁ(笑)

ちゅーことは、GetPixelを実装するには、各ラスターの先頭アドレスをテーブル化して予め計算しておく方がいいんでないかなー。そうすれば、y座標に関する引き算も不要になるし...

#define GetPixel32(x,y) (*(line_table[y] + x))

うーん。しかしやね。なんで、Windows標準のBitmap様に、こうまでしてピクセルの色を調べんとあかんねん。しかも、このBitmapってば変更して保存しよかーとか思ったら、めちゃ大変やぞ...。どうなってんねん、ゲイツ君。君は、本当にこの糞馬鹿Windowsでプログラムしたことあんのか?


戻る