【文章标题】: 新手补给之爆破1
【文章作者】: rocktx
【软件名称】: WinZip v12.1
【软件大小】: 13M
【下载地址】: 自己搜索下载
【使用工具】: OD
【操作平台】: Win2K/XP
【软件介绍】: 外星人都知道
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
其实本来不想发爆破的文章,总觉得不太合适,但算法又没功夫死磕,所以还是放出来,给新手参考之用,破解重在思路,成在执着,本文旨在探究一些在对程序一无所知的情况下深入核心算法验证代码的一般方法;
注:使用爆破一词,纯粹属于个人喜好,不是书写错误
破解步骤:
1、粗跟
OD载入,运行程序,输入注册信息:
name:rocktx
code:123456789
然后点确定,跳出错误提示,暂停程序,Alt+K查看调用堆栈:
调用堆栈
地址 堆栈 函数例程 / 参数 调用来自 框架
0013EF68 7E419418 包含 ntdll.KiFastSystemCallRet USER32.WaitMessage+0A 0013EF9C
0013EF6C 7E42DBA8 USER32.WaitMessage USER32.7E42DBA3 0013EF9C
0013EFA0 7E42593F USER32.7E42DA19 USER32.7E42593A 0013EF9C
0013EFC8 7E43A91E USER32.7E425889 USER32.7E43A919 0013EFC4
0013F288 7E43A284 USER32.SoftModalMessageBox USER32.7E43A27F 0013F284
0013F3D8 7E466301 USER32.7E43A10F USER32.7E4662FC 0013F3D4
0013F430 00495161 USER32.MessageBoxIndirectW WINZIP32.0049515B 0013F42C
0013F434 0013F44C pMsgBoxParams = 0013F44C
0013F490 00495954 ? WINZIP32.004950BC WINZIP32.0049594F 0013F48C
0013F4D4 00495FEE ? WINZIP32.004958DA WINZIP32.00495FE9 0013F4D0
0013F4EC 0040E891 WINZIP32.00495FDB WINZIP32.0040E88C 0013F4E8
0013F544 004045EA ? WINZIP32.0040E446 WINZIP32.004045E5 0013F540
双击 WINZIP32.0040E446 来到
0040E446 /$ 6A 28 push 28
0040E448 |. B8 8F075800 mov eax,WINZIP32.0058078F
0040E44D |. E8 C6B80F00 call WINZIP32.00509D18
0040E452 |. 8B45 08 mov eax,dword ptr ss:[ebp+8]
0040E455 |. 8B4D 0C mov ecx,dword ptr ss:[ebp+C]
0040E458 |. 8B1D 84075B00 mov ebx,dword ptr ds:[<&USER32.GetDlgItem>; USER32.GetDlgItemTextA
0040E45E |. 68 00010000 push 100 ; /Count = 100 (256.)
0040E463 |. BF 680F6300 mov edi,WINZIP32.00630F68 ; |ASCII "rocktx"
0040E468 |. 57 push edi ; |Buffer => WINZIP32.00630F68
0040E469 |. 68 800C0000 push 0C80 ; |ControlID = C80 (3200.)
0040E46E |. 50 push eax ; |hWnd
0040E46F |. 8945 E4 mov dword ptr ss:[ebp-1C],eax ; |
0040E472 |. 894D D8 mov dword ptr ss:[ebp-28],ecx ; |
0040E475 |. C645 EF 01 mov byte ptr ss:[ebp-11],1 ; |
0040E479 |. C645 EB 01 mov byte ptr ss:[ebp-15],1 ; |
0040E47D |. FFD3 call ebx ; \GetDlgItemTextA
可见,这里可以使用断点 GetDlgItemTextA,在 0040E446 处F2下断,继续运行并再次注册;
断下后,一直F8跟到
0040E81D |> \66:8B3D 640F6300 mov di,word ptr ds:[630F64]
0040E824 |. 56 push esi
0040E825 |. 66:891D 640F6300 mov word ptr ds:[630F64],bx
0040E82C |. E8 CFBF0F00 call WINZIP32.0050A800
0040E831 |. 83F8 08 cmp eax,8 ; 比较注册码长度
0040E834 |. 59 pop ecx
0040E835 |. 8D4D DC lea ecx,dword ptr ss:[ebp-24]
0040E838 |. 75 34 jnz short WINZIP32.0040E86E
-----------------------------------------------------------------------------------
为什么跟到这里要停下?答案是经验;
经验1:一般注册码的长度要心里有数,而且最好是16进制数,时刻注意一些call的返回值(一般看eax),如果返回注册码的长度,则往下跟踪要放缓脚步;
-----------------------------------------------------------------------------------
这里如果注册码长度不为8,则跳出错误提示,反之提示该注册码不属于当前版本的Winzip;
可见要想注册成功,就不能跳到 0040E81D,即:
0040E607 |> \381D 680F6300 cmp byte ptr ds:[630F68],bl ; 验证用户名是否为空
0040E60D |. 881D 5B0F6300 mov byte ptr ds:[630F5B],bl
0040E613 |. 0F84 04020000 je WINZIP32.0040E81D ; 不能跳
0040E619 |. 381D 6C106300 cmp byte ptr ds:[63106C],bl ; 验证注册码是否为空
0040E61F |. 0F84 F8010000 je WINZIP32.0040E81D ; 不能跳
0040E625 |. 53 push ebx
0040E626 |. FF75 E4 push dword ptr ss:[ebp-1C]
0040E629 |. E8 25551500 call WINZIP32.00563B53 ; 关键call
0040E62E |. 84C0 test al,al
0040E630 |. 59 pop ecx
0040E631 |. 59 pop ecx
0040E632 |. 0F84 E5010000 je WINZIP32.0040E81D ; 不能跳
二、细跟
这里先不去管关键call,重新跟踪到:
0040E500 |. E8 63C11500 call WINZIP32.0056A668
0040E505 |. 381D 680F6300 cmp byte ptr ds:[630F68],bl
0040E50B |. 0F84 F6000000 je WINZIP32.0040E607
0040E511 |. 56 push esi
0040E512 |. E8 5D521500 call WINZIP32.00563774
0040E517 |. 8BC8 mov ecx,eax
0040E519 |. E8 B0C81500 call WINZIP32.0056ADCE ; 注意这里,F7跟进
0040E51E |. 84C0 test al,al
0040E520 |. 0F84 E1000000 je WINZIP32.0040E607
0040E526 |. 57 push edi
0040E527 |. E8 D4C20F00 call WINZIP32.0050A800
0040E52C |. 83F8 64 cmp eax,64
如果使 0040E520 处的跳转不实现,则注册码需要满足以下条件
0056ADFA . FF75 08 push dword ptr ss:[ebp+8]
0056ADFD . E8 FEF9F9FF call WINZIP32.0050A800
0056AE02 . 59 pop ecx
0056AE03 . 8945 C0 mov dword ptr ss:[ebp-40],eax
0056AE06 . 837D C0 14 cmp dword ptr ss:[ebp-40],14 ; 注册码长度至少要20位
0056AE0A . 73 07 jnb short WINZIP32.0056AE13
0056AE0C . 32C0 xor al,al
0056AE0E . E9 CF010000 jmp WINZIP32.0056AFE2
0056AE85 . 50 push eax
0056AE86 . E8 75F9F9FF call WINZIP32.0050A800
0056AE8B . 59 pop ecx
0056AE8C . 83F8 14 cmp eax,14
0056AE8F . 75 12 jnz short WINZIP32.0056AEA3
0056AE91 . 6A 00 push 0
0056AE93 . 8D4D E4 lea ecx,dword ptr ss:[ebp-1C]
0056AE96 . E8 C0D2E9FF call WINZIP32.0040815B
0056AE9B . 0FB600 movzx eax,byte ptr ds:[eax]
0056AE9E . 83F8 41 cmp eax,41 ; 而且注册码首位必须是 A
0056AEA1 . 74 18 je short WINZIP32.0056AEBB
0056AF64 . 8845 EF mov byte ptr ss:[ebp-11],al
0056AF67 . 0FB645 EF movzx eax,byte ptr ss:[ebp-11]
0056AF6B . 8B4D E0 mov ecx,dword ptr ss:[ebp-20]
0056AF6E . 0FB649 13 movzx ecx,byte ptr ds:[ecx+13]
0056AF72 . 3BC1 cmp eax,ecx ; 最后一位必须是 Q
0056AF74 . 75 4B jnz short WINZIP32.0056AFC1
----------------------------------------------------------------
这些地方是怎么发现的?答案是注意单个字符的比较;
经验2:多留意程序对注册信息中单个字符的操作,尤其是在将这个字符拿去和某个值比较时;
----------------------------------------------------------------
但是如果使用注册信息:
name:rocktx
code:A111122222333334444Q
会提示输入激活信息,可能跟网络验证有关,所以再换一个注册信息:
name:rocktx
code:1111122222333334444455555
重新跟踪,来到上面提到的关键call:
0040E629 |. E8 25551500 call WINZIP32.00563B53 ; F7跟进
来到
00563E26 . 68 6C106300 push WINZIP32.0063106C ; /Arg3 = 0063106C ASCII "1111122222333334444455555"
00563E2B . 68 C8010000 push 1C8 ; |Arg2 = 000001C8
00563E30 . 8D85 18FEFFFF lea eax,dword ptr ss:[ebp-1E8] ; |
00563E36 . 50 push eax ; |Arg1 = 0013F304 ASCII "rocktx"
00563E37 . E8 03FCFFFF call WINZIP32.00563A3F ; F7跟进
-----------------------------------------------------------------------------
为什么要到这里跟进?答案又是经验;
经验3:如果遇到跟注册信息相关的数据入栈,则之后的call就要多加留意;
-----------------------------------------------------------------------------
跟进到
00563A3F /$ 55 push ebp
00563A40 |. 8BEC mov ebp,esp
00563A42 |. FF75 0C push dword ptr ss:[ebp+C]
00563A45 |. FF75 08 push dword ptr ss:[ebp+8]
00563A48 |. E8 D97DFAFF call WINZIP32.0050B826
00563A4D |. 59 pop ecx
00563A4E |. 59 pop ecx
00563A4F |. 85C0 test eax,eax
00563A51 |. 75 02 jnz short WINZIP32.00563A55
00563A53 |. EB 0F jmp short WINZIP32.00563A64
00563A55 |> 6A 41 push 41
00563A57 |. FF35 FCB66000 push dword ptr ds:[60B6FC] ; WINZIP32.005CAC1C
00563A5D |. E8 731EECFF call WINZIP32.004258D5
00563A62 |. 59 pop ecx
00563A63 |. 59 pop ecx
00563A64 |> FF75 10 push dword ptr ss:[ebp+10]
00563A67 |. FF75 08 push dword ptr ss:[ebp+8]
00563A6A |. 68 2CAC5C00 push WINZIP32.005CAC2C ; ASCII "SU_PRO"
00563A6F |. 8B0D D8106300 mov ecx,dword ptr ds:[6310D8]
00563A75 |. E8 6B690000 call WINZIP32.0056A3E5 ; 关键call
00563A7A |. 0FB6C0 movzx eax,al
00563A7D |. 85C0 test eax,eax
00563A7F |. 74 18 je short WINZIP32.00563A99 ; nop掉就直接爆破了
00563A81 |. C605 580F6300 01 mov byte ptr ds:[630F58],1
00563A88 |. C605 5A0F6300 01 mov byte ptr ds:[630F5A],1
00563A8F |. 66:8325 CC106300 00 and word ptr ds:[6310CC],0
00563A97 |. EB 43 jmp short WINZIP32.00563ADC
00563A99 |> FF75 10 push dword ptr ss:[ebp+10]
00563A9C |. FF75 08 push dword ptr ss:[ebp+8]
00563A9F |. 68 34AC5C00 push WINZIP32.005CAC34 ; ASCII "SU_STD"
00563AA4 |. 8B0D D8106300 mov ecx,dword ptr ds:[6310D8]
00563AAA |. E8 36690000 call WINZIP32.0056A3E5
00563AAF |. 0FB6C0 movzx eax,al
00563AB2 |. 85C0 test eax,eax
00563AB4 |. 74 18 je short WINZIP32.00563ACE
00563AB6 |. C605 580F6300 01 mov byte ptr ds:[630F58],1
00563ABD |. C605 5A0F6300 00 mov byte ptr ds:[630F5A],0
00563AC4 |. 66:8325 CC106300 00 and word ptr ds:[6310CC],0
00563ACC |. EB 0E jmp short WINZIP32.00563ADC
00563ACE |> C605 580F6300 00 mov byte ptr ds:[630F58],0 ; 将 0 改成 1 就爆破了
00563AD5 |. C605 5A0F6300 00 mov byte ptr ds:[630F5A],0 ; 将 0 改成 1 就成专业版了
00563ADC |> 5D pop ebp
00563ADD \. C3 retn
---------------------------------------------------------------
为什么一眼能看出这段代码是关键?答案是字符串"SU_PRO"和"SU_STD";
经验4:如果发现代码中连续出现类似"pro"、"std"、"home"、"personal"、"commercial"等表示软件授权版本的信息,则附近一般会有关键call;
经验5:多留意类似 mov byte ptr ds:[630F58],0 等对内存地址的直接赋值操作,因为这个值很可能是程序是否注册成功的标志;
---------------------------------------------------------------
为了更深层爆破,跟进关键call,来到
0056A4F0 |> \8D45 BC lea eax,dword ptr ss:[ebp-44]
0056A4F3 |. 50 push eax
0056A4F4 |. E8 0703FAFF call WINZIP32.0050A800
0056A4F9 |. 59 pop ecx
0056A4FA |. 83F8 1D cmp eax,1D ; 注册码长度是否等于29
0056A4FD |. 0F86 A6000000 jbe WINZIP32.0056A5A9
0056A5A9 |> \FF75 10 push dword ptr ss:[ebp+10]
0056A5AC |. E8 4F02FAFF call WINZIP32.0050A800
0056A5B1 |. 59 pop ecx
0056A5B2 |. 83F8 23 cmp eax,23 ; 注册码长度是否等于35
0056A5B5 |. 73 09 jnb short WINZIP32.0056A5C0
0056A5B7 C745 F0 6E000000 mov dword ptr ss:[ebp-10],6E ; 将 6E 改成 0 就爆破了
0056A5BE |. EB 46 jmp short WINZIP32.0056A606
往下
0056A625 |. 85C0 test eax,eax
0056A627 |. 75 09 jnz short WINZIP32.0056A632
0056A629 |. C745 9C 01000000 mov dword ptr ss:[ebp-64],1
0056A630 |. EB 04 jmp short WINZIP32.0056A636
0056A632 8365 9C 00 and dword ptr ss:[ebp-64],0 ; 修改这里也可以爆破
修改为
0056A632 ^\EB F5 jmp short WINZIP32.0056A629
0056A634 90 nop
0056A635 90 nop
------------------------------------------------------------------
经验6:跟进关键call后,除了留意程序对某些固定的内存地址的赋值操作以外,还要多留意call返回处对eax的赋值操作,一般如:
mov eax,dword ptr ss:[ebp-xxxx]
或
mov al,byte ptr ss:[ebp-xxxx]
或者干脆直接赋值,一般回溯ss:[ebp-xxxx]就能找到关键代码;
------------------------------------------------------------------
如果将注册信息换成:
name:rocktx
code:11111222223333344444555556666677777
重新跟踪,则
0056A5A9 |> \FF75 10 push dword ptr ss:[ebp+10]
0056A5AC |. E8 4F02FAFF call WINZIP32.0050A800
0056A5B1 |. 59 pop ecx
0056A5B2 |. 83F8 23 cmp eax,23
0056A5B5 |. 73 09 jnb short WINZIP32.0056A5C0 ; 这里会跳
0056A5B7 C745 F0 6E000000 mov dword ptr ss:[ebp-10],6E
0056A5BE |. EB 46 jmp short WINZIP32.0056A606
继续到
0056A5F4 |. 50 push eax
0056A5F5 |. 8B45 A0 mov eax,dword ptr ss:[ebp-60]
0056A5F8 |. FF70 19 push dword ptr ds:[eax+19]
0056A5FB |. E8 47340100 call WINZIP32.0057DA47 ; 这里进行算法验证
0056A600 |. 83C4 14 add esp,14
0056A603 |. 8945 F0 mov dword ptr ss:[ebp-10],eax ; 返回值eax必须为0
0056A606 |> 837D F0 00 cmp dword ptr ss:[ebp-10],0
0056A60A |. 75 26 jnz short WINZIP32.0056A632
此时堆栈:
0013EFF4 00F6EC20
0013EFF8 00F6DF98 ASCII "rocktx677777"
0013EFFC 0000000C
0013F000 0013F02C ASCII "11111222223333344444555556666"
跟进会发现调用 WZEAY32.DLL,具体算法未细究,爆破点:
0057DC95 |> \C785 C4FEFFFF 65000000 mov dword ptr ss:[ebp-13C],65
0057DC9F |> 8B4D FC mov ecx,dword ptr ss:[ebp-4]
0057DCA2 |. 8B85 C4FEFFFF mov eax,dword ptr ss:[ebp-13C] ; 改成 xor eax,eax 即可
0057DCA8 |. 5F pop edi
0057DCA9 |. 5E pop esi
0057DCAA |. 33CD xor ecx,ebp
0057DCAC |. 5B pop ebx
0057DCAD |. E8 4AFAF7FF call WINZIP32.004FD6FC
0057DCB2 |. C9 leave
0057DCB3 \. C3 retn
程序使用了黑名单机制,例如:
name:billedwin
code:RC4FV-H8P7E-CL6RN-90NE5-1NRRY
name:carlessjohn
code:MNWRN-UEY8K-FR4LA-U4YC6-1JJUD
name:markalain
code:NZJV0-M1612-KP6AF-U5ZLQ-M9ZL3
name:steveshea
code:RT65P-L587D-940NU-Q9DTN-1LXA4
三、小结:
爆破方法1(注册码不能少于35位):
0057DCA2 |. 8B85 C4FEFFFF mov eax,dword ptr ss:[ebp-13C] ; 改成 xor eax,eax
爆破方法2(注册码长度任意):
00563A7F |. 74 18 je short WINZIP32.00563A99 ; nop掉
或
0056A5B7 C745 F0 6E000000 mov dword ptr ss:[ebp-10],6E ; 将 6E 改成 0
或
0056A632 8365 9C 00 and dword ptr ss:[ebp-64],0 ; 改成 jmp 0056A629
注册信息保存方式:
1、文件:C:\Documents and Settings\All Users\Application Data\WinZip\WinZip.sureg
-------------------------------------
[Registration]
WinZip120_Name=rocktx
WinZip120_Code=1111111111111111111111111111111111111
-------------------------------------
2、注册表:
-------------------------------------
REGEDIT4
[HKEY_CURRENT_USER\Software\Nico Mak Computing\WinZip\WinIni]
"Name1"="rocktx"
"SN1"="1111111111111111111111111111111111111"
[HKEY_LOCAL_MACHINE\SOFTWARE\Nico Mak Computing\WinZip\WinIni]
"Name1"="rocktx"
"SN1"="1111111111111111111111111111111111111"
-------------------------------------
但是,现在的问题是,虽然程序已经显示为注册版,但当解压缩文件时,会提示Winzip32.exe文件已损坏;
四、解除暗桩
这里就要用到断点 MessageBoxIndirectW,至于这个函数是怎么得到的,可以参照第一部分 —— 粗跟,结尾处往下跟踪就能找到;
bp MessageBoxIndirectW下断后,运行程序,随便载入一个压缩文档,然后选择菜单Actions-Extract,在弹出的对话框中点击[Extract]按钮,程序断在:
00495133 |. 81C9 00400000 or ecx,4000
00495139 |. 50 push eax ; /pMsgBoxParams
0049513A |. C745 C0 28000000 mov dword ptr ss:[ebp-40],28 ; |
00495141 |. 8975 CC mov dword ptr ss:[ebp-34],esi ; |
00495144 |. 897D D0 mov dword ptr ss:[ebp-30],edi ; |
00495147 |. 894D D4 mov dword ptr ss:[ebp-2C],ecx ; |
0049514A |. 8955 DC mov dword ptr ss:[ebp-24],edx ; |
0049514D |. C745 E0 45FA4800 mov dword ptr ss:[ebp-20],WINZIP32.0>; |
00495154 |. C745 E4 00040000 mov dword ptr ss:[ebp-1C],400 ; |
0049515B |. FF15 4C065B00 call dword ptr ds:[<&USER32.MessageB>; \MessageBoxIndirectW
00495161 |. EB 35 jmp short WINZIP32.00495198 ; 返回到这里
查看堆栈信息,回溯到
0045067F > \803D 5F0F6300 00 cmp byte ptr ds:[630F5F],0 ; ds:[630F5F]的值是关键
00450686 . 74 0A je short WINZIP32.00450692 ; 这里必须跳
00450688 . E8 CF4D0400 call WINZIP32.0049545C ; 提示错误信息
0045068D .^ E9 F9FEFFFF jmp WINZIP32.0045058B
重新载入程序,在 00630F5F 处下内存写入断点(注意,这里只关心 00630F5F 一个字节),几次F9后断在:
0048A720 |. 33FF xor edi,edi ; edi清零
0048A722 |. 33DB xor ebx,ebx
0048A724 |. 897D D0 mov dword ptr ss:[ebp-30],edi
0048A727 |. 43 inc ebx
0048A728 |. 393D 90B66000 cmp dword ptr ds:[60B690],edi
0048A72E |. 75 18 jnz short WINZIP32.0048A748
0048A730 |. 393D A0B66000 cmp dword ptr ds:[60B6A0],edi
0048A736 |. 75 10 jnz short WINZIP32.0048A748
0048A738 |. 393D 98B66000 cmp dword ptr ds:[60B698],edi
0048A73E |. 75 08 jnz short WINZIP32.0048A748
0048A740 |. 393D 9CB66000 cmp dword ptr ds:[60B69C],edi
0048A746 |. 74 07 je short WINZIP32.0048A74F
0048A748 |> C605 5F0F6300 01 mov byte ptr ds:[630F5F],1 ; 断在这里
0048A74F |> 393D 90DD6000 cmp dword ptr ds:[60DD90],edi
0048A755 |. 75 12 jnz short WINZIP32.0048A769
可知 0060B690、0060B6A0、0060B698、0060B69C 的值都必须为0,简单起见,只修改
0048A748 |> C605 5F0F6300 01 mov byte ptr ds:[630F5F],1 ; 1 改成 0 即可去除暗桩
另外还有两个注册表值:
-----------------------------------------
REGEDIT4
[HKEY_LOCAL_MACHINE\SOFTWARE\Nico Mak Computing\WinZip\WinIni]
"UZQF"="J080"
[HKEY_CURRENT_USER\Software\Nico Mak Computing\WinZip\WinIni]
"UZQF"="J080"
-----------------------------------------
和一个文件:
C:\Documents and Settings\All Users\Application Data\WinZip
-----------------------------------------
[Addon]
UZQF=J080
AOFF=0
-----------------------------------------
具体什么作用,未作深究。
【一句话总结:新版 WinZip 可以用 MessageBoxIndirectW 断点搞定】
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!
2009年06月25日 1:03:34
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)