吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 3617|回复: 2
上一主题 下一主题
收起左侧

[原创] 160 个 CrackMe 之 120 -- cronos.1 之解码破解及注册过程分析

[复制链接]
跳转到指定楼层
楼主
solly 发表于 2019-6-25 00:37 回帖奖励
本帖最后由 solly 于 2019-6-25 16:48 编辑

160 个 CrackMe 之 120 -- cronos.1 是一个老的 Win9x 程序,并且与 WinNT系列的内核不兼容,不能在 Win10下运行。
该 CrackMe 没有壳,由 Borland C/C++ 4.x 编译,但是内置解码函数,函数内部分内代码是加密的,需要先通过内置解码函数解码后才能执行。
另外,该 CrackMe 除了用户名/注册码验证,还有一个环境变量的验证,如果通过环境变量验证,就可以利用一个 CrackMe 的 BUG 跳过其用户名/注册码的验证。
当然也可以通过计算注册码来通过验证,这里也会分析其注册算码的过程,并通过注册机算码通过验证。
由于是 Borland C/C++ 编译,还需要一个运行库支持,该运行库为 CW3215.DLL,网络上有下载,相当于 VC/MFC 的 MFC40.DLL/MFC42.DLL 之类的运行库。
该CrackMe 的説明中也説了,用户名和参数是通过命令行输入的,因此在 OD 载入时需指定命令行参数。
在Win9x虚拟机中,用  OD 载入,如下图,并指定其运行参数

载入后,停留在start()函数入口,运行会先转入到 CW3215.DLL 的启动函数中初始化运行环境,然后再由DLL调用 WinMain() 执行用户代码。
其本身的代码入口(WinMain函数)是 0x0041028F,直接在该处按 F4 即可来到该入口,如下图所示:

前面説了,其代码一部分是加密的,是在运行时解密后再执行,从上图可以看出,从 0x0041029A 开始的代码看起来就比较乱了,这就是因为加了密的原因。
而在这之前的一个调用 call 00410074 就是解密函数。函数代码如下:
[Asm] 纯文本查看 复制代码
;  解密代码的函数
00410074  /$  56              push    esi                             ;  使用 push 保存 esi
00410075  |.  50              push    eax
00410076  |.  8B7424 08       mov     esi, dword ptr [esp+8]          ;  取得函数返回地址(即长度参数的地址)
0041007A  |.  FC              cld
0041007B  |.  AD              lods    dword ptr [esi]                 ;  eax == 解码长度,esi += 0x04,现在 esi 指向解码密钥
0041007C  |.  51              push    ecx
0041007D  |.  8BC8            mov     ecx, eax                        ;  ecx 为解码长度 len
0041007F  |.  AD              lods    dword ptr [esi]                 ;  eax == 解码密钥,esi += 0x04,现在 esi 指向待解码的指令
00410080  |.  56              push    esi                             ;  压入新的函数返回地址
00410081  |>  3106            /xor     dword ptr [esi], eax           ;  解密
00410083  |.  83C6 04         |add     esi, 4
00410086  |.  6BC0 11         |imul    eax, eax, 11
00410089  |.  40              |inc     eax
0041008A  |.  83E9 04         |sub     ecx, 4                         ;  (--len) > 0
0041008D  |.^ 7D F2           \jge     short 00410081                 ;  循环解码
0041008F  |.  5E              pop     esi                             ;  现在 esi 为函数返回地址
00410090  |.  59              pop     ecx
00410091  |.  58              pop     eax                             ;  F4到这里
00410092  |.  873424          xchg    dword ptr [esp], esi            ;  恢复 esi,并将当前栈顶置换成新的返回地址,没有用pop恢复esi,导致栈没有平衡。由后面的加密函数来进行平衡。
00410095  \.  C3              retn


可见,其解密的参数是call后面的2个DWORD内容,整理一下,如下图所示:


可见,0x0041029A 处保存的是长度,0x0041029E 处保存的是解密密钥。
先不要急着运行,为了我们后面的操作,我们先找一个位置改动一下代码,激活OD保存patch的功能,不然,解码的代码无法直接保存。如下图,找一个不影响程序正常运行的地方改动一下代码:

改完后,代码变成红色,表示  OD 的 patch 功能已激活。这样可以记录所有的代码变动情况,包括由CrackMe解码函数自己解码代码后的变化情况。
我们再回到 WinMain() 函数(0x0041028F处),按 F8 执行到 call    00410074 时,请一定要按 F7 进入该函数。
我们执行完解码函数,并返回后,如下图,可以看到正确的代码了:


可以看到,反回地址并不是 0x0041029A,而是8个字节后的 0x004102A2,中间跳过了8字节,这8个字节就是解码函数中的解码长度和密钥,整理一下格式如下所示:
[Asm] 纯文本查看 复制代码
00410295      E8 DAFDFFFF  call    00410074                ;  F7 进入
0041029A   .  43000000     dd      00000043                ;  len == 0x00000043
0041029E   .  9166BF44     dd      44BF6691                ;  key == 0x44BF6691

也就是解码参数是放在call的后面,而不是在前面压入栈顶。同时从解码函数返回后,栈顶为 0x0041029A,即 call 调用自动压入的返回地址,这个地址还在栈顶,是作为后面的加密函数的参数,并由加密函数完成栈的平衡。加密函数代码如下:
[Asm] 纯文本查看 复制代码
; 加密代码的函数
00410096  /$  873424          xchg    dword ptr [esp], esi            ;  保存esi,并将返回地址取到esi,这里没有用 push 保存 esi。
00410099  |.  877424 04       xchg    dword ptr [esp+4], esi          ;  将返回地址放到原有加密函数留下来的堆栈位置,并将长度参数的地址取回到esi
0041009D  |.  50              push    eax
0041009E  |.  51              push    ecx
0041009F  |.  FC              cld
004100A0  |.  AD              lods    dword ptr [esi]                 ;  eax == 需加密的代码的长度, esi += 0x04,现在 esi 指向加密密钥
004100A1  |.  8BC8            mov     ecx, eax                        ;  ecx 为需加密的代码长度 len
004100A3  |.  AD              lods    dword ptr [esi]                 ;  eax == 加密密钥, esi += 0x04,现在 esi 指向待加密的指令
004100A4  |>  3106            /xor     dword ptr [esi], eax           ;  加密
004100A6  |.  83C6 04         |add     esi, 4
004100A9  |.  6BC0 11         |imul    eax, eax, 11
004100AC  |.  40              |inc     eax
004100AD  |.  83E9 04         |sub     ecx, 4                         ;  (--len)>0
004100B0  |.^ 7D F2           \jge     short 004100A4                 ;  循环加密代码
004100B2  |.  59              pop     ecx
004100B3  |.  58              pop     eax                             ;  F4到这里
004100B4  |.  5E              pop     esi                             ;  使用 pop 恢复 esi,同时平衡栈指针 esp,这里多一个 pop,所以栈重新恢复平衡。
004100B5  \.  C3              retn

代码会在后面重新加密,所以为了脱掉加密,不能让其再次加密,防范措施也很简单,如上面的图所示,就是将长度和密钥清0。等解码过程完成后,手动改成如下形式:
[Asm] 纯文本查看 复制代码
00410295   .  E8 DAFDFFFF     call    00410074                        ;  解码代码
0041029A   .  00000000        dd      00000000                        ;  len = 0x43
0041029E   .  00000000        dd      00000000                        ;  key = 0x44BF6691

就可以避免再次加密代码。
后面还有多个函数中也有这个解码后手动清0的过程,就不再重复详述了。
WinMain()函数解码后,如下所示,并带分析解释:
[Asm] 纯文本查看 复制代码
0041028F   .  55              push    ebp                             ; WinMain()
00410290   .  8BEC            mov     ebp, esp
00410292   .  53              push    ebx
00410293   .  56              push    esi
00410294   .  57              push    edi
00410295   .  E8 DAFDFFFF     call    00410074                        ;  解码代码
0041029A   .  00000000        dd      00000000                        ;  len = 0x43
0041029E   .  00000000        dd      00000000                        ;  key = 0x44BF6691
004102A2   .  BF 74004200     mov     edi, 00420074                   ;  edi ===> 待解码的字符串:"Cronos Says"
004102A7   .  BE 80004200     mov     esi, 00420080                   ;  esi ===> 待解码的字符串:"unregistered"
004102AC   .  8D46 02         lea     eax, dword ptr [esi+2]
004102AF   .  8BD8            mov     ebx, eax                        ;  ebx ===> "registered"
004102B1   .  FF75 0C         push    dword ptr [ebp+C]               ;  argv[3]
004102B4   .  FF75 08         push    dword ptr [ebp+8]               ;  argc == 3
004102B7   .  E8 CDFEFFFF     call    00410189                        ;  用户名和注册码处理(命令行参数)
004102BC   .  83C4 08         add     esp, 8
004102BF   .  85C0            test    eax, eax
004102C1   .  75 02           jnz     short 004102C5
004102C3   .  8BDE            mov     ebx, esi                        ;  ebx ===> "unregistered"
004102C5   >  57              push    edi
004102C6   .  E8 EDFDFFFF     call    004100B8                        ;  解码字符串("Cronos Says")
004102CB   .  59              pop     ecx
004102CC   .  FF75 10         push    dword ptr [ebp+10]              ;  push 0x00720008,[00720008] ===> env vars
004102CF   .  E8 EFFEFFFF     call    004101C3                        ;  环境变量处理
004102D4   .  59              pop     ecx
004102D5   .  85C0            test    eax, eax
004102D7   .  75 02           jnz     short 004102DB
004102D9   .  8BDE            mov     ebx, esi                        ;  ebx ===> "unregistered"
004102DB   >  53              push    ebx
004102DC   .  E8 D7FDFFFF     call    004100B8                        ;  解码字符串, "unregistered" 或 "registered"
004102E1   .  59              pop     ecx
004102E2   .  8003 E0         add     byte ptr [ebx], 0E0             ;  首字母大写
004102E5   .  E8 ACFDFFFF     call    00410096                        ;  加密代码
004102EA   .  6A 01           push    1                               ; /Style = MB_OKCANCEL|MB_APPLMODAL
004102EC   .  57              push    edi                             ; |Title
004102ED   .  53              push    ebx                             ; |Text
004102EE   .  6A 00           push    0                               ; |hOwner = NULL
004102F0   .  E8 B5020000     call    <jmp.&USER32.MessageBoxA>       ; \MessageBoxA
004102F5   .  33C0            xor     eax, eax
004102F7   .  5F              pop     edi
004102F8   .  5E              pop     esi
004102F9   .  5B              pop     ebx
004102FA   .  5D              pop     ebp
004102FB   .  C3              retn

主函数解码后第一个要执行的函数是 call 00410189( 其用户名和注册码处理 ),F7 进入,并解码后,如下所示:

主要就是对参数个数进行检查,如果程序有两个参数,则进行用户名/注册码验证,代码如下:
[Asm] 纯文本查看 复制代码
00410189   $  55              push    ebp                             ;  命令行参数处理函数
0041018A   .  8BEC            mov     ebp, esp
0041018C   .  53              push    ebx
0041018D   .  56              push    esi
0041018E   .  8B75 0C         mov     esi, dword ptr [ebp+C]
00410191   .  E8 DEFEFFFF     call    00410074                        ;  解码代码
00410196   .  00000000        dd      00000000                        ;  len = 0x1A
0041019A   .  00000000        dd      00000000                        ;  key = 0xBA1F4D45
0041019E   .  33DB            xor     ebx, ebx                        ;  return value
004101A0   .  837D 08 03      cmp     dword ptr [ebp+8], 3            ;  命令行带2个参数
004101A4   .  75 12           jnz     short 004101B8
004101A6   .  8B46 04         mov     eax, dword ptr [esi+4]          ;  eax ===> username
004101A9   .  8B56 08         mov     edx, dword ptr [esi+8]          ;  edx ===> regcode
004101AC   .  52              push    edx
004101AD   .  50              push    eax
004101AE   .  E8 5DFFFFFF     call    00410110                        ;  用户名和注册码判断,此函数有 Bug
004101B3   .  83C4 08         add     esp, 8
004101B6   .  8BD8            mov     ebx, eax
004101B8   >  E8 D9FEFFFF     call    00410096                        ;  加密代码
004101BD   .  8BC3            mov     eax, ebx
004101BF   .  5E              pop     esi
004101C0   .  5B              pop     ebx
004101C1   .  5D              pop     ebp
004101C2   .  C3              retn

其中 call 00410110 是对用户名和注册码进行验证,如下图所示:


具体分析如下(已解码):
[Asm] 纯文本查看 复制代码
00410110   $  55              push    ebp                             ;  用户名和注册码处理函数
00410111   .  8BEC            mov     ebp, esp
00410113   .  53              push    ebx
00410114   .  56              push    esi
00410115   .  57              push    edi
00410116   .  8B7D 0C         mov     edi, dword ptr [ebp+C]          ;  edi ===> regcode
00410119   .  8B75 08         mov     esi, dword ptr [ebp+8]          ;  esi ===> username
0041011C   .  E8 53FFFFFF     call    00410074                        ;  解码代码
00410121   .  00000000        dd      00000000                        ;  len = 0x54
00410125   .  00000000        dd      00000000                        ;  key = 0x290802D6
00410129   .  33DB            xor     ebx, ebx                        ;  int key = 0x00
0041012B   .  56              push    esi                             ;  esi ===> username
0041012C   .  E8 B6FFFFFF     call    004100E7                        ;  __strlen()
00410131   .  59              pop     ecx
00410132   .  83F8 06         cmp     eax, 6                          ;  strlen(username) >= 6
00410135   .  7C 3F           jl      short 00410176
00410137   .  57              push    edi                             ;  edi ===> regcode
00410138   .  E8 AAFFFFFF     call    004100E7                        ;  __strlen()
0041013D   .  59              pop     ecx
0041013E   .  83F8 0C         cmp     eax, 0C                         ;  strlen(regcode) >= 12
00410141   .  7C 33           jl      short 00410176
00410143   .  33C9            xor     ecx, ecx                        ;  int i = 0;
00410145   .  8BD7            mov     edx, edi                        ;  edx ===> regcode
00410147   .  8BC6            mov     eax, esi                        ;  eax ===> username
00410149   >  0FBE30          movsx   esi, byte ptr [eax]             ;  name[i]
0041014C   .  0FBE38          movsx   edi, byte ptr [eax]             ;  name[i]
0041014F   .  0FAFF7          imul    esi, edi                        ;  esi = name[i] * name[i]
00410152   .  0FBE3A          movsx   edi, byte ptr [edx]             ;  code[i]
00410155   .  03F7            add     esi, edi                        ;  esi = name[i] * name[i] + code[i]
00410157   .  0FBE7A 06       movsx   edi, byte ptr [edx+6]           ;  code[i+6]
0041015B   .  83C7 A0         add     edi, -60                        ;  edi = code[i+6] - 0x60, 0x60 == 96
0041015E   .  6BFF 1A         imul    edi, edi, 1A                    ;  edi = (code[i+6] - 0x60) * 0x1A, 0x1A == 26
00410161   .  03F7            add     esi, edi                        ;  esi = esi + edi
00410163   .  83C6 A0         add     esi, -60                        ;  esi = esi - 0x60, 0x60 == 96
00410166   .  0BDE            or      ebx, esi                        ;  key = key or esi
00410168   .  41              inc     ecx                             ;  i ++
00410169   .  42              inc     edx                             ;  code ++
0041016A   .  40              inc     eax                             ;  name ++
0041016B   .  83F9 06         cmp     ecx, 6                          ;  i < 6
0041016E   .^ 7C D9           jl      short 00410149
00410170   .  81E3 FF000000   and     ebx, 0FF                        ;  (char)key, ebx = 0x3FFF, esi=0x090A, edi=0xFFFFFCF4(-780)
00410176   >  83FB 01         cmp     ebx, 1                          ;  ebx == 0 才正确
00410179   .  1BDB            sbb     ebx, ebx                        ;  ebx = ebx - ebx - CF = 0xFFFFFFFF 才正确
0041017B   .  F7DB            neg     ebx                             ;  ebx == 1 才正确
0041017D   .  E8 14FFFFFF     call    00410096                        ;  加密代码
00410182   .  8BC3            mov     eax, ebx
00410184   .  5F              pop     edi
00410185   .  5E              pop     esi
00410186   .  5B              pop     ebx
00410187   .  5D              pop     ebp
00410188   .  C3              retn

上面代码中有一个 BUG ,不知大家有没有发现,暂时不指明,后面再説。
其中有两个调用(call    004100E7)是计算字符串长度的,如下图所示:

代码如下:
[Asm] 纯文本查看 复制代码
004100E7   $  55              push    ebp                             ;  __strlen()
004100E8   .  8BEC            mov     ebp, esp
004100EA   .  53              push    ebx
004100EB   .  E8 84FFFFFF     call    00410074                        ;  解码代码
004100F0   .  00000000        dd      00000000                        ;  len = 0x0E
004100F4   .  00000000        dd      00000000                        ;  key = 0x805E9A33
004100F8   .  33DB            xor     ebx, ebx
004100FA   .  8B45 08         mov     eax, dword ptr [ebp+8]
004100FD   .  EB 02           jmp     short 00410101
004100FF   >  43              inc     ebx
00410100   .  40              inc     eax
00410101   >  8038 00         cmp     byte ptr [eax], 0
00410104   .^ 75 F9           jnz     short 004100FF
00410106   .  E8 8BFFFFFF     call    00410096
0041010B   .  8BC3            mov     eax, ebx
0041010D   .  5B              pop     ebx
0041010E   .  5D              pop     ebp
0041010F   .  C3              retn


完成以上代码执行后,再次返回 WinMain(),来到 call 004100B8,有两个这个调用,后面还有一个,这个是对字符串进行解码的:


具体的代码如下:
[Asm] 纯文本查看 复制代码
004100B8   $  55              push    ebp                             ;  解码字符串
004100B9   .  8BEC            mov     ebp, esp
004100BB   .  E8 B4FFFFFF     call    00410074
004100C0   .  00000000        dd      00000000                        ;  len = 0x18
004100C4   .  00000000        dd      00000000                        ;  key = 0xDEADBEEF
004100C8   .  8B45 08         mov     eax, dword ptr [ebp+8]
004100CB   .  EB 0D           jmp     short 004100DA
004100CD   >  0FBED2          movsx   edx, dl
004100D0   .  8BCA            mov     ecx, edx
004100D2   .  C1E2 05         shl     edx, 5
004100D5   .  2BD1            sub     edx, ecx
004100D7   .  8810            mov     byte ptr [eax], dl              ;  字符串改成明文后,可以将这条指令nop掉,后面会有说明
004100D9   .  40              inc     eax
004100DA   >  8A10            mov     dl, byte ptr [eax]
004100DC   .  84D2            test    dl, dl
004100DE   .^ 75 ED           jnz     short 004100CD
004100E0   .  E8 B1FFFFFF     call    00410096
004100E5   .  5D              pop     ebp
004100E6   .  C3              retn

解码完一条字符串后,接下来就是 call  004101C3 ( 环境变量处理 ),如下图所示:


这个函数是从系统环境数组中循环取出每一个环境变量字符中,并判断是否存在该 CrackMe 所需要的环境变量字符串,如果存在,则返回成功,否则返回失败,具体分析如下所示:
[Asm] 纯文本查看 复制代码
004101C3   $  55              push    ebp                             ; 环境变量处理函数
004101C4   .  8BEC            mov     ebp, esp
004101C6   .  83C4 F0         add     esp, -10
004101C9   .  56              push    esi
004101CA   .  57              push    edi
004101CB   .  E8 A4FEFFFF     call    00410074
004101D0   .  00000000        dd      00000000                        ;  len = 0xA9
004101D4   .  00000000        dd      00000000                        ;  key = 0x82356CD5
004101D8   .  33C0            xor     eax, eax                        ;  0
004101DA   .  8945 FC         mov     dword ptr [ebp-4], eax          ;  return value == 0
004101DD   .  8B45 08         mov     eax, dword ptr [ebp+8]
004101E0   .  8945 F0         mov     dword ptr [ebp-10], eax
004101E3   .  E9 8C000000     jmp     00410274
004101E8   >  33FF            xor     edi, edi
004101EA   .  8BF0            mov     esi, eax
004101EC   .  8D55 F4         lea     edx, dword ptr [ebp-C]          ;  [ebp-C]保存环境变量字符串前6个字符
004101EF   .  8BC6            mov     eax, esi
004101F1   .  EB 05           jmp     short 004101F8
004101F3   >  880A            mov     byte ptr [edx], cl
004101F5   .  47              inc     edi
004101F6   .  42              inc     edx
004101F7   .  40              inc     eax
004101F8   >  8A08            mov     cl, byte ptr [eax]
004101FA   .  84C9            test    cl, cl
004101FC   .  74 05           je      short 00410203
004101FE   .  83FF 06         cmp     edi, 6
00410201   .^ 7C F0           jl      short 004101F3
00410203   >  C645 FA 00      mov     byte ptr [ebp-6], 0             ;  环境变量字符串第7个字符'\0'
00410207   .  C645 FB 00      mov     byte ptr [ebp-5], 0             ;  环境变量字符串第8个字符'\0'
0041020B   .  C645 FC 00      mov     byte ptr [ebp-4], 0             ;  null, '\0'
0041020F   .  8B45 F4         mov     eax, dword ptr [ebp-C]          ;  eax==环境变量字符串前4个字符
00410212   .  8B55 F8         mov     edx, dword ptr [ebp-8]          ;  edx==环境变量字符串第5、6个字符
00410215   .  69C8 4979DA00   imul    ecx, eax, 0DA7949
0041021B   .  8BC1            mov     eax, ecx
0041021D   .  69CA 4DAD6222   imul    ecx, edx, 2262AD4D
00410223   .  8BD1            mov     edx, ecx
00410225   .  3D 64998E6E     cmp     eax, 6E8E9964                   ; (eax * 0x00DA7949) & 0xFFFFFFFF == 0x6E8E9964 ?
0041022A   .  75 44           jnz     short 00410270
0041022C   .  81FA 2917DE55   cmp     edx, 55DE1729                   ; (edx * 0x2262AD4D) & 0xFFFFFFFF == 0x55DE1729 ?
00410232   .  75 3C           jnz     short 00410270
00410234   .  56              push    esi                             ;  环境变量串(key=value)
00410235   .  E8 ADFEFFFF     call    004100E7                        ;  strlen(env_string)
0041023A   .  59              pop     ecx
0041023B   .  83F8 0C         cmp     eax, 0C
0041023E   .  7C 30           jl      short 00410270
00410240   .  8A46 07         mov     al, byte ptr [esi+7]            ;  env[7]
00410243   .  3A06            cmp     al, byte ptr [esi]              ;  env[7] == env[0]
00410245   .  75 29           jnz     short 00410270
00410247   .  8A46 08         mov     al, byte ptr [esi+8]            ;  env[8]
0041024A   .  3A46 03         cmp     al, byte ptr [esi+3]            ;  env[8] == env[3]
0041024D   .  75 21           jnz     short 00410270
0041024F   .  8A46 09         mov     al, byte ptr [esi+9]            ;  env[9]
00410252   .  3A46 01         cmp     al, byte ptr [esi+1]            ;  env[9] == env[1]
00410255   .  75 19           jnz     short 00410270
00410257   .  8A46 0A         mov     al, byte ptr [esi+A]            ;  env[10]
0041025A   .  3A46 02         cmp     al, byte ptr [esi+2]            ;  env[10] == env[2]
0041025D   .  75 11           jnz     short 00410270
0041025F   .  8A46 0B         mov     al, byte ptr [esi+B]            ;  env[11]
00410262   .  3A46 05         cmp     al, byte ptr [esi+5]            ;  env[11] == env[5]
00410265   .  75 09           jnz     short 00410270
00410267   .  C745 FC 0100000>mov     dword ptr [ebp-4], 1            ;  return value == 1
0041026E   .  EB 11           jmp     short 00410281
00410270   >  8345 F0 04      add     dword ptr [ebp-10], 4
00410274   >  8B45 F0         mov     eax, dword ptr [ebp-10]
00410277   .  8B00            mov     eax, dword ptr [eax]
00410279   .  85C0            test    eax, eax
0041027B   .^ 0F85 67FFFFFF   jnz     004101E8
00410281   >  E8 10FEFFFF     call    00410096
00410286   .  8B45 FC         mov     eax, dword ptr [ebp-4]          ;  return value
00410289   .  5F              pop     edi
0041028A   .  5E              pop     esi
0041028B   .  8BE5            mov     esp, ebp
0041028D   .  5D              pop     ebp
0041028E   .  C3              retn

执行完这个函数后,返回主函数(WinMain)后,所有的代码解码过程都已完成,这个时候就可以保存解码后的代码了,如下图所示:

然后会弹出一个确认消息框,核对无误则点“复制”,会有多次确认,都选“复制”即可。

完成后,如下图:

再点右键,选择“保存文件”,弹出保存文件对话框:

输入新的文件名,按“保存”即可。
这样,我们就完成了解码的脱除,再次用 OD 载入前面保存后的解码后的新CrackMe程序,来到 WinMain(),如下所示,代码是明文的了:

另外,还有一个需要处理一下,就是字符串还是加密的,如下,我们可以手动修改,先把解码函数修改:

如上图,需要修改的代码和数据都已标成蓝色底色了,改成如下图所示内容:

也可以直接修改文件,不用在 OD 中修改,如下图,用 UE 进行修改,改好后的内容:

具体如下所示:
[Asm] 纯文本查看 复制代码
; 代码修改前
004100D7  |.  8810          |mov     byte ptr [eax], dl     ;保存解码后的字符

; 修改后
004100D7      90            nop
004100D8      90            nop


; 数据解码前
00420070  00 00 00 00 5D 4E B1 D2 B1 2D E0 4D 7F 67 2D 00  ....]N币?郙g-.
00420080  EB D2 4E FB B9 77 2D 0C FB 4E FB 1C 00 00 00 00  胍Nw-.鸑?....

; 修改后
00420070  00 00 00 00 43 72 6F 6E 6F 73 20 53 61 79 73 00  ....Cronos Says.
00420080  75 6E 72 65 67 69 73 74 65 72 65 64 00 00 00 00  unregistered....



所有的分析和修改都完成了。

  下面针对 CrackMe 的用户名/注册码验证,环境变量验证説明一下。
1、环境变量只有通过暴力计算,不过很快就可算得,环境字符串为:DREAMS=DARES
2、用户名/注册码验证函数有Bug,只要用户名长度小于6或者注册码长度小于12就可以通过该函数验证。



在命令行下运行 CrackMe,可以验证,如下图所示:



计算环境变量和注册码的代码如下,用 Dev-C++调试通过:
[C++] 纯文本查看 复制代码
#include <iostream>

void getEnv();
bool checkRegister(char * name, char *code);
int getRegister(char * name);

int main(int argc, char** argv) {
        
        ////  
        getEnv(); 
        ////
        char name[] = "solly88";  /// 需要什么名字,自己改!!! 
        //char name[] = "52pojie.cn";
        //char code[] = "1234567890ABC";
        int chk = getRegister(name);
        
        return 0;
}

bool checkRegister(char * name, char *code) {
        long s, d, key = 0;
        for(int i=0; i<6; i++) {
                s = name[i] * name[i] + code[i];
                d = (code[i+6] - 96) * 26;
                s = s + d - 96;
                key = key | s;
        }
        printf("key = %X\n", key);
        key = key & 0xFF;
        
        return (key==0)?true:false;
}

int getRegister(char * name) {
        char code[16] = {'\0'};
        long s, d, key = 0;
        for(int i=0; i<6; i++) {
                for(int j=0x41; j<(0x41+26); j++) {
                        s = name[i] * name[i] + j;
                        bool b = false;
                        for(int k=0x41; k<(0x41+26); k++) {
                                d = (k - 96) * 26;
                                if(((s + d - 96) & 0xFF) == 0) {
                                        code[i+6] = (char)k;
                                        b = true;
                                        break;
                                }
                        }
                        if(b) {
                                code[i]   = (char)j;
                                break;
                        }
                }
        }
        ///
        code[12] = '\0';
        if(code[0] != '\0') {
                bool b = checkRegister(name, code);
                if(b) {
                        printf("register code: %s\n", code);
                } else {
                        printf("no register code: %s\n", code);
                        return -1;
                }
        } else {
                printf("not found register code\n");
        }
        return 0;
}

void getEnv() {
        union {
                char env[4];
                long code;
        } env1, env2;
        
        for (long i = 0x20202020; i<0x7E7E7E7F; i++) {
                if (((i * 0x00DA7949) & 0xFFFFFFFF) == 0x6E8E9964) {
                        //printf("%X%X%X%X\n", i & 0xFF, (i>>8) & 0xFF, (i>>16) & 0xFF, (i>>24) & 0xFF);  /// 44524541
                        env1.code = i;
                        break;
                }
        }

        for (long i = 0x2020; i<0x7E7F; i++) {
                if (((i * 0x2262AD4D) & 0xFFFFFFFF) == 0x55DE1729) {
                        //printf("%X%X\n", i & 0xFF, (i>>8) & 0xFF);  /// 4D53
                        env2.code = i;
                        break;
                }
        }
        
        char env[16];
        ////
        env[0] = env1.env[0];
        env[1] = env1.env[1];
        env[2] = env1.env[2];
        env[3] = env1.env[3];
        env[4] = env2.env[0];
        env[5] = env2.env[1];
        /////
        env[6] = '=';
        /////
        env[7] = env[0];
        env[8] = env[3];
        env[9] = env[1];
        env[10] = env[2];
        env[11] = env[5];
        ////
        env[12] = '\0';
        
        ////
        printf("Environment variable String: %s\n", env);
}


计算结果如下:
[HTML] 纯文本查看 复制代码
Environment variable String: DREAMS=DARES
key = 3F00
register code: ACVVMBGVQQUK

--------------------------------
Process exited after 3.444 seconds with return value 0


附注:
有时代码会显示不正常,显示为数据,需要在右键菜单中的”分析“功能来处理,如下图所示:


然后再操作一下:

这样两步后,一般会显示正常。

全部结束!!!!


免费评分

参与人数 2威望 +1 吾爱币 +10 热心值 +2 收起 理由
Hmily + 1 + 7 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
pk8900 + 3 + 1 大神研究的太到位了,看来这个系列Crack有希望收集全了。

查看全部评分

本帖被以下淘专辑推荐:

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

头像被屏蔽
沙发
w780628d 发表于 2019-6-25 05:49
提示: 作者被禁止或删除 内容自动屏蔽
3#
pk8900 发表于 2019-6-25 06:55
大神研究的太到位了,看来这个系列Crack有希望收集全了。
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

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

GMT+8, 2024-4-23 19:28

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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