#09のKG(コンソール)


では、いきなりですが、図書室から肝心な部分を借りてきましょう。

少し長いので分けて見ていきましょう。

004012B5  /$ 33C0           XOR EAX,EAX
004012B7  |. BE 30304000    MOV ESI,crkme09.00403030                 ;  ASCII "abc"
004012BC  |> 803E 00        /CMP BYTE PTR DS:[ESI],0
004012BF  |. 74 17          |JE SHORT crkme09.004012D8
004012C1  |. 0FBE0E         |MOVSX ECX,BYTE PTR DS:[ESI]
004012C4  |. 81F1 5B7CCB3D  |XOR ECX,3DCB7C5B
004012CA  |. 81C1 F56ED76F  |ADD ECX,6FD76EF5
004012D0  |. C1C1 07        |ROL ECX,7
004012D3  |. 03C1           |ADD EAX,ECX
004012D5  |. 46             |INC ESI
004012D6  |.^EB E4          \JMP SHORT crkme09.004012BC

まずここで名前からなにやら計算されているみたいですねぇ
とりあえず、必要な物を書いていきましょう

名前のためにcharを用意します。今回も256バイトということで
char name[256];

すこし、ややこしい計算しています。
ECXに名前から一文字取り出し、計算後EAXにまとめて行っているみたいなのでまずは2つ
unsigned long a=0,x;
ちょっと、安易ですが、ヨシでしょう(^^;

ループを使っていますので
int i;

名前の取得には、またfgets()で行きましょう
fgets(name,256,stdin);

ループで抜ける条件がまた名前の終わりなので
for(i=0;name[i]!='\n';i++){

後は計算です。
x = name[i] ^ 0x3dcb7c5b;
x += 0x6fd76ef5;
x = _lrotl(x,7);

となるのですが
問題はないんですが、短くしたい人は
x = _lrotl((name[i] ^ 0x3dcb7c5b) + 0x6fd76ef5 ,7);
でも、結構だと思います。

そして、最後は
a += x;
}
です。計算からはいるのでaは最初に初期化しておきましょう。


さ、次行きましょう。

004012DD  |. 50             PUSH EAX
004012DE  |> 8BD8           /MOV EBX,EAX
004012E0  |. 83E3 0F        |AND EBX,0F
004012E3  |. 0FBE8B E831400>|MOVSX ECX,BYTE PTR DS:[EBX+4031E8]
004012EA  |. 880E           |MOV BYTE PTR DS:[ESI],CL
004012EC  |. 46             |INC ESI
004012ED  |. C1E8 04        |SHR EAX,4
004012F0  |. 83F8 00        |CMP EAX,0
004012F3  |. 74 02          |JE SHORT crkme09.004012F7
004012F5  |.^EB E7          \JMP SHORT crkme09.004012DE
004012F7  |> C606 2D        MOV BYTE PTR DS:[ESI],2D

さぁ、まずPUSH EAXで先ほどの計算結果を保存しているのでマネしておきましょう。
ついでに、MOV EBX ,EAXもあるので
unsigned long b;
b = a;


で、次はループです。EAXが0になるまでですので
for(i=0;a != 0;i++){

004012DEからパスの一部が作られるのでパスの変数も用意しましょう、とりあえず17バイト用意しましょう
char pas[17];
pas[i]=a;
pas[i]&=0x0f;


004012E3でEBX+4031E8とありますので4031E8をのぞいてみましょう
004031E8 53 31 41 43 34 51 4D 35 S1AC4QM5
004031F0 45 47 4F 55 38 49 4B 5A EGOU8IKZ
004031F8 52 47 36 57 58 50 44 37 RG6WXPD7
00403200 4E 54 39 42 56 32 48 4A NT9BV2HJ

これが、パスの文字を決めている物なので、これを作っておきましょう
const char *pmoji = "S1AC4QM5EGOU8IKZRG6WXPD7NT9BV2HJ";
constは、変更できない物です。↑これ以上書き換えできません。
*が付くのはポインターと言います。まぁ、後々勉強して下さい(^^;
とりあえずは、メモリのどっかのアドレスをさしています。で、
pas[i] = pmoji[pas[i]];
わかりにくいと思いますが、わかって下さい(^^;
たとえば、pas[j]が3だったらpmoji[3]と言う意味でCがpas[i]に入ります。

でSHR,4で
a >>= 4;
}

004012F7は、
pas[8] = '-';
こんな感じで(適当)


004012FA  |. 58             POP EAX
004012FB  |. C1C0 0D        ROL EAX,0D
004012FE  |. 35 5B7CCB3D    XOR EAX,3DCB7C5B
00401303  |. C1C0 07        ROL EAX,7

さ、またまた途中計算が入ります。
順番に書くと
a=b;
a=_lrotl(a,0xd);
a^=0x3dcb7c5b;
a=_lrotl(a,7);

こうなります。
まとめて書くと
a = _lrotl((_lrotl(a,0xd)) ^ 0x3dcb7c5b ,7);
となりますが・・・見にくいのでなるべくなら分けて書いた方がいいと思います。


00401306  |. B9 09000000    MOV ECX,9
0040130B  |> 8BD8           /MOV EBX,EAX
0040130D  |. 83E3 0F        |AND EBX,0F
00401310  |. 83C3 10        |ADD EBX,10
00401313  |. 0FBE8B E831400>|MOVSX ECX,BYTE PTR DS:[EBX+4031E8]
0040131A  |. 46             |INC ESI
0040131B  |. 880E           |MOV BYTE PTR DS:[ESI],CL
0040131D  |. C1E8 04        |SHR EAX,4
00401320  |. 83F8 00        |CMP EAX,0
00401323  |. 74 02          |JE SHORT crkme09.00401327
00401325  |.^EB E4          \JMP SHORT crkme09.0040130B

次に進めまして、これが最後のパス生成場所ですね
さっきまでで、pas[8]までは書きましたので9からですね
ループはEAXが0で抜けだしますから
for(i=9;a!=0;i++){
後は、さっきと同じような感じで・・・順番に書いていきます。
pas[j] = a;
pas[j] &= 0xf;
pas[j] += 0x10;
pas[j] = pmoji[pas[j]];
a = a >> 4;
}

わかりますね??

後は、表示だけです。
まず、パスの一番最初は、CRK9-で有ることはわかっているので
あとは、出来上がったパスを逆から表示しなければなりません。
printf("CRK9-%s",strrev(pas));
printfの中では、計算ができますが、関数(命令)も使うことが出来ます。
strrevと言うのは、文字列を逆から表示してくれます。(便利)
(ほかにstr〜はイッパイ出てきます)
あ・・・終わっちゃいましたね(汗

では、ソースです。


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>

int main(){
        char name[256],pas[20];
        unsigned long a=0,b,x;
        int i;
        const char *pmoji = "S1AC4QM5EGOU8IKZRG6WXPD7NT9BV2HJ";

        memset((char*)pas,0,20);                //pas[20]をすべて0で埋めます。最後でstrrevを使うので必要。

        printf("NAME:");                        //入力を促す。(08からだけど促してない・・・)
        fgets(name,256,stdin);          //入力

        for(i=0;name[i]!='\n';i++){             //ループと計算
                x =  name[i] ^ 0x3dcb7c5b;
                x += 0x6fd76ef5;
                x =  _lrotl(x,7);
                a += x;
        }

        b = a;

        for(i=0;a != 0;i++){
                pas[i] =  a;            //1バイトのchar入れたらやばそうだけど次に&0xfするので
                                        //結局一桁になるので大丈夫です。
                pas[i] &= 0xf;
                pas[i] =  pmoji[pas[i]];
                a >>= 4;
        }

        pas[8] = '-';

        a =  b;                         //コレをしないで、下の計算をbでやってもヨシ
        a =  _lrotl(a,0xd);
        a ^= 0x3dcb7c5b;
        a =  _lrotl(a,7);

        for(i=9;a != 0;i++){
                pas[i] =  a;
                pas[i] &= 0xf;
                pas[i] += 0x10;
                pas[i] =  pmoji[pas[i]];
                a >>= 4;
        }

        if(pas[7] == 0 || pas[16] == 0) //pas[7]とpas[16]が0のままであったら不可能なので
                printf("PASS:不可能");
        else
                printf("PASS:CRK9-%s\n",strrev(pas));

        getch();

        return 0;
}

さて、コレで終わりなんですが、#09は計算して、その数字からパスを作っています。
さらに、パスの文字数を調べています。
もし、計算結果が8桁に満たない場合は・・・正解と出すのは不可能です。
一例として、123が有ります。どう考えても入力できません。
この場合KGは、文字が足りないままパスが出力されますが
文字数チェックで引っかかって不正解になります。
かなり悔しいので、わかっているぞとアピールして見ました。(笑
ついでに、|| は、or(もしくは)と言う意味で、&&は、and(かつ)と言う意味です。

あと、charに数字を入れるものの追加情報(?)ですが
charに大きい数字を入れれるなんてしんじられんという方は
char x;
int y=0x3455da;
x=y;
printf("%x",x);

こんなのを適当に作って確認して下さい。

以上、第三回 適当KG講座でした。

間違い、説明不足などじゃんじゃん突っ込んで下さい(^^;
そろそろCになれてきましたかね?
#10は、結構難しいんですけど(汗
でも、09を理解できたら他のも作れると思いますが(^^;