xTiNtxTiNt【文章标题】: fornix'2nd crackme,利用INT3混乱算法
【文章作者】: laomms
【软件名称】: fornix'2nd crackme
【软件大小】: 16K
【下载地址】: 附件
【加壳方式】: 无
【编写语言】: MASM
【使用工具】: OLLYDBG
【操作平台】: WINXP SP2
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
这个CRACKME做的非常好,很灵活,防INT3断点,一旦检测到CC代码,就将关键的比较地方内存中正确的值进行修改,你永远都别想逆推到真的注册码。
OD载入,下GetWindowTextA断点或者根据字符串参考很容易找到关键处:
00401147 . 68 84324000 PUSH 00403284 ; 断在这里
0040114C . E8 D0000000 CALL 00401221 ; 跟进这个CALL,其实这个CALL中的算法是迷惑人的,没有什么用
======================
00401224 |. 8B75 08 MOV ESI,DWORD PTR SS:[EBP+8] ; 注册码
00401227 |> 803E 00 /CMP BYTE PTR DS:[ESI],0 ; 是否为0
0040122A |. 74 0C |JE 00401238
0040122C |. 8A06 |MOV AL,BYTE PTR DS:[ESI] ; 逐个取注册码
0040122E |. 34 15 |XOR AL,15 ; 异或15
00401230 |. C0C8 05 |ROR AL,5 ; 循环右移5
00401233 |. 8806 |MOV BYTE PTR DS:[ESI],AL ; 放回DS:[ESI],计算的最终结果就在这里
00401235 |. 46 |INC ESI ; ESI累加
00401236 |.^ EB EF \JMP 00401227
00401238 |> \E8 04000000 CALL 00401241 ; 检测断点
0040123D |. C9 LEAVE
0040123E \. C2 0400 RETN 4
00401241 /$ 8D3D 00104000 LEA EDI,DWORD PTR DS:[<ModuleEntryPoint>>; 入口地址401000装入EDI
00401247 |. B9 97020000 MOV ECX,297 ; ECX赋值297
0040124C |. E8 45000000 CALL 00401296 ; CC装入AL
00401251 |. F2:AE REPNE SCAS BYTE PTR ES:[EDI] ; 重复操作
比如断点设在00401147处,入口出处为00401000,则F8后,ECX=297-(00401147-00401000+1)=14F,当然你也可以在原地不停的按住F4,直到ECX=1后再按F8
00401253 |. 85C9 TEST ECX,ECX ; ECX是否为0,如果下了断点,这里的ECX是非0值
00401255 |. 75 3E JNZ 00401295 ; 既然你下了断点,这里一定不能跳
00401257 |. 8D05 9A124000 LEA EAX,DWORD PTR DS:[40129A]
0040125D |. A3 7D324000 MOV DWORD PTR DS:[40327D],EAX
00401262 |> A1 7D324000 /MOV EAX,DWORD PTR DS:[40327D]
00401267 |. 8B15 7D324000 |MOV EDX,DWORD PTR DS:[40327D]
0040126D |. 833A 00 |CMP DWORD PTR DS:[EDX],0
00401270 |. 74 14 |JE 00401286
00401272 |. 8BC8 |MOV ECX,EAX
00401274 |. E8 1D000000 |CALL 00401296
00401279 |. 3801 |CMP BYTE PTR DS:[ECX],AL
0040127B |. 74 18 |JE 00401295
0040127D |. 8305 7D324000>|ADD DWORD PTR DS:[40327D],6
00401284 |.^ EB DC \JMP 00401262
00401286 |> 8A1D 40324000 MOV BL,BYTE PTR DS:[403240] ; DS:[00403240]=02
0040128C |. FEC3 INC BL ; 02+1
0040128E |. 881D 40324000 MOV BYTE PTR DS:[403240],BL ; 放回DS:[403240]
00401294 |. C3 RETN
00401295 \> C3 RETN ; 如果下了断,跳到这里直接返回
======================
00401151 . BF 20114000 MOV EDI,00401120
00401156 . 83C7 0B ADD EDI,0B
00401159 . BE 84324000 MOV ESI,00403284 ; 可以看这里内存中的直接常数
0040115E . B9 09000000 MOV ECX,9
00401163 > 49 DEC ECX
00401164 . AC LODS BYTE PTR DS:[ESI] ; 刚才计算后的的注册码
00401165 . AE SCAS BYTE PTR ES:[EDI] ; 与寄存器ES:[EDI]中的各个值对比
00401166 .^ 74 FB JE 00401163 ; 没有跳
00401168 . 8BC1 MOV EAX,ECX
0040116A . C9 LEAVE
0040116B . C2 0400 RETN 4 ; 返回
004010B0 . 0BC0 OR EAX,EAX ; EAX是否为0
004010B2 . 75 14 JNZ 004010C8 ; 这个得让它跳,作者在这里开了个玩笑,如果这里不跳成立,注册码为fuckolly,但事实上是错误的
004010B4 . 68 33324000 PUSH 00403233 ; right serial
004010B9 . 68 E8314000 PUSH 004031E8 ; you've done it. write a tutorial and send it to fornix@fusionrulez.cjb.net
004010BE . FF75 08 PUSH DWORD PTR SS:[EBP+8]
004010C1 . E8 A8000000 CALL 0040116E
004010C6 . EB 12 JMP 004010DA
004010C8 > 68 DB314000 PUSH 004031DB ; wrong serial
004010CD . 68 B7314000 PUSH 004031B7 ; it's not so easy boy. keep tryin...
004010D2 . FF75 08 PUSH DWORD PTR SS:[EBP+8]
004010D5 . E8 94000000 CALL 0040116E ; 关键CALL,一定要跟入
004010DA > EB 37 JMP 00401113
=============================
0040116E $ 55 PUSH EBP
0040116F . 8BEC MOV EBP,ESP
00401171 . 68 68324000 PUSH 00403268 ; /lParam = 403268
00401176 . 6A 14 PUSH 14 ; |wParam = 14
00401178 . 6A 0D PUSH 0D ; |Message = WM_GETTEXT
0040117A . 68 EA030000 PUSH 3EA ; |ControlID = 3EA (1002.)
0040117F . FF75 08 PUSH DWORD PTR SS:[EBP+8] ; |hWnd
00401182 . E8 49010000 CALL <JMP.&user32.SendDlgItemMessageA> ; \SendDlgItemMessageA
00401187 . EB 08 JMP 00401191
00401189 . 91 XCHG EAX,ECX
0040118A . 71 39 JNO 004011C5
0040118C . A9 41112103 TEST EAX,3211141
00401191 > 68 68324000 PUSH 00403268
00401196 . E8 66000000 CALL 00401201 ; 跟进这个CALL,关键算法,可以用于做注册机
=============================
00401202 |. 8BEC MOV EBP,ESP
00401204 |. 8B75 08 MOV ESI,DWORD PTR SS:[EBP+8] ; 注册码入ESI
00401207 |> 803E 00 /CMP BYTE PTR DS:[ESI],0
0040120A |. 74 0C |JE 00401218
0040120C |. 8A06 |MOV AL,BYTE PTR DS:[ESI] ; 逐个取注册码ASCII
0040120E |. 34 41 |XOR AL,41 ; 异或41H
00401210 |. C0C0 03 |ROL AL,3 ; 循环左移3
00401213 |. 8806 |MOV BYTE PTR DS:[ESI],AL ; 放回DS:[ESI],循环完后这个段寄存器中放着最终的结果
00401215 |. 46 |INC ESI ; ESI累加
00401216 |.^ EB EF \JMP 00401207
00401218 |> E8 24000000 CALL 00401241
00401218 |> \E8 24000000 CALL 00401241
0040121D |. C9 LEAVE
0040121E \. C2 0400 RETN 4 ; 返回
================================
0040119B . B8 05000000 MOV EAX,5 ; EAX赋值5
004011A0 . F625 40324000 MUL BYTE PTR DS:[403240] ; 乘DS:[403240]的值,这个值为4才是对的,如果有断点这里是0
004011A6 . BE 68324000 MOV ESI,00403268 ; 正确的值放到ESI
004011AB . BF 75114000 MOV EDI,00401175 ; 刚才计算的结果
004011B0 . 03F8 ADD EDI,EAX ; 关键就在EAX的值,EAX=14H是对的
00401175 [00] 6A 14 6A 0D 68 EA 03 00 00 FF 75 08 E8 49 01 .jj.h?..?枭
00401185 00 00 EB 08 [91] 71 39 A9 41 11 21 03 68 68 32 40 ..??9┝!hh2@
这里的00401175处的00跟401189处的91正好差14H。
004011B2 . B9 09000000 MOV ECX,9 ; ECX=9
004011B7 > 49 DEC ECX ; ECX=ECX-1.
004011B8 . AC LODS BYTE PTR DS:[ESI] ; 这就是最终的结果
004011B9 . AE SCAS BYTE PTR ES:[EDI] ; 与ES:[EDI]地址放的结果对比
004011BA .^ 74 FB JE 004011B7 ; 如果相等就循环判断下一位
004011BC . 0BC9 OR ECX,ECX
004011BE . 74 21 JE 004011E1 ; 必须要跳,也就是循环8次后最终要相等
004011C0 . BF B6314000 MOV EDI,004031B6
004011C5 > BE DA314000 MOV ESI,004031DA
004011CA . 47 INC EDI
004011CB . 46 INC ESI
004011CC . B8 C9124000 MOV EAX,004012C9
004011D1 . 40 INC EAX
004011D2 . 6A 10 PUSH 10 ; /Style = MB_OK|MB_ICONHAND|MB_APPLMODAL
004011D4 . 56 PUSH ESI ; |Title => "Wrong Serial"
004011D5 . 57 PUSH EDI ; |Text
004011D6 . FF75 08 PUSH DWORD PTR SS:[EBP+8] ; |hOwner
004011D9 . FFD0 CALL EAX ; \MessageBoxA
004011DB . C9 LEAVE
004011DC . C2 0400 RETN 4
004011DF . EB 20 JMP 00401201
004011E1 > BF E7314000 MOV EDI,004031E7
004011E6 . BE 32324000 MOV ESI,00403232
004011EB . 47 INC EDI
004011EC . 46 INC ESI
004011ED . 90 NOP
004011EE . B8 C9124000 MOV EAX,04012C9
004011F3 . 40 INC EAX
004011F4 . 6A 40 PUSH 40 ; /Style = MB_OK|MB_ICONASTERISK|MB_APPLMODAL
004011F6 . 56 PUSH ESI ; |Title => "Right Serial"
004011F7 . 57 PUSH EDI ; |Text => "You've Done it. Write a tutorial and send it to fornix@fusionrulez.cjb.net"
004011F8 . FF75 08 PUSH DWORD PTR SS:[EBP+8] ; |hOwner
004011FB . FFD0 CALL EAX ; \MessageBoxA
004011FD . C9 LEAVE
004011FE . C2 0400 RETN 4
关键在下面这处:
004011B9 . AE SCAS BYTE PTR ES:[EDI] ; 这里的ES:[EDI]内存地址
假如检测到CC,这里的内存地址就变成这里:
00401175 00 6A 14 6A 0D 68 EA 03 00 00 FF 75 08 E8 49 01 .jj.h?..?枭
而真正的地址应该在这里:
00401189 91 71 39 A9 41 11 21 03 68 68 32 40 00 E8 66 00 ?9┝!hh2@.桄.
--------------------------------------------------------------------------------
【经验总结】
那逆推注册码应该很简单了,直接将原来的那段变形代码逆向一下嵌入高级语言:
function cacl(str: Byte): String;
var
a:Byte;
b:Byte;
s:string;
begin
a:= str;
asm
xor eax,eax
mov al,a
ror al,3
xor al,$41
mov b,al
end;
s:=chr(b);
Result := s;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
Edit1.Text:=cacl($91)+cacl($71)+cacl($39)+cacl($A9)+cacl($41)+cacl($11)+cacl($21)+cacl($03);
end;
end.
算出的注册码为softice!,作者还虚幻一招,用了假注册码fuckolly。
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!
2006年08月27日
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课