WinHex9.6破解手記,上次的有錯漏,這次重貼。讓各位見笑了。

看雪資料發表於2000-11-29

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]

相關文章