solly 发表于 2019-6-25 00:37

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

本帖最后由 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 就是解密函数。函数代码如下:
;解密代码的函数
00410074/$56            push    esi                           ;使用 push 保存 esi
00410075|.50            push    eax
00410076|.8B7424 08       mov   esi, dword ptr           ;取得函数返回地址(即长度参数的地址)
0041007A|.FC            cld
0041007B|.AD            lods    dword ptr                ;eax == 解码长度,esi += 0x04,现在 esi 指向解码密钥
0041007C|.51            push    ecx
0041007D|.8BC8            mov   ecx, eax                        ;ecx 为解码长度 len
0041007F|.AD            lods    dword ptr                ;eax == 解码密钥,esi += 0x04,现在 esi 指向待解码的指令
00410080|.56            push    esi                           ;压入新的函数返回地址
00410081|>3106            /xor   dword ptr , 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 , 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个字节就是解码函数中的解码长度和密钥,整理一下格式如下所示:
00410295      E8 DAFDFFFFcall    00410074                ;F7 进入
0041029A   .43000000   dd      00000043                ;len == 0x00000043
0041029E   .9166BF44   dd      44BF6691                ;key == 0x44BF6691
也就是解码参数是放在call的后面,而不是在前面压入栈顶。同时从解码函数返回后,栈顶为 0x0041029A,即 call 调用自动压入的返回地址,这个地址还在栈顶,是作为后面的加密函数的参数,并由加密函数完成栈的平衡。加密函数代码如下:
; 加密代码的函数
00410096/$873424          xchg    dword ptr , esi            ;保存esi,并将返回地址取到esi,这里没有用 push 保存 esi。
00410099|.877424 04       xchg    dword ptr , esi          ;将返回地址放到原有加密函数留下来的堆栈位置,并将长度参数的地址取回到esi
0041009D|.50            push    eax
0041009E|.51            push    ecx
0041009F|.FC            cld
004100A0|.AD            lods    dword ptr                ;eax == 需加密的代码的长度, esi += 0x04,现在 esi 指向加密密钥
004100A1|.8BC8            mov   ecx, eax                        ;ecx 为需加密的代码长度 len
004100A3|.AD            lods    dword ptr                ;eax == 加密密钥, esi += 0x04,现在 esi 指向待加密的指令
004100A4|>3106            /xor   dword ptr , 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。等解码过程完成后,手动改成如下形式:
00410295   .E8 DAFDFFFF   call    00410074                        ;解码代码
0041029A   .00000000      dd      00000000                        ;len = 0x43
0041029E   .00000000      dd      00000000                        ;key = 0x44BF6691
就可以避免再次加密代码。后面还有多个函数中也有这个解码后手动清0的过程,就不再重复详述了。
WinMain()函数解码后,如下所示,并带分析解释:
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
004102AF   .8BD8            mov   ebx, eax                        ;ebx ===> "registered"
004102B1   .FF75 0C         push    dword ptr                ;argv
004102B4   .FF75 08         push    dword ptr                ;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             ;push 0x00720008, ===> 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 , 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 进入,并解码后,如下所示:

主要就是对参数个数进行检查,如果程序有两个参数,则进行用户名/注册码验证,代码如下:
00410189   $55            push    ebp                           ;命令行参数处理函数
0041018A   .8BEC            mov   ebp, esp
0041018C   .53            push    ebx
0041018D   .56            push    esi
0041018E   .8B75 0C         mov   esi, dword ptr
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 , 3            ;命令行带2个参数
004101A4   .75 12         jnz   short 004101B8
004101A6   .8B46 04         mov   eax, dword ptr           ;eax ===> username
004101A9   .8B56 08         mov   edx, dword ptr           ;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 是对用户名和注册码进行验证,如下图所示:


具体分析如下(已解码):
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           ;edi ===> regcode
00410119   .8B75 08         mov   esi, dword ptr           ;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              ;name
0041014C   .0FBE38          movsx   edi, byte ptr              ;name
0041014F   .0FAFF7          imul    esi, edi                        ;esi = name * name
00410152   .0FBE3A          movsx   edi, byte ptr              ;code
00410155   .03F7            add   esi, edi                        ;esi = name * name + code
00410157   .0FBE7A 06       movsx   edi, byte ptr          ;code
0041015B   .83C7 A0         add   edi, -60                        ;edi = code - 0x60, 0x60 == 96
0041015E   .6BFF 1A         imul    edi, edi, 1A                  ;edi = (code - 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)是计算字符串长度的,如下图所示:

代码如下:
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
004100FD   .EB 02         jmp   short 00410101
004100FF   >43            inc   ebx
00410100   .40            inc   eax
00410101   >8038 00         cmp   byte ptr , 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,有两个这个调用,后面还有一个,这个是对字符串进行解码的:


具体的代码如下:
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
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 , dl            ;字符串改成明文后,可以将这条指令nop掉,后面会有说明
004100D9   .40            inc   eax
004100DA   >8A10            mov   dl, byte ptr
004100DC   .84D2            test    dl, dl
004100DE   .^ 75 ED         jnz   short 004100CD
004100E0   .E8 B1FFFFFF   call    00410096
004100E5   .5D            pop   ebp
004100E6   .C3            retn
解码完一条字符串后,接下来就是 call004101C3 ( 环境变量处理 ),如下图所示:


这个函数是从系统环境数组中循环取出每一个环境变量字符中,并判断是否存在该 CrackMe 所需要的环境变量字符串,如果存在,则返回成功,否则返回失败,具体分析如下所示:
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 , eax          ;return value == 0
004101DD   .8B45 08         mov   eax, dword ptr
004101E0   .8945 F0         mov   dword ptr , eax
004101E3   .E9 8C000000   jmp   00410274
004101E8   >33FF            xor   edi, edi
004101EA   .8BF0            mov   esi, eax
004101EC   .8D55 F4         lea   edx, dword ptr           ;保存环境变量字符串前6个字符
004101EF   .8BC6            mov   eax, esi
004101F1   .EB 05         jmp   short 004101F8
004101F3   >880A            mov   byte ptr , cl
004101F5   .47            inc   edi
004101F6   .42            inc   edx
004101F7   .40            inc   eax
004101F8   >8A08            mov   cl, byte ptr
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 , 0             ;环境变量字符串第7个字符'\0'
00410207   .C645 FB 00      mov   byte ptr , 0             ;环境变量字符串第8个字符'\0'
0041020B   .C645 FC 00      mov   byte ptr , 0             ;null, '\0'
0041020F   .8B45 F4         mov   eax, dword ptr           ;eax==环境变量字符串前4个字符
00410212   .8B55 F8         mov   edx, dword ptr           ;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             ;env
00410243   .3A06            cmp   al, byte ptr             ;env == env
00410245   .75 29         jnz   short 00410270
00410247   .8A46 08         mov   al, byte ptr             ;env
0041024A   .3A46 03         cmp   al, byte ptr             ;env == env
0041024D   .75 21         jnz   short 00410270
0041024F   .8A46 09         mov   al, byte ptr             ;env
00410252   .3A46 01         cmp   al, byte ptr             ;env == env
00410255   .75 19         jnz   short 00410270
00410257   .8A46 0A         mov   al, byte ptr             ;env
0041025A   .3A46 02         cmp   al, byte ptr             ;env == env
0041025D   .75 11         jnz   short 00410270
0041025F   .8A46 0B         mov   al, byte ptr             ;env
00410262   .3A46 05         cmp   al, byte ptr             ;env == env
00410265   .75 09         jnz   short 00410270
00410267   .C745 FC 0100000>mov   dword ptr , 1            ;return value == 1
0041026E   .EB 11         jmp   short 00410281
00410270   >8345 F0 04      add   dword ptr , 4
00410274   >8B45 F0         mov   eax, dword ptr
00410277   .8B00            mov   eax, dword ptr
00410279   .85C0            test    eax, eax
0041027B   .^ 0F85 67FFFFFF   jnz   004101E8
00410281   >E8 10FEFFFF   call    00410096
00410286   .8B45 FC         mov   eax, dword ptr           ;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 进行修改,改好后的内容:

具体如下所示:
; 代码修改前
004100D7|.8810          |mov   byte ptr , dl   ;保存解码后的字符

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


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

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



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

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


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



计算环境变量和注册码的代码如下,用 Dev-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 * name + code;
                d = (code - 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 = {'\0'};
      long s, d, key = 0;
      for(int i=0; i<6; i++) {
                for(int j=0x41; j<(0x41+26); j++) {
                        s = name * name + j;
                        bool b = false;
                        for(int k=0x41; k<(0x41+26); k++) {
                              d = (k - 96) * 26;
                              if(((s + d - 96) & 0xFF) == 0) {
                                        code = (char)k;
                                        b = true;
                                        break;
                              }
                        }
                        if(b) {
                              code   = (char)j;
                              break;
                        }
                }
      }
      ///
      code = '\0';
      if(code != '\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;
                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;
      ////
      env = env1.env;
      env = env1.env;
      env = env1.env;
      env = env1.env;
      env = env2.env;
      env = env2.env;
      /////
      env = '=';
      /////
      env = env;
      env = env;
      env = env;
      env = env;
      env = env;
      ////
      env = '\0';
      
      ////
      printf("Environment variable String: %s\n", env);
}

计算结果如下:
Environment variable String: DREAMS=DARES
key = 3F00
register code: ACVVMBGVQQUK

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

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


然后再操作一下:

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

全部结束!!!!

w780628d 发表于 2019-6-25 05:49

pk8900 发表于 2019-6-25 06:55

大神研究的太到位了,看来这个系列Crack有希望收集全了。
页: [1]
查看完整版本: 160 个 CrackMe 之 120 -- cronos.1 之解码破解及注册过程分析