首页
社区
课程
招聘
[原创]Guetta's R-KeyGenMe 算法分析
发表于: 2006-12-9 13:56 8905

[原创]Guetta's R-KeyGenMe 算法分析

2006-12-9 13:56
8905

【破文标题】Guetta's R-KeyGenMe 算法分析
【破文作者】XXNB
【作者邮箱】
【作者主页】http://free.ys168.com/?binbinbin7456
【破解工具】OD
【破解平台】xpsp2
【软件名称】Guetta's R-KeyGenMe
【软件大小】25kb
【软件简介】
Hello everybody, a little keygenme in asm :
Stuff: anti-xxx, layers...
Protection: U will see by yourself ;-)
Solution : Keygen & little solution.

Good luck,
Guetta.

Difficulty: 3 - Getting harder
Platform: Windows
Language: Assembler

Published: 07. Dec, 2006
【破解声明】向大侠们学习!!!只为学习!请尊重作者的劳动成功!
------------------------------------------------------------------------
【破解过程】

今天才在  http://www.crackmes.de/users/guetta/r_keygenme/  发现了个好东西。分析了下,算法还挺简单的。当然如果要用asm写出这个

keygenme我是万万不可能的(我很菜)。

这个keygenme是只有输入正确的注册信息,灰色按钮才是有效的。而且如果用激活按钮的工具的话直接可以看到结果。有不错的音乐听哦。

1、字符串查找可以轻松定位。

004010A4   $  55            push    ebp
004010A5   .  8BEC          mov     ebp, esp
004010A7   .  53            push    ebx
004010A8   .  56            push    esi
004010A9   .  57            push    edi
004010AA   .  6A 20         push    20                               ; /Count = 20 (32.)
004010AC   .  68 48624000   push    00406248                         ; |binbin
004010B1   .  68 94010000   push    194                              ; |ControlID = 194 (404.)
004010B6   .  FF75 08       push    dword ptr [ebp+8]                ; |hWnd
004010B9   .  E8 FC070000   call    <jmp.&user32.GetDlgItemTextA>    ; \GetDlgItemTextA
004010BE   .  83F8 04       cmp     eax, 4                           ;  用户名不能小于4位数
004010C1   .  72 4A         jb      short 0040110D
004010C3   .  6A 20         push    20                               ; /Count = 20 (32.)
004010C5   .  68 80604000   push    00406080                         ; |123456888
004010CA   .  68 95010000   push    195                              ; |ControlID = 195 (405.)
004010CF   .  FF75 08       push    dword ptr [ebp+8]                ; |hWnd
004010D2   .  E8 E3070000   call    <jmp.&user32.GetDlgItemTextA>    ; \GetDlgItemTextA
004010D7   .  83F8 1D       cmp     eax, 1D                          ;  输入的注册码要1D(29位数)
004010DA   .  75 31         jnz     short 0040110D
004010DC   .  E8 1F9F0100   call    0041B000                         ;  这里是算法call。跟进《《《《《《《《《《《-----
004010E1   .  50            push    eax
004010E2   .  68 65604000   push    00406065                         ; /Registered !
004010E7   .  68 95010000   push    195                              ; |ControlID = 195 (405.)
004010EC   .  FF75 08       push    dword ptr [ebp+8]                ; |hWnd
004010EF   .  E8 0E080000   call    <jmp.&user32.SetDlgItemTextA>    ; \SetDlgItemTextA
004010F4   .  B8 01000000   mov     eax, 1
004010F9   .  EB 17         jmp     short 00401112
004010FB   .  68 4C 60 40 0>ascii   "hL`@",0                         ;  You should enter a name.
00401100   .  68 95010000   push    195                              ; |ControlID = 195 (405.)
00401105   .  FF75 08       push    dword ptr [ebp+8]                ; |hWnd
00401108   .  E8 F5070000   call    <jmp.&user32.SetDlgItemTextA>    ; \SetDlgItemTextA
0040110D   >  B8 00000000   mov     eax, 0
00401112   >  5F            pop     edi
00401113   .  5E            pop     esi
00401114   .  5B            pop     ebx
00401115   .  C9            leave
00401116   .  C2 0400       retn    4

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

2、跟进算法call可以得到下面关键代码。

0041B000    33DB            xor     ebx, ebx
0041B002    8D35 84604000   lea     esi, dword ptr [406084]
0041B008    8A06            mov     al, byte ptr [esi]               ; 判断 第五位、第十位、第十五位、第二十位、第二十五位是

否是分隔符
0041B00A    83FB 14         cmp     ebx, 14
0041B00D    74 25           je      short 0041B034
0041B00F    83C6 05         add     esi, 5
0041B012    83C3 05         add     ebx, 5
0041B015    34 7F           xor     al, 7F                           ; 第五位和7F异或
0041B017    3C 52           cmp     al, 52                           ; 然后和 52H“R” 比较
0041B019    75 14           jnz     short 0041B02F                   ; 这里说明了每隔四位一定要是分隔符“-”
0041B01B  ^ EB EB           jmp     short 0041B008                   ; 跳回循环
0041B01D    33C0            xor     eax, eax
0041B01F    53              push    ebx
0041B020    3C 52           cmp     al, 52
0041B022    75 0B           jnz     short 0041B02F
0041B024    83C6 05         add     esi, 5
0041B027    8A06            mov     al, byte ptr [esi]
0041B029    34 7F           xor     al, 7F
0041B02B    3C 52           cmp     al, 52
0041B02D    74 05           je      short 0041B034
0041B02F  - E9 D960FEFF     jmp     0040110D
0041B034    8D35 80604000   lea     esi, dword ptr [406080]          ; 把整个输入的假码放到esi
0041B03A    8A06            mov     al, byte ptr [esi]               ; 取第一位
0041B03C    3C 00           cmp     al, 0                            ; 第一位不能为0
0041B03E    74 19           je      short 0041B059
0041B040    3C 2D           cmp     al, 2D                           ; 第一位不能为“-”
0041B042    74 12           je      short 0041B056
0041B044    3C 30           cmp     al, 30
0041B046    72 06           jb      short 0041B04E
0041B048    3C 39           cmp     al, 39
0041B04A    77 02           ja      short 0041B04E                   ; 第一位要求是数字1~9
0041B04C    EB 08           jmp     short 0041B056
0041B04E    3C 41           cmp     al, 41
0041B050  ^ 72 DD           jb      short 0041B02F
0041B052    3C 46           cmp     al, 46
0041B054  ^ 77 D9           ja      short 0041B02F
0041B056    46              inc     esi                              ; 继续下一位判断,
0041B057  ^ EB E1           jmp     short 0041B03A                   ; 循环回去判断。这个循环是检测输入的注册码是否都是数字的

1~9
0041B059    33C9            xor     ecx, ecx
0041B05B    8D35 D7614000   lea     esi, dword ptr [4061D7]
0041B061    BB 10000000     mov     ebx, 10                          ; 常数10H(16)
0041B066    0FBE81 80604000 movsx   eax, byte ptr [ecx+406080]       ; 第一位
0041B06D    3C 00           cmp     al, 0
0041B06F    74 3C           je      short 0041B0AD
0041B071    3C 2D           cmp     al, 2D
0041B073    74 2A           je      short 0041B09F
0041B075    3C 40           cmp     al, 40                           ; 和“@”比较
0041B077    72 04           jb      short 0041B07D
0041B079    2C 37           sub     al, 37
0041B07B    EB 02           jmp     short 0041B07F
0041B07D    2C 30           sub     al, 30
0041B07F    F7E3            mul     ebx                              ; 乘以常数
0041B081    86E0            xchg    al, ah                           ; 掉换高低位
0041B083    8A81 81604000   mov     al, byte ptr [ecx+406081]        ; 第二位
0041B089    3C 40           cmp     al, 40
0041B08B    72 04           jb      short 0041B091
0041B08D    2C 37           sub     al, 37
0041B08F    EB 02           jmp     short 0041B093
0041B091    2C 30           sub     al, 30
0041B093    02C4            add     al, ah                           ; 高位低位相加
0041B095    8806            mov     byte ptr [esi], al               ; 存储加的结果
0041B097    83C6 01         add     esi, 1
0041B09A    83C1 02         add     ecx, 2
0041B09D  ^ EB C7           jmp     short 0041B066                   ; 循环回去。每次循环取两位
0041B09F    83C6 02         add     esi, 2
0041B0A2    83C1 01         add     ecx, 1                           ; 这里是跳过分隔符
0041B0A5  ^ EB BF           jmp     short 0041B066                   ; 循环回去。这上面的循环只是对输入注册码的检测
0041B0A7    33DB            xor     ebx, ebx
0041B0A9    33D2            xor     edx, edx
0041B0AB    33F6            xor     esi, esi
0041B0AD    33C0            xor     eax, eax
0041B0AF    33DB            xor     ebx, ebx
0041B0B1    A1 D7614000     mov     eax, dword ptr [4061D7]          ; 3412
0041B0B6    35 37130000     xor     eax, 1337                        ; 和1337异或
0041B0BB    83C0 77         add     eax, 77                          ; 再加上常数77。记为A
0041B0BE    8B1D DB614000   mov     ebx, dword ptr [4061DB]          ; 8967
0041B0C4    81F3 31730000   xor     ebx, 7331                        ; 异或
0041B0CA    83EB 44         sub     ebx, 44                          ; 减44。     记为B
0041B0CD    83E8 77         sub     eax, 77                          ; A-77
0041B0D0    83C3 44         add     ebx, 44                          ; B+44
0041B0D3    35 37130000     xor     eax, 1337                        ; 异或。又得回3412
0041B0D8    81F3 31730000   xor     ebx, 7331                        ; 异或。得回8967
0041B0DE    A3 29624000     mov     dword ptr [406229], eax
0041B0E3    891D 2B624000   mov     dword ptr [40622B], ebx          ; 存储
0041B0E9    33C0            xor     eax, eax                         ; 清空
0041B0EB    33DB            xor     ebx, ebx
0041B0ED    A1 DF614000     mov     eax, dword ptr [4061DF]          ; 3412
0041B0F2    35 FC000000     xor     eax, 0FC                         ; 异或
0041B0F7    2D 5EA10F00     sub     eax, 0FA15E                      ; 减常量
0041B0FC    8B1D E3614000   mov     ebx, dword ptr [4061E3]          ; 8967
0041B102    81F3 33030000   xor     ebx, 333                         ; 异或
0041B108    81C3 FC000000   add     ebx, 0FC
0041B10E    05 5EA10F00     add     eax, 0FA15E
0041B113    81EB FC000000   sub     ebx, 0FC
0041B119    35 FC000000     xor     eax, 0FC
0041B11E    81F3 33030000   xor     ebx, 333
0041B124    A3 2F624000     mov     dword ptr [40622F], eax
0041B129    891D 31624000   mov     dword ptr [406231], ebx
0041B12F    33C0            xor     eax, eax
0041B131    33DB            xor     ebx, ebx
0041B133    A1 E7614000     mov     eax, dword ptr [4061E7]
0041B138    83F0 64         xor     eax, 64
0041B13B    8B1D EB614000   mov     ebx, dword ptr [4061EB]          ; 上面那堆东西目的是为了:
0041B141    83F3 32         xor     ebx, 32                          ; 把“1234-6789”转化成“89673412”。以后的依此类推
0041B144    A3 35624000     mov     dword ptr [406235], eax
0041B149    891D 37624000   mov     dword ptr [406237], ebx          ; 我跟完算法后发现这里这堆代码
0041B14F    8335 35624000 6>xor     dword ptr [406235], 64           ; 用处不是很大,可能是我水平菜
0041B156    8335 37624000 3>xor     dword ptr [406237], 32
0041B15D    833D 29624000 0>cmp     dword ptr [406229], 0
0041B164  - 0F84 A35FFEFF   je      0040110D
0041B16A    833D 2F624000 0>cmp     dword ptr [40622F], 0
0041B171  - 0F84 965FFEFF   je      0040110D
0041B177    833D 35624000 0>cmp     dword ptr [406235], 0
0041B17E  - 0F84 895FFEFF   je      0040110D
0041B184    33C0            xor     eax, eax
0041B186    33D2            xor     edx, edx
0041B188    8D35 48624000   lea     esi, dword ptr [406248]          ; 用户名到esi
0041B18E    8A06            mov     al, byte ptr [esi]               ; 取第一位ascii
0041B190    3C 00           cmp     al, 0
0041B192    74 05           je      short 0041B199
0041B194    03D0            add     edx, eax                         ; 这个循环得到用户名ascii码累加值
0041B196    46              inc     esi
0041B197  ^ EB F5           jmp     short 0041B18E
0041B199    8915 AD614000   mov     dword ptr [4061AD], edx          ; 存储累加值
0041B19F    FF35 AD614000   push    dword ptr [4061AD]               ; 累加值入栈
0041B1A5    68 7A604000     push    0040607A                         ; ASCII "%d"
0041B1AA    68 80624000     push    00406280
0041B1AF    E8 B866FEFF     call    <jmp.&user32.wsprintfA>
0041B1B4    FF35 AD614000   push    dword ptr [4061AD]
0041B1BA    68 7D604000     push    0040607D                         ; ASCII "%x"
0041B1BF    68 85624000     push    00406285
0041B1C4    E8 A366FEFF     call    <jmp.&user32.wsprintfA>
0041B1C9    33C0            xor     eax, eax
0041B1CB    33C9            xor     ecx, ecx
0041B1CD    33D2            xor     edx, edx
0041B1CF    A1 A5A14100     mov     eax, dword ptr [41A1A5]          ; A8AFA785   这个是固定值
0041B1D4    8B0D 29624000   mov     ecx, dword ptr [406229]          ; 89673412   这里是前两段
0041B1DA    8B15 80624000   mov     edx, dword ptr [406280]          ; 00363236  这个是用户名Ascii码  十进制
0041B1E0    33C2            xor     eax, edx                         ; eax  异或  edx
0041B1E2    3BC1            cmp     eax, ecx                         ; 比较。
0041B1E4  - 0F85 235FFEFF   jnz     0040110D                         ; 前两段是=固定值 异或 用户名的Ascii码
0041B1EA    33C0            xor     eax, eax
0041B1EC    33C9            xor     ecx, ecx
0041B1EE    33D2            xor     edx, edx
0041B1F0    A1 ABA14100     mov     eax, dword ptr [41A1AB]          ; 63366437  固定值
0041B1F5    8B0D 2F624000   mov     ecx, dword ptr [40622F]          ; 第三、第四段
0041B1FB    8B15 85624000   mov     edx, dword ptr [406285]          ; 00323732   十六进制
0041B201    33C2            xor     eax, edx
0041B203    3BC1            cmp     eax, ecx                         ; 在这里看信息框,然后一一对应就可以得到真码。
0041B205  - 0F85 025FFEFF   jnz     0040110D                         ; 参考上面同理,第三、第四段也可以得出了,
0041B20B    33C0            xor     eax, eax
0041B20D    33C9            xor     ecx, ecx
0041B20F    33D2            xor     edx, edx
0041B211    A1 56A14100     mov     eax, dword ptr [41A156]          ; F5166011   这个值在你注册成功后会变的。
0041B216    8B0D 35624000   mov     ecx, dword ptr [406235]          ; 最后两段
0041B21C    8B15 48624000   mov     edx, dword ptr [406248]          ; 直接使用用户名的十六进制字符串
0041B222    33C2            xor     eax, edx
0041B224    3BC1            cmp     eax, ecx                         ; 同理,在这里看信息框一一对应就可以得到真码。
0041B226  - 0F85 E15EFEFF   jnz     0040110D
0041B22C  - E9 C35EFEFF     jmp     004010F4
0041B231    68 65604000     push    00406065                         ; ASCII "Registered !"
0041B236    68 95010000     push    195
0041B23B    FF75 08         push    dword ptr [ebp+8]
0041B23E    E8 BF66FEFF     call    <jmp.&user32.SetDlgItemTextA>
0041B243    68 9F144000     push    0040149F
0041B248    C3              retn

------------------------------------------------------------------------
【破解总结】

1、这个keygenme写的好啊,算法虽然简单,但它包含了一般注册所需要的方法。

2、首先它就规定了输入的注册码要1D,就是29位数的。不够29位数,它一点反映都没有。然后规定“第五位、第十位、第十五位、第二十位、

第二十五位一定要是分隔符”。所以我一开始输入的假码是:1234-6789-8888-9999-5555-6666。

3、它把我们输入的假码分三段,第一段“1234-6789”转化为“89673412”;第二段“8888-9999”转化为“99998888”;第三段“5555-6666

”转化为“66665555”。

4、得到用户名binbin的ascii码累加值。10进制(626)转成“00363236”;16进制(272)转成“00323732”;还有用户名本身前四位(binb

)转成“626E6962”

5、然后对应每段共有3个固定值“A8AFA785”“63366437”“F5166011”。这三个固定值分别异或上面用户名的三个值。就得到相应段的真注

册码了。

有个技巧就是在每次“cmp     eax, ecx”真假比较的时候推算出注册码。

这个注册机难写哦。我不会。那位大叔贴出来让我们见识下吧。

+++++++++++++++++++++++++++++++++++++++++++++++++++++

刚才想放出可以的注册信息的时候发现了这个keygenme是有记忆和自修改功能的,就是说但你注册成功一次后,它会改变注册信息,同样是binbin这个用户名,但是那三个固定值中的第三个是变动的。

所以,我暂时没有发现固定的能用的注册信息,大家试试也发表下看法啊。

我又跟了下,发现我还有很多东西没有发现的。这个keygenme真牛。

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++


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

上传的附件:
收藏
免费 7
支持
分享
最新回复 (6)
雪    币: 200
能力值: (RANK:10 )
在线值:
发帖
回帖
粉丝
zcg
2
感谢楼主的分享,我照做来作一作。
2006-12-14 16:57
0
雪    币: 721
活跃值: (350)
能力值: ( LV9,RANK:1250 )
在线值:
发帖
回帖
粉丝
3
分析得不错。
2006-12-15 11:58
0
雪    币: 115
活跃值: (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
4
#include<stdio.h>
#include<string.h>
#include<windows.h>

int convert(int num){
        if(num>=10)
                num+=55;
        else
                num+=48;

        return num;
}

int convert2(int num){
        if(num>=10)
                num+=87;
        else
                num+=48;

        return num;
}

int memoryRead(){
        HWND hWnd;
        HANDLE hProc;
        DWORD proID;
        DWORD ads_code=0x0041A156;
        char value_code[4];

        if((hWnd=FindWindow(NULL,"R - KeygenMe #2 by Guetta")) ==NULL){
                printf("请启动crackme程序!\n");
                return 0;
        }
       
        GetWindowThreadProcessId(hWnd,&proID);
        hProc=OpenProcess(PROCESS_ALL_ACCESS,FALSE,proID);
        if(hProc==NULL) {
                printf("请启动crackme程序!\n");
                return 0;
        }

        ReadProcessMemory(hProc,(void *)ads_code,value_code,4,NULL);

        CloseHandle(hProc);

        return (value_code[3]&0xff)*0x1000000+(value_code[2]&0xff)*0x10000+(value_code[1]&0xff)*0x100+(value_code[0]&0xff);
}

int main(){
        char name[32];
        char pwd[30];
        int i, m;
        long edx, eax, tmp, sum;

        memset(pwd, 0x00, sizeof(pwd));
        printf("输入用户名(长度为4-31位):");
        scanf("%s", name);
       
        for(i=0, sum=0; i<strlen(name); i++)
                sum+=name[i];
        if(sum/1000==0)
                edx=convert(sum/100)+convert(sum%100/10)*0x100+convert(sum%100%10)*0x10000;
        else
                edx=convert(sum/1000)+convert(sum%1000/100)*0x100+convert(sum%1000%100/10)*0x10000+convert(sum%1000%100%10)*0x1000000;

        eax=0xA9A1A6AC;
        tmp=edx^eax;

        pwd[7]=convert((tmp&0xffffffff)/0x10000000);
        pwd[8]=convert((tmp&0xfffffff)/0x1000000);
        pwd[5]=convert((tmp&0xffffff)/0x100000);
        pwd[6]=convert((tmp&0xfffff)/0x10000);
        pwd[2]=convert((tmp&0xffff)/0x1000);
        pwd[3]=convert((tmp&0xfff)/0x100);
        pwd[0]=convert((tmp&0xff)/0x10);
        pwd[1]=convert(tmp&0xf);
        pwd[4]='-';

        edx=convert2((sum&0xf00)/0x100)+convert2((sum&0xf0)/0x10)*0x100+convert2(sum&0xf)*0x10000;
        eax=0x35396437;
        tmp=edx^eax;

        pwd[17]=convert((tmp&0xffffffff)/0x10000000);
        pwd[18]=convert((tmp&0xfffffff)/0x1000000);
        pwd[15]=convert((tmp&0xffffff)/0x100000);
        pwd[16]=convert((tmp&0xfffff)/0x10000);
        pwd[12]=convert((tmp&0xffff)/0x1000);
        pwd[13]=convert((tmp&0xfff)/0x100);
        pwd[10]=convert((tmp&0xff)/0x10);
        pwd[11]=convert(tmp&0xf);
        pwd[14]='-';
        pwd[9]='-';

        edx=name[0]+name[1]*0x100+name[2]*0x10000+name[3]*0x1000000;
        eax=memoryRead();
        if(eax==0){
                getch();
                return 0;
        }
        tmp=edx^eax;
       
        pwd[27]=convert((tmp&0xffffffff)/0x10000000);
        pwd[28]=convert((tmp&0xfffffff)/0x1000000);
        pwd[25]=convert((tmp&0xffffff)/0x100000);
        pwd[26]=convert((tmp&0xfffff)/0x10000);
        pwd[22]=convert((tmp&0xffff)/0x1000);
        pwd[23]=convert((tmp&0xfff)/0x100);
        pwd[20]=convert((tmp&0xff)/0x10);
        pwd[21]=convert(tmp&0xf);
        pwd[24]='-';
        pwd[19]='-';
        pwd[29]='\0';

        printf("注册码:%s\n", pwd);
         
        getch();
        return 0;
}
2009-5-13 11:21
0
雪    币: 452
活跃值: (10)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
5
被楼上的这个注册机源代码震撼住了:

。。。
  GetWindowThreadProcessId(hWnd,&proID);
  hProc=OpenProcess(PROCESS_ALL_ACCESS,FALSE,proID);
  if(hProc==NULL) {
    printf("请启动crackme程序!\n");
    return 0;
。。。

一语点醒梦中人呀!!
2009-5-14 12:08
0
雪    币: 10
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
支持,正在努力学习中。
2009-5-21 18:59
0
雪    币: 1
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
0041A024    0F31            rdtsc
0041A026    33D2            xor     edx,edx
0041A028    8981 51A14100   mov     dword ptr ds:[ecx+0x41A151],eax

这个值老变,没法写注册机,   上面的注册机是用C写的,还是C++.看不懂
2014-7-31 15:44
0
游客
登录 | 注册 方可回帖
返回
//