吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 5987|回复: 6
收起左侧

[CrackMe] 【吾爱2013CM大赛解答】--LoveKido Update-- JoyChou追码分析

  [复制链接]
封心锁爱 发表于 2013-12-14 17:33
CM是什么?Crackme是什么?这是什么东西?楼主发的什么?
他们都是一些公开给别人尝试破解的小程序,制作 Crackme 的人可能是程序员,想测试一下自己的软件保护技术,也可能是一位 Cracker,想挑战一下其它 Cracker 的破解实力,也可能是一些正在学习破解的人,自己编一些小程序给自己破解,KeyGenMe是要求别人做出它的 keygen (序号产生器), ReverseMe 要求别人把它的算法做出逆向分析, UnpackMe 是要求别人把它成功脱壳,本版块禁止回复非技术无关水贴。

本帖最后由 Chief 于 2013-12-14 17:47 编辑

[文章标题]: [吾爱2013CM大赛解答]--LoveKido Update-- JoyChou追码分析
[作者信息]: 封心锁爱

[操作平台]: Win7 Sp1
[使用工具]: OD
[软件名称]: LoveKido Update-- JoyChou
[下载地址]: http://www.52pojie.cn/thread-228422-1-1.html



第一关:
1> 激活按钮,下断点 bp EnableWindow, f9运行,Alt+F9返回,会返回到mfc90u模块中,继续单步几下走到程序模块,网上翻一点, 找到push 0, 改为push 1
01241A3F      6A 00         push    0x0                              ;  改为TRUE启用按钮
01241A41   .  68 EB030000   push    0x3EB
01241A46   .  8BCE          mov     ecx, esi
01241A48   .  E8 310B0000   call    <jmp.&mfc90u.#2904>
01241A4D   .  8BC8          mov     ecx, eax
01241A4F   .  E8 240B0000   call    <jmp.&mfc90u.#2360> ; 禁用按钮
01241A54   .  E8 37FAFFFF   call    01241490                         ;  从mfc90u返回到这里

2> 反调试,从
01241A9E - 01241ADA中的JNZ全部不能调,NOP掉
01241A54   .  E8 37FAFFFF   call    01241490                         ;  ┓
01241A59   .  85C0          test    eax, eax                               ;  ┃
01241A5B   .  0F85 AF000000 jnz     01241B10                     ;  ┃
01241A61   .  E8 CAFAFFFF   call    01241530                         ;  ┃
01241A66   .  85C0          test    eax, eax                               ;  ┃
01241A68   .  0F85 A2000000 jnz     01241B10                     ;  ┣ 这几个call为检测虚拟机的几个方法
01241A6E   .  E8 FDFBFFFF   call    01241670                         ;  ┃
01241A73   .  85C0          test    eax, eax                                ;  ┃
01241A75   .  0F85 95000000 jnz     01241B10                      ;  ┃
01241A7B   .  E8 50FCFFFF   call    012416D0                         ;  ┃
01241A80   .  85C0          test    eax, eax                                ;  ┃
01241A82   .  0F85 88000000 jnz     01241B10                      ;  ┛
01241A88   .  E8 83F9FFFF   call    01241410                         ;  清除硬件断点
01241A8D   .  E8 2EF9FFFF   call    012413C0                         ;  获取MessageBoxA函数,并将MessageBoxA保护属性改为PAGE_EXECUTE_READWRITE
01241A92   .  E8 A9F8FFFF   call    01241340                         ;  查找MessageBoxA中是否存在内存断点
01241A97   .  E8 64F5FFFF   call    01241000                         ;  查找是否存在调试器进程 "OllyDbg.EXE" "吾爱破解.EXE" "ICEYOD.EXE" "OLLYICE.EXE" "WINGUARD.EXE"
01241A9C   .  85C0          test    eax, eax
01241A9E      75 54         jnz     short 01241AF4
01241AA0   .  E8 9BF7FFFF   call    01241240                         ;  查找窗口类"OLLYXE"
01241AA5   .  85C0          test    eax, eax
01241AA7      75 4B         jnz     short 01241AF4
01241AA9   .  E8 F2F7FFFF   call    012412A0                         ;  判断父进程是不是explorer来反调试
01241AAE   .  85C0          test    eax, eax
01241AB0      75 42         jnz     short 01241AF4
01241AB2   .  FF15 6C402401 call    dword ptr [<&KERNEL32.GetCurrent>; [GetCurrentProcess
01241AB8   .  8D4C24 10     lea     ecx, dword ptr [esp+0x10]
01241ABC   .  51            push    ecx
01241ABD   .  50            push    eax
01241ABE   .  C74424 18 000>mov     dword ptr [esp+0x18], 0x0
01241AC6   .  FF15 68402401 call    dword ptr [<&KERNEL32.CheckRemot>;  kernel32.CheckRemoteDebuggerPresent
01241ACC   .  837C24 10 01  cmp     dword ptr [esp+0x10], 0x1        ;  调用CheckRemoteDebuggerPresent检查是否存在调试器
01241AD1      74 21         je      short 01241AF4
01241AD3   .  E8 B8F8FFFF   call    01241390                         ;  根据执行时间反调试
01241AD8   .  85C0          test    eax, eax
01241ADA      75 18         jnz     short 01241AF4

3> 按钮激活后,开始找Key,要比较Key是否正确,当然需要获取Key的内容,这里F9运行,随便输入Key,然后下断点
bp GetWindowTextW, 返回到程序模块

00091D18   .  8D4424 0C     lea     eax, dword ptr [esp+0xC]
00091D1C   .  50            push    eax
00091D1D   .  68 E9030000   push    0x3E9
00091D22   .  8BCE          mov     ecx, esi
00091D24   .  C68424 B00000>mov     byte ptr [esp+0xB0], 0x1
00091D2C   .  E8 6B080000   call    <jmp.&mfc90u.#2909>              ;  获取Key
00091D31   .  8B4C24 0C     mov     ecx, dword ptr [esp+0xC]         ;  ecx = Key -->到了程序模块后在这里
00091D35   .  8B41 F4       mov     eax, dword ptr [ecx-0xC]         ;  eax = StrLen
下面单步继续往下走,寻找比较Key的地方, 下面是一些除法运算(还原除数原理参见C++反汇编与逆向分析技术揭秘),还原后可知下面几个条件, 下面的Key(10)代表Key的10进制值:
    Key(10) - ((Key(10) / 3) * 3) == 1 &&
    Key(10) - ((Key(10) / 5) * 5) == 2 &&
    Key(10) - ((Key(10) / 7) * 7) == 4 &&
    Key(10) - ((Key(10) / 13) * 13) == 6 &&
    Key(10) - ((Key(10) / 17) * 17) == 8
这5个条件必须全部为TRUE,这里用了枚举方法算出Key,为18232,C代码见Code<1>

00091DA1   .  FFD6          call    esi                              ;  将Key转换为10进制
00091DA3   .  8BC8          mov     ecx, eax                         ;  除法运算 Key(10进制) / 3 除数的计算方法: 2^32 / 0x55555556四舍五入
00091DA5   .  B8 56555555   mov     eax, 0x55555556
00091DAA   .  F7E9          imul    ecx
00091DAC   .  8BC2          mov     eax, edx
00091DAE   .  C1E8 1F       shr     eax, 0x1F
00091DB1   .  03C2          add     eax, edx                         ;  eax = 商
00091DB3   .  8D1440        lea     edx, dword ptr [eax+eax*2]       ;  商 * 3
00091DB6   .  8BC1          mov     eax, ecx                         ;  eax = Key10进制
00091DB8   .  2BC2          sub     eax, edx
00091DBA   .  83C4 08       add     esp, 0x8
00091DBD   .  83F8 01       cmp     eax, 0x1                         ;  Key(10进制) - (商 * 3) == 1
00091DC0   .  0F85 FD000000 jnz     00091EC3
00091DC6   .  B8 67666666   mov     eax, 0x66666667                  ;  除法运算 Key(10) / 5 除数=2^33 / 0x66666667四舍五入
00091DCB   .  F7E9          imul    ecx                              ;  ecx = Key(10)
00091DCD   .  D1FA          sar     edx, 1                           ;  edx为乘法的高32位,相当于已经右移的32位,再右移1位为33位
00091DCF   .  8BC2          mov     eax, edx
00091DD1   .  C1E8 1F       shr     eax, 0x1F
00091DD4   .  03C2          add     eax, edx                         ;  eax = 商
00091DD6   .  8D1480        lea     edx, dword ptr [eax+eax*4]       ;  商 * 5
00091DD9   .  8BC1          mov     eax, ecx
00091DDB   .  2BC2          sub     eax, edx                         ;  Key(10) - (商 * 5) == 2
00091DDD   .  83F8 02       cmp     eax, 0x2
00091DE0   .  0F85 DD000000 jnz     00091EC3
00091DE6   .  B8 93244992   mov     eax, 0x92492493                  ;  除法运算 Key(10) / 7 除数=2^34 / 0x92492493四舍五入
00091DEB   .  F7E9          imul    ecx
00091DED   .  03D1          add     edx, ecx
00091DEF   .  C1FA 02       sar     edx, 0x2
00091DF2   .  8BC2          mov     eax, edx
00091DF4   .  C1E8 1F       shr     eax, 0x1F
00091DF7   .  03C2          add     eax, edx                         ;  eax = 商
00091DF9   .  8D14C5 000000>lea     edx, dword ptr [eax*8]           ;  商 * 8
00091E00   .  2BD0          sub     edx, eax                         ;  edx = 商 * 7
00091E02   .  8BC1          mov     eax, ecx                         ;  eax = Key(10)
00091E04   .  2BC2          sub     eax, edx
00091E06   .  83F8 04       cmp     eax, 0x4                         ;  Key(10) - (商 * 7) == 4
00091E09   .  0F85 B4000000 jnz     00091EC3
00091E0F   .  B8 4FECC44E   mov     eax, 0x4EC4EC4F                  ;  除法运算 Key(10) / 13 除数:2^34 / 0x4ec4ec4f四舍五入
00091E14   .  F7E9          imul    ecx
00091E16   .  C1FA 02       sar     edx, 0x2
00091E19   .  8BC2          mov     eax, edx
00091E1B   .  C1E8 1F       shr     eax, 0x1F
00091E1E   .  03C2          add     eax, edx                         ;  eax = 商
00091E20   .  6BC0 0D       imul    eax, eax, 0xD                    ;  商 * 13
00091E23   .  8BD1          mov     edx, ecx
00091E25   .  2BD0          sub     edx, eax                         ;  Key(10) - (商 * 13) == 6
00091E27   .  83FA 06       cmp     edx, 0x6
00091E2A   .  0F85 93000000 jnz     00091EC3
00091E30   .  B8 79787878   mov     eax, 0x78787879                  ;  除法运算 Key(10) / 17 除数:2^35 / 0x78787879四舍五入
00091E35   .  F7E9          imul    ecx
00091E37   .  C1FA 03       sar     edx, 0x3
00091E3A   .  8BC2          mov     eax, edx
00091E3C   .  C1E8 1F       shr     eax, 0x1F
00091E3F   .  03C2          add     eax, edx                         ;  eax = 商
00091E41   .  8BD0          mov     edx, eax
00091E43   .  C1E2 04       shl     edx, 0x4
00091E46   .  03D0          add     edx, eax                         ;  商 * 17
00091E48   .  2BCA          sub     ecx, edx                         ;  Key(10) - (商 * 17) == 8
00091E4A   .  83F9 08       cmp     ecx, 0x8
00091E4D   .  75 74         jnz     short 00091EC3



第二关:
和上面同理,要判断Key,就必须获取Key,同样下断点bp GetWindowTextW,输入Key点按钮断下,返回到程序模块

0009207D   .  8D4424 18     lea     eax, dword ptr [esp+0x18]
00092081   .  50            push    eax
00092082   .  68 EE030000   push    0x3EE
00092087   .  8BCE          mov     ecx, esi
00092089   .  C74424 6C 000>mov     dword ptr [esp+0x6C], 0x0
00092091   .  E8 06050000   call    <jmp.&mfc90u.#2909>              ;  获取Key
00092096   .  8B3D 40650900 mov     edi, dword ptr [0x96540]         ;  edi = 机器码 ->> 返回到程序模块后在这里

下面根据机器码计算Key, 下面说的字符长度和字节长度在Unicode环境下才有区别,便于理解,这里举个例子:
String: "Hello"
上面这个字符串的字符长度不管是Unicode还是非Unicode都是5,而字节长度在Ansi下是5,在Unicode就是10,因为一个Unicode字符2字节

000920C0   > /8D444D 00     lea     eax, dword ptr [ebp+ecx*2]
000920C4   . |66:8B5404 30  mov     dx, word ptr [esp+eax+0x30]      ;  取机器码一个字符
000920C9   . |66:42         inc     dx                               ;  加1
000920CB   . |66:83F2 1F    xor     dx, 0x1F                         ;  和0x1f异或
000920CF   . |8BC7          mov     eax, edi
000920D1   . |66:89544C 30  mov     word ptr [esp+ecx*2+0x30], dx    ;  保存算出的Key
000920D6   . |41            inc     ecx
000920D7   . |8D70 02       lea     esi, dword ptr [eax+0x2]
000920DA   . |8D9B 00000000 lea     ebx, dword ptr [ebx]
000920E0   > |66:8B10       mov     dx, word ptr [eax]
000920E3   . |83C0 02       add     eax, 0x2
000920E6   . |66:85D2       test    dx, dx
000920E9   .^|75 F5         jnz     short 000920E0
000920EB   . |2BC6          sub     eax, esi                        ; 机器码字节长度
000920ED   . |D1F8          sar     eax, 1                           ;  机器码字符长度
000920EF   . |3BC8          cmp     ecx, eax
000920F1   .^\72 CD         jb      short 000920C0

继续, 下面这段将机器码字节长度与0x11异或然后输出成为一个字符串
00092109   .  8B0D 40650900 mov     ecx, dword ptr [0x96540]         ;  机器码
0009210F   .  8B41 F4       mov     eax, dword ptr [ecx-0xC]         ;  机器码字符长度
00092112   .  8B35 30420900 mov     esi, dword ptr [<&mfc90u.#2537>] ;  mfc90u.#2537
00092118   .  8D1400        lea     edx, dword ptr [eax+eax]         ;  edx = 机器码字节长度
0009211B   .  83F2 11       xor     edx, 0x11                        ;  机器码字节长度与0x11异或
0009211E   .  52            push    edx
0009211F   .  8D4424 18     lea     eax, dword ptr [esp+0x18]
00092123   .  68 B04C0900   push    00094CB0                         ;  UNICODE "%d"
00092128   .  50            push    eax
00092129   .  FFD6          call    esi                              ;  mfc90u.#2537; <&mfc90u.#2537>

下面将上面根据机器码计算出的Key与刚才输出的字符串连接
0009214E   .  8D4424 20     lea     eax, dword ptr [esp+0x20]
00092152   .  50            push    eax
00092153   .  8D4C24 2C     lea     ecx, dword ptr [esp+0x2C]
00092157   .  51            push    ecx
00092158   .  8D4C24 24     lea     ecx, dword ptr [esp+0x24]
0009215C   .  E8 2F020000   call    00092390                         ;  将Key字节长度异或0x11后的值接入串后面
此时eax指向的内存保存着Key的地址

下面就是比较Key和我们的输入的Key了

00092189   .  52            push    edx                              ;  我们输入的Key
0009218A   .  8D4C24 14     lea     ecx, dword ptr [esp+0x14]
0009218E   .  884424 24     mov     byte ptr [esp+0x24], al          ;  这些mov是成功提示字符串
00092192   .  C64424 25 A7  mov     byte ptr [esp+0x25], 0xA7
00092197   .  C64424 26 CF  mov     byte ptr [esp+0x26], 0xCF
0009219C   .  C64424 27 B2  mov     byte ptr [esp+0x27], 0xB2
000921A1   .  C64424 28 00  mov     byte ptr [esp+0x28], 0x0
000921A6   .  C64424 2C B3  mov     byte ptr [esp+0x2C], 0xB3
000921AB   .  C64424 2D C9  mov     byte ptr [esp+0x2D], 0xC9
000921B0   .  884424 2E     mov     byte ptr [esp+0x2E], al
000921B4   .  C64424 2F A6  mov     byte ptr [esp+0x2F], 0xA6
000921B9   .  C64424 30 00  mov     byte ptr [esp+0x30], 0x0
000921BE   .  FF15 3C420900 call    dword ptr [<&mfc90u.#1599>]      ;  比较Key
000921C4   .  85C0          test    eax, eax
000921C6   .  75 13         jnz     short 000921DB


好了,计算Key已经看完了,现在来整理下:   
机器码的每个字符 + 1 ^ 0x1f组成字符串和机器码的字节长度 ^ 0x11后的字符串连接
根据上面这个我们来写KeyGen,见Code<2>




Code<1>
[C++] 纯文本查看 复制代码
#include "stdafx.h"
#include <windows.h>

int _tmain(int argc, _TCHAR* argv[])
{
        BOOL bFound = FALSE;
        unsigned int nValue = 0;

        do 
        {
                if (nValue - ((nValue / 3) * 3) == 1 &&
                        nValue - ((nValue / 5) * 5) == 2 &&
                        nValue - ((nValue / 7) * 7) == 4 &&
                        nValue - ((nValue / 13) * 13) == 6 &&
                        nValue - ((nValue / 17) * 17) == 8)
                {
                        bFound = TRUE;
                        break;
                }
        } while (++nValue <= 100000);

        if (bFound)
                _tprintf(TEXT("%d\r\n"), nValue);
        else
                _tprintf(TEXT("Not Found!\r\n"));

        return 0;
}


Code<2>
C代码:
[C++] 纯文本查看 复制代码
#include "stdafx.h"
#include <windows.h>

int _tmain(int argc, _TCHAR* argv[])
{
        TCHAR szMac[64];
        _tscanf_s(TEXT("%s"), szMac, _countof(szMac));
        TCHAR szSN[64];
        int nLen = _tcslen(szMac);
        int nIndex;
        for (nIndex = 0; nIndex < nLen; nIndex++)
        {
                szSN[nIndex] = szMac[nIndex] + 1 ^ 0x1f;
        }
        szSN[nIndex++] = (nLen * 2 ^ 0x11) + 0x30;
        szSN[nIndex] = TEXT('\0');
        _tprintf(TEXT("%s\r\n"), szSN);

        return 0;
}


吾爱破解注册机源码:

[Visual Basic] 纯文本查看 复制代码
Function GetMC(X) 

        GetMC=X 
        MC=GetMC 

End Function

Function GetName(X) 

End Function

Function GetSN() 
        
        mcLen = Len(MC)

        Key=""
        n = 1
        do while n <= mcLen
                tmp = Asc(Mid(MC, n, 1)) + 1
                tmp = tmp xor &H1f
                Key = Key & Chr(tmp)
                n = n + 1
        loop
        mcLen = mcLen * 2
        mcLen = mcLen xor &H11
        Key = Key & mcLen
        GetSN=Key

End Function


[版权声明]: 本文原创于封心锁爱, 转载请注明作者并保持文章的完整, 谢谢!

















本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册[Register]

x

免费评分

参与人数 3热心值 +3 收起 理由
吾爱扣扣 + 1 膜拜
低调(d-iao) + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩.
Chief + 1 吾爱破解2013CM大赛,有你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

Bds1r 发表于 2013-12-14 17:41
膜拜算法! 真的佩服!
头像被屏蔽
Ylca 发表于 2013-12-14 17:50
ZZ1196326205 发表于 2013-12-14 17:57
vipcrack 发表于 2013-12-14 18:17
精彩,认真学习一下,一会自己走一遍看看.
840870819 发表于 2013-12-14 18:20
去反调试
00401970      6A FF         push -0x1   --------------------改为retn
00401972      68 E9324000   push CrackMe.004032E9
00401977      64:A1 0000000>mov eax,dword ptr fs:[0]
0040197D   .  50            push eax

cui3030 发表于 2013-12-14 18:20
- - 大神在上...
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-15 15:40

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表