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