• 标 题:WinHex9.6破解手记,上次的有错漏,这次重贴。让各位见笑了。
  • 作 者:hying[CCG]
  • 时 间:2000-11-29 14:11:13
  • 链 接:http://bbs.pediy.com

WinHex9.6破解手记,上次的有错漏,这次重贴。
    WinHex是一个功能强大的编辑软件,最新是9.6版,我从其官方主页下载的软件包打开后,其WinHex.exe的日期是11月19日,如果不是这个日期的,即使同是9.6版,可能注册方法也可能会不一样.
    WinHex把注册码存放在winhex.cfg中,比如code1为78787878(16进制04b23526),code2为69696969(16进制04277dc9),在winhex.cfg中就可查找到2635b204c97d2704,启动时读入内存ds:00458344和ds:00458348,用bpm 458344可停在如下地方.

0167:0043FE45  MOV      EAX,[00458344]    <-停在此处,取出code1
0167:0043FE4A  MOV      EDX,EAX
0167:0043FE4C  SHL      EAX,03
0167:0043FE4F  SUB      EAX,EDX         
0167:0043FE51  ADD      EAX,00016AAA
0167:0043FE56  TEST    EAX,EAX
0167:0043FE58  JNS      0043FE5D
0167:0043FE5A  ADD      EAX,BYTE +07
0167:0043FE5D  SAR      EAX,03
0167:0043FE60  CMP      EAX,[00458348]    <-code1运算后和code2比较
0167:0043FE66  SETZ    [0045A7B1]        <-置标志位

    上面一段代码很简单,大家都应该能读明白,破解似乎到此也该结束了,但事实是不管标志位为0或1,都显示未注册.而且下bpm 45a7b1发现这个标志位再也没有用到.而且code1和code2也再也没用到.难道没法注册吗?
    再回头看,由它的未注册提示框向前反推,得到地址[45a7d3]是一个关键标志位,如为0则提示未注册,如位1则不在提示.那哪个地方对此标志置1呢?反汇编后找到如下地址

0167:0044016A  CMP      BYTE [0045A75F],00
0167:00440171  SETNZ    AL
0167:00440174  MOV      EDX,0045A7DB
0167:00440179  SUB      EDX,BYTE +08
0167:0044017C  MOV      [EDX],AL

    可看出45a75f如为0则标志位也为0,为未注册,如0045A75F处不为0,则为注册版.那又是哪个地方控制着45a75f的值呢?经查找有两个地方值得怀疑,其中一个是4152fb,但调试时发现始终没有运行到那个地方,另外一个是43fa17,它处在一个call内,全部调用如下:

0167:0043F8DC  PUSH    EBX
0167:0043F8DD  PUSH    ESI
0167:0043F8DE  PUSH    EDI
0167:0043F8DF  PUSH    EBP
0167:0043F8E0  ADD      ESP,FFFFF004
0167:0043F8E6  PUSH    EAX
0167:0043F8E7  ADD      ESP,BYTE -04
0167:0043F8EA  MOV      EBP,ESP
0167:0043F8EC  MOV      EAX,00453BD4
0167:0043F8F1  CALL    0040D624
0167:0043F8F6  MOV      EAX,0045AFC8
0167:0043F8FB  MOV      ECX,08000000
0167:0043F900  MOV      EDX,80000000
0167:0043F905  CALL    0040AA04            <-进入看一下,下面有说明
0167:0043F90A  MOV      EBX,EAX
0167:0043F90C  LEA      EAX,[ESP+04]
0167:0043F910  MOV      [EBP+00],EAX
0167:0043F913  PUSH    DWORD 1000
0167:0043F918  MOV      EAX,[EBP+00]
0167:0043F91B  PUSH    EAX
0167:0043F91C  PUSH    EBX
0167:0043F91D  CALL    `KERNEL32!_lread`  <-读user.txt          注1
0167:0043F922  MOV      [0045A884],EAX
0167:0043F927  PUSH    EBX
0167:0043F928  CALL    `KERNEL32!FindCloseChangeNotification`
0167:0043F92D  INC      EBX
0167:0043F92E  JZ      NEAR 0043FA77      <-如没读到则跳 (拜托!千万别让它跳)
0167:0043F934  CMP      DWORD [0045A884],BYTE +19
0167:0043F93B  JL      NEAR 0043FA77      <-如文件太短则跳
0167:0043F941  MOV      EAX,EBP
0167:0043F943  CALL    004099D4
0167:0043F948  TEST    AL,AL
0167:0043F94A  JZ      NEAR 0043FA77
0167:0043F950  MOV      EAX,EBP
0167:0043F952  CALL    00409A2C
0167:0043F957  TEST    AL,AL
0167:0043F959  JZ      NEAR 0043FA77
0167:0043F95F  PUSH    DWORD 00453BE0
0167:0043F964  PUSH    DWORD 0045AFC8
0167:0043F969  CALL    `KERNEL32!lstrcmpiA` 〈-第一行是否为"User:"  注2
0167:0043F96E  TEST    EAX,EAX
0167:0043F970  JNZ      NEAR 0043FA77
0167:0043F976  MOV      EAX,EBP
0167:0043F978  CALL    004099D4
0167:0043F97D  TEST    AL,AL
0167:0043F97F  JZ      NEAR 0043FA77
0167:0043F985  MOV      EAX,EBP
0167:0043F987  CALL    00409A2C
0167:0043F98C  TEST    AL,AL
0167:0043F98E  JZ      NEAR 0043FA77
0167:0043F994  MOV      EDX,0045AFC8
0167:0043F999  MOV      EAX,0045A6A8
0167:0043F99E  CALL    004050A4
0167:0043F9A3  MOV      BL,02
0167:0043F9A5  MOV      ESI,00453BE8
0167:0043F9AA  MOV      EDI,0045A6E5
0167:0043F9AF  MOV      EAX,EBP
0167:0043F9B1  CALL    004099D4
0167:0043F9B6  TEST    AL,AL
0167:0043F9B8  JZ      NEAR 0043FA77
0167:0043F9BE  MOV      EAX,EBP
0167:0043F9C0  CALL    00409A2C
0167:0043F9C5  TEST    AL,AL
0167:0043F9C7  JZ      NEAR 0043FA77
0167:0043F9CD  PUSH    ESI
0167:0043F9CE  PUSH    DWORD 0045AFC8
0167:0043F9D3  CALL    `KERNEL32!lstrcmpiA` <-第3行是否为"Addr1:"
0167:0043F9D8  TEST    EAX,EAX
0167:0043F9DA  JNZ      NEAR 0043FA77
0167:0043F9E0  MOV      EAX,EBP
0167:0043F9E2  CALL    004099D4
0167:0043F9E7  TEST    AL,AL
0167:0043F9E9  JZ      NEAR 0043FA77
0167:0043F9EF  MOV      EAX,EBP
0167:0043F9F1  CALL    00409A2C
0167:0043F9F6  TEST    AL,AL
0167:0043F9F8  JZ      0043FA77
0167:0043F9FA  MOV      EDX,0045AFC8
0167:0043F9FF  MOV      EAX,EDI
0167:0043FA01  CALL    004050A4
0167:0043FA06  ADD      EDI,BYTE +3D
0167:0043FA09  ADD      ESI,BYTE +07
0167:0043FA0C  DEC      BL
0167:0043FA0E  JNZ      0043F9AF          <-跳回,再比较第5行是否为"Addr2:"
0167:0043FA10  MOV      BL,02
0167:0043FA12  MOV      ESI,00453BF8
0167:0043FA17  MOV      EDI,0045A75F      <-注意这个地方,0045A75F比较可疑
0167:0043FA1C  MOV      EAX,EBP
0167:0043FA1E  CALL    004099D4
0167:0043FA23  TEST    AL,AL
0167:0043FA25  JZ      0043FA77
0167:0043FA27  MOV      EAX,EBP
0167:0043FA29  CALL    00409A2C
0167:0043FA2E  TEST    AL,AL
0167:0043FA30  JZ      0043FA77
0167:0043FA32  PUSH    ESI
0167:0043FA33  PUSH    DWORD 0045AFC8
0167:0043FA38  CALL    `KERNEL32!lstrcmpiA`  <-第7行是否为"Code1:"
0167:0043FA3D  TEST    EAX,EAX
0167:0043FA3F  JNZ      0043FA77
0167:0043FA41  MOV      EAX,EBP
0167:0043FA43  CALL    004099D4
0167:0043FA48  TEST    AL,AL
0167:0043FA4A  JZ      0043FA77
0167:0043FA4C  MOV      EAX,EBP
0167:0043FA4E  CALL    00409A2C
0167:0043FA53  TEST    AL,AL
0167:0043FA55  JZ      0043FA77
0167:0043FA57  MOV      EDX,EDI
0167:0043FA59  MOV      EAX,0045AFC8
0167:0043FA5E  MOV      ECX,10
0167:0043FA63  CALL    0040D3A8      <-进入看一下,下面有说明
0167:0043FA68  CMP      EAX,BYTE +10
0167:0043FA6B  JNZ      0043FA77      <-第8行是否有32个字符.上次我竟然连16进
0167:0043FA6D  ADD      EDI,BYTE +10    制与10进制都没看清,真是糊涂
0167:0043FA70  ADD      ESI,BYTE +07
0167:0043FA73  DEC      BL
0167:0043FA75  JNZ      0043FA1C      <-跳回,再比较第9行是否为"Code2:"、
0167:0043FA77  ADD      ESP,1004        第10行是否有32个字符
0167:0043FA7D  POP      EBP
0167:0043FA7E  POP      EDI
0167:0043FA7F  POP      ESI
0167:0043FA80  POP      EBX
0167:0043FA81  RET   
————————————————————————————
CALL 0040AA04 的内容   
0167:0040AA04  PUSH    BYTE +00
0167:0040AA06  OR      ECX,80
0167:0040AA0C  PUSH    ECX
0167:0040AA0D  PUSH    BYTE +03
0167:0040AA0F  PUSH    BYTE +00
0167:0040AA11  PUSH    BYTE +01
0167:0040AA13  PUSH    EDX
0167:0040AA14  PUSH    EAX   
0167:0040AA15  CALL    `KERNEL32!CreateFileA`  <-打开文件  注3
0167:0040AA1A  RET   
————————————————————————————
CALL 0040D3A8 的内容
0167:0040D3A8  PUSH    EBX
0167:0040D3A9  PUSH    ESI
0167:0040D3AA  PUSH    EDI
0167:0040D3AB  PUSH    EBP
0167:0040D3AC  PUSH    ECX
0167:0040D3AD  MOV      [ESP],ECX
0167:0040D3B0  MOV      EBP,EDX        <-EBP变为0045A75F
0167:0040D3B2  MOV      EDI,EAX
0167:0040D3B4  XOR      ESI,ESI
0167:0040D3B6  JMP      SHORT 0040D3B9
0167:0040D3B8  INC      EDI
0167:0040D3B9  MOV      AL,[EDI]        <-取第8行第1位
0167:0040D3BB  CMP      AL,20
0167:0040D3BD  JZ      0040D3B8
0167:0040D3BF  CMP      AL,09
0167:0040D3C1  JZ      0040D3B8
0167:0040D3C3  CMP      AL,0D
0167:0040D3C5  JZ      0040D3B8
0167:0040D3C7  CMP      AL,0A
0167:0040D3C9  JZ      0040D3B8
0167:0040D3CB  CMP      BYTE [EDI],00
0167:0040D3CE  JZ      0040D432
0167:0040D3D0  MOV      AL,[EDI]
0167:0040D3D2  CMP      AL,61
0167:0040D3D4  JC      0040D3DD
0167:0040D3D6  CMP      AL,7A
0167:0040D3D8  JA      0040D3DD
0167:0040D3DA  SUB      BYTE [EDI],20
0167:0040D3DD  INC      EDI
0167:0040D3DE  MOV      AL,[EDI]        <-取第8行第2位
0167:0040D3E0  CMP      AL,61
0167:0040D3E2  JC      0040D3EB
0167:0040D3E4  CMP      AL,7A
0167:0040D3E6  JA      0040D3EB
0167:0040D3E8  SUB      BYTE [EDI],20
0167:0040D3EB  MOV      EAX,EDI
0167:0040D3ED  DEC      EAX
0167:0040D3EE  MOV      BL,[EAX]
0167:0040D3F0  MOV      EAX,EBX
0167:0040D3F2  AND      EAX,FF
0167:0040D3F7  BT      [00453940],EAX
0167:0040D3FE  JNC      0040D432        <-第1位为空则跳
0167:0040D400  MOV      AL,[EDI]
0167:0040D402  AND      EAX,FF
0167:0040D407  BT      [00453940],EAX
0167:0040D40E  JNC      0040D432        <-第2位为空则跳,
0167:0040D410  MOV      EAX,EBX
0167:0040D412  CALL    0040D38C      \
0167:0040D417  SHL      EAX,04          |
0167:0040D41A  PUSH    EAX            |  如第1、2位分别为"1"和"2",
0167:0040D41B  MOV      AL,[EDI]        |- 则经此处变换后dl中值为16进
0167:0040D41D  CALL    0040D38C        |  制数"12"
0167:0040D422  POP      EDX            |
0167:0040D423  ADD      DL,AL          /  /运行到此0045A75F已不再为零了,但启
0167:0040D425  MOV      [EBP+ESI+00],DL  <-\动画面仍有……only(仅供试用)字样
0167:0040D429  INC      ESI              <-每使用2位code,ESI加1
0167:0040D42A  CMP      ESI,[ESP]        <-ESI是否等于16,故猜想code有32位
0167:0040D42D  JZ      0040D432
0167:0040D42F  INC      EDI
0167:0040D430  JMP      SHORT 0040D3B9
0167:0040D432  MOV      EAX,ESI
0167:0040D434  POP      EDX
0167:0040D435  POP      EBP
0167:0040D436  POP      EDI
0167:0040D437  POP      ESI
0167:0040D438  POP      EBX
0167:0040D439  RET 
----------------------------------------------------------
如果第8行太短,则启动时会出现"For evaluation purposes only"(仅供试用)字样,由于小弟E文比较差劲,经有人提醒后才注意到,虽然好象没别的问题,但最好还是去掉它,如下
0167:00433739  MOV      AL,[0045A76B]      <-取第8行第25、26组成的字符,如太短则取出为00
0167:0043373E  ADD      AX,025E
0167:00433742  CALL    00408B28            <-下面说明
0167:00433747  MOV      EDX,EAX            <-如上面al为00,则返回eax为"For……"的地址
0167:00433749  MOV      EAX,0045AFC8
0167:0043374E  CALL    004050A4
0167:00433753  CMP      BYTE [0045A7D3],00
0167:0043375A  JNZ      0043377A
0167:0043375C  XOR      EAX,EAX
0167:0043375E  MOV      AL,[00459F15]
0167:00433763  LEA      EAX,[EAX+EAX*8]
0167:00433766  LEA      EAX,[EAX*2+00453B58]
0167:0043376D  PUSH    EAX
0167:0043376E  PUSH    DWORD 0045AFC8
0167:00433773  CALL    `KERNEL32!lstrcatA`
0167:00433778  JMP      SHORT 00433798
0167:0043377A  PUSH    DWORD 004337D0
0167:0043377F  PUSH    DWORD 0045AFC8
0167:00433784  CALL    `KERNEL32!lstrcatA`
0167:00433789  PUSH    DWORD 0045A6A8
0167:0043378E  PUSH    DWORD 0045AFC8
0167:00433793  CALL    `KERNEL32!lstrcatA`
0167:00433798  PUSH    BYTE +01
0167:0043379A  PUSH    EDI
0167:0043379B  PUSH    BYTE -01
0167:0043379D  PUSH    DWORD 0045AFC8
0167:004337A2  PUSH    EBX
0167:004337A3  CALL    `USER32!DrawTextA`  <-显示字符,用d 45afc8就可看见将显示的内容
0167:004337A8  MOV      EAX,[ESP]

---------------------------------------------------------------
CALL  00408B28的内容
0167:00408B28  PUSH    EBX
0167:00408B29  PUSH    ESI
0167:00408B2A  MOV      EBX,[0045B810]
0167:00408B30  ADD      EBX,BYTE +0A
0167:00408B33  TEST    EBX,EBX
0167:00408B35  JZ      00408B96
0167:00408B37  CMP      AX,[0045A82C]    <-如eax大于16进制27D(即原AL不小于20)则跳,
0167:00408B3E  JA      00408B96          如跳,启动时名字前就不会有其他字样,
0167:00408B40  MOV      DL,[00459F15]
0167:00408B46  CMP      DL,01
0167:00408B49  JZ      00408B54
0167:00408B4B  MOVZX    ECX,WORD [0045A832]
0167:00408B52  ADD      EBX,ECX
0167:00408B54  CMP      DL,01
0167:00408B57  JNA      00408B62
0167:00408B59  MOVZX    ECX,WORD [0045A834]
0167:00408B60  ADD      EBX,ECX
0167:00408B62  CMP      DL,02
0167:00408B65  JNA      00408B70
0167:00408B67  MOVZX    ECX,WORD [0045A836]
0167:00408B6E  ADD      EBX,ECX
0167:00408B70  CMP      DL,03
0167:00408B73  JNA      00408B7E
0167:00408B75  MOVZX    EDX,WORD [0045A838]
0167:00408B7C  ADD      EBX,EDX
0167:00408B7E  MOVZX    ESI,AX
0167:00408B81  SUB      ESI,BYTE +02
0167:00408B84  JL      00408B9B
0167:00408B86  INC      ESI
0167:00408B87  MOV      EAX,EBX    \
0167:00408B89  CALL    00405038    |
0167:00408B8E  INC      EAX          |对EBX进行运算,得到指向某一字符串的地址
0167:00408B8F  ADD      EBX,EAX      |如原AL取00,则EBX指向"For……only",如AL
0167:00408B91  DEC      ESI          |为其他值,则指向其它字符串
0167:00408B92  JNZ      00408B87    /
0167:00408B94  JMP      SHORT 00408B9B
0167:00408B96  MOV      EBX,00408BA0
0167:00408B9B  MOV      EAX,EBX
0167:00408B9D  POP      ESI
0167:00408B9E  POP      EBX
由此可见,第8行必须至少有26位,而且第25位必须大于2。
——-------————————————————————————————
注1:注意上边DS:EAX就是所读到内容存放的地址,我是6AEAD8
注2:注意上边DS:453BE0是正确内容的地址,DS:45AFC8是有待判断的内容的地址。(似乎不区分大小写)
注3:用d ds:eax就可看到打开文件的文件名,winhex安装在d:\winhex,则可看到d:\winhex\user.txt

    写到这儿,查看了一下看雪论坛精华II,发现有好几篇winhex的破解文章,有9.3、9.4、9.5、9.53,每次注册方法都不一样,到这个9.6的注册已经与code1和code2无关了.由此想到,做一个假的注册功能(幸好假注册还不算太复杂,假标志也没有用来产生一些"事故",不然我的爱机……)可能也是一种不错的保护方法.
    本人水平有限,不对之处请各位高手指正.
                              作者:hying[CCG]