Winny解析::キャッシュ

次にWinnyのキャッシュについての解析結果を少し書いておきます.Winny本体の解析と同時進行で行っていたので,キャッシュへのアクセス部分は暗号鍵だけ調べて,あとはバイナリエディタで見ながら解析しました.

…というか,キャッシュの暗号を解くために本体の解析を始めたのですが.

ファイル名

キャッシュのファイル名はMD5値を暗号化して16進数表記してから先頭に「%」をつけたものです.メモによると,暗号化する時の暗号鍵は"CHeader"っぽいです(たぶん).

キャッシュを操作するプログラムでは,先頭からリトルエンディアンで,「0x9d01505e,0x14672a9a,0x5ec6dc74,0x2c840d8f」とXORを取ってたりしました(この方が速いし…).

ヘッダの構造体

キャッシュのヘッダの構造は「Winnyの技術」にも書いてあり,データがどういう風に並んでいるかわかります.ただ,実際にプログラムを書くときは型情報も含めた構造体の定義があると便利です.というわけで,以前書いたキャッシュ変換プログラムに使った構造体の定義を書いておきます.

それぞれのメンバの説明は,本を読んでください.

// キャッシュのヘッダ(リトルエンディアン)
struct NY_CACHE_HEADER{
	unsigned long version;
	unsigned long size; // ファイルサイズ
	unsigned long blockref; // 参照量
	long update_time;
	char data_md5[16];
	char trip[11];
	char nanika1[2];
	unsigned char bbsflag; // ?
	unsigned char name_len;
	unsigned char upflag;
	short name_sum; // ファイルの文字の合計
	char name[254]; // ファイル名
//	char block_flag[blocks];
};

nanika1というメンバは何だか分からなかったので,とりあえず放置していたのですが,「Winnyの技術」を見たら,「予約」となっていました.何か書き込んでいたような気もしたけど….

ヘッダの解析

最初のバージョンだけ,違う鍵("header")で暗号化していました.これは過去のバージョンのWinnyでもバージョンのチェックだけは出来るようにするためだと思われます(昔のWinnyは知らないのでほんとのところは分かりませんが).

tripはトリップ文字列がそのまま書き込まれています.トリップを作るときには,RSAみたいな演算をしているのですが,受け取ったトリップ自体は特にチェックしてはいない見たいなので,このメンバを書き換えれば自由にトリップが付けられます.普通にトリップを作ったのでは,あり得ないトリップも付けられるようです.

name_sumはファイル名の文字をunsigned charとして全て足したものです.

ファイル名は,さらに暗号化されています.RC4は乱数とのxorなので,元のファイル名とxorすればRC4の乱数列が得られます.色々なファイル名に対して,乱数列を得ることを繰り返していると,ファイル名中の文字の位置を入れ替えても,乱数列が変化しないことに気付くと思います.となると,name_sumが暗号化に使われていると予測できます.ついでにname_sumに0x100の倍数が加算されるようにしても,暗号が変化しないことに気付けばラッキーで,すぐにname_sumの下位8ビットが暗号鍵だと分かります.

block_flagには,ダウンロード済みのブロックであれば,1が入ります.

ブロック

続いて実際のファイルのデータを64KBずつ格納したブロックが続きます.ブロックの前には,そのブロックに含まれるデータのmd5ハッシュ値が付いてます.つまり,1ブロックは65536+16 = 65552バイトです.

ブロックのデータ部分は暗号化されています.暗号鍵は,ブロックの番号を文字列で表したものにスペースを挟んでファイル自体のハッシュ文字列が付いたものです.sprintf(s,"%d %s",block,hash)です.

最初のブロックのみ,"header"という暗号鍵を使っています.

最後のブロックのみ,データの長さが不定です.

この文書の履歴

Copyright © binzume all rights reserved.