好友
阅读权限 35
听众
最后登录 1970-1-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 胍Nw-.鸑?....
; 修改后
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有希望收集全了。
查看全部评分