東方に学ぶプログラミング

最初は何でコンパイルされているか見るだけだった。
後悔はしていない。
NOPで埋めて無敵にしたりとかそんなくだらないことはしない。
デバッガも使わない。バイナリエディタで読むだけ。別に解析って程じゃない。


ターゲットは東方地霊殿体験版(だけのつもりだった)。
CodeZineのEXEファイルのPEフォーマットに関する記事(の構造体の定義)を参考に、
http://codezine.jp/article/detail/412?p=1
IMAGE_OPTIONAL_HEADER32構造体のMajorLinkerVersionとMinorLinkerVersionを調べる。
どうもPEヘッダは0x110から始まるようなので面倒なので決めうちでいくことに。
と思ったら風神録は0x120からで死んだ。
しょうがないのでDOSヘッダの最後についているPEヘッダの場所にfseekすることにした。

#define _CRT_SECURE_NO_WARNINGS
#include <windows.h>
#include <stdio.h>

int main(int argc, char **argv){
	if(argc < 2)
		return 1;
	FILE *fp = fopen(argv[1], "rb");
	if(fp == NULL)
		return 1;
	BYTE unused[0x110];
	fread(&unused, sizeof(unused), 1, fp);
	IMAGE_NT_HEADERS32 nt;
	fread(&nt, sizeof(nt), 1, fp);
	printf("%08x\n", nt.Signature);
	printf("%d %d\n", nt.OptionalHeader.MajorLinkerVersion, nt.OptionalHeader.MinorLinkerVersion);
	fclose(fp);
	return 0;
}


地霊殿 9 0
風神録 7 10
永夜抄 7 0
自作のVS2008 VC9製のEXE 9 0
自作のVS2005 VC8製のEXE 8 0


バイナリエディタで構造体を脳内で再現して見たときと違う・・・。
やはり普段やらないからなあ。バイナリ能力が足りないらしい。
最近のVCが吐くMSIL(Managed C++)に関するエラーメッセージが自分のプログラムとも共通で含まれているあたり、VCで間違いなさそう(いや普通VCだろ・・・)。


めでたしめでたし。
・・・じゃないんだなあこれが。
最近の(2005以降)のVCはデフォルトのRelease設定ではデバッグ情報を出力し、さらにEXEファイルにそのデバッグ情報ファイルのフルパスが格納されるという一歩間違えれば個人情報の漏洩につながる恐ろしい仕様なのですが、
参照
http://connect.microsoft.com/VisualStudioJapan/feedback/ViewFeedback.aspx?FeedbackID=346253
ちょっと「c:\」で検索してしまった。


それは見つかりませんでした。
が、代わりにヒットしたものとは・・・!?
c:\cygwin\home\zun\prog\th11\src\core\../core/zunlib.h
まさかのcygwin
びっくりした。VCの話に突然cygwin持ってこられても・・・。
しかしその周辺に多数のソースファイル名とデバッグ文字列(と普通の文字列データ)が・・・!
多分__FILE__と__LINE__マクロによるものかと推測している。__LINE__は#define中で#で文字列化したものかと推測している。
多分デバッグ出力用文字列かと推測している。
多分モジュールのテストにコンソール+ int main() が素早くできると便利だからcygwin以下にVCプロジェクトを作っていると推測している。
そしてさらにDLLのインポートテーブルへ・・・!


わかったこと:

  • 言語はC++(どのくらいC++なのかは不明)
  • DirectGraphics/Input/Soundバリバリ。DirectSoundは自分でwavファイルを解析して波形データを取り出さないといけないのは常識("RIFF"の文字列が・・・)。と思ったら・・・?
  • (少なくとも)src/以下に次のモジュールがある。
    • core
    • game
    • pack
  • pack/LzssUtil.cppがある。圧縮/解凍アルゴリズム自前実装の可能性あり。
  • core/zunlib.h core/zunlib.cppが(ネーミングからして)気になっている人も多いようだ(最低でも1574行はある模様)。
  • CWaveFileなるクラスっぽいもの発見!・・・と思ったらなんとDirectSoundのサンプルだった。MSDNにあるメンバ関数も見つかったので間違いない。(おそるおそるDirectXのライセンスを読んでみたがOKのようだ)
  • スクリプトも自前実装。最低でも600行はあるようだ。spttest.cppが見つかったのでこれを実行するためにcygwin以下にあるのではないか?
  • スクリプトでStack overとStack underが発生する可能性があるようだ。サブルーチン呼び出しを実装か?
  • "scene %d -> %d"なる文字列を発見。シーンシステムを使っているようだ。そういえば永夜抄の「タイトルに戻る」は普通のスタートとスペルプラクティスで戻るところが違ったっけ。
  • ミューテックスで二重起動防止か。
  • マルチスレッドあり。CriticalSection、PostThreadMessage使用。ロード(少女以下略あたりだろうか)


ZUNからの教訓

  • 逃げるな。正面からDirectGraphics/Input/Soundを使え。一度パターン化(ライブラリ化)してしまえ。
  • でも面倒だからDirectSoundのwavファイル解析はサンプルをコピればいいよ。
  • ライブラリには自分の名前をつけろ。
  • lzss圧縮アルゴリズムくらい実装しろ。
  • テストコードはcygwinで実行するといいよ。
  • シーンシステム
  • スクリプト言語は自分で作れ。スタックも用意しろ。
  • スレッド間通信にはPostThreadMessageだ。Windowsがメッセージキューを用意してくれるぞ。Get/PeekMessageできる。


これは本人談ではないので注意してください。
BGMの抜き出しツールがありますね。ソースが公開されててデータファイルの展開をやっているはずだけどまだ読んでないので圧縮に関してはまだよくわかってません。


2008/09/02追記
音楽ファイルはZWAVというフォーマットで、"ZWAV"といくつかの0があった後、すべての曲のWAVのサンプリングデータの導入部・ループ部が連続して入っているらしいです。
zwav.h/cppとかあったような・・・。
WAVにはループポイントとかありませんからねえ。
切れ目は多分決めうちで実行ファイルに入っているのだろうとのこと。
ZWAV・・・。ZUN WAVEフォーマット・・・!
これ以外と参考になるんじゃないか?
thbgm.datにだけ関して言えば圧縮とか暗号化とかはまったくしていないみたいですね。