首页
社区
课程
招聘
[原创]riijj系列剖析(km1注册机实现)
发表于: 2009-4-10 23:32 4518

[原创]riijj系列剖析(km1注册机实现)

2009-4-10 23:32
4518
目标:riijj的keygenme1.
这个是前段时间弄的, 因为打算把riijj的cm和km都分析一遍,当时分析的时候
因为没看原帖子, 所以花了很多时间(真的是好多时间 ), 现在看来可能有些手法比较笨拙, 也不大算改了.
原原本本贴上来算了.

00401777  |> \50            push    eax                              ; /Arg4
00401778  |.  FF75 9C       push    dword ptr [ebp-64]               ; |Arg3
0040177B  |.  56            push    esi                              ; |Arg2
0040177C  |.  56            push    esi                              ; |/pModule
0040177D  |.  FF15 48904000 call    [<&KERNEL32.GetModuleHandleA>]   ; |\GetModuleHandleA
00401783  |.  50            push    eax                              ; |Arg1
00401784  |.  E8 77F8FFFF   call    riijj_km.00401000                ; \这里是WinMain, 跟进

00401000  /$  83EC 1C       sub     esp, 1C                          ;  Winmain
00401003  |.  56            push    esi
00401004  |.  8B7424 24     mov     esi, [esp+24]
00401008  |.  57            push    edi
00401009  |.  8B3D E8904000 mov     edi, [<&USER32.LoadStringA>]     ;  USER32.LoadStringA
0040100F  |.  6A 64         push    64                               ; /Count = 64 (100.)
00401011  |.  68 A4CD4000   push    riijj_km.0040CDA4                ; |Buffer = riijj_km.0040CDA4
00401016  |.  6A 67         push    67                               ; |RsrcID = STRING "Riijj Keygenme 1 30112007"
00401018  |.  56            push    esi                              ; |hInst
00401019  |.  FFD7          call    edi                              ; \LoadStringA
0040101B  |.  6A 64         push    64                               ; /Count = 64 (100.)
0040101D  |.  68 3CCD4000   push    riijj_km.0040CD3C                ; |Buffer = riijj_km.0040CD3C
00401022  |.  6A 6D         push    6D                               ; |RsrcID = STRING "Riijj Keygenme 1 30112007"
00401024  |.  56            push    esi                              ; |hInst
00401025  |.  FFD7          call    edi                              ; \LoadStringA
00401027  |.  56            push    esi
00401028  |.  E8 43030000   call    riijj_km.00401370                ;  光标,图标及窗体的注册.
0040102D  |.  8B4424 38     mov     eax, [esp+38]
00401031  |.  50            push    eax
00401032  |.  56            push    esi
00401033  |.  E8 28040000   call    riijj_km.00401460                ;  这个call里面会创建对话框.跟进.

004014B8  |.  6A 00         push    0                                ; /lParam = 0
004014BA  |.  68 00144000   push    riijj_km.00401400                ; |pDlgProc = riijj_km.00401400
004014BF  |.  56            push    esi                              ; |hOwner
004014C0  |.  6A 65         push    65                               ; |pTemplate = 65
004014C2  |.  57            push    edi                              ; |hInst
004014C3  |.  FF15 C8904000 call    [<&USER32.CreateDialogParamA>]   ; \CreateDialogParamA

得到DialogFunc. 跳转至之.

00401400   .  817C24 08 110>cmp     dword ptr [esp+8], 111           ;  DialogFunc
00401408   .  75 4D         jnz     short riijj_km.00401457
0040140A   .  817C24 0C EA0>cmp     dword ptr [esp+C], 3EA
00401412   .  75 43         jnz     short riijj_km.00401457
00401414   .  A1 38CD4000   mov     eax, [40CD38]
00401419   .  56            push    esi
0040141A   .  8B35 D4904000 mov     esi, [<&USER32.GetDlgItemTextA>] ;  USER32.GetDlgItemTextA
00401420   .  6A 14         push    14                               ; /Count = 14 (20.)
00401422   .  68 0CCE4000   push    riijj_km.0040CE0C                ; |Buffer = riijj_km.0040CE0C
00401427   .  68 E8030000   push    3E8                              ; |ControlID = 3E8 (1000.)
0040142C   .  50            push    eax                              ; |hWnd => 016E0CBC (class='#32770',parent=00380C10)
0040142D   .  FFD6          call    esi                              ; \GetDlgItemTextA
0040142F   .  8B0D 38CD4000 mov     ecx, [40CD38]
00401435   .  68 FF000000   push    0FF                              ; /Count = FF (255.)
0040143A   .  68 24CE4000   push    riijj_km.0040CE24                ; |Buffer = riijj_km.0040CE24
0040143F   .  68 E9030000   push    3E9                              ; |ControlID = 3E9 (1001.)
00401444   .  51            push    ecx                              ; |hWnd => 016E0CBC (class='#32770',parent=00380C10)
00401445   .  FFD6          call    esi                              ; \GetDlgItemTextA
00401447   .  E8 74FCFFFF   call    riijj_km.004010C0                ;  这个是数据转换Call.     :记为keycall1
0040144C   .  E8 4FFEFFFF   call    riijj_km.004012A0                ;  这个是比较及弹信息Call. :记为keycall2
00401451   .  33C0          xor     eax, eax
00401453   .  5E            pop     esi
00401454   .  C2 1000       retn    10
00401457   >  33C0          xor     eax, eax
00401459   .  C2 1000       retn    10

DialogFunc就这么少了, 从中可知,用户名和注册码保存在全局变量中.

到这里,我们用由下至上的思想去跟踪,先去keycall逆着推.

//keycall2:
004012A0  /$  83EC 40       sub     esp, 40
004012A3  |.  B8 2D000000   mov     eax, 2D
004012A8  |.  56            push    esi                              ;  现场保护.
004012A9  |.  894424 04     mov     [esp+4], eax
004012AD  |.  894424 10     mov     [esp+10], eax
004012B1  |.  B8 55000000   mov     eax, 55
004012B6  |.  C74424 08 620>mov     dword ptr [esp+8], 62
004012BE  |.  894424 14     mov     [esp+14], eax
004012C2  |.  894424 2C     mov     [esp+2C], eax
004012C6  |.  C74424 0C 240>mov     dword ptr [esp+C], 24
004012CE  |.  C74424 18 570>mov     dword ptr [esp+18], 57
004012D6  |.  C74424 1C 170>mov     dword ptr [esp+1C], 17
004012DE  |.  C74424 20 560>mov     dword ptr [esp+20], 56
004012E6  |.  C74424 24 530>mov     dword ptr [esp+24], 53
004012EE  |.  C74424 28 0B0>mov     dword ptr [esp+28], 0B
004012F6  |.  C74424 30 5E0>mov     dword ptr [esp+30], 5E
004012FE  |.  C74424 34 480>mov     dword ptr [esp+34], 48
00401306  |.  C74424 38 540>mov     dword ptr [esp+38], 54
0040130E  |.  C74424 3C 1A0>mov     dword ptr [esp+3C], 1A
00401316  |.  C74424 40 580>mov     dword ptr [esp+40], 58           ;  从此往上是对局部DWORD m[16]填充常量.
0040131E  |.  33C0          xor     eax, eax
00401320  |.  BA 01000000   mov     edx, 1
00401325  |>  8B88 00F04000 /mov     ecx, [eax+40F000]               ;  我们吧40f000记为DWORD g[16], 这里是g[i]
0040132B  |.  8B7404 04     |mov     esi, [esp+eax+4]
0040132F  |.  2BCE          |sub     ecx, esi                        ;  m[i] - g[i],且置标志位.
00401331  |.  8988 00F04000 |mov     [eax+40F000], ecx
00401337  |.  79 08         |jns     short riijj_km.00401341
00401339  |.  F7D9          |neg     ecx                             ;  小于0则求补,这里实际是在求绝对值.
0040133B  |.  8988 00F04000 |mov     [eax+40F000], ecx
00401341  |>  3990 00F04000 |cmp     [eax+40F000], edx               ;  edx就是常数1.
00401347  |.  7F 20         |jg      short riijj_km.00401369         ;  这里不能跳.
00401349  |.  83C0 04       |add     eax, 4
0040134C  |.  83F8 40       |cmp     eax, 40
0040134F  |.^ 7C D4         \jl      short riijj_km.00401325
00401351  |.  A1 08CE4000   mov     eax, [40CE08]
00401356  |.  6A 00         push    0                                ; /Style = MB_OK|MB_APPLMODAL
00401358  |.  68 54A04000   push    riijj_km.0040A054                ; |Title = "Riijj Keygenme 1"
0040135D  |.  68 38A04000   push    riijj_km.0040A038                ; |Text = "Registration successful."
00401362  |.  50            push    eax                              ; |hOwner => NULL
00401363  |.  FF15 E4904000 call    [<&USER32.MessageBoxA>]          ; \MessageBoxA
00401369  |>  5E            pop     esi
0040136A  |.  83C4 40       add     esp, 40
0040136D  \.  C3            retn

从00401347这处可以看出, 这里的判断就是|m[i] - g[i]| <= 1 . 只要满足这个条件就OK.
现在m[16]为常量, 关键是看g[16]的生成过程. 我们下写断点于0040F000处.  结果断在这里:

00401288  |.  8907          |mov     [edi], eax

这句就是在keycall1栈帧里面了.

那我们就去看看KeyCall1, 依然是倒着看:

00401261  |> /DD8434 A80000>/fld     qword ptr [esp+esi+A8]
00401268  |. |DCA434 280100>|fsub    qword ptr [esp+esi+128]
0040126F  |. |83EC 08       |sub     esp, 8
00401272  |. |DC05 08914000 |fadd    qword ptr [409108]
00401278  |. |DD1C24        |fstp    qword ptr [esp]
0040127B  |. |E8 C0020000   |call    riijj_km.00401540
00401280  |. |83C4 08       |add     esp, 8
00401283  |. |E8 0C040000   |call    riijj_km.00401694
00401288  |. |8907          |mov     [edi], eax
0040128A  |. |83C7 04       |add     edi, 4
0040128D  |. |83C6 08       |add     esi, 8
00401290  |. |81FF 40F04000 |cmp     edi, riijj_km.0040F040
00401296  |.^\72 C9         \jb      short riijj_km.00401261
00401298  |>  5F            pop     edi
00401299  |.  5E            pop     esi
0040129A  |.  5D            pop     ebp
0040129B  |.  5B            pop     ebx
0040129C  |.  8BE5          mov     esp, ebp
0040129E  |.  5D            pop     ebp
0040129F  \.  C3            retn

我们把esp+A8处的记为double m1[16], esp+128处的记为double m2[16];
则这里是: g[i] = m1[i] - m2[i] + 0.4 ; qword ptr [409108]就是double型的0.4

所以我们目前要知道m1[16]和m2[16]的生成过程.

我们在OD往上看看,看哪个循环是在对m1和m2生成数据.

很明显, 向上翻5行, 就看到这句:

0040124F  |> \DD9CD4 A80000>|fstp    qword ptr [esp+edx*8+A8]

这是在对吗m1就行写入了. 这里是个双重循环, 我们来看看:
004011F2  |> \33D2          xor     edx, edx                         ;  计数器,16次.
004011F4  |>  DD05 30914000 /fld     qword ptr [409130]              ;  这里是double型的0,貌似没用到.
004011FA  |.  895424 18     |mov     [esp+18], edx
004011FE  |.  897424 1C     |mov     [esp+1C], esi
00401202  |.  DF6C24 18     |fild    qword ptr [esp+18]              ;  64位型整数push进STx.
00401206  |.  8D4C24 28     |lea     ecx, [esp+28]
0040120A  |.  B8 01000000   |mov     eax, 1                          ;  内部一个小循环.
0040120F  |>  894424 20     |/mov     [esp+20], eax
00401213  |.  897424 24     ||mov     [esp+24], esi
00401217  |.  DF6C24 20     ||fild    qword ptr [esp+20]
0040121B  |.  83C0 02       ||add     eax, 2
0040121E  |.  83C1 08       ||add     ecx, 8
00401221  |.  83F8 21       ||cmp     eax, 21
00401224  |.  D8C9          ||fmul    st, st(1)
00401226  |.  DC0D 28914000 ||fmul    qword ptr [409128]
0040122C  |.  DC0D 20914000 ||fmul    qword ptr [409120]
00401232  |.  D9FF          ||fcos
00401234  |.  DC49 F8       ||fmul    qword ptr [ecx-8]              ;  这里在乘m1_1[i],作为引入参数.
00401237  |.  DEC2          ||faddp   st(2), st
00401239  |.^ 72 D4         |\jb      short riijj_km.0040120F
0040123B  |.  3BD6          |cmp     edx, esi                        ;  esi始终为0.
0040123D  |.  DDD8          |fstp    st
0040123F  |.  75 08         |jnz     short riijj_km.00401249         ;  第一次不会跳,以后都跳.
00401241  |.  DC0D 18914000 |fmul    qword ptr [409118]              ;  0.25
00401247  |.  EB 06         |jmp     short riijj_km.0040124F
00401249  |>  DC0D 10914000 |fmul    qword ptr [409110]              ;  0.3535...
0040124F  |>  DD9CD4 A80000>|fstp    qword ptr [esp+edx*8+A8]        ;  写入m1[i]
00401256  |.  42            |inc     edx
00401257  |.  83FA 10       |cmp     edx, 10
0040125A  |.^ 72 98         \jb      short riijj_km.004011F4

上面这段生成m1依靠的其实是: 循环计数(i,j)和上面的m1_1[16] ( 也即esp+28处).这个嵌套循环很简单, 现在关键要知道m1_1如何来的,
继续上溯:
004011B5  |.  BB 24CE4000   mov     ebx, riijj_km.0040CE24           ;  ASCII "999999999"
004011BA  |.  C1E9 03       shr     ecx, 3
004011BD  |.  897424 14     mov     [esp+14], esi
004011C1  |.  74 2F         je      short riijj_km.004011F2
004011C3  |.  8D7C24 28     lea     edi, [esp+28]                    ;  取m1_1地址.
004011C7  |.  8BE9          mov     ebp, ecx
004011C9  |>  8D5424 14     /lea     edx, [esp+14]                   ;  这是sscanf的第三个参数.记为dw.
004011CD  |.  52            |push    edx
004011CE  |.  68 30A04000   |push    riijj_km.0040A030               ;  ASCII "%08x"
004011D3  |.  53            |push    ebx
004011D4  |.  E8 36040000   |call    riijj_km.0040160F               ;  调用sscanf.
004011D9  |.  DB4424 20     |fild    dword ptr [esp+20]              ;  这里就是dw. +20是因为前面push了3次.
004011DD  |.  83C4 0C       |add     esp, 0C
004011E0  |.  83C3 08       |add     ebx, 8
004011E3  |.  83C7 08       |add     edi, 8
004011E6  |.  4D            |dec     ebp
004011E7  |.  DC0D 38914000 |fmul    qword ptr [409138]              ;  乘以0.00001
004011ED  |.  DD5F F8       |fstp    qword ptr [edi-8]               ;  对m1_1写入.
004011F0  |.^ 75 D7         \jnz     short riijj_km.004011C9
现在m1就很明了了, 就是这样的:

注册码:--变形-->>m1_1 ----再变形-->>m1.

再来看看m2.m2相对很简单, 就不贴反汇编了,免得占地方.

所以最后是: name --变1--> m2[16]
            reg --变2--> m1_1 ----变22---m1[16].

这里的"变22"是最复杂的一个.  因为每个m1[i]都与所有的m1_1有关系.

其实是一个16元一次方程.

我想起了大一的线性代数又讲解法的,不过我的书扔了, 室友的没扔, 借来看看,可以用Cramer定律做.
于是求行列式, 开始我用递归去求, 结果发现太慢, 最后反倒后面有讲高斯消去法的, 于是用高斯法,
结果速度很快.(高斯消去的代码是在网上找的.)

我调了好久,算是凑了个注册机了,代码实在惨不忍睹

#include <stdio.h>
#include <conio.h>
#include <windows.h>
#include <math.h>

#define PI 3.1415926535897932384626433832795

#define JK

int m[16] = {0x2d,0x62,0x24,0x2d,0x55,0x57,0x17,0x56,0x53,0xb,0x55,0x5e,0x48,0x54,0x1a,0x58};

char name[256] = {0};
char reg[1024] = {0};
double rec_name[16] = {0}; //就是上面分析的m2.
double rec_reg2[16] = {0}; //注册名第二次变化后. 就是上面分析的m1
double rec_reg1[16] = {0}; //注册名第一次变换后.就是m1_1.

double b[16] ;
double a[16][16];
double x[16] ;

void mk_name();
void mk_reg2();
void mk_reg1();

const int n = 16;
//double aa[n][n] = {{2,1,-5,1},{1,-3,0,-6},{0,2,-1,2},{1,4,-7,6}};
//double bb[n] = {8,9,-5,0};

//5个高斯消去相关函数.
int find_line(int i,double a[n][n]);
void chang_line(int line,int other_line,double a[n][n]);
void clear_num(int i,double a[n][n]);
double calculate_det(double a[n][n]);
void JGus(double a[n][n],double b[n],double x[n]);

DWORD f2dw(double x)
{
        DWORD dw =(DWORD)x;
        double d = (double)dw;
        if (x-d>d+1-x)
        {
                dw++;
        }
        return dw;
}

void main(void)
{
        int i;
        DWORD dw[n];
        char _t[10];
        printf("Enter your name : \n");
        scanf("%s",name);
                mk_name();
        mk_reg2();
        mk_reg1();  //得x[16]

        FILE *fp = fopen("d:\\dd.txt","w+");

        for(i =0;i<n;i++)
        {
                x[i] /= 0.00001;

                fprintf(fp,"x[%d] = %f \n",i,x[i]);
                dw[i] = f2dw(x[i]);
                fprintf(fp,"dw[%d] = %08X \n\n",i,dw[i]);

                memset(_t,0,sizeof(_t));
                sprintf(_t,"%08X",dw[i]);
                strcat(reg,_t);
        }

        printf("Your RegCode is :\n%s\n",reg);
        printf("Press any key to exit ...");
        getch();
       
}

void mk_name()
{
        int i,len;
        int t,total = 1;
        double f;
        char ch;
        len = strlen(name);
        for (i=0;i<16;i++)
        {
                f = (double)name[(i+1)%len];
                f *= 10.0;
                f = sin(f);
                f *= 5527;
                total += (int)fabs(f);

                t = (int)name[i%len];
                t *= 37;
                total += t + 0xB;

                ch = (char)total;
                total = (int)ch;

                rec_name[i] = (double)total;
        }
}
void mk_reg2()
{
        int i;
        for (i=0;i<16;i++)
        {
                rec_reg2[i] = rec_name[i] - 0.4 + m[i];
        }
}

void mk_reg1()
{
        FILE *fp;
        int i,j;

        for (i = 0;i<16;i++)
        {
                for (j = 0;j<16;j++)
                {
                        a[i][j] = (double)cos(PI * i * (2*j + 1) / 32);
                }
                                if (0 == i)
                {
                        b[i] = (double)rec_reg2[i] / (double)0.25;
                }
                else
                {
                        b[i] = (double)rec_reg2[i] / (double)0.35355339;
                }

        }

#ifdef JK
        fp= fopen("d:\\dd.txt","a+");
        fprintf(fp,"a[16][16]:\n\n");
//         for(i=0;i<16;i++)
//         {
//                 for (j=0;j<16;j++)
//                 {
//                         fprintf(fp," a[%d][%d] :%f\n",i,j,a[i][j]);
//                 }       
//         }

        fprintf(fp,"b[16]:\n\n");
        for(i=0;i<16;++i)
        {
                fprintf(fp," b[%d] :%f\n",i,b[i]);
        }
       
        fprintf(fp,"generating ... \n\n");
#endif

        JGus(a,b,x);

#ifdef JK
        fprintf(fp,"\n\n== done ! x[16]: \n\n");
        for(i=0;i<16;++i)
        {
                fprintf(fp," x[%d] :%f\n",i,x[i]);
        }
        fclose(fp);
#endif
}

//这后面都是高斯消去法解方程相关.网上找的.
void JGus(double a[n][n],double b[n],double x[n])
{
        double a2[n][n];
        int i,j,k;
        double D = calculate_det(a);
        double D2;
        for (i=0;i<n;i++)
        {
                ////copy
                for (j=0;j<n;j++)
                        for (k = 0;k<n;k++)
                        {
                                if (k == i)
                                        a2[j][k] = b[j];
                                else
                                        a2[j][k] = a[j][k];
                        }
                D2 = calculate_det(a2);
                x[i] = D2/D;
        }
}

int find_line(int i,double ar[n][n])
{
    int max_a_line=i; //max_a_line为最大元素所在的行
       
    double max_a=ar[i][i]; //max_a为最大元素的值
       
    int out_i=i; //out_i为i的初始值
       
    for(i=i+1;i<n;i++)
    {
        if(ar[i][out_i]<0)
            if(max_a<-ar[i][out_i])
            {
                max_a=-ar[i][out_i];
                max_a_line=i;
            };
                        if(max_a<ar[i][out_i])
                        {
                                max_a=ar[i][out_i];
                                max_a_line=i;
                        };
    }
    return max_a_line;
}

void chang_line(int line,int other_line,double ar[n][n])
{
    double m; //m为中间变量
       
    for(int j=line;j<n;j++)
    {
        m=ar[line][j];
        ar[line][j]=ar[other_line][j];
        ar[other_line][j]=m;
    }
}

void clear_num(int i,double ar[n][n])
{
    int line=i,j;
    double m;
    for(i=i+1;i<n;i++)
    {
        m=-ar[i][line]/ar[line][line];
        for(j=line;j<n;j++)
        {
            ar[i][j]=ar[i][j]+m*ar[line][j];
        }
    }
}
double calculate_det(double ar[n][n])
{
    double det=1;
    int i=0,j;

//----------copy-----------
        double copy_ar[n][n];
        for (i=0;i<n;i++)
                for (j=0;j<n;j++)
                        copy_ar[i][j] = ar[i][j];
//--------------------------               

        i=0;
    do{
        //print_num(a);
               
        j=find_line(i,copy_ar);
        if(i!=j)
        {
            chang_line(i,j,copy_ar);
            det=-det;
        };
        if(copy_ar[i][i]==0)
            return 0;
        det=det*copy_ar[i][i];
        if(i<n-1)
            clear_num(i,copy_ar);
        i++;
    }while(i<n);
    return det;
}

各位不要笑哦, 我代码一直都写的乱七八糟的.   也没怎么改,直接copy了到这里.

总结:

riijj这个km应该来说用的是F(U,R)= 0 这种方法.
对于最后的比较, 如果直接弄成g[i] == m[i] 的. 这样就又要加一点
代码了.

第一次弄注册机, 弄的很烂, 大家别笑话我.

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 0
支持
分享
最新回复 (2)
雪    币: 452
活跃值: (10)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
2
16元一次方程, 好好的温习了,谢谢你的分享
2009-4-13 12:04
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
很好
2009-4-13 13:34
0
游客
登录 | 注册 方可回帖
返回
//