#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;
        }
}

これだけですね。
ソースは長いので、ここから見て下さい。