#10のKG(コンソール)
え〜っと、vol.1の最後だけあって、かなり難しいです(^^;
ちょっとややこしいですが、がんばっていきましょ〜(^^)ノ
まず、IDですが作っちゃってもいいのですが、コンソールだとめんどくさいので今回はパスです。
IDを入力してもらい、パスを表示されるようにしましょう。
さて、まず取得の部分を作ります。が、IDは数字になっているので
文字で取得すると、文字から数字に変換しなければなりません。
ダルイですが作りましょう(汗
(scanfなら数字で取得できますが:汗)
では、pasは19文字と言うことで pas[20]で、IDは8文字なのでid[9]を作りましょう。
なにげに、多めに取っていますが気にしないで下さい(^^;
大きくて駄目なことは、そんなにありませんから。
char
pas[20],id[9];
あとついでにidが数字になるので
unsigned
long nid;
取得はおなじみ
fgets(id,9,stdin);
さて、コレを数字に変換します。
今回は、関数を作ってみましょう。最初はmainのようにこう書きます。
unsigned long
myAtoI(char* str,int len){
( )の中は、charとintがここに入ってやってくるよ、と言う意味です(違うかな?:汗)
char*となっているのは、charのポインターです。(たぶんね)
ですので、myAtoI(id,8);とした場合、この関数内のstrは、mainのidを指しています。
nid
=
myAtoI(id,8);こんな感じで使うと中で計算された物が出てきてnidに入ります。
nidに帰ってくる物が返値といいます。まぁそれは後回しで続き行きましょう
まず、文字を取り出して、余計な分を引き、それを数字にしていきます。
わかりにくいと思いますが、次を見ればわかると思います。
int
i;
unsigned long x = 0;
ループ用のiと、計算結果のxです。
for(i=0;i<len;i++){
x <<=
4;
ループさせて、xを4bitシフトさせます。これを繰り返すことにより数字が並んでいきます。
if(0x30
<= str[i] && str[i] <= 0x39)
x += str[i]-0x30;
else if(0x41
<= str[i] && str[i] <= 0x46)
x += str[i]-0x37;
else if(0x61
<= str[i] && str[i] <= 0x66)
x += str[i]-0x57;
else
return 0;
}
return x;
}
え〜、str[i]の文字が数字なら-0x30、大文字なら-0x37、小文字なら-0x57で数字になります。
それ以外なら、0を返すようにして、最後まで数字を作れたらxの値を返します。
要するに失敗すると0になります。
これで、IDから数字に変換できました(^^
え〜しかし作れたのはイイですが、実は一つ一つ分けなければなりません(^^;
mainで分けておきましょう。
分けた時は1バイトで間に合うので、char
id[9];を使っちゃいましょう(^^;
charは文字だけではなく、数字として扱うことも出来ます。
for(i=8;i>0;i++){
id[i] = bid & 0xf;
bid >>=
4;
}
こんな感じで大丈夫です!
とりあえず、今のソースを書いておきましょう。
#include <stdio.h> #include <conio.h> unsigned long myAtoI(char* str, int len); //プロトタイプ宣言といって、関数を宣言する。 //書きたくない場合は、main()を下に書く。(自作関数を上にする) int main(){ char pas[20] ,id[9]; unsigned long nid ,mid[8]; fgets(id,9,stdin); nid = myAtoI(id,8); printf("%X",nid); //確認用です getch(); bid = nid; //nidは、また使うのでbidを使うことにする。 for(i=7;i>=0;i--){ //7,6,5,4,3,2,1,0に書き込むので id[i] = bid & 0xf; //&0xfで一桁にして入れる bid >>= 4; //SHR4で一文字ずらす } for(i=0;i<8;i++) //こちらも確認用 printf("%X",mid[i]); return 0; } unsigned long myAtoI(char* str, int len) { int i; unsigned int x = 0; for(i=0;i<len;i++){ if(str[i]=='\n')return 0; //8桁に満たない場合も0を返す。 x <<= 4; if(0x30 <= str[i] && str[i] <= 0x39) x += str[i]-0x30; else if(0x41 <= str[i] && str[i] <= 0x46) x += str[i]-0x37; else if(0x61 <= str[i] && str[i] <= 0x66) x += str[i]-0x57; else return 0; } return x; }
とりあえず、今は入力したIDが数字になるだけです(^^;
関数の作り方、使い方は、だいたいわかりましたか?
次は、最初の4桁を作っていきましょう。
まず、パスになる4つのキーワードを作りましょう
"BINARYEDIT","DEBUGTRACE","KRACKPATCH","REGISTCODE"ですね
ということは、各10文字*4つあります。
const char
key[4][11]={"BINARYEDIT","DEBUGTRACE","KRACKPATCH","REGISTCODE"};
11バイトの物を4作るという意味ですね。(ん?)
まぁ、こうやって作れることも覚えておいて下さい。
理解の方は、適当にしてください。
本題です。図書室から拝借します。
004012D7 > 50 PUSH EAX 004012D8 . 33C0 XOR EAX,EAX 004012DA . 02044E ADD AL,BYTE PTR DS:[ESI+ECX*2] 004012DD . 02444E 01 ADD AL,BYTE PTR DS:[ESI+ECX*2+1] 004012E1 . 33D2 XOR EDX,EDX 004012E3 . BB 0A000000 MOV EBX,0A 004012E8 . F7F3 DIV EBX 004012EA . 0FB61417 MOVZX EDX,BYTE PTR DS:[EDI+EDX] 004012EE . 58 POP EAX 004012EF . 38D0 CMP AL,DL 004012F1 .^75 9D JNZ SHORT crkme10.00401290 004012F3 . C1E8 08 SHR EAX,8 004012F6 . 83C7 10 ADD EDI,10 004012F9 . 41 INC ECX 004012FA . 83F9 04 CMP ECX,4 004012FD . 73 04 JNB SHORT crkme10.00401303 004012FF .^EB D6 JMP SHORT crkme10.004012D7
ここで、決められていますね。
IDの(ループ回数*2)+(ループ回数*2+1)÷10の余りの分をキーワードから抜いてきた物がパスになります。
ループは4回です。ということは、
for(i = 0;i < 4;i++){
pas[i] = key[i][((id[i*2] +
id[i*2+1]) % 10)];
}
こうなります。OKでしょうか??
最初の4文字は、たったこれだけで出来てしまいます。
あと5文字目はハイフンなのでここで追加しておきましょう。
一応関数にしましょうか?(^^;
void one(char* pas ,char* id) { const char key[4][11]={"BINARYEDIT","DEBUGTRACE","KRACKPATCH","REGISTCODE"}; int i; for(i = 0;i < 4;i++){ pas[i] = key[i][((id[i*2] + id[i*2+1])%10)]; } pas[4] = '-'; }
後でまとめるのでとりあえずこれだけ(^^;
使う時は、one(pas,id);こう使います。
さてさて、次は6〜9文字目に行きましょうか
コレは、パスから計算して、IDと比較していますので逆算が必要です。
なんか、本格的っぽくなってきましたね(笑
0040133E . 33C2 XOR EAX,EDX 00401340 . 66:C1C0 04 ROL AX,4 00401344 . 35 DCFE0000 XOR EAX,0FEDC 00401349 . 66:C1C8 04 ROR AX,4 0040134D . 35 98BA0000 XOR EAX,0BA98 00401352 . C0C4 04 ROL AH,4 00401355 . 35 54760000 XOR EAX,7654 0040135A . C0C8 04 ROR AL,4 0040135D . 35 10320000 XOR EAX,3210
ここです。
パスの上4桁を、入力したパスでXORして、そこからROL、XOR、RORと続いていきます。
で、結果が下4桁と同じか調べています。
では、どうしたら答えは出るか・・・
答えは、下4桁を逆から計算していき、最後に上4桁とXORすれば答えが出ます。
XORはもう一度XORしたら同じ答えが出るので、ROLとRORを逆にすれば大丈夫です。
では、まず変数を作りましょう
IDの上と下4桁がいります。
unsigned short id4=0,id4u=0;
for(i=0;i<4;i++){
id4
<<= 4;
id4u <<=4;
id4 += id[i];
id4u += id[i+4];
}
これで、上下4桁ずつに分けれました。
変数は、必要になればまた後で作りましょう。
では、計算に入ります。AX、AH、ALがとてつもなくややこしいですね(汗
とりあえず
id4u ^=
0x3210;
次にこの4桁の数字の下2桁をローテートしなければなりません、どうしましょう?(^^;
ん〜強行手段しかないですね(笑
unsigned long idk;
idk=id4u;
idk =
(((idk&0xff)<<8)+(idk&0xff))>>4;
id4u &= 0xff00;
id4u += idk &
0xff;
よし、これでたぶん大丈夫でしょう。
id4uをidkに写し、idkの下2桁で4桁作ります(汗
例えば8654なら、8645になればよいわけです。
&0xffで54になります。それを<<8すると5400です、で54を足せば5454
それをshr4bitすると545になります、で&0xffで45
あとは、8654&0xff00で8600ですから、45を足せば、8645と言うわけです。(^^)v
そして
id4u ^= 0x7654;
次は、上2桁の計算です。
idk=id4u;
idk = ((idk&0xff00)+((idk&0xff00)>>8))>>4;
id4u &=
0xff;
id4u += idk&0xff00;
ん〜、説明は上とあんまり変わりないです。
途中計算
id4u ^=
0xba98;
次はAXなので4桁のローテートですね
2345なら23452345にして、ローテートさせます。
そしたら34523452になりますので&ffffで3452になります。
id4u = _lrotl((id4u << 16)+id4u ,4);
id4u &=
0xffff;
最後に
id4u ^= 0xfedc;
id4u =
((id4u << 16)+id4u) >> 4;
id4u &= 0xffff;
id4u ^=
id4;
説明はいりませんね??
あとは、pas[9]に'-'を指定しましょう。
コレは10文字目なんですが、このmojiは何でもいいのですが、見やすさを優先してハイフンにしておきます。
よし、これで完成です。
ソースです。
コレでやっと半分です。みなさん着いてこれていますか〜(^^;
こんな適当な説明じゃ着いてこれないか(汗
void two(char* pas,char* id) { unsigned long id4=0,id4u=0,idk; int i; for(i=0;i<4;i++){ id4 <<= 4; id4u <<=4; id4 += id[i]; id4u += id[i+4]; } id4u ^= 0x3210; idk = id4u; idk = (((idk&0xff)<<8)+(idk&0xff))>>4; id4u &= 0xff00; id4u += idk & 0xff; id4u ^= 0x7654; idk = id4u; idk = ((idk&0xff00)+((idk&0xff00)>>8))>>4; id4u &= 0xff; id4u += (idk&0xff)<<8; id4u ^= 0xba98; id4u = _lrotl((id4u << 16)+id4u ,4); id4u &= 0xffff; id4u ^= 0xfedc; id4u = ((id4u << 16)+id4u) >> 4; id4u &= 0xffff; id4u ^= id4; for(i = 8;i > 4;i--){ pas[i] = id4u & 0xf; if(9 >= pas[i]) pas[i] += 0x30; else pas[i] += 0x37; id4u >>= 4; } pas[9] = '-'; }
え〜、それでは11〜14文字目に行きます。
ちょっとややこしいですが
ここはcrkmeでは、パスから計算した結果と、IDから計算した結果が同じでなければなりません
このIDの結果をパスの計算と同じ事をしたら、正解のパスが出ます。
ですので、KGでは、IDから計算して、その結果をcrkmeのパスからの計算と同じ事をやりパスを出します。
まず、IDの計算を見てみます。
0040148E |> 0FBE06 /MOVSX EAX,BYTE PTR DS:[ESI] 00401491 |. 83F8 30 |CMP EAX,30 00401494 |. 72 17 |JB SHORT crkme10a.004014AD 00401496 |. 83F8 39 |CMP EAX,39 00401499 |. 77 12 |JA SHORT crkme10a.004014AD 0040149B |. 83E8 30 |SUB EAX,30 0040149E |. 93 |XCHG EAX,EBX 0040149F |. 6BC0 0A |IMUL EAX,EAX,0A 004014A2 |. 03D8 |ADD EBX,EAX 004014A4 |. 49 |DEC ECX 004014A5 |. 83F9 00 |CMP ECX,0 004014A8 |. 74 06 |JE SHORT crkme10a.004014B0 004014AA |. 46 |INC ESI 004014AB |.^EB E1 \JMP SHORT crkme10a.0040148E
ここです。
IDから一文字EAX取り出し、30を引く=バイナリ値になり、EAXとEBXを交換
EAX*0xA(10)をしてEBXにEAXをたす。
簡単に説明するとIDの初めから4桁を一つずつ取り出しバイナリ値に変換それに、0XA(10)をかけ、足していくだけです。
実はCにするとすごくあっさりします。
すでに、id[]にはバイナリ値に変換された物が入っているので
int i;
unsigned long ida=0;
for(i = 0;i < 4;i++){
ida *= 10;
ida += id[i];
}
たったこれだけです。
入れ替えなどは何処に行ったと思われるでしょうが
crkmeはここで、バイナリ値に変換する作業が入るのでこういうやり方をしているだけです。
すでに、変換しているのでコレでOKです。
これで、IDからの計算は、終わりました。あとはパスにしていきます。
あと、気づいた人もいるかもしれませんが0xFFFFまでしか使わないのでlongではなくshortでもたぶん大丈夫です。
0040139C > 51 PUSH ECX 0040139D . 33C9 XOR ECX,ECX 0040139F > D1E2 SHL EDX,1 004013A1 . 8BD8 MOV EBX,EAX 004013A3 . D3EB SHR EBX,CL 004013A5 . 83E3 01 AND EBX,1 004013A8 . 0BD3 OR EDX,EBX 004013AA . 83C1 04 ADD ECX,4 004013AD . 83F9 10 CMP ECX,10 004013B0 .^72 ED JB SHORT crkme10.0040139F 004013B2 . 59 POP ECX 004013B3 . 41 INC ECX 004013B4 . D1E8 SHR EAX,1 004013B6 . 83F9 04 CMP ECX,4 004013B9 .^72 E1 JB SHORT crkme10.0040139C
ここでパスが作られます。
まずループがあり、その中にループがあります。ですので、もう一つintを増やしましょう
int
j;
そして、計算があります。
EAX、EBX、EDXが使われています。
idaを使うとしても、もう2つ必要になります。
計算をまとめて書く方は1つでも大丈夫だと思います。
unsigned idb,idc;
idaをEAX、idbをEBX、idcをEDXに見立てることにしましょう。
では、ループを作りましょう大きい方からです。4回ループします。
for(i=0;i<4;i++){
で小さい方ですが、4*4=16(0x10)なのでこれも4回ループします。
for(j=0;j<16;j+4){
こう書いたらいいのでしょうが、私はこう書きます。
for(j=0;j<4;j++){
問題はSHR
EBX,CLの部分なんですが、私はその場で4かけてやることにします。
では小さいループの中身です。
SHL EDX,1;は
idc<<=1;
MOV EBX,EAX;ですので代入です
idb=ida;
SHR EBX,CLなのでカウントのbit数だけ移動です。i+4ではなくi++でループしているので4をかけます。
idb>>=j*4;
あとはANDとORの計算です。
idb&=1;
idc|=idb;
}
その後、小さいループを抜けて大きいループに計算が一つあります。
SHR
EAX,1;です。
ida>>=1;
}
コレで計算は完成です。
この数字がパスになります。
後は、pas(文字)に変換していきましょう。
一文字ずつの処理なのでループです。
数字の後ろから処理するので、
for(i
= 13;i > 9;i--){
こうなります。そして、一桁を取り出します。
pas[i] = idc & 0xf;
それが数字なら+0x30します。
if(9 >= pas[i])
pas[i] +=
0x30;
それ以外ならA〜Fと言うことになりますから+0x37足します。
else
pas[i] += 0x37;
ループの際に一桁削ります。
idc
>>= 4;
}
これで、文字に変換できました。
あとは、15文字目は'-'なので
pas[14]='-';
を追加しておきましょう。
ソースです。
void thr(char* pas ,char* id) { int i,j; unsigned short ida=0,idb,idc; for(i = 0;i < 4;i++){ ida *= 10; ida += id[i]; } for(i=0;i<4;i++){ for(j=0;j<4;j++){ idc <<= 1; idb = ida; idb >>= j*4; idb &= 1; idc |= idb; } ida >>= 1; } for(i = 13;i > 9;i--){ pas[i]=idc & 0xf; if(9 >= pas[i]) pas[i] += 0x30; else pas[i] += 0x37; idc >>= 4; } pas[14]='-'; }
さぁ、すごく長くなってきました。。
図書館のように2つに分けたら良かったですかね(汗
まぁ、気合いを入れて最後の4文字行きましょう。
え〜ここは、入力したパスから計算をして、その結果が、IDの2〜6文字と同じなら正解です。
と、言うことは、IDから逆に計算をしていくとパスが出ると言うことで逆算しましょう。
の前に逆汗ですね。図書室から拝借して・・・
004013F5 > 46 INC ESI 004013F6 . 8B06 MOV EAX,DWORD PTR DS:[ESI] 004013F8 . BE 90314000 MOV ESI,crkme10.00403190 ; ASCII "ABCDEFGHJKLMNPQRSTUVWXYZ23456789" 004013FD . 33D2 XOR EDX,EDX 004013FF . 33C9 XOR ECX,ECX 00401401 > 51 PUSH ECX 00401402 . 33C9 XOR ECX,ECX 00401404 > 83F9 20 CMP ECX,20 00401407 . 73 0B JNB SHORT crkme10.00401414 00401409 . 0FBE1C31 MOVSX EBX,BYTE PTR DS:[ECX+ESI] 0040140D . 38D8 CMP AL,BL 0040140F . 74 03 JE SHORT crkme10.00401414 00401411 . 41 INC ECX 00401412 .^EB F0 JMP SHORT crkme10.00401404 00401414 > 8BD9 MOV EBX,ECX 00401416 . 59 POP ECX 00401417 . 83FB 20 CMP EBX,20 0040141A .^0F83 70FEFFFF JNB crkme10.00401290 00401420 . C1E2 05 SHL EDX,5 00401423 . 0BD3 OR EDX,EBX 00401425 . C1E8 08 SHR EAX,8 00401428 . 41 INC ECX 00401429 . 83F9 04 CMP ECX,4 0040142C .^72 D3 JB SHORT crkme10.00401401 0040142E . BE C0314000 MOV ESI,crkme10.004031C0 00401433 . 8BC2 MOV EAX,EDX 00401435 . 33C9 XOR ECX,ECX 00401437 . 33D2 XOR EDX,EDX 00401439 > C1E2 04 SHL EDX,4 0040143C . 8BD8 MOV EBX,EAX 0040143E . 83E3 0F AND EBX,0F 00401441 . 0FBE1C33 MOVSX EBX,BYTE PTR DS:[EBX+ESI] 00401445 . 0BD3 OR EDX,EBX 00401447 . C1E8 04 SHR EAX,4 0040144A . 41 INC ECX 0040144B . 83F9 05 CMP ECX,5 0040144E .^72 E9 JB SHORT crkme10.00401439 00401450 . 52 PUSH EDX 00401451 . BE E6314000 MOV ESI,crkme10.004031E6 ; ASCII "ID:46484833" 00401456 . 83C6 04 ADD ESI,4 00401459 . 6A 05 PUSH 5 0040145B . 56 PUSH ESI 0040145C . E8 55000000 CALL crkme10.004014B6 00401461 . 5A POP EDX 00401462 . 3BC2 CMP EAX,EDX 00401464 .^0F85 26FEFFFF JNZ crkme10.00401290
えらく長いですね(^^;
では、まずIDの2〜6文字目を抜き取りましょう。
IDを数字化したnidがありますので最後と言うこともありこれを使います
nid &= 0xfffff00;
IDが46484833の場合これで6484800になりますので右に8bitシフトします
nid
>>=8;
これで64848になりました。
さて計算です。
まずしたから見ていくと00401439〜0040144Eのループがあります。
CMP
ECX,5で5回ループしています。
int i;
for(i=0;i<5;i++){
途中なんですがループはひとまずおいておくとして中身を考えましょう
、00401441のMOVSXで004031C0から文字を抜き抱いています
004031C0 09 01 04 0B 03 08 0F 06 0D 05 0C 00 0A 0E 02
07 ←ココからです
crkmeは、パスからココまでの計算結果の一桁+004031C0をします。
2なら04を取り出し、EBXに取り出しEDXに論理和、ループの最初でコレをSHL4しています。
それを5回繰り返して結果を出しています。
ようするに64848にしたければ、52527が入っていなければなりません。
では正解はどうやって出せばいいかと考えると
ループでパスの一桁をこの文字と合わせていって、一致したループ回数を出して足していけば、
00401439までのcrkmeの計算結果と同じになるわけです。
具体例を挙げると、こういう作業をさせたらいいのです
64848を&0xfしたら8、004031C0の08を探す。0から数えて5個目、ですので5
64848を>>4する、6484
5を<<4する、50
6484&0xfで4、004031C0から探す。2個目(0含め)
50に2をたす52
と続くわけです。
わかりましたか?
それではソースにしていきましょう。
004031C0の部分は
const unsigned long pk[16]
={9,1,4,11,3,8,15,6,13,5,12,0,10,14,2,7};
こんなのでいいでしょう。ちなみに0xがめんどくさかったので10進数に戻しています。
unsigned
longでなく、intでもイイですが、警告が出ます。(何故かは自分で考えてね)
計算結果の入れ物を作ります
unsigned
long x=0;
ループごとに、コレが左ローテートすることにしましょう。
何故かというと、52527にしたい場合、最後に書くと525270になっちゃいますので
最初はどうせ0ですので変わりはしませんので、最初に書きます。
x <<= 4;
でpkから探します。
int
j;
for(j=0;pk[j] != (nid&0xf);j++);
forは{ }を書かずに ;
だけ書けば、この場合だと、比較 → j++ → 比較 → j++ となります。
これで、一致すれば抜け出ます。
何故かはもう解りますよね?解らなければ勉強するか質問してください。
ここで、jの値が計算結果ですので
x
|= j;
します。
あとは、IDはずらします。
nid >>=
4;
}
これで、下のループは終わりです。
少しややこしいですね。遅いかもしれませんが、トレースしながらじゃないと解らないと思いますよ(笑
上の部分を見ましょう
crkmeは、入力したパスの最後4文字を00403190から一つずつ比べていき同じなら飛び出します。
00403190
41 42 43 44 45 46 47 48 4A 4B 4C 4D 4E 50 51 52 ABCDEFGHJKLMNPQR
004031A0
53 54 55 56 57 58 59 5A 32 33 34 35 36 37 38 39
STUVWXYZ23456789
ここですね。
で、その結果をEDXに入れます。EDXは、2回目からSHL5されます。
LKKHと入れると、10個目にLはきますので0xAですね。
Kは9、Hは8ですので
A<<5は140、140|9は149、149<<5は2920、2920|9は2929、2929<<5は52520、52520|7は52527
はい、さっきと同じようになりましたね。
さて要するに52527から7を作りだし、>>5した2929から9、149から9、149を>>5するとAにすればいいのです。
え〜、この場合だと52527&0xfすると7が出てきそうなんですが
見ている文字は0x1F個あります。と、言うことは&0x1fしたほうが無難ですね
あと、52527から7を引いて>>5するのが普通なのですが、どうせ消えてしまうので省きましょう。
あと、もうpasに入れていくので・・・
まずは変数です。
const char *pmoji =
"ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
どうなっているかは解りますね。
あとは
for(i = 18;i >= 15;i--){
pas[i] = pmoji[(x&0x1f)];
x >>= 5;
}
たったこれだけです。
18〜15のループは、pasの変数に直接入れていくからです。
pmoji[(x&0x1f)]は、x&0x1fが52527だと7になるのでpmoji[7]、pmoji[7]は'H'なので、まずはpas[18]にHが入ります
でx>>=5で2929になります。で&0x1fで17にKがはいって・・・・16にKがはいってと続きます。
さて、これで終わりです。
4は
void four(char* pas ,unsigned long nid) { const unsigned long pk[16] ={9,1,4,11,3,8,15,6,13,5,12,0,10,14,2,7}; const char *pmoji = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789"; unsigned long x=0; int i,j; nid &= 0xfffff00; nid >>= 8; for(i=0;i<5;i++){ x <<= 4; for(j=0;pk[j]!=(nid&0xf);j++); x |= j; nid >>=4; } for(i = 18;i >= 15;i--){ pas[i] = pmoji[(x&0x1f)]; x >>= 5; } }
これだけですね。
ソースは長いので、ここから見て下さい。