首页
社区
课程
招聘
[原创]一个CrackMe的分析
发表于: 2016-6-5 15:11 18549

[原创]一个CrackMe的分析

2016-6-5 15:11
18549

最近学习了CCDebuger前辈的【OllyDBG 入门系列】文章(PS:虽然这系列文章已经发表十年了,但对我这个菜鸟依然很有帮助,谢谢作者)。

原文链接在这里: http://bbs.pediy.com/showthread.php?threadid=21532

在原文中,作者详细介绍了使用消息断点和RUN跟踪的方法找到这个CrackMe的关键部分,但是没有对关键部分进行分析,小菜我就斗胆分享一下我的分析结果,由于这个CrackMe的算法有点复杂,注册码无法通过简单的逆向计算得到,需要进行一定的爆破猜解,就没有写注册机代码了(其实是技术太菜人又太懒),但是找到了一个可用的注册码。

无论是使用作者介绍的消息断点还是函数参考,我们都可以定位到下面这个函数中。这个函数即为本CrackMe的主体函数,全部逻辑都在这个函数中实现,或者调用其他函数实现。

0040109C  /$  C705 82214000>MOV DWORD PTR DS:[402182],FEDCBA98
004010A6  |.  6A 11         PUSH 11                                  ; /Count = 11 (17.)
004010A8  |.  68 71214000   PUSH cycle.00402171                      ; |Buffer = cycle.00402171
004010AD  |.  68 E9030000   PUSH 3E9                                 ; |ControlID = 3E9 (1001.)
004010B2  |.  FF75 08       PUSH DWORD PTR SS:[EBP+8]                ; |hWnd
004010B5  |.  E8 0F020000   CALL <JMP.&USER32.GetDlgItemTextA>       ; \get serial number
004010BA  |.  0BC0          OR EAX,EAX                               ;  判断是否得到序列号的有效输入
004010BC  |.  74 61         JE SHORT cycle.0040111F
004010BE  |.  6A 11         PUSH 11                                  ; /Count = 11 (17.)
004010C0  |.  68 60214000   PUSH cycle.00402160                      ; |Buffer = cycle.00402160
004010C5  |.  68 E8030000   PUSH 3E8                                 ; |ControlID = 3E8 (1000.)
004010CA  |.  FF75 08       PUSH DWORD PTR SS:[EBP+8]                ; |hWnd
004010CD  |.  E8 F7010000   CALL <JMP.&USER32.GetDlgItemTextA>       ; \GetDlgItemTextA
004010D2  |.  0BC0          OR EAX,EAX                               ;  判断是否得到用户名有效输入
004010D4  |.  74 49         JE SHORT cycle.0040111F
004010D6  |.  B9 10000000   MOV ECX,10                               ;  如果用户输入的用户名短于16个字符
004010DB  |.  2BC8          SUB ECX,EAX                              ;  则将其复制扩展为16个字符长度
004010DD  |.  BE 60214000   MOV ESI,cycle.00402160
004010E2  |.  8BFE          MOV EDI,ESI
004010E4  |.  03F8          ADD EDI,EAX
004010E6  |.  FC            CLD
004010E7  |.  F3:A4         REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[>
004010E9  |.  33C9          XOR ECX,ECX
004010EB  |.  BE 71214000   MOV ESI,cycle.00402171
004010F0  |>  41            /INC ECX                                 ;  判断输入的序列号字符串每个字符是否有效
004010F1  |.  AC            |LODS BYTE PTR DS:[ESI]                  ;  有效字符的范围在ASCII码的 0x30 到 0x7E 之间
004010F2  |.  0AC0          |OR AL,AL
004010F4  |.  74 0A         |JE SHORT cycle.00401100
004010F6  |.  3C 7E         |CMP AL,7E
004010F8  |.  7F 06         |JG SHORT cycle.00401100
004010FA  |.  3C 30         |CMP AL,30
004010FC  |.  72 02         |JB SHORT cycle.00401100
004010FE  |.^ EB F0         \JMP SHORT cycle.004010F0
00401100  |>  83F9 11       CMP ECX,11                               ;  判断输入的序列号长度是否为17
00401103  |.  75 1A         JNZ SHORT cycle.0040111F           ;  这里包括16个合法字符和1个0x00 的字符串结束符
00401105  |.  E8 E7000000   CALL cycle.004011F1              ;  第一个转换函数,具体在下面进行分析,这里使用了全局的数据段进行传参,计算结果保存在EAX和EBX中
0040110A  |.  B9 01FF0000   MOV ECX,0FF01
0040110F  |.  51            PUSH ECX                                 ;  第二个转换函数,这里也到了一个全局变量var_402182和EAX EBX ECX 进行传参
00401110  |.  E8 7B000000   CALL cycle.00401190                      ;  ECX 在上面进行了初始化,EAX和EBX则由sub_4011f1 这个函数进行赋值
00401115  |.  83F9 01       CMP ECX,1                                ;  这里是第一次验证,如果ECX返回值不为1则验证失败,程序报错,否则进行第二次验证
00401118  |.  74 06         JE SHORT cycle.00401120
0040111A  |>  E8 47000000   CALL cycle.00401166                      ;  输出验证失败消息函数
0040111F  |>  C3            RETN
00401120  |>  A1 68214000   MOV EAX,DWORD PTR DS:[402168]            ;  这里进行了第二次验证,验证的参数分别是
00401125  |.  8B1D 6C214000 MOV EBX,DWORD PTR DS:[40216C]            ;  输入的用户名后8位字符,转换成两个DWORD进行异或操作
0040112B  |.  33C3          XOR EAX,EBX
0040112D  |.  3305 82214000 XOR EAX,DWORD PTR DS:[402182]            ;  将上面计算的结果与sub_401190 函数对全局变量var_402182的计算结果进行异或
00401133  |.  0D 40404040   OR EAX,40404040                          ;  置位和复位上面计算的结果的相应bit位
00401138  |.  25 77777777   AND EAX,77777777
0040113D  |.  3305 79214000 XOR EAX,DWORD PTR DS:[402179]            ;  继续将结果与输入的序列号的后8个字符进行异或操作
00401143  |.  3305 7D214000 XOR EAX,DWORD PTR DS:[40217D]
00401149  |.^ 75 CF         JNZ SHORT cycle.0040111A                 ;  第二次验证,如果上面得到的结果为0,则验证通过,否则验证失败
0040114B  |.  E8 2B000000   CALL cycle.0040117B                      ;  输出验证通过消息函数
00401150  \.  C3            RETN

上面这个函数主要做了四个工作:

1)得到用户输入的用户名和序列号字符串,判断用户名长度是否达到16字符长度,如果没有,则复制拷贝,下面的C代码实现了类似的功能。判断用户输入的序列号是否在合法字符范围内,
合法字符范围为ASCII码的0x30-0x7E之间,并且序列号长度也为16个有效字符。

static void fullfill_name(char *name, size_t size)
{
    int i;
    size_t len = strlen(name) - 1;         // 键盘输入,会多一个回车符,需要删除
    for(i = 0; i < size-len; ++i){
        name[i+len] = name[i];
    }
    name[size] = '\0';
}

2)调用第一个转换函数 cycle.004011F1,这个函数使用的参数为输入的用户名和输入的序列号,返回结果保存在 EAX 和 EBX 寄存器中,作为下一个转换函数的参数。
004011F1  /$  A1 60214000   MOV EAX,DWORD PTR DS:[402160]            ;  将输入的16字节长度的用户名和序列号分别转换为整型数组name, serial
004011F6  |.  8B1D 64214000 MOV EBX,DWORD PTR DS:[402164]            ;  一个整数长度为4字节,16字节可视作具有4个整数的整型数组
004011FC  |.  3305 71214000 XOR EAX,DWORD PTR DS:[402171]            ;  分别取整型数组的0号位和1号位进行异或处理,保存在EAX和EBX中
00401202  |.  331D 75214000 XOR EBX,DWORD PTR DS:[402175]            ;  EAX=name[0] ^ serial[0], EBX = name[1] ^ serial[1]
00401208  |.  25 0F1F3F7F   AND EAX,7F3F1F0F                         ;  取相应的有效位
0040120D  |.  81E3 00010307 AND EBX,7030100                          ;  下面是一个for循环,ECX作为循环变量,初始值为0,进行8次循环
00401213  |.  33C9          XOR ECX,ECX                              ;  循环先得到EAX和EBX的副本,保存在ESI和EDI寄存器中
00401215  |>  8BF0          /MOV ESI,EAX
00401217  |.  8BFB          |MOV EDI,EBX
00401219  |.  D3E6          |SHL ESI,CL                              ;  对副本先进行移位ECX位,ECX是循环控制变量
0040121B  |.  D3E7          |SHL EDI,CL
0040121D  |.  81E6 80808080 |AND ESI,80808080                        ;  取副本的每个字节的最高位(副本长度为4个字节长)
00401223  |.  81E7 80808080 |AND EDI,80808080
00401229  |.  8BD6          |MOV EDX,ESI                             ;  下面是将得到的副本的每个字节的最高位组合放在一个字节的4位中
0040122B  |.  C0EE 07       |SHR DH,7                                ;  这一块处理的是EAX的副本ESI
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                                ;  这里移位1位是为了将所有最高位保存在DX的最低字节的高4位
00401245  |.  8BF2          |MOV ESI,EDX
00401247  |.  8BD7          |MOV EDX,EDI                             ;  同样将EBX的副本EDI的每个字节的最高位组合成一个字节的4位
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                                ;  这里移位5位是为了将所有最高位保存在DX的最低字节的低4位
00401264  |.  8BFA          |MOV EDI,EDX
00401266  |.  33FE          |XOR EDI,ESI                             ;  上面处理之后的ESI、EDI分别保存了原副本每个字节的最高位,两个寄存器一共保存了8位
00401268  |.  8BD7          |MOV EDX,EDI                             ;  上面分别处理的副本又重新组合成一个8位的字节码,保存在EDX寄存器中
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                            ;  判断循环变量是否大于3,如果大于3,则将EBX进行循环移位,否则将EAX进行循环移位
00401278  |.  83F8 03       |CMP EAX,3
0040127B  |.  7F 0F         |JG SHORT cycle.0040128C
0040127D  |.  F6E2          |MUL DL                                  ;  如果ECX小于等于3,则循环移位EAX,移位次数为 ECX * 8 + 8
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                             ;  移位之后与上面得到的8位字节码做异或处理,结果写回原寄存器中
00401288  |.  D3C8          |ROR EAX,CL                              ;  再将EAX反向循环移位ECX * 8 + 8
0040128A  |.  EB 0D         |JMP SHORT cycle.00401299
0040128C  |>  83E8 03       |SUB EAX,3
0040128F  |.  F6E2          |MUL DL                                  ;  如果ECX大于3,则循环移位EBX,移位次数为 (ECX-4) * 8 + 8
00401291  |.  5A            |POP EDX
00401292  |.  91            |XCHG EAX,ECX
00401293  |.  D3C3          |ROL EBX,CL                              ;  这里的处理步骤与上面类似,只是操作数为EBX
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 cycle.00401215
004012A4  \.  C3            RETN

第一个转换函数使用了输入的用户名和序列号的字符串的前8位,先得到每个字节的最高位,组合成一个掩码,将EAX或者EBX的某一字节与掩码进行异或处理,然后重新计算新的掩码,再进
行下一个字节的异或处理。循环八次,将EAX和EBX的每一个字节都与相应的最高有效位进行异或保存。

// 这个函数将参数的最高有效位保存在一个整数中返回。
static int gather_byte_msb(unsigned int value)
{
        int ret = 0;
        int i;
        for(i = 0; i < sizeof(value); ++i){
            ret |= ((value >> (i * 8)) & 0x80) >> (7-i);
        }
        return ret;
}

// 实现了上面的基本逻辑的C代码
static void sub_4011f1(const char *name, const char *serial, unsigned int *eax, unsigned int *ebx)
{
        int i;
        *eax = ((int *)name)[0];
        *ebx = ((int *)name)[1];

        *eax ^= ((int *)serial)[0];
        *ebx ^= ((int *)serial)[1];

        *eax &= 0x7f3f1f0f;
        *ebx &= 0x7030100;

        for(i = 0; i < 8; ++i){
                int esi = *eax;
                int edi = *ebx;
                int edx, tmp;

                esi <<= i;
                edi <<= i;

                esi = gather_byte_msb(esi);
                edi = gather_byte_msb(edi);

        // 将上面得到的两个半字节数组合成一个字节数
                edi = (esi << 4) ^ edi;

                // edx 最为掩码对相应字节进行异或处理
        edx = edi & 0xff;

        tmp = 8;
        if(i <= 3){
            tmp = 8 * i + 8;
            *eax = rol(*eax, tmp);
            *eax ^= edx;
            *eax = ror(*eax, tmp);
        }else{
            tmp = 8 * (i-3);
            *ebx = rol(*ebx, tmp);
            *ebx ^= edx;
            *ebx = ror(*ebx, tmp);
        }
        }
}

3)调用 cycle.00401190函数,这个函数是一个递归函数,递归的参数保存在ECX中,初始值为0xFF01,这两个字节,高字节0xFF作为掩码,进行与运算;低字节0x01,作为移位次数的控制
变量,这里的0x01,又被分为两个半字节,高半字节控制EBX,低半字节控制EAX,但是不会同时有效,所以一次调用中,这个字节只会有某1个bit位被置1,即如果该值为0x01,则将EAX循环
移动1个8位,如果该值为0x08,则将EAX循环移位4个8位。如果该值为0x40,则将EBX循环移位3个8位。移位之后,再将移位的副本与ECX中的掩码参数进行与,得到一个字节,如果该字节不
为0,则找到该字节的最高有效位,比如该字节为0xA8,则最高有效位为0x80,将该有效位清除,即该字节变为0x28,同时ECX的掩码中的相应有效位清除,移位中的相应位置位,作为下一
次递归调用的参数,如前所述,如果最高有效位为0x80,则ECX进行计算(0xFF01 & 0xFF00 ) ^ 0x8080==0x7F80,作为下一次递归调用的ECX参数,同时将全局变量dword_402182自增一次,
作为统计。

004011F1  /$  A1 60214000   MOV EAX,DWORD PTR DS:[402160]            ;  将输入的16字节长度的用户名和序列号分别转换为整型数组name, serial
004011F6  |.  8B1D 64214000 MOV EBX,DWORD PTR DS:[402164]            ;  一个整数长度为4字节,16字节可视作具有4个整数的整型数组
004011FC  |.  3305 71214000 XOR EAX,DWORD PTR DS:[402171]            ;  分别取整型数组的0号位和1号位进行异或处理,保存在EAX和EBX中
00401202  |.  331D 75214000 XOR EBX,DWORD PTR DS:[402175]            ;  EAX=name[0] ^ serial[0], EBX = name[1] ^ serial[1]
00401208  |.  25 0F1F3F7F   AND EAX,7F3F1F0F                         ;  取相应的有效位
0040120D  |.  81E3 00010307 AND EBX,7030100                          ;  下面是一个for循环,ECX作为循环变量,初始值为0,进行8次循环
00401213  |.  33C9          XOR ECX,ECX                              ;  循环先得到EAX和EBX的副本,保存在ESI和EDI寄存器中
00401215  |>  8BF0          /MOV ESI,EAX
00401217  |.  8BFB          |MOV EDI,EBX
00401219  |.  D3E6          |SHL ESI,CL                              ;  对副本先进行移位ECX位,ECX是循环控制变量
0040121B  |.  D3E7          |SHL EDI,CL
0040121D  |.  81E6 80808080 |AND ESI,80808080                        ;  取副本的每个字节的最高位(副本长度为4个字节长)
00401223  |.  81E7 80808080 |AND EDI,80808080
00401229  |.  8BD6          |MOV EDX,ESI                             ;  下面是将得到的副本的每个字节的最高位组合放在一个字节的4位中
0040122B  |.  C0EE 07       |SHR DH,7                                ;  这一块处理的是EAX的副本ESI
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                                ;  这里移位1位是为了将所有最高位保存在DX的最低字节的高4位
00401245  |.  8BF2          |MOV ESI,EDX
00401247  |.  8BD7          |MOV EDX,EDI                             ;  同样将EBX的副本EDI的每个字节的最高位组合成一个字节的4位
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                                ;  这里移位5位是为了将所有最高位保存在DX的最低字节的低4位
00401264  |.  8BFA          |MOV EDI,EDX
00401266  |.  33FE          |XOR EDI,ESI                             ;  上面处理之后的ESI、EDI分别保存了原副本每个字节的最高位,两个寄存器一共保存了8位
00401268  |.  8BD7          |MOV EDX,EDI                             ;  上面分别处理的副本又重新组合成一个8位的字节码,保存在EDX寄存器中
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                            ;  判断循环变量是否大于3,如果大于3,则将EBX进行循环移位,否则将EAX进行循环移位
00401278  |.  83F8 03       |CMP EAX,3
0040127B  |.  7F 0F         |JG SHORT cycle.0040128C
0040127D  |.  F6E2          |MUL DL                                  ;  如果ECX小于等于3,则循环移位EAX,移位次数为 ECX * 8 + 8
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                             ;  移位之后与上面得到的8位字节码做异或处理,结果写回原寄存器中
00401288  |.  D3C8          |ROR EAX,CL                              ;  再将EAX反向循环移位ECX * 8 + 8
0040128A  |.  EB 0D         |JMP SHORT cycle.00401299
0040128C  |>  83E8 03       |SUB EAX,3
0040128F  |.  F6E2          |MUL DL                                  ;  如果ECX大于3,则循环移位EBX,移位次数为 (ECX-4) * 8 + 8
00401291  |.  5A            |POP EDX
00401292  |.  91            |XCHG EAX,ECX
00401293  |.  D3C3          |ROL EBX,CL                              ;  这里的处理步骤与上面类似,只是操作数为EBX
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 cycle.00401215
004012A4  \.  C3            RETN

4)做了两次验证,第一次验证cycle.00401190函数结束后,ECX是否为0x01,如果 ECX != 1,则输出验证失败消息,本次验证结束。如果ECX为1,则进行第二部分的验证,本部分的验证
使用了输入的用户名和序列号的后八个字符,利用其进行异或运算,最终判断输入的用户名和序列号是否匹配。

00401110  |.  E8 7B000000   CALL cycle.00401190                      ;  ECX 在上面进行了初始化,EAX和EBX则由sub_4011f1 这个函数进行赋值
00401115  |.  83F9 01       CMP ECX,1                                ;  这里是第一次验证,如果ECX返回值不为1则验证失败,程序报错,否则进行第二次验证
00401118  |.  74 06         JE SHORT cycle.00401120
0040111A  |>  E8 47000000   CALL cycle.00401166                      ;  输出验证失败消息函数
0040111F  |>  C3            RETN
00401120  |>  A1 68214000   MOV EAX,DWORD PTR DS:[402168]            ;  这里进行了第二次验证,验证的参数分别是
00401125  |.  8B1D 6C214000 MOV EBX,DWORD PTR DS:[40216C]            ;  输入的用户名后8位字符,转换成两个DWORD进行异或操作
0040112B  |.  33C3          XOR EAX,EBX
0040112D  |.  3305 82214000 XOR EAX,DWORD PTR DS:[402182]            ;  将上面计算的结果与sub_401190 函数对全局变量var_402182的计算结果进行异或
00401133  |.  0D 40404040   OR EAX,40404040                          ;  置位和复位上面计算的结果的相应bit位
00401138  |.  25 77777777   AND EAX,77777777
0040113D  |.  3305 79214000 XOR EAX,DWORD PTR DS:[402179]            ;  继续将结果与输入的序列号的后8个字符进行异或操作
00401143  |.  3305 7D214000 XOR EAX,DWORD PTR DS:[40217D]
00401149  |.^ 75 CF         JNZ SHORT cycle.0040111A                 ;  第二次验证,如果上面得到的结果为0,则验证通过,否则验证失败
0040114B  |.  E8 2B000000   CALL cycle.0040117B                      ;  输出验证通过消息函数
00401150  \.  C3            RETN

算法总结:
1)使用输入的用户名和序列号,分别转换为2个整型数组name[0..3], serial[0..3]
2)进行第一次转换,使用了name[0], name[1], serial[0], serial[1],转换结果保存在EAX和EBX寄存器中
3)进行第二次转换,使用上面转换得到的EAX、EBX寄存器,ECX==0xFF01, 全局变量dword_402182进行统计结果初始值为 0xfedcba98,转换过程中使用dword_402182进行统计结果
4)验证上述转换后ECX 是否等于1,如果否则验证失败,结束,否则进行再次验证
5)第二次验证,使用了 name[2], name[3], serial[2], serial[3], dword_402182,依次进行相应的运算
6)如果第5步结果为0,则验证成功,输出成功消息,否则验证失败

得到一组注册信息:
用户名:litao3rd
序列号:123456782332ASaA

附件是使用C语言实现类似的验证,基本就是汇编翻译到C代码。CrackMe源程序请到原文链接下载。


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 3
支持
分享
最新回复 (4)
雪    币: 115
活跃值: (23)
能力值: (RANK:20 )
在线值:
发帖
回帖
粉丝
2
厉害。。。。
2016-6-11 19:34
0
雪    币: 60
活跃值: (50)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
学习。。。。。
2016-6-11 21:01
0
雪    币: 4
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
好久没玩cm了
2016-6-12 11:15
0
雪    币: 448
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
我好久没玩过cm了 学习下~~~
2016-6-26 15:01
0
游客
登录 | 注册 方可回帖
返回
//