首页 > 代码库 > [反汇编练习] 160个CrackMe之032
[反汇编练习] 160个CrackMe之032
[反汇编练习] 160个CrackMe之032.
本系列文章的目的是从一个没有任何经验的新手的角度(其实就是我自己),一步步尝试将160个CrackMe全部破解,如果可以,通过任何方式写出一个类似于注册机的东西。
其中,文章中按照如下逻辑编排(解决如下问题):
1、使用什么环境和工具
2、程序分析
3、思路分析和破解流程
4、注册机的探索
----------------------------------
提醒各位看客: 如果文章中的逻辑看不明白,那你一定是没有亲手操刀!OD中的跳转提示很强大,只要你跟踪了,不用怎么看代码就理解了!
----------------------------------
1、工具和环境:
WinXP SP3 + 52Pojie六周年纪念版OD + PEID + 汇编金手指。
160个CrackMe的打包文件。
下载地址: http://pan.baidu.com/s/1xUWOY 密码: jbnq
注:
1、Win7系统对于模块和程序开启了随机初始地址的功能,会给分析带来很大的负担,所以不建议使用Win7进行分析。
2、以上工具都是在52PoJie论坛下的原版程序,NOD32不报毒,个人承诺绝对不会进行任何和木马病毒相关内容。
2、程序分析:
想要破解一个程序,必须先了解这个程序。所以,在破解过程中,对最初程序的分析很重要,他可以帮助我们理解作者的目的和意图,特别是对于注册码的处理细节,从而方便我们反向跟踪和推导。
和上一节一样,打开CHM,选择第32个crackme.2.exe,保存下来。运行程序,程序界面如下:
xxxxxx
直接信息框提示没有注册文件!晕啊!
使用PEID看看:
还好,只是一个UPX的壳,直接使用【->】按钮里面的通用脱壳工具脱了!
得到 crackme.2.unpacked.exe,再用PEID看看:Borland Delphi 3.0
我去,又是Delphi的,坑人啊!
3、思路分析和破解流程
不用多想,直接上IDR吧:
窗口中的入口信息:
EntryPoint 004383DC push ebp 004383DD mov ebp,esp 004383DF add esp,0FFFFFFF4 004383E2 mov eax,4382E4 004383E7 call @InitExe 004383EC mov edx,438498; ‘Reg.dat‘ 004383F1 mov eax,43A760 004383F6 call @Assign 004383FB mov edx,80 00438400 mov eax,43A760 00438405 call @ResetFile 0043840A call IOResult 0043840F test eax,eax>00438411 je 00438428 00438413 push 0 00438415 push 4384A0; ‘Missing!‘ 0043841A push 4384AC; ‘Hey, where is my little Reg.dat\rI love it so much that I can‘t\rlive without it. Return it back! Arrgh!‘ 0043841F push 0 00438421 call USER32.MessageBoxA>00438426 jmp 00438488 00438428 mov eax,[00439A90]; ^Application:TApplication 0043842D mov eax,dword ptr [eax] 0043842F call TApplication.Initialize 00438434 mov ecx,dword ptr ds:[439B0C]; ^gvar_0043A758:TForm1 0043843A mov eax,[00439A90]; ^Application:TApplication 0043843F mov eax,dword ptr [eax] 00438441 mov edx,dword ptr ds:[4380C8]; TForm1 00438447 call TApplication.CreateForm 0043844C mov ecx,dword ptr ds:[439B20]; ^gvar_0043A728:TForm2 00438452 mov eax,[00439A90]; ^Application:TApplication 00438457 mov eax,dword ptr [eax] 00438459 mov edx,dword ptr ds:[4379C0]; TForm2 0043845F call TApplication.CreateForm 00438464 mov ecx,dword ptr ds:[439A6C]; ^gvar_0043A750:TForm3 0043846A mov eax,[00439A90]; ^Application:TApplication 0043846F mov eax,dword ptr [eax] 00438471 mov edx,dword ptr ds:[437F38]; TForm3 00438477 call TApplication.CreateForm 0043847C mov eax,[00439A90]; ^Application:TApplication 00438481 mov eax,dword ptr [eax] 00438483 call TApplication.Run 00438488 call @Halt0
它用来判断是否存在一个叫做Reg.dat的文件,不存在就弹窗,然后退出!好吧,我们在目录下建一个Reg.dat的空文件!
运行:
在IDR中发现,Reg模块才是我们注册的这个窗口:
由于OK按钮被禁用了,所以他肯定是当文本发生变化时计算的,我们找到TForm2.EditxChange一共4个事件,进去看看吧:
Reg::TForm2.Edit1Change 00437E70 mov eax,1 00437E75 call 00437D1C 00437E7A ret Reg::TForm2.Edit1Change 00437E70 mov eax,1 00437E75 call 00437D1C 00437E7A ret
内部调用了Call 00437D1C,相当于是参数为eax,函数为00437D1C。看看这个Call的内容:
Reg::sub_00437D1C 00437D1C push ebp 00437D1D mov ebp,esp 00437D1F push 0 00437D21 push ebx 00437D22 mov ebx,eax 00437D24 xor eax,eax 00437D26 push ebp 00437D27 push 437DEE 00437D2C push dword ptr fs:[eax] 00437D2F mov dword ptr fs:[eax],esp 00437D32 mov eax,ebx 00437D34 dec eax>00437D35 je 00437D45 00437D37 dec eax>00437D38 je 00437D69 00437D3A dec eax>00437D3B je 00437D8D 00437D3D dec eax>00437D3E je 00437DB1>00437D40 jmp 00437DD3 00437D45 lea edx,[ebp-4] 00437D48 mov eax,[0043A728]; 0x0 gvar_0043A728:TForm2 00437D4D mov eax,dword ptr [eax+1E8]; TForm2.Edit1:TEdit 00437D53 call TControl.GetText 00437D58 mov eax,dword ptr [ebp-4] 00437D5B call StrToInt 00437D60 mov dword ptr [ebx*4+43A738],eax; gvar_0043A738:Integer>00437D67 jmp 00437DD3 00437D69 lea edx,[ebp-4] 00437D6C mov eax,[0043A728]; 0x0 gvar_0043A728:TForm2 00437D71 mov eax,dword ptr [eax+1EC]; TForm2.Edit2:TEdit 00437D77 call TControl.GetText 00437D7C mov eax,dword ptr [ebp-4] 00437D7F call StrToInt 00437D84 mov dword ptr [ebx*4+43A738],eax; gvar_0043A738:Integer>00437D8B jmp 00437DD3 00437D8D lea edx,[ebp-4] 00437D90 mov eax,[0043A728]; 0x0 gvar_0043A728:TForm2 00437D95 mov eax,dword ptr [eax+1F0]; TForm2.Edit3:TEdit 00437D9B call TControl.GetText 00437DA0 mov eax,dword ptr [ebp-4] 00437DA3 call StrToInt 00437DA8 mov dword ptr [ebx*4+43A738],eax; gvar_0043A738:Integer>00437DAF jmp 00437DD3 00437DB1 lea edx,[ebp-4] 00437DB4 mov eax,[0043A728]; 0x0 gvar_0043A728:TForm2 00437DB9 mov eax,dword ptr [eax+1F4]; TForm2.Edit4:TEdit 00437DBF call TControl.GetText 00437DC4 mov eax,dword ptr [ebp-4] 00437DC7 call StrToInt 00437DCC mov dword ptr [ebx*4+43A738],eax; gvar_0043A738:Integer 00437DD3 call 00437BD8 00437DD8 xor eax,eax 00437DDA pop edx 00437DDB pop ecx 00437DDC pop ecx 00437DDD mov dword ptr fs:[eax],edx 00437DE0 push 437DF5 00437DE5 lea eax,[ebp-4] 00437DE8 call @LStrClr 00437DED ret<00437DEE jmp @HandleFinally<00437DF3 jmp 00437DE5 00437DF5 pop ebx 00437DF6 pop ecx 00437DF7 pop ebp 00437DF8 ret
在OD中,从开头地址 00437D1C 跟踪分析:
00437D1C 55 push ebp ; // Serial数字发生变化时调用00437D1D 8BEC mov ebp,esp00437D1F 6A 00 push 0x000437D21 53 push ebx00437D22 8BD8 mov ebx,eax ; // eax 传过来的参数,1-400437D24 33C0 xor eax,eax00437D26 55 push ebp00437D27 68 EE7D4300 push 00437DEE00437D2C 64:FF30 push dword ptr fs:[eax]00437D2F 64:8920 mov dword ptr fs:[eax],esp00437D32 8BC3 mov eax,ebx00437D34 48 dec eax00437D35 74 0E je short 00437D45 ; 100437D37 48 dec eax00437D38 74 2F je short 00437D69 ; 200437D3A 48 dec eax00437D3B 74 50 je short 00437D8D ; 300437D3D 48 dec eax00437D3E 74 71 je short 00437DB1 ; 400437D40 E9 8E000000 jmp 00437DD300437D45 8D55 FC lea edx,dword ptr ss:[ebp-0x4] ; // 1的处理00437D48 A1 28A74300 mov eax,dword ptr ds:[0x43A728] ; 0x0 gvar_0043A728:TForm200437D4D 8B80 E8010000 mov eax,dword ptr ds:[eax+0x1E8] ; TForm2.Edit1:TEdit00437D53 E8 6854FEFF call 0041D1C0 ; TControl.GetText00437D58 8B45 FC mov eax,dword ptr ss:[ebp-0x4]00437D5B E8 D0EBFCFF call 00406930 ; StrToInt00437D60 89049D 38A74300 mov dword ptr ds:[ebx*4+0x43A738],eax ; gvar_0043A738:Integer00437D67 EB 6A jmp short 00437DD300437D69 8D55 FC lea edx,dword ptr ss:[ebp-0x4] ; // 2的处理00437D6C A1 28A74300 mov eax,dword ptr ds:[0x43A728]00437D71 8B80 EC010000 mov eax,dword ptr ds:[eax+0x1EC] ; TForm2.Edit2:TEdit00437D77 E8 4454FEFF call 0041D1C000437D7C 8B45 FC mov eax,dword ptr ss:[ebp-0x4]00437D7F E8 ACEBFCFF call 0040693000437D84 89049D 38A74300 mov dword ptr ds:[ebx*4+0x43A738],eax00437D8B EB 46 jmp short 00437DD300437D8D 8D55 FC lea edx,dword ptr ss:[ebp-0x4] ; // 3的处理00437D90 A1 28A74300 mov eax,dword ptr ds:[0x43A728]00437D95 8B80 F0010000 mov eax,dword ptr ds:[eax+0x1F0] ; TForm2.Edit3:TEdit00437D9B E8 2054FEFF call 0041D1C000437DA0 8B45 FC mov eax,dword ptr ss:[ebp-0x4]00437DA3 E8 88EBFCFF call 0040693000437DA8 89049D 38A74300 mov dword ptr ds:[ebx*4+0x43A738],eax00437DAF EB 22 jmp short 00437DD300437DB1 8D55 FC lea edx,dword ptr ss:[ebp-0x4] ; // 4的处理00437DB4 A1 28A74300 mov eax,dword ptr ds:[0x43A728]00437DB9 8B80 F4010000 mov eax,dword ptr ds:[eax+0x1F4] ; TForm2.Edit4:TEdit00437DBF E8 FC53FEFF call 0041D1C000437DC4 8B45 FC mov eax,dword ptr ss:[ebp-0x4]00437DC7 E8 64EBFCFF call 0040693000437DCC 89049D 38A74300 mov dword ptr ds:[ebx*4+0x43A738],eax00437DD3 E8 00FEFFFF call 00437BD8 ; // 这里是另外一个关键Call00437DD8 33C0 xor eax,eax00437DDA 5A pop edx00437DDB 59 pop ecx00437DDC 59 pop ecx00437DDD 64:8910 mov dword ptr fs:[eax],edx00437DE0 68 F57D4300 push 00437DF500437DE5 8D45 FC lea eax,dword ptr ss:[ebp-0x4]00437DE8 E8 0FB9FCFF call 004036FC ; @LStrClr
这个Call没有进行计算,主要功能就是获取编辑框文本,然后转化为整数,存起来(存放的地址很特殊,如果不注意,后面注册码就悲剧了!)。
最后,这个Call又调用了另外一个Call:
IDR中查看:
Reg::sub_00437BD8 00437BD8 push ebp 00437BD9 mov ebp,esp 00437BDB push 0 00437BDD push 0 00437BDF push ebx 00437BE0 push esi 00437BE1 xor eax,eax 00437BE3 push ebp 00437BE4 push 437D0C 00437BE9 push dword ptr fs:[eax] 00437BEC mov dword ptr fs:[eax],esp 00437BEF lea edx,[ebp-4] 00437BF2 mov eax,[0043A728]; 0x0 gvar_0043A728:TForm2 00437BF7 mov eax,dword ptr [eax+20C]; TForm2.Edit5:TEdit 00437BFD call TControl.GetText 00437C02 mov eax,dword ptr [ebp-4] 00437C05 call @LStrLen 00437C0A cmp eax,5>00437C0D jl 00437CC2 00437C13 mov eax,dword ptr [ebp-4] 00437C16 movzx eax,byte ptr [eax] 00437C19 mov ecx,0A 00437C1E cdq 00437C1F idiv eax,ecx 00437C21 mov [0043A72C],eax; gvar_0043A72C:Integer 00437C26 mov eax,dword ptr [ebp-4] 00437C29 movzx eax,byte ptr [eax+2] 00437C2D mov ecx,0A 00437C32 cdq 00437C33 idiv eax,ecx 00437C35 mov [0043A730],eax; gvar_0043A730:Integer 00437C3A mov eax,dword ptr [ebp-4] 00437C3D movzx eax,byte ptr [eax+3] 00437C41 mov ecx,0A 00437C46 cdq 00437C47 idiv eax,ecx 00437C49 mov [0043A734],eax; gvar_0043A734:Integer 00437C4E mov eax,dword ptr [ebp-4] 00437C51 movzx eax,byte ptr [eax+4] 00437C55 mov ecx,0A 00437C5A cdq 00437C5B idiv eax,ecx 00437C5D mov [0043A738],eax; gvar_0043A738:Integer 00437C62 mov esi,1 00437C67 mov ebx,43A72C; gvar_0043A72C:Integer 00437C6C lea edx,[ebp-8] 00437C6F mov eax,dword ptr [ebx] 00437C71 call IntToStr 00437C76 mov eax,dword ptr [ebp-8] 00437C79 call @LStrLen 00437C7E dec eax>00437C7F je 00437C8D 00437C81 mov eax,dword ptr [ebx] 00437C83 mov ecx,0A 00437C88 cdq 00437C89 idiv eax,ecx 00437C8B mov dword ptr [ebx],eax 00437C8D inc esi 00437C8E add ebx,4 00437C91 cmp esi,5<00437C94 jne 00437C6C 00437C96 mov esi,1 00437C9B mov eax,43A72C; gvar_0043A72C:Integer 00437CA0 mov edx,43A73C 00437CA5 mov ecx,dword ptr [edx] 00437CA7 cmp ecx,dword ptr [eax]>00437CA9 je 00437CB2 00437CAB mov ecx,1>00437CB0 jmp 00437CC7 00437CB2 xor ecx,ecx 00437CB4 inc esi 00437CB5 add edx,4 00437CB8 add eax,4 00437CBB cmp esi,5<00437CBE jne 00437CA5>00437CC0 jmp 00437CC7 00437CC2 mov ecx,1 00437CC7 test ecx,ecx>00437CC9 jne 00437CDF 00437CCB mov eax,[0043A728]; 0x0 gvar_0043A728:TForm2 00437CD0 mov eax,dword ptr [eax+1E0]; TForm2.Button1:TButton 00437CD6 mov dl,1 00437CD8 call TControl.SetEnabled>00437CDD jmp 00437CF1 00437CDF mov eax,[0043A728]; 0x0 gvar_0043A728:TForm2 00437CE4 mov eax,dword ptr [eax+1E0]; TForm2.Button1:TButton 00437CEA xor edx,edx 00437CEC call TControl.SetEnabled 00437CF1 xor eax,eax 00437CF3 pop edx 00437CF4 pop ecx 00437CF5 pop ecx 00437CF6 mov dword ptr fs:[eax],edx 00437CF9 push 437D13 00437CFE lea eax,[ebp-8] 00437D01 mov edx,2 00437D06 call @LStrArrayClr 00437D0B ret<00437D0C jmp @HandleFinally<00437D11 jmp 00437CFE 00437D13 pop esi 00437D14 pop ebx 00437D15 pop ecx 00437D16 pop ecx 00437D17 pop ebp 00437D18 ret
OD中跟踪调试:
00437BD8 55 push ebp ; // 处理数据的Call00437BD9 8BEC mov ebp,esp00437BDB 6A 00 push 0x000437BDD 6A 00 push 0x000437BDF 53 push ebx00437BE0 56 push esi00437BE1 33C0 xor eax,eax00437BE3 55 push ebp00437BE4 68 0C7D4300 push 00437D0C00437BE9 64:FF30 push dword ptr fs:[eax]00437BEC 64:8920 mov dword ptr fs:[eax],esp00437BEF 8D55 FC lea edx,dword ptr ss:[ebp-0x4]00437BF2 A1 28A74300 mov eax,dword ptr ds:[0x43A728] ; 0x0 gvar_0043A728:TForm200437BF7 8B80 0C020000 mov eax,dword ptr ds:[eax+0x20C] ; TForm2.Edit5:TEdit00437BFD E8 BE55FEFF call 0041D1C0 ; TControl.GetText00437C02 8B45 FC mov eax,dword ptr ss:[ebp-0x4]00437C05 E8 6EBDFCFF call 00403978 ; @LStrLen00437C0A 83F8 05 cmp eax,0x5 ; // 与5做比较,不能小于500437C0D 0F8C AF000000 jl 00437CC2 ; // 小于5失败00437C13 8B45 FC mov eax,dword ptr ss:[ebp-0x4]00437C16 0FB600 movzx eax,byte ptr ds:[eax] ; // "bbdxf"00437C19 B9 0A000000 mov ecx,0xA00437C1E 99 cdq ; // edx = 000437C1F F7F9 idiv ecx ; // 除法, eax/ecx, 余数=ebx,结果=eax00437C21 A3 2CA74300 mov dword ptr ds:[0x43A72C],eax ; gvar_0043A72C:Integer00437C26 8B45 FC mov eax,dword ptr ss:[ebp-0x4]00437C29 0FB640 02 movzx eax,byte ptr ds:[eax+0x2] ; // 序号为2的字符00437C2D B9 0A000000 mov ecx,0xA00437C32 99 cdq00437C33 F7F9 idiv ecx ; // 除法00437C35 A3 30A74300 mov dword ptr ds:[0x43A730],eax ; gvar_0043A730:Integer00437C3A 8B45 FC mov eax,dword ptr ss:[ebp-0x4]00437C3D 0FB640 03 movzx eax,byte ptr ds:[eax+0x3] ; // 序号为3的字符00437C41 B9 0A000000 mov ecx,0xA00437C46 99 cdq00437C47 F7F9 idiv ecx ; // 除法00437C49 A3 34A74300 mov dword ptr ds:[0x43A734],eax ; gvar_0043A734:Integer00437C4E 8B45 FC mov eax,dword ptr ss:[ebp-0x4]00437C51 0FB640 04 movzx eax,byte ptr ds:[eax+0x4] ; // 序号为4的字符00437C55 B9 0A000000 mov ecx,0xA00437C5A 99 cdq00437C5B F7F9 idiv ecx ; // 除法00437C5D A3 38A74300 mov dword ptr ds:[0x43A738],eax ; gvar_0043A738:Integer00437C62 BE 01000000 mov esi,0x100437C67 BB 2CA74300 mov ebx,0043A72C ; gvar_0043A72C:Integer00437C6C 8D55 F8 lea edx,dword ptr ss:[ebp-0x8]00437C6F 8B03 mov eax,dword ptr ds:[ebx] ; // ebx=第一个余数的地址,递增+4,去下一个整数00437C71 E8 8AECFCFF call 00406900 ; IntToStr00437C76 8B45 F8 mov eax,dword ptr ss:[ebp-0x8] ; "9" "10"...00437C79 E8 FABCFCFF call 00403978 ; @LStrLen00437C7E 48 dec eax00437C7F 74 0C je short 00437C8D ; // 长度为1则跳转00437C81 8B03 mov eax,dword ptr ds:[ebx]00437C83 B9 0A000000 mov ecx,0xA00437C88 99 cdq00437C89 F7F9 idiv ecx ; // 除法00437C8B 8903 mov dword ptr ds:[ebx],eax ; // 将余数写回去00437C8D 46 inc esi00437C8E 83C3 04 add ebx,0x400437C91 83FE 05 cmp esi,0x500437C94 ^ 75 D6 jnz short 00437C6C ; // 处理之后,所有的余数都小于1000437C96 BE 01000000 mov esi,0x100437C9B B8 2CA74300 mov eax,0043A72C ; gvar_0043A72C:Integer00437CA0 BA 3CA74300 mov edx,0043A73C ; //---这个地址是Edit1-Edit4的整数值存放地址00437CA5 8B0A mov ecx,dword ptr ds:[edx] ; // ecx = 100437CA7 3B08 cmp ecx,dword ptr ds:[eax]00437CA9 74 07 je short 00437CB200437CAB B9 01000000 mov ecx,0x100437CB0 EB 15 jmp short 00437CC7 ; // 跳过去了00437CB2 33C9 xor ecx,ecx00437CB4 46 inc esi00437CB5 83C2 04 add edx,0x400437CB8 83C0 04 add eax,0x400437CBB 83FE 05 cmp esi,0x500437CBE ^ 75 E5 jnz short 00437CA500437CC0 EB 05 jmp short 00437CC700437CC2 B9 01000000 mov ecx,0x100437CC7 85C9 test ecx,ecx ; // 测试ecx的值00437CC9 75 14 jnz short 00437CDF ; // 关键跳转00437CCB A1 28A74300 mov eax,dword ptr ds:[0x43A728] ; 0x0 gvar_0043A728:TForm200437CD0 8B80 E0010000 mov eax,dword ptr ds:[eax+0x1E0] ; TForm2.Button1:TButton00437CD6 B2 01 mov dl,0x100437CD8 E8 7B54FEFF call 0041D158 ; TControl.SetEnabled00437CDD EB 12 jmp short 00437CF100437CDF A1 28A74300 mov eax,dword ptr ds:[0x43A728]00437CE4 8B80 E0010000 mov eax,dword ptr ds:[eax+0x1E0]00437CEA 33D2 xor edx,edx00437CEC E8 6754FEFF call 0041D158 ; TControl.SetEnabled00437CF1 33C0 xor eax,eax00437CF3 5A pop edx00437CF4 59 pop ecx00437CF5 59 pop ecx00437CF6 64:8910 mov dword ptr fs:[eax],edx00437CF9 68 137D4300 push 00437D1300437CFE 8D45 F8 lea eax,dword ptr ss:[ebp-0x8]00437D01 BA 02000000 mov edx,0x200437D06 E8 15BAFCFF call 00403720 ; @LStrArrayClr00437D0B C3 retn
首先,只有Name的第1、3、4、5这四个字符有用,Name长度不小于5就可以了。
然后,四个Edit里面的数字是1、3、4、5字符对应的ANSII码值除以10的整数商,如果商大于10,则继续除以10。商的结果放在0043A72C开头的四个int里面。
最后,循环比较0043A72C和0043A73C为开头的4个int值,如果相等,则通过。
等等,地址 0043A73C 地址处的值是从哪里来的呢?上下翻阅,也终究没找到,但是查看他们的值发现,他就是4个编辑框的值,即四个编辑框的整数值存放在地址0043A73C开头的4个int里面。还记得前面分析编辑框事件吗?看看那里,就是修改这个地址的值啊!
好啦,都弄明白了,可以进行注册机了!
// CrackMeDemo.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include <iostream>int _tmain(int argc, _TCHAR* argv[]){ char pName[] = "bbdxf"; char pNum[4] = {0}; pNum[0] = pName[0] / 0x0A; pNum[1] = pName[2] / 0x0A; pNum[2] = pName[3] / 0x0A; pNum[3] = pName[4] / 0x0A; for ( int i=0;i<4;i++) { if ( pNum[i]>=0x0A ) // 程序中是通过转为字符串,判断字符串长度 { pNum[i] = pNum[i]/0x0A; } } printf("Num: %d - %d - %d - %d\r\n",pNum[0],pNum[1],pNum[2],pNum[3]); system("pause"); return 0;}
pName设置为输入的Name,计算后的四个数字则为4个编辑框对应的内容!
BY 笨笨D幸福