Winnyをいじる・その1
- 4 11月, 2008 -
- ニート -
- Tags :
- 0 Comments
Winnyの初期ノード
ネットで初期ノードリストが配布されている。これは
@9581aebb9b2f93d548fc274b2655e0a8b67118
のような形になっている。最初の@は不要なので読み飛ばす。その先の数値とアルファベットは16進数になっている。つまり、9581aebb9b2f93d548fc274b2655e0a8b67118は16進数で
0×95, 0×81, 0xae, 0xbb, 0x9b, 0x2f, 0×93, 0xd5, 0×48, 0xfc, 0×27, 0x4b, 0×26, 0×55, 0xe0, 0xa8, 0xb6, 0×71, 0×18
という16進数の列と読み替えればいい。
文字を16進数数値に
static unsigned char asciiToInt( char c )
{
// 数値?
if ( 0x30 <= c && c <= 0x39 )
return c - '0';
return c - 'a' + 10;
}
なお、unsigned charは1バイトの数値を扱うとき、charは1バイト文字を扱うときです。これを使って
初期ノードリストの16進数表記をデコードする
/* -------------------------------------------------------
初期ノードリストの16進数表記をデコードする。
この中でしか使わないため、char *で返す。
戻り値はdelete []すること。
-------------------------------------------------------*/
static unsigned char *decodeHexString( const char *s )
{
int length = strlen( s ) / 2;
unsigned char *result;
if( length % 2 != 0 )
{
// 2の倍数じゃないときはおかしい
return NULL;
}
result = new unsigned char[ length + 1 ];
for( int i = 0; i < length; i++ )
{
char hi = *s++;
char lo = *s++;
result[ i ] = (asciiToInt(hi) << 4) | asciiToInt(lo);
}
result[ length ] = ' ';
return result;
}
これをRC4暗号で復号すればよい。なお、RC4のキーはほとんど既知で
// デフォルト暗号化キー
const unsigned char RC4Key[] = { 0x6f, 0x70, 0x69, 0x65, 0x77, 0x66, 0x36, 0x61, 0x73, 0x63, 0x78, 0x6c, 0x76 };
がデフォルトになっている。
この暗号化キーの最初の1バイトを、Node情報の最初の1バイトと入れ替えてキーにする。
key[ 0 ] = decoded[ 0 ];
が該当部分。あとの部分は得られたキーで復号してやればよい。
デコード
/* -------------------------------------------------------
Winnyの初期ノードリスト
@9581aebb9b2f93d548fc274b2655e0a8b67118
のような表記を
61.201.38.38:25316
にデコードする
-------------------------------------------------------*/
void decode( const char *s )
{
// 簡易チェック
if( s[0] != '@' )
{
return;
}
// @を飛ばす
s++;
int size = strlen( s ) / 2;
unsigned char *decoded = decodeHexString( s );
unsigned char *key = new unsigned char[ sizeof( RC4Key ) ];
// デコードできない
if( decoded == NULL )
return;
// 最初の1バイトを暗号化キーに使う
memcpy( key, RC4Key, sizeof( RC4Key ) );
key[ 0 ] = decoded[ 0 ];
RC4 r( key, sizeof( RC4Key ) );
r.decrypt( &decoded[ 1 ], size - 1 );
puts( ( const char * )&decoded[1] );
delete [] decoded;
}
RC4を復号する
RC4はストリーム暗号で、1バイトずつ処理していきますが、その都度関数の内部状態が変化します。そのためRC4クラスを作って処理します。
swap
変数を入れ替える処理を多用するのでswap()関数を作ってしまう。
template < typename T >
void swap( T &left, T &right )
{
T temp;
temp = left;
left = right;
right = temp;
}
RC4クラス
#ifndef __RC4__
#define __RC4__
class RC4
{
public:
RC4( const unsigned char *key, int size );
virtual ~RC4(){}
void Initialize();
void decrypt( unsigned char *in, int size );
private:
int _x;
int _y;
unsigned char *_key;
unsigned char _state[256];
};
#endif
コンストラクタ
RC4::RC4( const unsigned char *key, int size )
{
_key = new unsigned char[ size ];
memcpy( _key, key, size );
Initialize();
}
暗号に使うキーとサイズ(C++は配列のサイズを別に覚えておかなくてはならない、不便だ)を渡して初期化してやる。
初期化
void RC4::Initialize()
{
unsigned int length;
unsigned char state2[256];
unsigned char *p = _key;
length = 0;
while( *p++ != 0 )
{
length++;
}
if( length == 0 )
length = 1;
_x = 0;
_y = 0;
for( int i = 0; i < sizeof( _state ); i++ )
{
_state[ i ] = i;
state2[ i ] = _key[ i % length ];
}
int j = 0;
for( int i = 0; i < sizeof( _state ); i++ )
{
j = ( j + _state[ i ] + state2[ i ] ) & 0xff;
swap( _state[ i ], _state[ j ] );
}
}
暗号化/復号化
void RC4::decrypt( unsigned char *in, int size )
{
unsigned char x = _x;
unsigned char y = _y;
unsigned char sx, sy;
long index = 0;
while ( size-- != 0 )
{
x++;
sx = _state[x];
y = ( y + sx ) & 0xff;
sy = _state[y];
_state[y] = sx;
_state[x] = sy;
sx = (sx + sy) & 0xff;
in[index++] ^= _state[sx];
}
_x = x;
_y = y;
}
- 著者/訳者:ティモシー フェリス
- 出版社:青志社( 2007-09-21 )
- 単行本:255 ページ
- ISBN-10 : 490385311X
- ISBN-13 : 9784903853116
- 定価:¥ 1,470
- 著者/訳者:ティモシー・フェリス
- 出版社:青志社( 2011-02-03 )
- 単行本:640 ページ
- ISBN-10 : 4905042097
- ISBN-13 : 9784905042099
- 定価:¥ 1,995
- 著者/訳者:篠山 半太
- 出版社:PHP研究所( 2012-06-16 )
- 文庫:340 ページ
- ISBN-10 : 4569678467
- ISBN-13 : 9784569678467
- 定価:¥ 720


