• 标 题:一个网友求助的软件的算法分析------explzh好象是压缩与解压缩软件
  • 作 者:txm123
  • 时 间: 2003年9月23日 11:24
  • 链 接:http://bbs.pediy.com

一个网友求助的软件的算法分析------explzh好象是压缩与解压缩软件
    说明:这个软件的破解是一个网友给我发了一封EMAIL,求助这个软件的破解,原信如下:
发件人: "Chris Wahl" <smalltalk-80@tom.com>
收件人: 隐去我的邮件地址  抄送: (无)
发送时间: 2003-09-17 15:00:56  优先级: 普通
标题: help me to understand Float Computing 
Hello ,  would you like to help me ?, 
I am learning crack . 
the progie I want to crack is explzh, a file compress software
like WinRAR. 
I use OllyDbg 1.09 too, but I found there are lots of floating 
calculation in the code. I am confused. 
 
fortunately , I found your article http://www.jxlb.com/cgi-bin/view.cgi?forum=2&topic=2155
and I think  I can get some help from you. 
 
the progie's site is , the updated version has only Japanese version.
I hope you will not reject 
http://village.infoweb.ne.jp/~fwhv5283/mirror.htm
 
regrards.
Chris
     这是一封英文信件,我的英语水平太菜,看了很久才明白,昨天晚上看到这封信,软件也发到了我的邮箱,
所以就下来看一看,这是一个日本人做的解压缩软件,软件界面的文字我又不认得,找了半天才找到注册处,弄
清了算法,就贴出来看一看,注册错误有信息,但反汇编找不到,所以只能动态调试找关键点。下载地址在:
http://village.infoweb.ne.jp/~fwhv5283/mirror.htm这也是一个日本网站。

     软件介绍:好象这是一个压缩与解压缩的软件,我自己也不太清楚。
     破解作者:
  yzez[DFCG]
     破解工具:
  OLLYDBG1.09
     破解过程:
1、OLLYDBG1.09载入要破的程序,点击菜单栏上的插件,选命令行,然后在出现的信息框里输入:bpx hmemcpy,
按Enter键,又会出现一个调用的CALL的框 ,在所有的CALL上都设置好断点,然后按F9,反复按,直至出现注册
信息框,输入注册信息,用户名:yzez[DFCG],Email:yzez@163.com,试验码:12345678-87654321,点确定,程序
中断在004B9781处,代码如下,说明也在下面:

004B9774  |.  CALL    EXPLZH.004B96EC
004B9779  |.  CMP     DWORD PTR DS:[EDI], 0
004B977C  |.  MOV     ESIEAX
004B977E  |.  JE      SHORT EXPLZH.004B97A8
004B9780  |.  PUSH    ESI                              
004B9781  |.  CALL    DWORD PTR DS:[<&USER32.GetWindow>****此CALL设断,F9运行程序,输入任意注册信息
004B9787  |.  LEA     ECXDWORD PTR DS:[EAX+1]************点确定,程序被断,按F8走,这里连续按F8走
004B978A  |.  PUSH    ECX**********************************会在中断处循环两次,不要管,继续按F8,直
004B978B  |.  MOV     ECX, [ARG.3]*************************到00403088处,才到核心段
004B978E  |.  PUSH    EAX
********************************省略************************************************
004B97B3  |>  POP     EDI                              
004B97B4  |.  POP     ESI                              
004B97B5  |.  POP     EBP                              
004B97B6  .  RETN    0C

***********************程序核心段的代码如下!***************************************
00403088   .  MOV     EAXDWORD PTR DS:[503C30]*****进入核心处,我们停在这里!
0040308D   .  MOV     DWORD PTR SS:[ESP+10], EAX
00403091   .  MOV     EAXDWORD PTR SS:[EBP+5C]
00403094   .  MOV     DWORD PTR SS:[ESP+22C], 0
0040309F   .  MOV     ECXDWORD PTR DS:[EAX-8]
004030A2   .  TEST    ECXECX
*************************************省略N行代码!*********************************************
004031C6   .  E8 2DEE0A00   CALL    EXPLZH.004B1FF8
004031CB   .  8D4C24 14     LEA     ECXDWORD PTR SS:[ESP+14]
004031CF   .  C68424 2C0200>MOV     BYTE PTR SS:[ESP+22C], 0
004031D7   .  E8 2FED0A00   CALL    EXPLZH.004B1F0B
004031DC   .  8B4424 18     MOV     EAXDWORD PTR SS:[ESP+18]
004031E0   .  8B5424 1C     MOV     EDXDWORD PTR SS:[ESP+1C]
004031E4   .  8B1B          MOV     EBXDWORD PTR DS:[EBX]
004031E6   .  2BF0          SUB     ESIEAX
004031E8   .  1BFA          SBB     EDIEDX
004031EA   .  81EE D78A6E3C SUB     ESI, 3C6E8AD7
004031F0   .  53            PUSH    EBX                             
004031F1   .  MOV     ECX, EXPLZH.0050A328             
004031F6   .  SBB     EDI, 0                           
004031F9   .  CALL    EXPLZH.0042AF60**********这里是关键CALL,按F7跟进!                 
004031FE   .  TEXT    EAXEAX*****************测试EAX的值,注册成功EAX的值为1,反之值为0
00403200   .  JE      SHORT EXPLZH.00403214****相等就跳,跳就失败
00403202   .  PUSH    EDI                            
00403203   .  PUSH    ESI                             
00403204   .  MOV     ECXEBP                      
00403206   .  CALL    EXPLZH.004032B0                  
0040320B   .  MOV     ECXEBP
0040320D   .  CALL    EXPLZH.004AE153**********到了这里我们就是快乐的CRACKER,注册成功!
00403212   .  JMP     SHORT EXPLZH.0040327F
00403214   >  PUSH    81C7*********************上面不等就会跳到这里!,向下走几步,就要你交钱!注册失败                             
00403219   .  LEA     ECXDWORD PTR SS:[ESP+14]      
0040321D   .  CALL    EXPLZH.004B24CE                 
00403222   .  ECXDWORD PTR DS:[50A3A0]
00403228   .  MOV     EDXDWORD PTR SS:[ESP+10]
0040322C   .  PUSH    10
0040322E   .  PUSH    ECX
0040322F   .  JMP     SHORT EXPLZH.00403259
00403231   >  MOV     EAXDWORD PTR DS:[50A390]
00403236   .  LEA     EDXDWORD PTR SS:[ESP+24]
0040323A   .  PUSH    200                             
0040323F   .  PUSH    EDX                             
00403240   .  PUSH    80E0*********************** "入力されたレジストコードは" 这是失败信息!

**********************************关键CALL的代码!****************************************

0042AF60  /$  MOV     EAXDWORD PTR FS:[0]****进入关键CALL后,我们就在这里!
0042AF66  |.  PUSH    -1
0042AF68  |.  PUSH    EXPLZH.004CEA68
0042AF6D  |.  PUSH    EAX
0042AF6E  |.  MOV     DWORD PTR FS:[0], ESP
0042AF75  |.  SUB     ESP, 14
0042AF78  |.  PUSH    EBX
0042AF79  |.  PUSH    EBP
0042AF7A  |.  PUSH    ESI
0042AF7B  |.  MOV     ESIDWORD PTR SS:[ESP+30]       
0042AF7F  |.  PUSH    EDI
0042AF80  |.  MOV     EBXECX                         
0042AF82  |.  CMP     BYTE PTR DS:[ESI], 0
0042AF85  |.  JE      EXPLZH.0042B101
0042AF8B  |.  PUSH    0
0042AF8D  |.  PUSH    EXPLZH.004FD278                 
0042AF92  |.  LEA     EAXDWORD PTR SS:[ESP+18]
0042AF96  |.  PUSH    EXPLZH.004FD290                 
0042AF9B  |.  PUSH    EAX
0042AF9C  |.  CALL    EXPLZH.004C57E7
0042AFA1  |.  MOV     EAXDWORD PTR SS:[ESP+10]
0042AFA5  |.  MOV     DWORD PTR SS:[ESP+2C], 0
0042AFAD  |.  MOV     ECXDWORD PTR DS:[EAX-8]
0042AFB0  |.  TEST    ECXECX                        
0042AFB2  |.  JE      EXPLZH.0042B0F0
0042AFB8  |.  PUSH    0
0042AFBA  |.  PUSH    0
0042AFBC  |.  PUSH    EAX
0042AFBD  |.  MOV     ECXEBX
0042AFBF  |.  CALL    EXPLZH.0042B130***************此CALL对用户名进行处理,处理过程是这样,取用户名各位的
**************ASCII码值,然后把它们相加,我输入的用户名是yzez[DFCG],其结果是这样:79+7A+65+7A+5B+44+46+43+
**************47+5D=39E,结果保存在EAX中,代码就不列了,有兴趣自己跟进去看一看!
0042AFC4  |.  PUSH    ESI***************************输入的试验码入ESI
0042AFC5  |.  LEA     ECXDWORD PTR SS:[ESP+14]****保存用户名运算的结果!
0042AFC9  |.  MOV     DWORD PTR SS:[ESP+20], EAX
0042AFCD  |.  MOV     DWORD PTR SS:[ESP+24], EDX
0042AFD1  |.  CALL    EXPLZH.004B2048
0042AFD6  |.  PUSH    2D****************************2D入栈,2D是“-”的ASCII码值,注册码中必须有“-”,故
************************注册码的形式应是:XXXXXXXX-YYYYYYYY
0042AFD8  |.  LEA     ECXDWORD PTR SS:[ESP+14]
0042AFDC  |.  CALL    EXPLZH.004B23B9***************此CALL检验注册码中是否有“-”,有,就把第一组注册码的
*******************位数赋给EAX,没有EAX赋值为FFFFFFFF(-1)
0042AFE1  |.  MOV     EBPEAX**********************第一组注册码的位数8移入EBP中
0042AFE3  |.  CMP     EBP, -1***********************比较EBP是不是-1
0042AFE6  |.  JE      EXPLZH.0042B0F0***************相等就跳,一跳就送你去睡觉!所以注册码中必须有“-”
0042AFEC  |.  PUSH    EBP***************************不跳就往下,位数8入栈!我们继续往下走!
0042AFED  |.  LEA     ECXDWORD PTR SS:[ESP+1C]
0042AFF1  |.  PUSH    0
0042AFF3  |.  PUSH    ECX                             
0042AFF4  |.  LEA     ECXDWORD PTR SS:[ESP+1C]
0042AFF8  |.  CALL    EXPLZH.004AA18B
0042AFFD  |.  PUSH    EXPLZH.0050021C
0042B002  |.  LEA     EDXDWORD PTR SS:[ESP+18]
0042B006  |.  PUSH    EAX
0042B007  |.  PUSH    EDX
0042B008  |.  MOV     BYTE PTR SS:[ESP+38], 1
0042B00D  |.  CALL    EXPLZH.004B2154
0042B012  |.  PUSH    EAX
0042B013  |.  LEA     ECXDWORD PTR SS:[ESP+14]
0042B017  |.  MOV     BYTE PTR SS:[ESP+30], 2
0042B01C  |.  CALL    EXPLZH.004B1FF8
0042B021  |.  LEA     ECXDWORD PTR SS:[ESP+14]
0042B025  |.  MOV     BYTE PTR SS:[ESP+2C], 1
0042B02A  |.  CALL    EXPLZH.004B1F0B
0042B02F  |.  LEA     ECXDWORD PTR SS:[ESP+18]
0042B033  |.  MOV     BYTE PTR SS:[ESP+2C], 0
0042B038  |.  CALL    EXPLZH.004B1F0B
0042B03D  |.  MOV EAXDWORD PTR SS:[ESP+10]****把试验码的第一组12345678,注意后面加了H,代表是十六进制值入EAX
0042B041  |.  PUSH    EAX***********************试验码第一组入栈,准备处理
0042B042  |.  CALL    EXPLZH.00478D80
0042B047  |.  MOV     ECXEAX
0042B049  |.  CALL    EXPLZH.00479060
0042B04E  |.  MOV     ECXDWORD PTR SS:[ESP+1C]****把用户名计算后的结果入ECX,这里是39E,开始计算第一组注册码!
0042B052  |.  MOV     ESIEAX**********************第一组试验码12345678移入ESI
0042B054  |.  MOV     EDIEDX**********************EDX的值为0,赋EDI的值为0
0042B056  |.  MOV     EDXDWORD PTR SS:[ESP+20]****赋EDX的值为0
0042B05A  |.  SUB     EAXECX**********************EAX=EAX-ECX=12345678-39E=123452DA                         
0042B05C  |.  MOV     ECXEDI**********************EDI的值入ECX
0042B05E  |.  SBB     ECXEDX**********************ECX=ECX-EDX=0
0042B060  |.  SUB     EAX, 3C6E8AD7*****************EAX=EAX-3C6E8AD7=123452DA-3C6E8AD7=D5C5C803
0042B065  |.  SBB     ECX, 0************************ECX=ECX-0=0
0042B068  |.  PUSH    ECX                              
0042B069  |.  PUSH    EAX***************************上述计算后的结果:D5C5C803入栈!
0042B06A  |.  MOV     ECXEBX
0042B06C  |.  CALL    EXPLZH.0042AE00***************在这里进行比较,我们按F7进去看一看!比较CALL
0042B071  |.  TEST    EAXEAX**********************上面CALL的比较成功,这里EAX的值为FFFFFFFE,否则EAX的值为0
0042B073  |.  MOV     DWORD PTR SS:[ESP+1C], EAX****保存EAX的值
0042B077  |.  JE      SHORT EXPLZH.0042B0F0*********相等就跳,一跳就失败,爆破点1,改成NOP
0042B079  |.  CMP     EAX, -1***********************与-1比较
0042B07C  |.  JE      SHORT EXPLZH.0042B0F0*********相等就跳,一跳就失败,此处不必改!
0042B07E  |.  MOV     ECXDWORD PTR SS:[ESP+34]****试验码入ECX,准备取第二组试验码
0042B082  |.  LEA     EDXDWORD PTR DS:[ECX+EBP+1]*第二组试验码所在的地址赋给EDX
0042B086  |.  LEA     ECXDWORD PTR SS:[ESP+10]****试验码的地址赋给ECX
0042B08A  |.  PUSH    EDX
0042B08B  |.  CALL    EXPLZH.004B2048
0042B090  |.  MOV     EBPDWORD PTR SS:[ESP+1C]****FFFFFFFE(-2)入EBP
0042B094  |.  MOV     EAXDWORD PTR DS:[EAX]*******第二组的试验码的地址给EAX
0042B096  |.  CMP     EBP, -2***********************比较EBP是不是-2
0042B099  |.  JNZ     SHORT EXPLZH.0042B0AE*********不相等就跳,跳到下面
0042B09B  |.  CMP     BYTE PTR DS:[EAX], 31*********第二组试验码的第一位与31(1)比较
0042B09E  |.  JNZ     SHORT EXPLZH.0042B0AE*********不相等就跳
0042B0A0  |.  MOV     DLBYTE PTR DS:[EAX+1]
0042B0A3  |.  MOV     CL, 34
0042B0A5  |.  CMP     DLCL
0042B0A7  |.  JNZ     SHORT EXPLZH.0042B0AE
0042B0A9  |.  CMP     BYTE PTR DS:[EAX+2], CL
0042B0AC  |.  JE      SHORT EXPLZH.0042B0E2
0042B0AE  |>  PUSH    EXPLZH.0050021C***************跳到这里!
0042B0B3  |.  LEA     ECXDWORD PTR SS:[ESP+14]
0042B0B7  |.  CALL    EXPLZH.004B229B
0042B0BC  |.  MOV     EAXDWORD PTR SS:[ESP+10]
0042B0C0  |.  PUSH    EAX
0042B0C1  |.  CALL    EXPLZH.00478D80
0042B0C6  |.  MOV     ECXEAX
0042B0C8  |.  CALL    EXPLZH.00479060
0042B0CD  |.  SUB     ESIEAX*********************ESI=ESI-EAX=12345678(第一组试验码)-
******************************87654321(第二组试验码)=8ACF1357
0042B0CF  |.  MOV     ECXEBX
0042B0D1  |.  SBB     EDIEDX
0042B0D3  |.  PUSH    EDI
0042B0D4  |.  PUSH    ESI**************************上述计算的值8ACF1357入栈
0042B0D5  |.  CALL    EXPLZH.0042AE00**************进行第二次比较,调用同一个比较CALL
0042B0DA  |.  TEST    EAXEAX*********************比较的值不相等就赋EAX的值为0
0042B0DC  |.  JE      SHORT EXPLZH.0042B0F0********相等就跳,EAX的值为0就跳,一跳就失败!不能跳,爆破点2,改JNZ
0042B0DE  |.  CMP     EBPEAX*********************比较EBP与EAX
0042B0E0  |.  JE      SHORT EXPLZH.0042B118********相等就跳,跳就成功!爆破点3,改JE为JMP
0042B0E2  |>  PUSH    -1
0042B0E4  |.  PUSH    10
0042B0E6  |.  PUSH    81EB
0042B0EB  |.  CALL    EXPLZH.004B9A50
0042B0F0  |>  LEA     ECXDWORD PTR SS:[ESP+10]
0042B0F4  |.  MOV     DWORD PTR SS:[ESP+2C], -1
0042B0FC  |.  CALL    EXPLZH.004B1F0B
0042B101  |>  XOR     EAXEAX
0042B103  |>  MOV     ECXDWORD PTR SS:[ESP+24]
0042B107  |.  POP     EDI                              
0042B108  |.  POP     ESI                              
0042B109  |.  POP     EBP                            
0042B10A  |.  POP     EBX                              
0042B10B  |.  MOV     DWORD PTR FS:[0], ECX           
0042B112  |.  ADD     ESP, 20
0042B115  |.  RETN    4
0042B118  |>  LEA     ECXDWORD PTR SS:[ESP+10]*****跳到这里!
0042B11C  |.  MOV     DWORD PTR SS:[ESP+2C], -1
0042B124  |.  CALL    EXPLZH.004B1F0B
0042B129  |.  MOV     EAX, 1*************************在这里赋EAX的值为1,这是注册成功的标志位
0042B12E  .^ JMP     SHORT EXPLZH.0042B103
0042B130  /$  PUSH    EBX
0042B131  |.  PUSH    EBP
0042B132  |.  MOV     EBPDWORD PTR SS:[ESP+C]       
0042B136  |.  PUSH    ESI
0042B137  |.  PUSH    EDI
0042B138  |.  PUSH    EBP                              
0042B139  |.  XOR     EDIEDI                         ; |
0042B13B  |.  XOR     EBXEBX                         ; |
0042B13D  |.  CALL    DWORD PTR DS:[<&KERNEL32.lstrlen>; lstrlenA
0042B143  |.  MOV     ESIEAX
0042B145  |.  TEST    ESIESI
0042B147  |.  JNZ     SHORT EXPLZH.0042B152
0042B149  |.  POP     EDI                              
0042B14A  |.  POP     EBP                              
0042B14C  |.  XOR     EDXEDX
0042B14E  |.  POP     EBX                              
0042B14F  |.  0C

**********************************比较CALL的代码************************************************

0042AE00  /$  MOV     EAXDWORD PTR SS:[ESP+8]****进入比较CALL后我们停在这里!0入EAX
0042AE04  |.  MOV     ECXDWORD PTR SS:[ESP+4]****把上述运算过的值:D5C5C803移入ECX中
0042AE08  |.  CMP     EAX, 1***********************EAX的值和1比较
0042AE0B  |.  JG      EXPLZH.0042AED0**************如果大于就跳走,不进行后面的比较
0042AE11  |.  JL      SHORT EXPLZH.0042AE1F********如果小于就跳到下面去进行比较
0042AE13  |.  CMP     ECX, 6132023A
0042AE19  |.  JA      EXPLZH.0042AED0
0042AE1F  |>  CMP     ECX, 6132023A****************计算过的值与6132023A比较
0042AE25  |.  JNZ     SHORT EXPLZH.0042AE30********不相等就跳,跳到下面继续进行比较!
0042AE27  |.  CMP     EAX, 1***********************EAX与1比较
0042AE2A  |.  JE      EXPLZH.0042AEC8**************相等就跳!
0042AE30  |>  TEST    EAXEAX
0042AE32  |.  JG      SHORT EXPLZH.0042AE96
0042AE34  |.  JL      SHORT EXPLZH.0042AE3E********跳到0042AE96
0042AE36  |.  CMP     ECX, F87A404F
0042AE3C  |.  JA      SHORT EXPLZH.0042AE96
0042AE3E  |>  CMP     ECX, F87A404F****************比较计算的值与F87A404F
0042AE44  |.  JNZ     SHORT EXPLZH.0042AE4A********不相等就跳,跳到下面!
0042AE46  |.  TEST    EAXEAX
0042AE48  |.  JE      SHORT EXPLZH.0042AE8E
0042AE4A  |>  CMP     ECX, 87A30DE3****************再与87A30DE3比较
0042AE50  |.  JNZ     SHORT EXPLZH.0042AE56********不相等就跳
0042AE52  |.  TEST    EAXEAX
0042AE54  |.  JE      SHORT EXPLZH.0042AE86
0042AE56  |>  CMP     ECX, B64FBAC4****************与B64FBAC4比较
0042AE5C  |.  JNZ     SHORT EXPLZH.0042AE62********不相等就跳
0042AE5E  |.  TEST    EAXEAX
0042AE60  |.  JE      SHORT EXPLZH.0042AE7E
0042AE62  |>  CMP     ECX, BD507501****************与BD507501比较
0042AE68  |.  JNZ     EXPLZH.0042AF4D**************不相等就跳,跳就失败
0042AE6E  |.  TEST    EAXEAX*********************测试EAX的值
0042AE70  |.  JNZ     EXPLZH.0042AF4D**************不相等就跳,跳就失败
0042AE76  |.  MOV     EAX, -2**********************到这里赋EAX的值为FFFFFFFE(-2)
0042AE7B  |.  RETN    8****************************子程序结束!

2、算法小结:
   注册码的形式是:XXXXXXXX-YYYYYYYY
   第一组注册码减去用户名计算的值再减去3C6E8AD7必须等于BD507501
   第一组注册码减去第二组注册码也必须等于BD507501,所以其算法如下:

   计算用到用户名,用户名计算是这样,取用户名的各位ASCII码值相加,设计算的结果是:T。
   设第一组注册码是S1,S1=T+3C6E8AD7+BD507501
   设第二组注册码是S2,S2=S1-BD507501
3、验证算法:
   用户名为:yzez[DFCG]
   用户名计算的值:T=79+7A+65+7A+5B+44+46+43+47+5D=39E
   第一组注册码S1=39E+3C6E8AD7+BD507501=F9BF0376
   第二组注册码S2=F9BF0376-BD507501=3C6E8E75
  所以对应用户名yzez[DFCG]的注册码是:F9BF0376-3C6E8E75,输入进去我们看看,注册成功了吧!
4、爆破:
  点1:0042B077  |.  JE改成NOP
  点2:0042B0DC  |.  JE改成JNZ
  点3:0042B0E0  |.  JE改成JMP
   上述修改,在输入的注册码中间必须有“-”,如果任意输入都成功,还要在0042AFE6  |.  JE处改
  点4:0042AFE6  |.  JE改成NOP或者:JNZ
  这样修改,输入任意信息都可成为注册版。