首页
社区
课程
招聘
[原创]CycleCrack注册机
发表于: 2009-5-6 20:44 8414

[原创]CycleCrack注册机

2009-5-6 20:44
8414
CCDebug有一篇文章:OllyDBG 入门系列(五)-消息断点及 RUN 跟踪(http://bbs.pediy.com/showthread.php?t=21532),
讲解了怎么设置消息断点,研究了一下那个CycleCrack,写了一个注册机。虽然学习这么多年了,这还是我写的第一个注册机,非常惭愧。

先来看看序列号的主要的认证流程:如果输入的名字不足16字节,就扩展成16字节,序列号必须为16字节。
名字和序列号的字符的取值范围为[0x30, 0x7E]。
判断序列号的汇编代码如下:
00401105  |. |E8 E7000000        call    004011F1     ;比较序列号算法
0040110A  |. |B9 01FF0000        mov     ecx, 0FF01
0040110F  |. |51                 push    ecx
00401110  |.  E8 7B000000   call    00401190           ;比较序列号算法
00401115  |.  83F9 01       cmp     ecx, 1             ;ecx必须要等于1
00401118  |.  74 06         je      short 00401120
0040111A  |>  E8 47000000   call    00401166           ;register failed
0040111F  |>  C3            retn
00401120  |>  A1 68214000   mov     eax, dword ptr [402168] ;name的第8字节
00401125  |.  8B1D 6C214000 mov     ebx, dword ptr [40216C] ;name的第12字节
0040112B  |.  33C3          xor     eax, ebx
0040112D  |.  3305 82214000 xor     eax, dword ptr [402182] ;一个DWORD变量,由00401190生成
00401133  |.  0D 40404040   or      eax, 40404040
00401138  |.  25 77777777   and     eax, 77777777
0040113D  |.  3305 79214000 xor     eax, dword ptr [402179] ;code的第8字节
00401143  |.  3305 7D214000 xor     eax, dword ptr [40217D] ;code的第12字节
00401149  |.^ 75 CF         jnz     short 0040111A          ;如果eax为0,表示注册码正确        
0040114B  |.  E8 2B000000   call    0040117B           ;register ok
00401150  \.  C3            retn

以上汇编代码改成c语言代码为:

        typedef unsigned int DWORD;
        typedef unsigned short WORD;
        typedef unsigned char BYTE;
       
        DWORD dwName[4];
        DWORD dwCode[4];

    dwName[0] = *((DWORD *)name);
    dwName[1] = *((DWORD *)&name[4]);
    dwName[2] = *((DWORD *)&name[8]);
    dwName[3] = *((DWORD *)&name[12]);

    dwCode[0] = *((DWORD *)code);
    dwCode[1] = *((DWORD *)&code[4]);
    dwCode[2] = *((DWORD *)&code[8]);
    dwCode[3] = *((DWORD *)&code[12]);

    count_402182 = 0xFEDCBA98;

    function4011F1();

    unsigned int ecx = 0xff01;      
    ecx = function401190(ecx);   
    if (ecx == 1)
    {
        unsigned int eax = dwName[2] ^ dwName[3];
        eax ^= count_402182;
        eax |= 0x40404040;
        eax &= 0x77777777;
        eax ^= dwCode[2];  
        eax ^= dwCode[3];  
        if (eax == 0)
        {
            printf("register ok");
        }      
    }

序列号的算法主要在函数004011F1和函数00401190中。
004011F1  /$  A1 60214000        mov     eax, dword ptr [402160]
004011F6  |.  8B1D 64214000      mov     ebx, dword ptr [402164]
004011FC  |.  3305 71214000      xor     eax, dword ptr [402171]
00401202  |.  331D 75214000      xor     ebx, dword ptr [402175]
00401208  |.  25 0F1F3F7F        and     eax, 7F3F1F0F
0040120D  |.  81E3 00010307      and     ebx, 7030100
00401213  |.  33C9               xor     ecx, ecx
00401215  |>  8BF0               /mov     esi, eax
00401217  |.  8BFB               |mov     edi, ebx
00401219  |.  D3E6               |shl     esi, cl
0040121B  |.  D3E7               |shl     edi, cl
0040121D  |.  81E6 80808080      |and     esi, 80808080
00401223  |.  81E7 80808080      |and     edi, 80808080
00401229  |.  8BD6               |mov     edx, esi
0040122B  |.  C0EE 07            |shr     dh, 7
0040122E  |.  66:C1E2 07         |shl     dx, 7
00401232  |.  C1EA 08            |shr     edx, 8
00401235  |.  C0EE 07            |shr     dh, 7
00401238  |.  66:C1E2 07         |shl     dx, 7
0040123C  |.  C1EA 08            |shr     edx, 8
0040123F  |.  C0EE 07            |shr     dh, 7
00401242  |.  66:D1EA            |shr     dx, 1
00401245  |.  8BF2               |mov     esi, edx
00401247  |.  8BD7               |mov     edx, edi
00401249  |.  C0EE 07            |shr     dh, 7
0040124C  |.  66:C1E2 07         |shl     dx, 7
00401250  |.  C1EA 08            |shr     edx, 8
00401253  |.  C0EE 07            |shr     dh, 7
00401256  |.  66:C1E2 07         |shl     dx, 7
0040125A  |.  C1EA 08            |shr     edx, 8
0040125D  |.  C0EE 07            |shr     dh, 7
00401260  |.  66:C1EA 05         |shr     dx, 5
00401264  |.  8BFA               |mov     edi, edx
00401266  |.  33FE               |xor     edi, esi
00401268  |.  8BD7               |mov     edx, edi
0040126A  |.  81E2 FF000000      |and     edx, 0FF
00401270  |.  51                 |push    ecx
00401271  |.  52                 |push    edx
00401272  |.  BA 08000000        |mov     edx, 8
00401277  |.  91                 |xchg    eax, ecx
00401278  |.  83F8 03            |cmp     eax, 3
0040127B  |.  7F 0F              |jg      short 0040128C
0040127D  |.  F6E2               |mul     dl
0040127F  |.  5A                 |pop     edx
00401280  |.  83C0 08            |add     eax, 8
00401283  |.  91                 |xchg    eax, ecx
00401284  |.  D3C0               |rol     eax, cl
00401286  |.  33C2               |xor     eax, edx
00401288  |.  D3C8               |ror     eax, cl
0040128A  |.  EB 0D              |jmp     short 00401299
0040128C  |>  83E8 03            |sub     eax, 3
0040128F  |.  F6E2               |mul     dl
00401291  |.  5A                 |pop     edx
00401292  |.  91                 |xchg    eax, ecx
00401293  |.  D3C3               |rol     ebx, cl
00401295  |.  33DA               |xor     ebx, edx
00401297  |.  D3CB               |ror     ebx, cl
00401299  |>  59                 |pop     ecx
0040129A  |.  41                 |inc     ecx
0040129B  |.  83F9 08            |cmp     ecx, 8
0040129E  |.^ 0F85 71FFFFFF      \jnz     00401215
004012A4  \.  C3                 retn

这个函数主要是通过一系列算法,生成新的dwName[0]和dwName[1]。
以上汇编代码改成c语言代码为:
void function4011F1()
{      
    dwName[0] ^= dwCode[0];
    dwName[1] ^= dwCode[1];
   
    dwName[0] &= 0x7f3f1f0f;
    dwName[1] &= 0x07030100;
   
    for (int i=0; i<8; i++)
    {
            DWORD name0 = dwName[0];
            DWORD name1 = dwName[1];
            name0 <<= i;
            name1 <<= i;
            
            name0 &= 0x80808080;
            name1 &= 0x80808080;   
            DWORD temp1 = name0;
            
            BYTE dh;
            WORD dx;
            for (int j=0; j<2; j++)
            {
                dh =  (temp1 >> 8) & 0XFF;
                dh >>= 7;
                temp1 &= 0xffff00ff;
                temp1 |= (dh << 8);
               
                dx = temp1 & 0xffff;
                dx <<= 7;
                temp1 &= 0xffff0000;
                temp1 |= dx;
               
                temp1 >>= 8;
            }
            
            dh =  (temp1 >> 8) & 0XFF;
            dh >>= 7;
            temp1 &= 0xffff00ff;
            temp1 |= (dh << 8);
            
            dx = temp1 & 0xffff;
            dx >>= 1;
            temp1 &= 0xffff0000;
            temp1 |= dx;
            
            name0 = temp1;
            
            temp1 = name1;
            for (j=0; j<2; j++)
            {
                dh =  (temp1 >> 8) & 0XFF;
                dh >>= 7;
                temp1 &= 0xffff00ff;
                temp1 |= (dh << 8);
               
                dx = temp1 & 0xffff;
                dx <<= 7;
                temp1 &= 0xffff0000;
                temp1 |= dx;
               
                temp1 >>= 8;
            }
            
            dh =  (temp1 >> 8) & 0XFF;
            dh >>= 7;
            temp1 &= 0xffff00ff;
            temp1 |= (dh << 8);
            
            dx = temp1 & 0xffff;
            dx >>= 5;
            temp1 &= 0xffff0000;
            temp1 |= dx;
            
            name1 = temp1;   
            
            name1 ^= name0;
            
            DWORD edx = name1 & 0xff;
            int k = i;
            
            if (k <= 3)
            {
                k *= 8;
                k += 8;
               
                unsigned int hi = dwName[0]>>(32-k);
                dwName[0] <<= k;
                dwName[0] |= hi;
               
                dwName[0] ^= edx;

                hi = dwName[0]<<(32-k);
                dwName[0] >>= k;
                dwName[0] |= hi;
            }
            else
            {
                k -= 3;
                k *= 8;
               
                unsigned int hi = dwName[1]>>(32-k);
                dwName[1] <<= k;
                dwName[1] |= hi;
               
                dwName[1] ^= edx;
               
                hi = dwName[1]<<(32-k);
                dwName[1] >>= k;
                dwName[1] |= hi;
            }   
    }
}

00401190  /$  5F            pop     edi
00401191  |.  59            pop     ecx
00401192  |.  57            push    edi
00401193  |.  81F9 80000000 cmp     ecx, 80
00401199  |.  7E 55         jle     short 004011F0
0040119B  |.  51            push    ecx
0040119C  |.  8BF1          mov     esi, ecx
0040119E  |.  81E1 FF000000 and     ecx, 0FF
004011A4  |.  8BF8          mov     edi, eax
004011A6  |.  83F9 08       cmp     ecx, 8
004011A9  |.  7E 05         jle     short 004011B0
004011AB  |.  8BFB          mov     edi, ebx
004011AD  |.  C1E9 04       shr     ecx, 4
004011B0  |>  C1C7 08       /rol     edi, 8
004011B3  |.  D1E9          |shr     ecx, 1
004011B5  |.^ 75 F9         \jnz     short 004011B0
004011B7  |.  C1EE 08       shr     esi, 8
004011BA  |.  23FE          and     edi, esi
004011BC  |.  81E7 FF000000 and     edi, 0FF
004011C2  |.  59            pop     ecx
004011C3  |>  BE 80000000   mov     esi, 80
004011C8  |>  85FE          /test    esi, edi
004011CA  |.  74 20         |je      short 004011EC
004011CC  |.  33FE          |xor     edi, esi
004011CE  |.  57            |push    edi
004011CF  |.  81E1 00FF0000 |and     ecx, 0FF00
004011D5  |.  87CE          |xchg    esi, ecx
004011D7  |.  32E9          |xor     ch, cl
004011D9  |.  33F1          |xor     esi, ecx
004011DB  |.  87F1          |xchg    ecx, esi
004011DD  |.  51            |push    ecx
004011DE  |.  FF05 82214000 |inc     dword ptr [402182]
004011E4  |.  E8 A7FFFFFF   |call    00401190
004011E9  |.  5F            |pop     edi
004011EA  |.^ EB D7         |jmp     short 004011C3
004011EC  |>  D1EE          |shr     esi, 1
004011EE  |.^ 75 D8         \jnz     short 004011C8
004011F0  \>  C3            retn

这个函数主要是产生count_402182供后面运算,同时ecx必须为1。
以上汇编代码改成c语言代码为:
unsigned int count_402182 = 0xFEDCBA98;
unsigned int function401190(unsigned int ecx)
{
    if (ecx <= 0x80)
        return ecx;
   
    unsigned int saveecx = ecx;
    unsigned int esi = ecx;
    ecx &= 0xff;
    unsigned int edi = dwName[0];   
    if (ecx > 8)
    {
        edi = dwName[1];
        ecx >>= 4;
    }

    while (ecx != 0)
    {
        unsigned int hi = edi>>24;
        edi <<= 8;
        edi |= hi;
        ecx >>= 1;
    }

    esi >>= 8;
    edi &= esi;
    edi &= 0xff;
   
    ecx = saveecx;
    esi = 0x80;
   
    while(1)
    {
       int ret = esi & edi;
       if (ret == 0)
       {
        esi >>= 1;
        if (esi == 0)
            return ecx;
        else
            continue;
       }
      
       edi ^= esi;
       unsigned int saveedi = edi;
       ecx &= 0xff00;
      
       unsigned char esi_h = (esi >> 8) & 0xff;
       unsigned char esi_l = (esi ) & 0xff;
       esi_h ^= esi_l;
       esi = (esi & 0xffff00ff ) | (esi_h<<8);
       ecx ^= esi;
       count_402182++;
      
       ecx = function401190(ecx);
      
       edi = saveedi;
       esi = 0x80;
    }   
   
    return ecx;
}

从上面的代码可以看到,我们可以固定dwCode[0],找到一个使ecx=1的dwCode[1]。
同样也可以固定dwCode[2],找到满足条件的dwCode[3],从而得到16字节的序列号。

计算序列号代码为:
void PrintCode(unsigned int dwCode)
{
    int i;
    for(i=0; i<4; i++)
    {
        printf("%c", dwCode&0xff);
        dwCode >>= 8;
    }
}

void  GetCode(unsigned int nName2, unsigned int nName3)
{
    unsigned int dwCode2;
    char *pCode2 = "1234";
    dwCode2 = *((unsigned int *)pCode2);
   
    unsigned int eax = nName2 ^ nName3;
    eax ^= count_402182;
    eax |= 0x40404040;
    eax &= 0x77777777;
    eax ^= dwCode2;
   
    printf("%s", pCode2);  
    PrintCode(eax);
   
    printf("\n");
}

void GetSeiralNumber(char *pName)
{
        char name[32];
       
        memset(name, 0, sizeof(name));
    int nLen = strlen(pName);
        if (nLen > 16)
                nLen = 16;
   
        //填充为16 byte
        strcpy(name, pName);
        for (int i=0; i<16-nLen; i++)
        {
                name[nLen+i] = name[i];       
        }
       
       
        dwCode[0] = 0x30303030;
       
        int k1,k2,k3,k4;
        for(k1=0x30; k1<=0x7e; k1++)
        {
                unsigned int code1 = (k1<<24);
               
                for(k2=0x30; k2<=0x7e; k2++)
                {
                        unsigned int code2 = (k1<<16);
                       
                        for(k3=0x30; k3<=0x7e; k3++)
                        {
                                unsigned int code3 = (k1<<8);
                               
                                for(k4=0x30; k4<=0x7e; k4++)
                                {
                                        dwCode[1] = code1 | code2 | code3 | k4;;
                                        count_402182 = 0xFEDCBA98;
                                        dwName[0] = *((DWORD *)name);
                                        dwName[1] = *((DWORD *)&name[4]);
                                        dwName[2] = *((DWORD *)&name[8]);
                                        dwName[3] = *((DWORD *)&name[12]);
                                       
                                        function4011F1();
                                       
                                        unsigned int ecx = 0xff01;       
                                        ecx = function401190(ecx);   
                                        if (ecx == 1)
                                        {
                                                printf("serial num:");
                                                PrintCode(dwCode[0]);
                                                PrintCode(dwCode[1]);
                                               
                                                GetCode(dwName[2] , dwName[3]);
                                                return;
                                        }
                                }                               
                        }
                }
               
        }
}

int main(int argc, char* argv[])
{
        char name[128];
        printf("input name:\n");
        scanf("%s", name);
        GetSeiralNumber(name);
       
        getchar();       
        return 0;
}

给出一组序列号:
name = "afeiwangafeiwang";
code = "000000001234UGdD";

[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

收藏
免费 8
支持
分享
最新回复 (8)
雪    币: 252
活跃值: (27)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
2
谢谢加精!!!!!!自己顶一下。
2009-5-6 22:58
0
雪    币: 93954
活跃值: (200229)
能力值: (RANK:10 )
在线值:
发帖
回帖
粉丝
3
Support.
2009-5-6 23:31
0
雪    币: 211
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
楼主分析得仔细啊。
2009-5-8 08:28
0
雪    币: 252
活跃值: (27)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
5
唉,这么多年了第一次写破解程序,而且还是普通的给新手练习的程序!只是简单的把汇编翻译成了c而已,没什么技术含量。
2009-5-8 10:29
0
雪    币: 638
活跃值: (495)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
感觉已经很厉害啦~
我现在也正在初步研究汇编,以后也会破解了吧~
2009-5-8 14:42
0
雪    币: 216
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
厉害啊  写注册机  羡慕
2009-10-22 12:01
0
雪    币: 267
活跃值: (24)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
8
support!
2009-12-6 15:57
0
雪    币: 432
活跃值: (412)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
如果我没理解错的话,楼主应该是使用了爆破的方法来生成注册码的,但是这个crack的readme上面要求不能使用爆破,有兴趣的话可以参考一下这篇文章:https://bbs.pediy.com/thread-272767.htm
2022-5-13 13:07
0
游客
登录 | 注册 方可回帖
返回
//