ClassExplorer的破解 (13千字)

看雪資料發表於2001-07-29

今天來說說ClassExplorer的破解。

這是個非常好的Delphi工具,有點類似VB中各個sub之間切換的味道,當然還有其他功能,對Delphi感興趣的網友記得看看。

以前它是收費軟體,而今它已經是free了,只是不那麼徹底,下載的時候需要提供給站臺自己的資訊,它才會給你寄上註冊碼。說是一個工作日完成,結果我等了n個工作日也沒有等到。

這是我為什麼要破解這個free軟體的其中一個原因。另外一個原因是,2年前我用過它,只是自己沒有追出註冊碼,是在BBS上認識的一個朋友給的。而今我想看看自己到底有沒有長進。

破解完這個軟體,以後恐怕很難再有時間破解了。算是對自己破解的一段總結吧。

用trw2000 bpx hmemcpy斷下,F12大約14次看到進入ClassExplorer領空就使用F10跟。

015F:021CE428  PUSH    EBX
015F:021CE429  PUSH    ESI
015F:021CE42A  PUSH    EDI
015F:021CE42B  PUSH    EBP
015F:021CE42C  MOV      EBP,ECX
015F:021CE42E  MOV      EDI,EDX
015F:021CE430  MOV      EBX,EAX
015F:021CE432  MOV      ESI,00C1B362
015F:021CE437  MOV      EAX,EBX
015F:021CE439  CALL    021CE350
015F:021CE43E  TEST    AL,AL
015F:021CE440  JNZ      021CE456
015F:021CE442  MOV      ECX,EBP
015F:021CE444  MOV      EDX,EDI
015F:021CE446  MOV      EAX,EBX
015F:021CE448  CALL    021CE1B8  《--  這個Call需要跟進去看。
015F:021CE44D  TEST    AL,AL
015F:021CE44F  JZ      021CE456     
015F:021CE451  MOV      ESI,0040D3DA
015F:021CE456  MOV      EAX,ESI
015F:021CE458  POP      EBP
015F:021CE459  POP      EDI
015F:021CE45A  POP      ESI
015F:021CE45B  POP      EBX
015F:021CE45C  RET   


程式會帶你到這裡來,這是一張黑名單,凡是不幸榜上有名者不能註冊。舉個例子:Markus, NAMESergy等等。
記憶體21CE330處是張表,程式根據它來產生黑名單。也就是黑名單的變相加密解密。

015F:021CE372  MOV      EBX,021CE330         
015F:021CE377  MOV      AL,[EBX]
015F:021CE379  XOR      AL,35
015F:021CE37B  AND      EAX,FF
015F:021CE380  MOV      [EBP-08],EAX         
015F:021CE383  MOV      DWORD [EBP-0C],01   
015F:021CE38A  XOR      EDI,EDI
015F:021CE38C  CMP      EDI,[EBP-08]
015F:021CE38F  JNL      021CE3E2
015F:021CE391  LEA      EAX,[EBP-10]         
015F:021CE394  CALL    `VCL50!@System@@LStrClr$qqrr17System@AnsiString`
015F:021CE399  INC      EBX
015F:021CE39A  MOV      AL,[EBX]
015F:021CE39C  XOR      AL,35
015F:021CE39E  AND      EAX,FF
015F:021CE3A3  LEA      EDX,[EAX+01]
015F:021CE3A6  ADD      [EBP-0C],EDX
015F:021CE3A9  MOV      ESI,EAX
015F:021CE3AB  DEC      ESI
015F:021CE3AC  TEST    ESI,ESI
015F:021CE3AE  JL      021CE3CD
015F:021CE3B0  INC      ESI
015F:021CE3B1  INC      EBX
015F:021CE3B2  LEA      EAX,[EBP-14]
015F:021CE3B5  MOV      DL,[EBX]
015F:021CE3B7  XOR      DL,35
015F:021CE3BA  CALL    `VCL50!@System@@LStrFromChar$qqrr17System@AnsiStringc`
015F:021CE3BF  MOV      EDX,[EBP-14]
015F:021CE3C2  LEA      EAX,[EBP-10]
015F:021CE3C5  CALL    `VCL50!@System@@LStrCat$qqrv`
015F:021CE3CA  DEC      ESI
015F:021CE3CB  JNZ      021CE3B1
015F:021CE3CD  MOV      EDX,[EBP-10]    //程式在這裡準備比對黑名單。
015F:021CE3D0  MOV      EAX,[EBP-04]    //
015F:021CE3D3  CALL    `VCL50!@Sysutils@CompareText$qqrx17System@AnsiStringt1`
015F:021CE3D8  TEST    EAX,EAX
015F:021CE3DA  JZ      021CE3E2
015F:021CE3DC  INC      EDI
015F:021CE3DD  CMP      EDI,[EBP-08]
015F:021CE3E0  JL      021CE391
015F:021CE3E2  CMP      EDI,[EBP-08]
015F:021CE3E5  JL      021CE3F9
015F:021CE3E7  SUB      EBX,021CE330
015F:021CE3ED  MOV      EAX,[EBP-0C]
015F:021CE3F0  DEC      EAX
015F:021CE3F1  CMP      EBX,EAX
015F:021CE3F3  JNZ      021CE3F9
015F:021CE3F5  XOR      EAX,EAX
015F:021CE3F7  JMP      SHORT 021CE3FB
015F:021CE3F9  MOV      AL,01
015F:021CE3FB  MOV      EBX,EAX
015F:021CE3FD  XOR      EAX,EAX
015F:021CE3FF  POP      EDX
015F:021CE400  POP      ECX
015F:021CE401  POP      ECX
015F:021CE402  MOV      [FS:EAX],EDX
015F:021CE405  PUSH    DWORD 021CE41F
015F:021CE40A  LEA      EAX,[EBP-14]
015F:021CE40D  MOV      EDX,02
015F:021CE412  CALL    `VCL50!@System@@LStrArrayClr$qqrv`
015F:021CE417  RET   

如此我們進入了第二段,從21CE448進去,進入21Ce115 Call 21CDFBC看看。
這裡程式將對你的名字進行變形換位。
015F:021CDFD5  PUSH    DWORD 021CE066
015F:021CDFDA  PUSH    DWORD [FS:EAX]
015F:021CDFDD  MOV      [FS:EAX],ESP
015F:021CDFE0  MOV      EAX,EBX
015F:021CDFE2  MOV      EDX,[EBP-04]
015F:021CDFE5  CALL    `VCL50!@System@@LStrAsg$qqrv`
015F:021CDFEA  MOV      EAX,[EBX]
015F:021CDFEC  CALL    `VCL50!@System@@LStrLen$qqrv`
015F:021CDFF1  MOV      EDI,EAX
015F:021CDFF3  SAR      EDI,1
015F:021CDFF5  JNS      021CDFFA
015F:021CDFF7  ADC      EDI,BYTE +00
015F:021CDFFA  TEST    EDI,EDI
015F:021CDFFC  JNG      021CE050
015F:021CDFFE  MOV      ESI,01
015F:021CE003  MOV      EAX,[EBX]        <-- [EBX],名字的地址。
015F:021CE005  MOV      AL,[EAX+ESI-01]
015F:021CE009  XOR      EDX,EDX
015F:021CE00B  MOV      DL,AL
015F:021CE00D  AND      EDX,BYTE +01
015F:021CE010  CMP      EDX,BYTE +01
015F:021CE013  JNZ      021CE04C
015F:021CE015  MOV      EDX,[EBX]
015F:021CE017  MOV      [EBP-05],AL
015F:021CE01A  MOV      EAX,[EBX]
015F:021CE01C  CALL    `VCL50!@System@@LStrLen$qqrv`
015F:021CE021  SUB      EAX,ESI
015F:021CE023  MOV      EDX,[EBX]
015F:021CE025  PUSH    DWORD [EDX+EAX]
015F:021CE028  MOV      EAX,EBX
015F:021CE02A  CALL    `VCL50!@System@UniqueString$qqrr17System@AnsiString`
015F:021CE02F  POP      EDX
015F:021CE030  MOV      [EAX+ESI-01],DL
015F:021CE034  MOV      EAX,[EBX]
015F:021CE036  CALL    `VCL50!@System@@LStrLen$qqrv`
015F:021CE03B  SUB      EAX,ESI
015F:021CE03D  PUSH    EAX
015F:021CE03E  MOV      EAX,EBX
015F:021CE040  CALL    `VCL50!@System@UniqueString$qqrr17System@AnsiString`
015F:021CE045  POP      EDX
015F:021CE046  MOV      CL,[EBP-05]
015F:021CE049  MOV      [EAX+EDX],CL
015F:021CE04C  INC      ESI
015F:021CE04D  DEC      EDI
015F:021CE04E  JNZ      021CE003
015F:021CE050  XOR      EAX,EAX
015F:021CE052  POP      EDX
015F:021CE053  POP      ECX
015F:021CE054  POP      ECX
015F:021CE055  MOV      [FS:EAX],EDX
015F:021CE058  PUSH    DWORD 021CE06D
015F:021CE05D  LEA      EAX,[EBP-04]
015F:021CE060  CALL    `VCL50!@System@@LStrClr$qqrr17System@AnsiString`
015F:021CE065  RET   


過了這段,下一段程式將產生兩個數字序列,為
一、01 02 03 04 ... 0F 10
二、01 23 45 67 89 AB CD EF FE DC ...32 10
在21CE120處的Call要進去看看,會發現生成第一個數字序列。
當執行Call 21CD4C0的時候,生成第二個序列。就像這樣:
015F:021CD4D1  MOV      DWORD [EBX],67452301       
015F:021CD4D7  MOV      DWORD [EBX+04],EFCDAB89
015F:021CD4DE  MOV      DWORD [EBX+08],98BADCFE
015F:021CD4E5  MOV      DWORD [EBX+0C],10325476
015F:021CD4EC  POP      EBX
015F:021CD4ED  RET   

程式在這裡將變形的姓名和上述的數字序列生成一個新的字串:
015F:021CDCF4  PUSH    EBX
015F:021CDCF5  PUSH    ESI
015F:021CDCF6  PUSH    EDI
015F:021CDCF7  PUSH    EBP
015F:021CDCF8  PUSH    ECX
015F:021CDCF9  MOV      ESI,ECX        ECX= 變形姓名長度
015F:021CDCFB  MOV      [ESP],EDX      EDX= 變形姓名地址
015F:021CDCFE  MOV      EBX,EAX
015F:021CDD00  MOV      EBP,[EBX+10]
015F:021CDD03  MOV      EAX,ESI       
015F:021CDD05  SHL      EAX,03
015F:021CDD08  ADD      [EBX+10],EAX    [EBX]=01 23 45 67 89 AB CD EF FE DC BA 98 76 54 32 10
015F:021CDD0B  CMP      EBP,[EBX+10]
015F:021CDD0E  JNG      021CDD13
015F:021CDD10  INC      DWORD [EBX+14]
015F:021CDD13  MOV      EAX,ESI
015F:021CDD15  SHR      EAX,1D
015F:021CDD18  ADD      [EBX+14],EAX
015F:021CDD1B  SHR      EBP,03
015F:021CDD1E  AND      EBP,BYTE +3F
015F:021CDD21  XOR      EDI,EDI
015F:021CDD23  TEST    EBP,EBP
015F:021CDD25  JZ      021CDD6D
015F:021CDD27  MOV      EDI,EBP
015F:021CDD29  MOV      EAX,40
015F:021CDD2E  SUB      EAX,EBP
015F:021CDD30  MOV      EBP,EAX
015F:021CDD32  CMP      EBP,ESI
015F:021CDD34  JNG      021CDD49
015F:021CDD36  MOVZX    EAX,DI
015F:021CDD39  LEA      EDX,[EBX+EAX+18]
015F:021CDD3D  MOV      EAX,[ESP]
015F:021CDD40  MOV      ECX,ESI
015F:021CDD42  CALL    `VCL50!@System@Move$qqrpxvpvi`
015F:021CDD47  JMP      SHORT 021CDDB8
015F:021CDD49  MOVZX    EAX,DI
015F:021CDD4C  LEA      EDX,[EBX+EAX+18]
015F:021CDD50  MOV      EAX,[ESP]
015F:021CDD53  MOV      ECX,EBP
015F:021CDD55  CALL    `VCL50!@System@Move$qqrpxvpvi`
015F:021CDD5A  PUSH    BYTE +0F
015F:021CDD5C  LEA      ECX,[EBX+18]
015F:021CDD5F  MOV      EAX,EBX
015F:021CDD61  MOV      EDX,03
015F:021CDD66  CALL    021CD5D8
015F:021CDD6B  SUB      ESI,EBP
015F:021CDD6D  CMP      ESI,BYTE +40
015F:021CDD70  JL      021CDDA5
015F:021CDD72  MOVZX    EAX,DI
015F:021CDD75  MOV      EDX,[ESP]
015F:021CDD78  LEA      EAX,[EDX+EAX]
015F:021CDD7B  LEA      EDX,[EBX+18]
015F:021CDD7E  MOV      ECX,40
015F:021CDD83  CALL    `VCL50!@System@Move$qqrpxvpvi`
015F:021CDD88  PUSH    BYTE +0F
015F:021CDD8A  LEA      ECX,[EBX+18]
015F:021CDD8D  MOV      EAX,EBX
015F:021CDD8F  MOV      EDX,03
015F:021CDD94  CALL    021CD5D8
015F:021CDD99  ADD      DI,BYTE +40
015F:021CDD9D  SUB      ESI,BYTE +40
015F:021CDDA0  CMP      ESI,BYTE +40
015F:021CDDA3  JNL      021CDD72
015F:021CDDA5  MOVZX    EAX,DI
015F:021CDDA8  MOV      EDX,[ESP]
015F:021CDDAB  LEA      EAX,[EDX+EAX]
015F:021CDDAE  LEA      EDX,[EBX+18]
015F:021CDDB1  MOV      ECX,ESI
015F:021CDDB3  CALL    `VCL50!@System@Move$qqrpxvpvi` 把變形名字接到後面。
015F:021CDDB8  POP      EDX
015F:021CDDB9  POP      EBP
015F:021CDDBA  POP      EDI
015F:021CDDBB  POP      ESI
015F:021CDDBC  POP      EBX
015F:021CDDBD  RET   

015F:021CDDC0  PUSH    EBX
015F:021CDDC1  PUSH    ESI
015F:021CDDC2  MOV      EBX,EDX
015F:021CDDC4  MOV      ESI,EAX
015F:021CDDC6  MOV      EAX,[EBX+10]
015F:021CDDC9  SHR      EAX,03
015F:021CDDCC  AND      AX,BYTE +3F
015F:021CDDD0  MOV      EDX,EAX
015F:021CDDD2  XOR      ECX,ECX
015F:021CDDD4  MOV      CL,DL
015F:021CDDD6  MOV      BYTE [EBX+ECX+18],80    <-- 變形名字所在位置後。
015F:021CDDDB  INC      EDX
015F:021CDDDC  MOV      CX,3F
015F:021CDDE0  SUB      CX,AX
015F:021CDDE3  MOV      EAX,ECX
015F:021CDDE5  CMP      AX,BYTE +08
015F:021CDDE9  JNC      021CDE22
015F:021CDDEB  AND      EDX,FF
015F:021CDDF1  LEA      EDX,[EBX+EDX+18]
015F:021CDDF5  MOVZX    EAX,AX
015F:021CDDF8  XOR      ECX,ECX
015F:021CDDFA  XCHG    EAX,EDX
015F:021CDDFB  CALL    `VCL50!@System@@FillChar$qqrv`
015F:021CDE00  PUSH    BYTE +0F
015F:021CDE02  LEA      ECX,[EBX+18]
015F:021CDE05  MOV      EAX,EBX
015F:021CDE07  MOV      EDX,03
015F:021CDE0C  CALL    021CD5D8
015F:021CDE11  LEA      EAX,[EBX+18]
015F:021CDE14  XOR      ECX,ECX
015F:021CDE16  MOV      EDX,38
015F:021CDE1B  CALL    `VCL50!@System@@FillChar$qqrv`
015F:021CDE20  JMP      SHORT 021CDE3A
015F:021CDE22  AND      EDX,FF
015F:021CDE28  LEA      EDX,[EBX+EDX+18]
015F:021CDE2C  MOVZX    EAX,AX
015F:021CDE2F  SUB      EAX,BYTE +08
015F:021CDE32  XOR      ECX,ECX
015F:021CDE34  XCHG    EAX,EDX
015F:021CDE35  CALL    `VCL50!@System@@FillChar$qqrv`
015F:021CDE3A  MOV      EAX,[EBX+10]
015F:021CDE3D  MOV      [EBX+50],EAX
015F:021CDE40  MOV      EAX,[EBX+14]
015F:021CDE43  MOV      [EBX+54],EAX
015F:021CDE46  PUSH    BYTE +0F
015F:021CDE48  LEA      ECX,[EBX+18]
015F:021CDE4B  MOV      EAX,EBX
015F:021CDE4D  MOV      EDX,03
015F:021CDE52  CALL    021CD5D8        〈--------  關鍵Call進去看看。
015F:021CDE57  MOV      EDX,ESI
015F:021CDE59  MOV      EAX,EBX
015F:021CDE5B  MOV      ECX,10
015F:021CDE60  CALL    `VCL50!@System@Move$qqrpxvpvi`
015F:021CDE65  MOV      EAX,EBX
015F:021CDE67  XOR      ECX,ECX
015F:021CDE69  MOV      EDX,58
015F:021CDE6E  CALL    `VCL50!@System@@FillChar$qqrv`
015F:021CDE73  POP      ESI
015F:021CDE74  POP      EBX
015F:021CDE75  RET   

程式的準備工作做完,下面開始註冊第一步。21CDE52 Call 21CD5D8,這個Call有600多行。
進行一系列運算後生成一個16位的數字。然後將這個16位數字轉成一個32位的字串。

最後從這個32位字串中取出8位作ID,另外24位作為註冊碼。
這是最後的程式:
015F:021CE125  MOV      EAX,[EBP-10]        <-- EAX中就是32位的字串地址。
015F:021CE128  CALL    `VCL50!@System@@LStrLen$qqrv`
015F:021CE12D  MOV      ESI,EAX
015F:021CE12F  TEST    ESI,ESI
015F:021CE131  JNG      021CE186
015F:021CE133  MOV      EBX,01
015F:021CE138  MOV      EAX,EBX
015F:021CE13A  AND      EAX,80000003
015F:021CE13F  JNS      021CE146
015F:021CE141  DEC      EAX
015F:021CE142  OR      EAX,BYTE -04
015F:021CE145  INC      EAX
015F:021CE146  TEST    EAX,EAX
015F:021CE148  JNZ      021CE165
015F:021CE14A  LEA      EAX,[EBP-14]
015F:021CE14D  MOV      EDX,[EBP-10]
015F:021CE150  MOV      DL,[EDX+EBX-01]
015F:021CE154  CALL    `VCL50!@System@@LStrFromChar$qqrr17System@AnsiStringc`
015F:021CE159  MOV      EDX,[EBP-14]
015F:021CE15C  MOV      EAX,EDI
015F:021CE15E  CALL    `VCL50!@System@@LStrCat$qqrv`  <--- ID連線
015F:021CE163  JMP      SHORT 021CE182
015F:021CE165  LEA      EAX,[EBP-18]
015F:021CE168  MOV      EDX,[EBP-10]
015F:021CE16B  MOV      DL,[EDX+EBX-01]
015F:021CE16F  CALL    `VCL50!@System@@LStrFromChar$qqrr17System@AnsiStringc`
015F:021CE174  MOV      EDX,[EBP-18]
015F:021CE177  MOV      EAX,[EBP-08]
015F:021CE17A  CALL    `VCL50!@System@@LStrCat$qqrv`  <--- 註冊碼連線
015F:021CE17F  MOV      EAX,[EBP-08]
015F:021CE182  INC      EBX
015F:021CE183  DEC      ESI
015F:021CE184  JNZ      021CE138           
015F:021CE186  XOR      EAX,EAX
015F:021CE188  POP      EDX
015F:021CE189  POP      ECX
015F:021CE18A  POP      ECX
015F:021CE18B  MOV      [FS:EAX],EDX
015F:021CE18E  PUSH    DWORD 021CE1B0
015F:021CE193  LEA      EAX,[EBP-18]
015F:021CE196  MOV      EDX,04
015F:021CE19B  CALL    `VCL50!@System@@LStrArrayClr$qqrv`
015F:021CE1A0  LEA      EAX,[EBP-04]
015F:021CE1A3  CALL    `VCL50!@System@@LStrClr$qqrr17System@AnsiString`
015F:021CE1A8  RET   

以下就是比較ID和註冊碼了,不貼了。

對於那個600多行的Call,沒看懂,只是寫序號產生器乾脆就把它貼上,注意傳入的引數位置就可以了。反正傳出的結果是正確的。其實我寫這個序號產生器所學到的東西遠比破解這個軟體要多。

序號產生器程式碼太長,不貼了。

感謝大家看完。

相關文章