经过一段时间的逆向学习,决定实际破解一款共享软件,检验自己的逆向水平,最终决定以某大辞典豪华版V3.6试刀。
本文分为两部分,爆破和算法分析
第一部分:暴力破解
首先通过peid进行查壳:
结果显示是delphi编写的程序,尝试过各种查找敏感词的方法一无所获,那就只能祭出逆向dephi的神器DeDeDark,深入剖析,看看这个程序到底是什么鬼。
通过DeDeDark经过一番探查,最后定位到了0x754574处的regzhc
为了验证初步判断是否正确,使用OD进行动态调试,在0x754574打断点,任意输入错误序列号:111111111111111111,点击注册,OD成功断在了0x754574!说明初步判断函数成功:
进一步动态跟进,寻找关键的条件判断代码,尝试初级的爆破。F8单步跟进,在0x754338处观察堆栈窗口,赫然发现“注册失败”等字样,似乎看到了成功的曙光:
向上分析,定位到最近的跳转位置0x75420C,在0x75420C打断点,OD重新运行,在断点处将jnz指令直接nop,F9运行看看效果:
注册成功!
但是这只是成功第一步,仅仅爆破也太LOW,分析一下算法,写出注册机才是cracker的至高追求。
第二部分:算法分析
使用IDA和OD结合分析以后,主要的验证机制的详细分析就不给出了,核心 函数仍然是
0x754574:
00754574 /$ 55 push ebp
00754575 |. 8BEC mov ebp,esp
00754577 |. 83C4 DC add esp,-0x24
0075457A |. 53 push ebx
0075457B |. 56 push esi
0075457C |. 57 push edi
0075457D |. 33C9 xor ecx,ecx
0075457F |. 894D EC mov [local.5],ecx
00754582 |. 894D F8 mov [local.2],ecx
00754585 |. 894D F4 mov [local.3],ecx
00754588 |. 894D F0 mov [local.4],ecx
0075458B |. 8955 FC mov [local.1],edx ; [local.1]储存输入的密码
0075458E |. 8B45 FC mov eax,[local.1]
00754591 |. E8 960ECBFF call 0040542C
00754596 |. 33C0 xor eax,eax
00754598 |. 55 push ebp
00754599 |. 68 CA467500 push 007546CA
0075459E |. 64:FF30 push dword ptr fs:[eax]
007545A1 |. 64:8920 mov dword ptr fs:[eax],esp
007545A4 |. 8B45 FC mov eax,[local.1]
007545A7 |. 85C0 test eax,eax
007545A9 |. 74 05 je short 007545B0
007545AB |. 83E8 04 sub eax,0x4
007545AE |. 8B00 mov eax,dword ptr ds:[eax]
007545B0 |> 8BF0 mov esi,eax
007545B2 |. BA 50000000 mov edx,0x50
007545B7 |. B8 1E000000 mov eax,0x1E
007545BC |. E8 939ECDFF call 0042E454
007545C1 |. 8BF8 mov edi,eax
007545C3 |. 83FE 14 cmp esi,0x14
007545C6 |. 75 18 jnz short 007545E0
007545C8 |. 8D45 F0 lea eax,[local.4]
007545CB |. 8B15 14BC7800 mov edx,dword ptr ds:[0x78BC14] ; 给力大辞.007948B8
007545D1 |. 8B12 mov edx,dword ptr ds:[edx]
007545D3 |. 8B92 DC050000 mov edx,dword ptr ds:[edx+0x5DC]
007545D9 |. E8 560ACBFF call 00405034
007545DE |. EB 16 jmp short 007545F6
007545E0 |> 8D45 F0 lea eax,[local.4]
007545E3 |. 8B15 14BC7800 mov edx,dword ptr ds:[0x78BC14] ; 给力大辞.007948B8
007545E9 |. 8B12 mov edx,dword ptr ds:[edx]
007545EB |. 8B92 D8050000 mov edx,dword ptr ds:[edx+0x5D8]
007545F1 |. E8 3E0ACBFF call 00405034 ;得到机器码,例如笔者机器码:ED2B0E8B48821A060A
007545F6 |> 8D45 EC lea eax,[local.5]
007545F9 |. 50 push eax
007545FA |. B9 08000000 mov ecx,0x8
007545FF |. BA 06000000 mov edx,0x6
00754604 |. 8B45 F0 mov eax,[local.4]
00754607 |. E8 980ECBFF call 004054A4 ;机器码截取:从第6个开始截取8个字符,例如:E8B48821
0075460C |. FF75 EC push [local.5]
0075460F |. FF75 F0 push [local.4]
00754612 |. 68 E4467500 push 007546E4
00754617 |. 8D45 F8 lea eax,[local.2]
0075461A |. BA 03000000 mov edx,0x3
0075461F |. E8 1C0DCBFF call 00405340 ;上述截取的字符串+机器码+phpshao,组成新的字符串,例如 E8B48821ED2B0E8B48821A060Aphpshao
00754624 |. B2 01 mov dl,0x1
00754626 |. A1 243F7500 mov eax,dword ptr ds:[0x753F24]
0075462B |. E8 1CF9CAFF call 00403F4C
00754630 |. 8BD8 mov ebx,eax
00754632 |. 8D4D DC lea ecx,[local.9]
00754635 |. 8B55 F8 mov edx,[local.2]
00754638 |. 8BC3 mov eax,ebx
0075463A |. E8 5D3ADEFF call 0053809C ;对新生成的字符串进行md5加密
0075463F |. 8D55 DC lea edx,[local.9]
00754642 |. 8D4D F4 lea ecx,[local.3]
00754645 |. 8B03 mov eax,dword ptr ds:[ebx]
00754647 |. E8 C83ADEFF call 00538114
0075464C |. 8BC3 mov eax,ebx
0075464E |. E8 29F9CAFF call 00403F7C
00754653 |. 83FE 14 cmp esi,0x14
00754656 |. 75 18 jnz short 00754670
00754658 |. 8D45 F4 lea eax,[local.3]
0075465B |. 50 push eax
0075465C |. B9 14000000 mov ecx,0x14
00754661 |. BA 03000000 mov edx,0x3
00754666 |. 8B45 F4 mov eax,[local.3]
00754669 |. E8 360ECBFF call 004054A4 ; 截取md5加密结果,从第三个字符开始,如果输入的密码长度为20,则截取20个字符长度,否则截取18个
0075466E |. EB 16 jmp short 00754686
00754670 |> 8D45 F4 lea eax,[local.3]
00754673 |. 50 push eax
00754674 |. B9 12000000 mov ecx,0x12
00754679 |. BA 03000000 mov edx,0x3
0075467E |. 8B45 F4 mov eax,[local.3]
00754681 |. E8 1E0ECBFF call 004054A4
00754686 |> 8B45 F4 mov eax,[local.3]
00754689 |. 8B55 FC mov edx,[local.1]
0075468C |. E8 430DCBFF call 004053D4 ;对比输入的密码和上述截取的真实注册码是否相同
….
007546C9 \. C3 retn
分析出了算法具体流程,很容易利用python写出注册机,直接上代码:
# -*- coding:utf-8 -*
import sys,os
import hashlib
import os
def md5(str):
m = hashlib.md5()
m.update(str)
return m.hexdigest()
if __name__ == '__main__':
if len(sys.argv)==2:
machinecode = sys.argv[1]
print "machinecode is " + str(machinecode)
print "generating register code:"
addcode = "phpshao"
newcode = machinecode[5:13]+machinecode+addcode
result = md5(newcode)
print "register code is :" + str(result[2:20].upper() )
else:
print "no machine code!"
脚本运行结果:
get it!
敬请各路大神吐槽~
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课