这个crackme坑比较多,绕了很久才找到真正的注册算法。说一下程序运行的大致流程。
程序启动会对下列数据进行解密,解密大小为0x34,DO不需要解密
003273A0 78 00 9E 5B 50 99 97 B6 9D 97 23 07 A9 34 7D 0B x.瀃P櫁稘??}
003273B0 0F 77 04 EE CB 86 A5 13 AD 6A F2 B4 D5 E7 10 C1 w钏啣璲虼甄?
003273C0 22 6C D7 E0 0A 01 C0 71 9E 91 74 11 23 5F 4B 8B "l奏.纐瀾t#_K?
003273D0 6E 03 E2 66 6E CF 20 1E 54 D4 67 92 00 n鈌n?T詆?...
其中 CF 20 1E 54 D4 67 92 00 为 变异MD5的值,后面会用到,设为h。
解密的算法为 t[i]^(FF-i), 解密的数据后为
00328420 78 FE 63 A7 AB 63 6E 4E 6A 61 D6 F3 5A C6 8C FB xЙcnNja煮Z茖?
00328430 E0 99 E9 02 20 6C 4C FB 4A 8C 17 50 36 05 F1 21 鄼? lL鸍?P6?
00328440 FD B2 0A 3C D1 DB 19 A9 49 47 A1 C5 F0 8D 9A 5B .<眼㊣G∨饙歔
00328450 A1 CD 2F AA A5 ⊥/..
注册码长度为56个字节,每当输入注册码时就会触发txtinput_Change事件,完成对t的解密
004057BD . 0FB600 movzx eax, byte ptr [eax]
004057C0 . 03C3 add eax, ebx ; sn[1]+i
004057C2 . B9 00010000 mov ecx, 100
004057C7 . 0F80 D3000000 jo 004058A0
004057CD . 99 cdq
004057CE . F7F9 idiv ecx
004057D0 . 53 push ebx
004057D1 . FF35 78E04000 push dword ptr [40E078]
004057D7 . 8995 7CFFFFFF mov dword ptr [ebp-84], edx
004057DD . E8 F0BDFFFF call <jmp.&MSVBVM60.__vbaDerefAry1> ; t[i]
004057E2 . 0FB600 movzx eax, byte ptr [eax]
004057E5 . 8B8D 7CFFFFFF mov ecx, dword ptr [ebp-84]
004057EB . 33C8 xor ecx, eax ; t[i] xor (sn[1]+i)
004057ED . 8B47 50 mov eax, dword ptr [edi+50]
004057F0 . 8B40 04 mov eax, dword ptr [eax+4]
004057F3 . 03C3 add eax, ebx ; xor (sn[1]+i)
004057F5 . 0F80 A5000000 jo 004058A0
004057FB . 33C8 xor ecx, eax
004057FD . E8 94BDFFFF call <jmp.&MSVBVM60.__vbaUI1I4>
00405802 . FF75 E8 push dword ptr [ebp-18]
00405805 . 8AD8 mov bl, al
解密算法为 i = 1~0x34; t[i] = t[i] ^ (sn[1]+i) ^ i; txtinput_Change事件完成。
当点击注册按钮时触发cmdReg_Click事件,这里只有一件有意义的事 “禁用按钮”,其他的都是坑啊!!
纠结下面这段代码的,说明已入坑
00403DBF . E8 ECD8FFFF call <jmp.&MSVBVM60.__vbaVarCat>
00403DC4 . 50 push eax
00403DC5 . 8D85 6CFFFFFF lea eax, dword ptr [ebp-94]
00403DCB . 50 push eax
00403DCC . E8 91400000 call 00407E62
00403DD1 . 8D85 6CFFFFFF lea eax, dword ptr [ebp-94]
00403DD7 . C785 04FFFFFF>mov dword ptr [ebp-FC], 0040284C ; UNICODE "033788636d9acb22"
00403DE1 . 50 push eax ; /var18
00403DE2 . 8D85 FCFEFFFF lea eax, dword ptr [ebp-104] ; |
00403DE8 . 50 push eax ; |var28
00403DE9 . 8D85 5CFFFFFF lea eax, dword ptr [ebp-A4] ; |
00403DEF . C785 FCFEFFFF>mov dword ptr [ebp-104], 8008 ; |
00403DF9 . 50 push eax ; |SaveTo8
00403DFA . E8 B7D8FFFF call <jmp.&MSVBVM60.__vbaVarCmpEq> ; \__vbaVarCmpEq
00403DFF . 8BD0 mov edx, eax
00403E01 . 8D4D DC lea ecx, dword ptr [ebp-24]
00403E04 . E8 B3D8FFFF call <jmp.&MSVBVM60.__vbaVarMove>
check_Timer是个计时器事件,当发现按钮被禁用后,开始验证序列号,真正的算法在这里。过程如下
00404CA1 . 8D45 DC lea eax, dword ptr [ebp-24]
00404CA4 . 50 push eax
00404CA5 . 8D45 BC lea eax, dword ptr [ebp-44]
00404CA8 . 50 push eax
00404CA9 . E8 F70B0000 call 004058A5 ; check(out, sn)
00404CAE . 8D45 BC lea eax, dword ptr [ebp-44]
00404CB1 . 50 push eax
00404CB2 . E8 BDC9FFFF call <jmp.&MSVBVM60.__vbaBoolVarNull>
00404CB7 . 8D4D BC lea ecx, dword ptr [ebp-44]
00404CBA . 66:8BF8 mov di, ax
00404CBD . E8 E2C9FFFF call <jmp.&MSVBVM60.__vbaFreeVar>
00404CC2 . 8B06 mov eax, dword ptr [esi]
00404CC4 . 66:3BFB cmp di, bx
00404CC7 . 56 push esi
00404CC8 . 0F84 3C030000 je 0040500A
check过程是输入序列号,输出bool结果,非0表示注册成功。check过程如下
调用zlib动态库压缩sn,输出t2
00405914 . 8B45 C4 mov eax, dword ptr [ebp-3C]
00405917 . 8D95 54FFFFFF lea edx, dword ptr [ebp-AC]
0040591D . 52 push edx
0040591E . 8BD8 mov ebx, eax
00405920 . FF75 0C push dword ptr [ebp+C]
00405923 . 8B08 mov ecx, dword ptr [eax]
00405925 . 50 push eax
00405926 . FF51 2C call dword ptr [ecx+2C] ; CompressString(strIn)
00405929 . 3BC6 cmp eax, esi
处理压缩后的结果t2,3处修改,取余交换15和20位置,末尾(34)位置取余
00405991 . 6A 15 push 15
00405993 . 8818 mov byte ptr [eax], bl ; t2[n] = t2[n]%21
00405995 . FF75 CC push dword ptr [ebp-34]
00405998 . E8 35BCFFFF call <jmp.&MSVBVM60.__vbaDerefAry1>
0040599D . 0FB600 movzx eax, byte ptr [eax] ; t2[15]
004059A0 . 6A 20 push 20
004059A2 . 8945 E4 mov dword ptr [ebp-1C], eax
004059A5 . FF75 CC push dword ptr [ebp-34]
004059A8 . E8 25BCFFFF call <jmp.&MSVBVM60.__vbaDerefAry1>
004059AD . 66:0FB600 movzx ax, byte ptr [eax] ; t2[20]
004059B1 . 66:99 cwd
004059B3 . 66:B9 4200 mov cx, 42
004059B7 . 66:F7F9 idiv cx
004059BA . 8BCA mov ecx, edx ; t2[20]%42
004059BC . E8 13BDFFFF call <jmp.&MSVBVM60.__vbaUI1I2>
004059C1 . 6A 15 push 15
004059C3 . 8AD8 mov bl, al
004059C5 . FF75 CC push dword ptr [ebp-34]
004059C8 . E8 05BCFFFF call <jmp.&MSVBVM60.__vbaDerefAry1>
004059CD . 8818 mov byte ptr [eax], bl ; t2[15]=t2[20]%42
004059CF . 8B45 E4 mov eax, dword ptr [ebp-1C]
004059D2 . 6A 63 push 63
004059D4 . 99 cdq
004059D5 . 59 pop ecx
004059D6 . F7F9 idiv ecx
004059D8 . 8BCA mov ecx, edx ; t2[15]%63
004059DA . E8 B7BBFFFF call <jmp.&MSVBVM60.__vbaUI1I4>
004059DF . 6A 20 push 20
004059E1 . 8AD8 mov bl, al
004059E3 . FF75 CC push dword ptr [ebp-34]
004059E6 . E8 E7BBFFFF call <jmp.&MSVBVM60.__vbaDerefAry1> ; t2[20]=t2[15]%63
004059EB . 8818 mov byte ptr [eax], bl
对sn进行md5,结果为h2
00405A7D . 898D 68FFFFFF mov dword ptr [ebp-98], ecx
00405A83 . E8 DA230000 call 00407E62 ; hasn(sn)
00405A88 . 8D85 60FFFFFF lea eax, dword ptr [ebp-A0]
00405A8E . 50 push eax
00405A8F . 8D45 B0 lea eax, dword ptr [ebp-50]
00405A92 . 50 push eax
00405A93 . 8D45 A0 lea eax, dword ptr [ebp-60]
00405A96 . 50 push eax
00405A97 . E8 14BCFFFF call <jmp.&MSVBVM60.__vbaVarCat> ; sn+hash(sn)
00405A9C . 50 push eax
00405A9D . 8D45 90 lea eax, dword ptr [ebp-70]
00405AA0 . 50 push eax
00405AA1 . E8 BC230000 call 00407E62 ; hash(sn+hash(sn))
00405AA6 . 8D45 90 lea eax, dword ptr [ebp-70]
00405AA9 . 50 push eax
00405AAA . 8D45 80 lea eax, dword ptr [ebp-80]
00405AAD . 50 push eax
00405AAE . E8 1BBCFFFF call <jmp.&MSVBVM60.#528> ; uper(y)
00405AB3 . 8D45 80 lea eax, dword ptr [ebp-80]
对比结果 h == h2 && t == t2
00405B98 . FF75 C0 push dword ptr [ebp-40]
00405B9B . FF75 E8 push dword ptr [ebp-18]
00405B9E . 56 push esi
00405B9F . E8 24BBFFFF call <jmp.&MSVBVM60.__vbaInStr>
00405BA4 . 48 dec eax
00405BA5 . 6A 0B push 0B
00405BA7 . F7D8 neg eax
00405BA9 . 1BC0 sbb eax, eax
00405BAB . 5F pop edi
00405BAC . 40 inc eax
00405BAD . 8D95 60FFFFFF lea edx, dword ptr [ebp-A0]
00405BB3 . F7D8 neg eax
00405BB5 . 8D4D D4 lea ecx, dword ptr [ebp-2C]
00405BB8 . 66:8985 68FFF>mov word ptr [ebp-98], ax ; ==
00405BBF . 89BD 60FFFFFF mov dword ptr [ebp-A0], edi
00405BC5 . E8 F2BAFFFF call <jmp.&MSVBVM60.__vbaVarMove>
00405BCA . 8D4D C0 lea ecx, dword ptr [ebp-40]
00405BCD . E8 A8BAFFFF call <jmp.&MSVBVM60.__vbaFreeStr>
00405BD2 . 6A 01 push 1
00405BD4 . FF75 C8 push dword ptr [ebp-38]
00405BD7 . FF75 D0 push dword ptr [ebp-30]
00405BDA . 56 push esi
00405BDB . E8 E8BAFFFF call <jmp.&MSVBVM60.__vbaInStr> ; ==
00405BE0 . 48 dec eax
00405BE1 . 89BD 70FFFFFF mov dword ptr [ebp-90], edi
分析完成后,整理下表达式
t2 = mod(compress(sn)) = decode(t, sn[1])
h2 = hash(sn+hash(sn)) = "CF201E54D4679200"
由于存在 decode和取余操作,所以需要穷举一下,代码中借用了作者的zlib动态库
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)