#19のKG(コンソール)


と、言うわけでやってきました19です。
実際のKGとしては、これが最後になりますね。
#20はパス出しですので・・・

それでは、タバコでも吸いながら・・・(ぉ
と、今自分の作ったKGのソースを眺めていると、
凄くいらないことをしているのに気づいてみたり(汗
コレいらない事しなければ凄く短いソースになりそうです(^^;
それでは、行ってみましょう!図書館!

さぁ、簡単な部分はチャチャっと行きます。
>キーファイルの内容先頭16文字が、ASCII "CRKME#19 KEYFILE"かの比較です。
こうあります。
と言うことは、先頭16文字は確定しているので、次行きます。

ここからは、図書館の内容では、KGを作りにくいかもしれないので、
適当にOllyから引っ張ってきて、説明します。

004011A2   > 0FB60431       MOVZX EAX,BYTE PTR DS:[ECX+ESI]
004011A6 . 8BD8 MOV EBX,EAX
004011A8 . 81F3 80000000 XOR EBX,80
004011AE . 881C39 MOV BYTE PTR DS:[ECX+EDI],BL
004011B1 . 8AE0 MOV AH,AL
004011B3 . 52 PUSH EDX
004011B4 . F7E0 MUL EAX
004011B6 . 41 INC ECX
004011B7 . 33C2 XOR EAX,EDX
004011B9 . 5A POP EDX
004011BA . 03D0 ADD EDX,EAX
004011BC . C1C2 07 ROL EDX,7
004011BF . 83F9 0C CMP ECX,0C
004011C2 .^72 DE JB SHORT crkme19.004011A2

ここで、名前を判定しているみたいです。
12回ループしているのでkeyファイルの17文字目から12文字が名前になります。
では、変数から作りましょうか
名前用の変数
unsigned char name[13]="      ";
' '*12;です(^^; ↑は全角ですが半角でお願いします。

名前の取得は、いつも通りですが
fgets((char*)name,13,stdin);
fgetsはunsigned charだとダメなので(char*)でcharに見せかけています。
こう言うのをキャストと呼びます。(たぶん)
ちなみに、変数がcharだと、keyファイルがうまく作れません(^^;
13文字取るのは、改行も含めるため

keyファイル用の変数(全部で50文字で16文字は固定だから34文字必要)
unsigned char key[35]="AAAAAAAAAAAAAAAA!!!!!!!!!!!!!!!!!!";
Aの部分は、名前と名前から計算された4文字が入る
!は変わっていく部分

あとは計算のために必要な変数2つ
unsigned int x=0,y;
xは溜め込むよう、yはその場の計算用とします(え?わからないって?:汗)

ループ用に1つ
int i;
こんな物ですね。では、ループの中身を書いていきましょう。

まずは、12回ループするので
for(i=0;i<12;i++){

fgetsは'\n'が混じるので
if(name[i]=='\n') name[i]=' ';

次は名前の部分です 17文字目から一つずつXOR 80をしていっているだけですね。
XORは、もう一度XORをすると元に戻るので、名前を決めたらそれをXOR 80するだけで良いです。
key[i] = name[i] ^ 0x80;
これで取得した名前をXOR 80してkeyの0〜11に入っていきます。

残りは計算です。 文字を計算用の変数に移しましょう
y = key[i];

そして MOV AH,ALしています。
これは、00000012だと00001212になります。(文字は1バイトなので)
では、どうすればよいか、私は、8bit左にシフトさせた物と、元の物をORしました。(単純に足しても良いと思いますが)
念のために、&ffなんかしたりして(w
y = (y << 8) | (y & 0xff);

これを単純に2乗します。それを足します。
MUL EAX と ADD EDX,EAX の部分です。
(途中にXOR EAX,EDXってのが有りますが、直前でMULしていてEDXは0になりますので、気にしなくてOKです:たぶん)
x += y*y;

で、その結果をROL 7です。
x = _lrotl(x,7);
これで、名前のループは終わりです。


004011C7   . C60439 00      MOV BYTE PTR DS:[ECX+EDI],0
004011CB . 3B56 04 CMP EDX,DWORD PTR DS:[ESI+4]
004011CE .^0F85 D2FEFFFF JNZ crkme19.004010A6

さてここですが、keyファイルの29〜32文字目を取り出しEDXと比べています。
EDXとは先ほどの計算結果のxがそれにあたります。
ですので、xから1バイトずつ取り出して変数keyの12〜15に入れてしまえばいいわけです。
for(i=0;i<4;i++){
key[i+12] = x & 0xff;
x >>= 8;
}

説明をすると、x&0xffで下1バイトを取り出し、key[12]〜[15]に入れていきます。
その間x>>=8で2バイトずつ削っていきます。
これで、29〜32の部分は出来ました。


次を見ましょう

004011D6   . B9 03000000    MOV ECX,3
004011DB   > 034431 0B      ADD EAX,DWORD PTR DS:[ECX+ESI+B]
004011DF .^E2 FA LOOPD SHORT crkme19.004011DB

さて、ここでは、EAXにECX+ESI+B要するに
変数keyで説明すると20〜23文字+ループ回数と言うことになります。
それを足せばいいわけです。
y=0; //yをクリア
for(i=3;i>0;i--)
y += key[i+19] + (key[i+20] << 8) + (key[i+21] << 16) + (key[i+22] << 24);

iは3,2,1と変わっていきます。ですので、[i+19]は22,21,21となっていきます。
これで、yに値が取れました。
わからない方は、Ollyでトレースでもしながら(^^;
で、ココで作られた文字は、最後の方で、keyファイルの最後の部分と比べられています。

0040123F   . 58             POP EAX
00401240 . 3B46 0E CMP EAX,DWORD PTR DS:[ESI+E]

ここです。スゴイ後のことなので見忘れがちですが(^^;
(と、言うより私自身今スゴクなやんでいました。:w)
と、言うわけで早速keyのお尻に入れてしまいましょう。
for(i=0;i<4;i++){
key[30+i] = y & 0xff;
y >>= 8;
}
要領はさきほどと同じですので説明はいりませんね。


さてさいごです。

004011E2   . 83C6 08        ADD ESI,8
004011E5 . 0FB606 MOVZX EAX,BYTE PTR DS:[ESI]
004011E8 . B9 05000000 MOV ECX,5
004011ED > 0FB61C31 MOVZX EBX,BYTE PTR DS:[ECX+ESI]
004011F1 . 03C3 ADD EAX,EBX
004011F3 .^E2 F8 LOOPD SHORT crkme19.004011ED
004011F5 . 50 PUSH EAX
004011F6 . 33DB XOR EBX,EBX
004011F8 . 0FB656 0A MOVZX EDX,BYTE PTR DS:[ESI+A]
004011FC . 8B46 06 MOV EAX,DWORD PTR DS:[ESI+6]
004011FF . B9 04000000 MOV ECX,4
00401204 > 8AD8 MOV BL,AL
00401206 . 03D3 ADD EDX,EBX
00401208 . C1E8 08 SHR EAX,8
0040120B .^E2 F7 LOOPD SHORT crkme19.00401204
0040120D . 0FB65E 0B MOVZX EBX,BYTE PTR DS:[ESI+B]
00401211 . 03D3 ADD EDX,EBX
00401213 . 0FB64E 0D MOVZX ECX,BYTE PTR DS:[ESI+D]
00401217 . 03D1 ADD EDX,ECX
00401219 . 0FB646 0C MOVZX EAX,BYTE PTR DS:[ESI+C]
0040121D . 03D0 ADD EDX,EAX
0040121F . 58 POP EAX
00401220 . 03D0 ADD EDX,EAX
00401222 . 33C9 XOR ECX,ECX
00401224 > 0FB64431 F0 MOVZX EAX,BYTE PTR DS:[ECX+ESI-10]
00401229 . 03D0 ADD EDX,EAX
0040122B . 41 INC ECX
0040122C . 83F9 10 CMP ECX,10
0040122F .^72 F3 JB SHORT crkme19.00401224
00401231 . 81E2 FF000000 AND EDX,0FF
00401237 . 85D2 TEST EDX,EDX
00401239 .^0F85 67FEFFFF JNZ crkme19.004010A6

と、スゴク長いんですが、全部説明する気はありません(汗
簡単に言いますと、keyファイルの名前部分から30文字足してAND FFした数が0で有ればOKです。
わからない方はメモを取りながらトレースということで(^^;
さて、ここは原始的に行きましょう(w
変えれる部分='!'の部分を1ずつ足していき、zになった時点で次の'!'をたしていく
それを計算結果が0になるまで繰り返す。
と言うことです。
実際に書いていきましょう
do{
まず必ず最初に一度は実行するのでdoです。
x=0;
for(i=0;i<30;i++)
x += key[i];

xを0にしてkey[0]〜[29]までをxに足していきます。そして
x &= 0xff;
AND FFです。この値が0なら終わりと言うことです。
で、0じゃない場合は、!を変えていかなければなりません。そこで
if(x != 0 && key[16+y] < 0x7a)
key[16+y]++;

もし、xが0出ない場合、なおかつkey[16+y]がzより小さい場合、key[16+y]を一つ進めます。
yは、前の計算で0になっていますので、y=0;と言うのは出てきません。
で、もし、zまできちゃったらどうするか、
else if(x != 0)
key[16+(++y)]++;

です。なぜelseではないのか?それは、x!=0で、無ければ実行してはならないからです(^^;
コレを忘れると、登録されません。(w
[16+(++y)]と言うのは、++yはその場でインクリメントされます。yが0ならここで1になります。(y+1)だと、yは0のままです。
コレを間違えるとエライ目にあいます(^^;
こうすることで次々に!の部分を変えていくことが出来ます。
} while(x != 0);
最後はきちんと閉めておきましょう(w
これで、xが0になるまでループを続けます。
さて、このループを抜けた時点で、完成です。



あとは、keyファイルに書き出しましょう。
FILE *fp;
if( ( fp = fopen("crk19.key","w+") ) == NULL) exit(-1);

こうすることで、ファイルが開けない場合自動で終了してくれます。
まぁ、今までのをまとめただけですが。。。
ファイル名は、別にコレじゃなくて良いです。
せっかく名前入力してるんだからそれを使っても良いですしね。
その場で入力させるのも有りですね。
fprintf(fp,"%s%s","CRKME#19 KEYFILE",key);
fclose(fp);
後は書き出して、ファイルを閉じればおしまいです。
printf("KEYファイル[crk19.key]を出力しました。\n");
getch();
こんなの書いておくと解りやすいでしょう。v(^^
では、恒例(?)となりましたソースです。
ここからDLしてください(^^;
wipipiオリジナルお遊びKGも入れておきます。
それでkeyファイル作ってメモ帳などで開いて一番お尻を見てみると!?
(ちなみにお尻に漢字が出ていたら、そのエディタは未対応と言うことで:w)