萬能五筆2001註冊碼分析及暴力破解 ---可憐的思考者 (27千字)

看雪資料發表於2002-04-15

此軟體比較複雜,未註冊前,給出註冊框,並限定了使用次數,使用兩百次之後,不能繼續使用,哪怕是輸入正確的註冊碼也不行,重灌也不行。輸入註冊碼之後,軟體退出,在每次啟動時都要重新判斷註冊碼正確與否。   
    它在註冊時採用了從電腦獲取電腦碼,並將輸入的註冊碼進行計算,算得的值同電腦碼進行比較,相等則表示註冊正確。由於每臺電腦的電腦碼不同,保證了一個註冊碼只能夠用於同一臺電腦。
    若用序號產生器的方法進行註冊,由於在某些使用者的機子上,已經超過了使用次數。這時註冊已經晚了。所以沒辦法,最後還是採取暴力破解更可行。
    在註冊方面,作者設定了很多的障礙:輸入的註冊碼有固定的前四位和後四位,只有中間的幾位才參與計算;在程式入口,也設定了相當多的障礙,加了許多的判斷,讓我幾乎迷失在無窮的跳轉中,即使在子程式也加入了跳轉。最後很無賴,只好跟蹤正確註冊的程式,才找到正確的路徑。
    寫的有點長,對不起大家。
 
以下是對註冊碼的分析,然後是再對其進行暴力破解
執行TRW,裝入!WNM,在出現對話方塊時,下BPX HMEMCPY,大家都是成年人,不用我說得太具體吧。
跟蹤到以下程式碼:


016F:0048CB74  MOV      EDX,[00496D34]    此處存的是“tt98 0615"     
016F:0048CB7A  MOVSX    EAX,CX
016F:0048CB7D  MOV      DL,[EDX+EAX]      依次取出8,9,t,t
016F:0048CB80  CMP      DL,3F
016F:0048CB83  JZ      0048CB8B
016F:0048CB85  CMP      [ESP+EAX+1C],DL    依次輸入的註冊碼的第4,3,2,1位
016F:0048CB89  JNZ      0048CB8F
016F:0048CB8B  DEC      CX
016F:0048CB8D  JNS      0048CB74          以上為比較前面四個位元組是否為 tt98
016F:0048CB8F  CMP      CX,BYTE -01
016F:0048CB93  JNZ      0048CB9A
016F:0048CB95  MOV      EBP,01            =1  可能表示首四位是正確的
016F:0048CB9A  MOV      EDI,[00496CBC]    為 "0615"
016F:0048CBA0  MOV      ECX,FFFFFFFF       
016F:0048CBA5  SUB      EAX,EAX
016F:0048CBA7  REPNE SCASB
016F:0048CBA9  NOT      ECX               
016F:0048CBAB  DEC      ECX                算出為4位
016F:0048CBAC  LEA      EDI,[ESP+1C]      為輸入的註冊碼
016F:0048CBB0  MOV      DX,CX
016F:0048CBB3  SUB      EAX,EAX
016F:0048CBB5  MOV      ECX,FFFFFFFF
016F:0048CBBA  REPNE SCASB
016F:0048CBBC  NOT      ECX         
016F:0048CBBE  DEC      ECX                算出輸入的註冊碼位數
016F:0048CBBF  SUB      CX,DX              減去4位
016F:0048CBC2  TEST    CX,CX
016F:0048CBC5  JNG      0048CBF6
016F:0048CBC7  XOR      SI,SI
016F:0048CBCA  TEST    DX,DX
016F:0048CBCD  JNG      0048CBF0
016F:0048CBCF  MOV      EAX,[00496CBC]  存的是0615的地址
016F:0048CBD4  MOVSX    EDI,SI
016F:0048CBD7  MOV      AL,[EAX+EDI]    0615中的0
016F:0048CBDA  CMP      AL,3F            小於F
016F:0048CBDC  JZ      0048CBE9
016F:0048CBDE  MOVSX    EBX,CX
016F:0048CBE1  ADD      EBX,EDI
016F:0048CBE3  CMP      [ESP+EBX+1C],AL
016F:0048CBE7  JNZ      0048CBF0
016F:0048CBE9  INC      SI
016F:0048CBEB  CMP      DX,SI
016F:0048CBEE  JG      0048CBCF        以上幾行比較後四位是否為0615
016F:0048CBF0  CMP      DX,SI
016F:0048CBF3  JNZ      0048CBF6
016F:0048CBF5  INC      EBP              由48CB95,可知道 EBP=2,可能表示首四位和末四位都正確
016F:0048CBF6  CMP      EBP,BYTE +02
016F:0048CBF9  JZ      0048CC05        跳到下面,

016F:0048CBFB  MOV      EBP,FFFFFFFE
016F:0048CC00  JMP      0048CD05

016F:0048CC05  MOV      EDI,[00496D34]      此處存的是“tt98 0615"
016F:0048CC0B  MOV      ECX,FFFFFFFF       
016F:0048CC10  SUB      EAX,EAX
016F:0048CC12  REPNE SCASB
016F:0048CC14  NOT      ECX                  ecx=5,這幾行好像沒什麼用
016F:0048CC16  SUB      EAX,EAX
016F:0048CC18  LEA      ESI,[ESP+ECX+1B]  為輸入的註冊碼後的第五位,即tt98後面的一位的地址
016F:0048CC1C  MOV      EDI,ESI           
016F:0048CC1E  MOV      ECX,FFFFFFFF
016F:0048CC23  REPNE SCASB
016F:0048CC25  NOT      ECX                ecx=b,即tt98後面剩餘的位數+1,包括0615
016F:0048CC27  MOV      EDI,[00496CBC]      edi為0615地址
016F:0048CC2D  SUB      EAX,EAX           
016F:0048CC2F  LEA      EDX,[ECX-01]        edx=a,即tt98後面剩餘的位數           
016F:0048CC32  MOV      ECX,FFFFFFFF
016F:0048CC37  REPNE SCASB
016F:0048CC39  NOT      ECX
016F:0048CC3B  DEC      ECX                ECX=4
016F:0048CC3C  MOV      EAX,ESI         
016F:0048CC3E  SUB      EAX,ECX            即輸入的註冊碼位置               
016F:0048CC40  MOV      ECX,ESI           
016F:0048CC42  MOV      BYTE [EAX+EDX],00  即輸入註冊碼的倒數第四位處,改位0,
                                            以便於下面呼叫函式判斷註冊碼中部(除tt98和
                                            0165)的位數
016F:0048CC46  CALL    00491A20            !! : 判斷輸入的字串是否滿足要求,見子程式1
016F:0048CC4B  TEST    EAX,EAX           
016F:0048CC4D  JNZ      0048CC59            eax=1時,正確,跳轉
016F:0048CC4F  MOV      EBP,FFFFFFFD
016F:0048CC54  JMP      0048CD05

016F:0048CC59  MOV      EDX,004930E8        此時存的“0604”字元
016F:0048CC5E  MOV      ECX,ESI            ESI為中間註冊碼首位地址
016F:0048CC60  MOV      EBP,FFFFFFFC
016F:0048CC65  CALL    00491A70            將其由字串轉換成二進位制的數,見子程式2
016F:0048CC6A  CMP      WORD [00496D28],BYTE +01
016F:0048CC72  MOV      ESI,EAX
016F:0048CC74  JNZ      0048CCCF

016F:0048CC76  MOV      DI,[00496D2E]
016F:0048CC7D  MOV      EDX,[00496CB0]
016F:0048CC83  SHR      DI,08
016F:0048CC87  MOV      CX,[00496D2E]
016F:0048CC8E  AND      CX,FF
016F:0048CC93  CALL    0048C790
016F:0048CC98  ADD      ESI,EAX
016F:0048CC9A  TEST    DI,DI
016F:0048CC9D  JNZ      0048CCA9
016F:0048CC9F  MOV      EDX,[00496CB4]
016F:0048CCA5  MOV      ECX,EDI
016F:0048CCA7  JMP      SHORT 0048CCB4
016F:0048CCA9  MOV      CX,DI
016F:0048CCAC  MOV      EDX,[00496CB4]
016F:0048CCB2  INC      CX
016F:0048CCB4  CALL    0048C790
016F:0048CCB9  MOV      ECX,EAX
016F:0048CCBB  TEST    ECX,ECX
016F:0048CCBD  JNZ      0048CCC6
016F:0048CCBF  MOV      EBP,FFFFFFFB
016F:0048CCC4  JMP      SHORT 0048CCFC
016F:0048CCC6  MOV      EAX,ESI
016F:0048CCC8  CDQ   
016F:0048CCC9  IDIV    ECX
016F:0048CCCB  MOV      EBP,EDX
016F:0048CCCD  JMP      SHORT 0048CCFC

016F:0048CCCF  CMP      WORD [00496D28],BYTE +02
016F:0048CCD7  JNZ      0048CCFC
016F:0048CCD9  MOV      DX,[00496D2E]      存的是 63 64,即6463
016F:0048CCE0  MOV      EAX,[00496CB4]      輸入的註冊人名地址
016F:0048CCE5  PUSH    EAX
016F:0048CCE6  MOV      ECX,[00496CB0]      也是 輸入的註冊人名地址
016F:0048CCEC  PUSH    ECX
016F:0048CCED  MOV      ECX,[00496AC4]      取出17EF7,十進位制為98039,即我機子上的電腦碼
016F:0048CCF3  CALL    0048C820            是由註冊人名和電腦碼算出一個數值
                                            !!! 若將此值換算成十進位制,即為正確的中間註冊碼
016F:0048CCF8  MOV      EBP,EAX           
016F:0048CCFA  SUB      EBP,ESI           
016F:0048CCFC  TEST    EBP,EBP     
016F:0048CCFE  JZ      0048CD29            !!!  此值與原算得的二進位制數比較,
                                                相等表示輸入的註冊碼正確,應跳轉

016F:0048CD00  MOV      EBP,FFFFFFFB       
016F:0048CD05  TEST    EBP,EBP
016F:0048CD07  JNL      0048CD29           
016F:0048CD09  INC      WORD [ESP+12]         
016F:0048CD0E  MOV      AX,[ESP+12]
016F:0048CD13  CMP      [00496D38],AX
016F:0048CD1A  JG      NEAR 0048C913
016F:0048CD20  JMP      SHORT 0048CD29
016F:0048CD22  MOV      EBP,[ESP+84]

016F:0048CD29  XOR      ESI,ESI           
016F:0048CD2B  TEST    EBP,EBP
016F:0048CD2D  JL      NEAR 0048CE08        若註冊碼正確,不跳
016F:0048CD33  MOV      AX,[ESP+12]       
016F:0048CD38  CMP      [00496D38],AX
016F:0048CD3F  JNG      NEAR 0048CE08
016F:0048CD45  MOV      EDX,01
016F:0048CD4A  MOV      ECX,[ESP+12]
016F:0048CD4E  CALL    0048C4C0            此處是判斷是否過時,若過時,即使註冊碼對,也不能用   
016F:0048CD53  TEST    EAX,EAX
016F:0048CD55  JZ      0048CDCD            過時則不跳轉,應跳轉
016F:0048CD57  PUSH    DWORD 1010
016F:0048CD5C  MOV      EBX,[00496D3C]
016F:0048CD62  MOVSX    EAX,WORD [ESP+16]
016F:0048CD67  SHL      EAX,02
016F:0048CD6A  PUSH    DWORD 004930E0
016F:0048CD6F  LEA      ECX,[EAX+EAX*2]
016F:0048CD72  LEA      EDX,[ECX+ECX*4]
016F:0048CD75  MOV      ECX,[ESP+1C]
016F:0048CD79  MOV      EAX,[EDX+EBX+34]
016F:0048CD7D  PUSH    EAX
016F:0048CD7E  PUSH    ECX
016F:0048CD7F  CALL    `USER32!MessageBoxA`      出現過時框
016F:0048CD85  MOV      ECX,[ESP+14]
016F:0048CD89  PUSH    DWORD 1001
016F:0048CD8E  PUSH    ECX
016F:0048CD8F  CALL    `USER32!GetDlgItem`
016F:0048CD95  MOV      ECX,EAX
016F:0048CD97  CALL    0048B910
016F:0048CD9C  MOV      [00496A5E],SI
016F:0048CDA3  PUSH    ESI
016F:0048CDA4  MOV      [004931C0],SI
016F:0048CDAB  PUSH    DWORD 8002
016F:0048CDB0  PUSH    DWORD 0111
016F:0048CDB5  MOV      ECX,[00496C80]
016F:0048CDBB  PUSH    ECX
016F:0048CDBC  CALL    `USER32!SendMessageA`
016F:0048CDC2  POP      EBP
016F:0048CDC3  POP      EDI
016F:0048CDC4  POP      ESI
016F:0048CDC5  POP      EBX
016F:0048CDC6  ADD      ESP,A8
016F:0048CDCC  RET   

016F:0048CDCD  MOV      EAX,[ESP+14]
016F:0048CDD1  MOV      ECX,[00496C80]
016F:0048CDD7  MOV      BYTE [00496AB3],02
016F:0048CDDE  PUSH    EAX
016F:0048CDDF  PUSH    DWORD 8000
016F:0048CDE4  PUSH    DWORD 0111
016F:0048CDE9  PUSH    ECX
016F:0048CDEA  CALL    `USER32!SendMessageA`
016F:0048CDF0  MOV      ECX,[ESP+14]
016F:0048CDF4  PUSH    BYTE +01
016F:0048CDF6  PUSH    ECX
016F:0048CDF7  CALL    `USER32!EndDialog`
016F:0048CDFD  POP      EBP
016F:0048CDFE  POP      EDI
016F:0048CDFF  POP      ESI
016F:0048CE00  POP      EBX
016F:0048CE01  ADD      ESP,A8
016F:0048CE07  RET   








子程式1


016F:00491A20  PUSH    ESI                 
016F:00491A21  MOV      EDX,ECX        edx,ecx為註冊碼中間部分的起始地址
016F:00491A23  PUSH    EDI
016F:00491A24  XOR      ESI,ESI       
016F:00491A26  MOV      EDI,EDX        edi為註冊碼中間部分的起始地址
016F:00491A28  MOV      ECX,FFFFFFFF
016F:00491A2D  SUB      EAX,EAX
016F:00491A2F  REPNE SCASB
016F:00491A31  NOT      ECX         
016F:00491A33  DEC      ECX            中間部分的位數
016F:00491A34  TEST    ECX,ECX     
016F:00491A36  JNG      00491A56      位數小於1,跳轉,但不出錯;位數大於1,不跳
          以下迴圈判斷中間註冊碼是否滿足條件
016F:00491A38  MOV      AL,[EDX+ESI]  取出字元
016F:00491A3B  CMP      AL,30
016F:00491A3D  JC      00491A5E
016F:00491A3F  CMP      AL,39
016F:00491A41  JA      00491A5E      是否在0~9之間,不再,則出錯輸出EAX=0
016F:00491A43  INC      ESI   
016F:00491A44  MOV      EDI,EDX
016F:00491A46  MOV      ECX,FFFFFFFF
016F:00491A4B  SUB      EAX,EAX
016F:00491A4D  REPNE SCASB
016F:00491A4F  NOT      ECX
016F:00491A51  DEC      ECX
016F:00491A52  CMP      ECX,ESI
016F:00491A54  JG      00491A38      迴圈判斷
016F:00491A56  MOV      EAX,01        正確,輸出EAX=1
016F:00491A5B  POP      EDI
016F:00491A5C  POP      ESI
016F:00491A5D  RET   
016F:00491A5E  XOR      EAX,EAX
016F:00491A60  POP      EDI
016F:00491A61  POP      ESI
016F:00491A62  RET   








子程式2


016F:00491A70  SUB      ESP,BYTE +08 
016F:00491A73  MOV      [ESP+04],EDX        0604字串
016F:00491A77  PUSH    EBX
016F:00491A78  MOV      DWORD [ESP+04],00
016F:00491A80  PUSH    ESI
016F:00491A81  PUSH    EDI
016F:00491A82  PUSH    EBP
016F:00491A83  MOV      ESI,01
016F:00491A88  PUSH    ECX
016F:00491A89  MOV      EBP,ECX              ESI為中間註冊碼首位地址
016F:00491A8B  CALL    `KERNEL32!lstrlenA`  求出中間註冊碼長度
016F:00491A91  LEA      EDI,[EAX-01]          EDI=長度-1
016F:00491A94  TEST    EDI,EDI
016F:00491A96  JL      00491AD3              長度大於0則不跳,否則出錯
                                       
                                      以下迴圈       
016F:00491A98  MOV      BL,[EBP+EDI+00]      依次取出中間註冊碼末位,末位-1,......
016F:00491A9C  CMP      BL,30
016F:00491A9F  JC      00491AAA
016F:00491AA1  CMP      BL,39
016F:00491AA4  JA      00491AAA              是否在0~9之間
016F:00491AA6  TEST    EDI,EDI     
016F:00491AA8  JNL      00491AB8            肯定要跳
016F:00491AAA  MOV      ECX,00493504
016F:00491AAF  MOV      EDX,[ESP+14]
016F:00491AB3  CALL    00491600

016F:00491AB8  XOR      EAX,EAX
016F:00491ABA  LEA      ECX,[ESI+ESI*4]      由491A83知,esi開始1,算得ECX=5,以後依次esi*10,即10,100,1000.....
016F:00491ABD  MOV      AL,BL
016F:00491ABF  SUB      EAX,BYTE +30        將此字元轉換成二進位制數
016F:00491AC2  IMUL    EAX,ESI             
016F:00491AC5  LEA      ESI,[ECX*2+`DOSMGR_BackFill_Allowed`] 
                                            DOSMGR_BackFill_Allowed=0
                                            算得ESI=10
016F:00491ACC  ADD      [ESP+10],EAX        原來的字元
016F:00491AD0  DEC      EDI
016F:00491AD1  JNS      00491A98            迴圈,直至所有的字元 

016F:00491AD3  MOV      EAX,[ESP+10]          由上面的分析,可知此子程式將輸入中間註冊碼
016F:00491AD7  POP      EBP                                  由字串轉換成二進位制的數
016F:00491AD8  POP      EDI
016F:00491AD9  POP      ESI
016F:00491ADA  POP      EBX
016F:00491ADB  ADD      ESP,BYTE +08
016F:00491ADE  RET   


總結一下,以上程式碼將輸入的註冊碼進行判斷,首先看註冊碼的起始和結尾的固定碼是否正確,若正確判斷中間註冊碼是否滿足一定要求。然後取出本機的電腦碼,由其算出正確的註冊碼。
關鍵點:
在48ccf3處,算出正確的註冊碼(要轉換成十進位制才能看到)
在48ccfe處與輸入的註冊碼進行比較。

上面的這一段,其實是我的失敗經驗。因為我不知怎麼亂搞,把註冊次數搞成了0次,這下即使得到註冊碼也沒用了,只好用暴力法破解。


分析檔案入口處的程式碼:


016F:0048E01D  MOV      ECX,01
016F:0048E022  CALL    00490AA0                      取得電腦資訊碼98039
016F:0048E027  XOR      EAX,EAX
016F:0048E029  MOV      AX,[00496D32]                 
016F:0048E02F  TEST    AH,C0                          ah=f0
016F:0048E032  JNZ      NEAR 0048E066                  應該跳轉

016F:0048E038  XOR      EAX,EAX
016F:0048E03A  MOV      AX,[00496D32]
016F:0048E040  TEST    AH,10
016F:0048E043  JZ      NEAR 0048E066                [496d32]=10 表示次數已用完
016F:0048E049  PUSH    BYTE +00
016F:0048E04B  PUSH    DWORD 8003
016F:0048E050  PUSH    DWORD 0111
016F:0048E055  MOV      EAX,[00496C80]
016F:0048E05A  PUSH    EAX
016F:0048E05B  CALL    `USER32!SendMessageA`          次數已用完錯誤框
016F:0048E061  JMP      0048E06B

016F:0048E066  CALL    0048E680
016F:0048E06B  CMP      DWORD [00493170],BYTE +00
016F:0048E072  JZ      NEAR 0048E08E
016F:0048E078  MOV      ECX,[EBP-50]
016F:0048E07B  CALL    00490CC0                      若登錄檔中的註冊碼不對,顯示開始的註冊框,裡面又有跳轉見子程式3,要改
016F:0048E080  MOV      [EBP-50],EAX
016F:0048E083  MOV      ECX,[EBP-50]
016F:0048E086  CALL    00490D80                      若註冊碼正確,即顯示正確框,裡面有跳轉,見子程式4,要改
016F:0048E08B  MOV      [EBP-50],EAX
016F:0048E08E  CMP      DWORD [EBP-50],BYTE +01
016F:0048E092  JNZ      NEAR 0048E0BF
016F:0048E098  XOR      EAX,EAX
016F:0048E09A  MOV      AX,[004931B8]
016F:0048E0A0  TEST    EAX,EAX
016F:0048E0A2  JZ      NEAR 0048E0BF
016F:0048E0A8  XOR      EAX,EAX
016F:0048E0AA  MOV      AX,[00496A9F]
016F:0048E0B0  TEST    EAX,EAX
016F:0048E0B2  JZ      NEAR 0048E0BF
016F:0048E0B8  DEC      WORD [00496A9F]
016F:0048E0BF  CMP      DWORD [EBP-50],BYTE +01
016F:0048E0C3  JNZ      NEAR 0048E1D5
016F:0048E0C9  XOR      EAX,EAX
016F:0048E0CB  MOV      AX,[004931B8]
016F:0048E0D1  TEST    EAX,EAX
016F:0048E0D3  JZ      NEAR 0048E1D5
016F:0048E0D9  XOR      EAX,EAX
016F:0048E0DB  MOV      AX,[0049317C]
016F:0048E0E1  TEST    AL,02
016F:0048E0E3  JNZ      NEAR 0048E107
016F:0048E0E9  CMP      DWORD [00493178],BYTE +00
016F:0048E0F0  JZ      NEAR 0048E107                  應該跳轉

016F:0048E0F6  XOR      EAX,EAX
016F:0048E0F8  MOV      AX,[0049317C]
016F:0048E0FE  OR      EAX,BYTE +02
016F:0048E101  MOV      [0049317C],AX
016F:0048E107  XOR      EAX,EAX
016F:0048E109  MOV      AX,[0049317C]
016F:0048E10F  TEST    AL,02
016F:0048E111  JZ      NEAR 0048E146                  應該跳轉

016F:0048E117  CALL    00491250
016F:0048E11C  MOV      [004931B8],AX
016F:0048E122  XOR      EAX,EAX
016F:0048E124  MOV      AX,[004931B8]
016F:0048E12A  TEST    EAX,EAX
016F:0048E12C  JNZ      NEAR 0048E146
016F:0048E132  PUSH    BYTE +00
016F:0048E134  PUSH    DWORD 004930B8
016F:0048E139  PUSH    DWORD 004932DC
016F:0048E13E  PUSH    BYTE +00
016F:0048E140  CALL    `USER32!MessageBoxA`            server is full 錯誤資訊

016F:0048E146  XOR      EAX,EAX
016F:0048E148  MOV      AX,[0049317C]
016F:0048E14E  TEST    AL,01
016F:0048E150  JNZ      NEAR 0048E1D5
016F:0048E156  CMP      DWORD [00493174],BYTE +00
016F:0048E15D  JZ      NEAR 0048E198                  應該跳轉

016F:0048E163  MOVSX    EAX,WORD [00496AB1]
016F:0048E16A  TEST    EAX,EAX
016F:0048E16C  JL      NEAR 0048E198
016F:0048E172  MOVSX    EAX,WORD [00496AB1]
016F:0048E179  SHL      EAX,02
016F:0048E17C  LEA      EAX,[EAX+EAX*2]
016F:0048E17F  LEA      EAX,[EAX+EAX*4]
016F:0048E182  MOV      ECX,[00496D3C]
016F:0048E188  XOR      EDX,EDX
016F:0048E18A  MOV      DX,[EAX+ECX+28]
016F:0048E18F  TEST    DL,08
016F:0048E192  JNZ      NEAR 0048E1C4
016F:0048E198  CMP      DWORD [00493174],BYTE +00
016F:0048E19F  JZ      NEAR 0048E1D5                  應該跳轉 

016F:0048E1A5  MOVSX    EAX,WORD [00496AB1]
016F:0048E1AC  TEST    EAX,EAX
016F:0048E1AE  JNL      NEAR 0048E1D5
016F:0048E1B4  XOR      EAX,EAX
016F:0048E1B6  MOV      AX,[00496D44]
016F:0048E1BC  TEST    AL,08
016F:0048E1BE  JZ      NEAR 0048E1D5
016F:0048E1C4  XOR      EAX,EAX
016F:0048E1C6  MOV      AX,[0049317C]
016F:0048E1CC  OR      EAX,BYTE +01
016F:0048E1CF  MOV      [0049317C],AX
016F:0048E1D5  XOR      EAX,EAX
016F:0048E1D7  MOV      AX,[0049317C]
016F:0048E1DD  TEST    EAX,EAX
016F:0048E1DF  JZ      NEAR 0048E2B7                  應該跳轉

016F:0048E1E5  CMP      DWORD [EBP-50],BYTE +01
016F:0048E1E9  JNZ      NEAR 0048E2B7
016F:0048E1EF  XOR      EAX,EAX
016F:0048E1F1  MOV      AX,[004931B8]
016F:0048E1F7  TEST    EAX,EAX
016F:0048E1F9  JZ      NEAR 0048E2B7
016F:0048E1FF  LEA      EAX,[EBP-64]
016F:0048E202  PUSH    EAX
016F:0048E203  MOV      EDX,00496C70
016F:0048E208  LEA      ECX,[00496AA1]
016F:0048E20E  CALL    00491B50
016F:0048E213  MOV      ECX,00496A40
016F:0048E218  ADD      ECX,BYTE +61
016F:0048E21B  MOV      EDX,[EAX]
016F:0048E21D  MOV      [ECX],EDX
016F:0048E21F  MOV      EDX,[EAX+04]
016F:0048E222  MOV      [ECX+04],EDX
016F:0048E225  MOV      EDX,[EAX+08]
016F:0048E228  MOV      [ECX+08],EDX
016F:0048E22B  MOV      EAX,[EAX+0C]
016F:0048E22E  MOV      [ECX+0C],EAX
016F:0048E231  CALL    00490640
016F:0048E236  TEST    EAX,EAX
016F:0048E238  JNZ      NEAR 0048E24D
016F:0048E23E  MOV      EDX,004932D4
016F:0048E243  MOV      ECX,004932B8
016F:0048E248  CALL    00491600
016F:0048E24D  MOV      EDX,00496B40
016F:0048E252  LEA      ECX,[00496AA1]
016F:0048E258  CALL    00490BC0
016F:0048E25D  MOV      ECX,[EBP+10]
016F:0048E260  CALL    00491100
016F:0048E265  TEST    EAX,EAX
016F:0048E267  JZ      NEAR 0048E295
016F:0048E26D  CALL    00491080
016F:0048E272  MOV      [EBP-50],EAX
016F:0048E275  PUSH    BYTE +00
016F:0048E277  PUSH    BYTE +00
016F:0048E279  PUSH    BYTE +10
016F:0048E27B  MOV      EAX,[00496C80]
016F:0048E280  PUSH    EAX
016F:0048E281  CALL    `USER32!SendMessageA`
016F:0048E287  MOV      WORD [004931B8],00
016F:0048E290  JMP      0048E2B7
016F:0048E295  MOV      DWORD [EBP-50],00
016F:0048E29C  MOV      WORD [004931B8],00
016F:0048E2A5  PUSH    BYTE +00
016F:0048E2A7  PUSH    BYTE +00
016F:0048E2A9  PUSH    BYTE +10
016F:0048E2AB  MOV      EAX,[00496C80]
016F:0048E2B0  PUSH    EAX
016F:0048E2B1  CALL    `USER32!SendMessageA`
016F:0048E2B7  LEA      EDX,[EBP-4C]
016F:0048E2BA  LEA      ECX,[EBP-54]
016F:0048E2BD  CALL    0048E3D0
016F:0048E2C2  MOV      [EBP-48],EAX
016F:0048E2C5  PUSH    BYTE +00
016F:0048E2C7  PUSH    BYTE +00
016F:0048E2C9  PUSH    BYTE +10
016F:0048E2CB  MOV      EAX,[00496C80]
016F:0048E2D0  PUSH    EAX
016F:0048E2D1  CALL    `USER32!SendMessageA`
016F:0048E2D7  CMP      DWORD [00493180],BYTE +02
016F:0048E2DE  JZ      NEAR 0048E32C                      要改
016F:0048E2E4  CMP      DWORD [EBP-50],BYTE +01
016F:0048E2E8  JNZ      NEAR 0048E32C                      要改
016F:0048E2EE  XOR      EAX,EAX
016F:0048E2F0  MOV      AX,[004931B8]
016F:0048E2F6  TEST    EAX,EAX
016F:0048E2F8  JZ      NEAR 0048E32C                      要改
016F:0048E2FE  MOV      EAX,[EBP+08]
016F:0048E301  PUSH    EAX
016F:0048E302  PUSH    DWORD 004931A8
016F:0048E307  CALL    `USER32!UnregisterClassA`
016F:0048E30D  XOR      EAX,EAX
016F:0048E30F  MOV      AX,[004931BC]
016F:0048E315  TEST    EAX,EAX
016F:0048E317  JZ      NEAR 0048E32C                        要改
016F:0048E31D  MOV      EAX,[EBP-4C]
016F:0048E320  PUSH    EAX
016F:0048E321  LEA      EDX,[EBP-54]
016F:0048E324  MOV      ECX,[EBP-48]
016F:0048E327  CALL    0048E360                      好了,就是它,但此過程中又有跳轉,見下面子程式5,要改
016F:0048E32C  CMP      DWORD [EBP-54],BYTE +00
016F:0048E330  JZ      NEAR 0048E33E
016F:0048E336  MOV      ECX,[EBP-54]
016F:0048E339  CALL    004915F0
016F:0048E33E  MOV      EAX,[EBP-50]
016F:0048E341  PUSH    EAX
016F:0048E342  CALL    `KERNEL32!ExitProcess`
016F:0048E348  MOV      EAX,[EBP-50]
016F:0048E34B  JMP      0048E350
016F:0048E350  POP      EDI
016F:0048E351  POP      ESI
016F:0048E352  POP      EBX
016F:0048E353  LEAVE 
016F:0048E354  RET      10



子程式3:若上次退出前輸入的註冊碼正確,此處不顯示註冊碼對話方塊,否則要顯示


016F:00490CC0  TEST    BYTE [00496D33],80
016F:00490CC7  PUSH    ESI
016F:00490CC8  PUSH    EDI
016F:00490CC9  MOV      ESI,ECX
016F:00490CCB  JZ      NEAR 00490D7A
016F:00490CD1  CMP      WORD [004931B8],BYTE +00
016F:00490CD9  JNZ      00490CE4
016F:00490CDB  CMP      BYTE [00496AB3],02
016F:00490CE2  JNZ      00490D15                        跳轉

016F:00490CE4  CMP      WORD [00496AB1],BYTE +00
016F:00490CEC  JL      00490D0B
016F:00490CEE  MOVSX    EAX,WORD [00496AB1]
016F:00490CF5  SHL      EAX,02
016F:00490CF8  LEA      ECX,[EAX+EAX*2]
016F:00490CFB  MOV      EAX,[00496D3C]
016F:00490D00  LEA      EDX,[ECX+ECX*4]
016F:00490D03  CMP      WORD [EDX+EAX+02],BYTE +00
016F:00490D09  JNZ      00490D15
016F:00490D0B  CMP      WORD [00493160],BYTE +02
016F:00490D13  JNZ      00490D7A

016F:00490D15  XOR      EDX,EDX
016F:00490D17  MOV      ECX,68
016F:00490D1C  MOV      ESI,00
016F:00490D21  CALL    00491510
016F:00490D26  MOV      EDX,00496B20
016F:00490D2B  MOV      ECX,EAX
016F:00490D2D  MOV      [00496CC0],EAX
016F:00490D32  CALL    0048D4E0
016F:00490D37  TEST    EAX,EAX
016F:00490D39  JZ      00490D4C                      應該跳轉
                     
016F:00490D3B  MOV      EDX,0048D010
016F:00490D40  MOV      ECX,00496B20
016F:00490D45  CALL    0048D680                      即註冊對話方塊
016F:00490D4A  MOV      ESI,EAX

016F:00490D4C  MOV      ECX,00496B20                  到此處
016F:00490D51  CALL    0048B200
016F:00490D56  MOV      EAX,[00496CC0]
016F:00490D5B  MOV      EDI,[00497394]
016F:00490D61  PUSH    EAX
016F:00490D62  CALL    EDI
016F:00490D64  PUSH    EAX
016F:00490D65  CALL    `KERNEL32!GlobalUnlock`
016F:00490D6B  MOV      EAX,[00496CC0]
016F:00490D70  PUSH    EAX
016F:00490D71  CALL    EDI
016F:00490D73  PUSH    EAX
016F:00490D74  CALL    `KERNEL32!GlobalFree`
016F:00490D7A  MOV      EAX,ESI
016F:00490D7C  POP      EDI
016F:00490D7D  POP      ESI



子程式4:若上次退出前輸入的註冊碼正確,顯示註冊人和註冊名框,否則不顯示


016F:00490D80  TEST    BYTE [00496D33],40
016F:00490D87  PUSH    ESI
016F:00490D88  PUSH    EDI
016F:00490D89  MOV      ESI,ECX
016F:00490D8B  JZ      NEAR 00490E86
016F:00490D91  CMP      WORD [00496AB1],BYTE +00
016F:00490D99  JL      00490DBC
016F:00490D9B  MOVSX    EAX,WORD [00496AB1]
016F:00490DA2  SHL      EAX,02
016F:00490DA5  LEA      ECX,[EAX+EAX*2]
016F:00490DA8  MOV      EAX,[00496D3C]
016F:00490DAD  LEA      EDX,[ECX+ECX*4]
016F:00490DB0  CMP      WORD [EDX+EAX+02],BYTE +00
016F:00490DB6  JNZ      NEAR 00490E86
016F:00490DBC  CMP      WORD [004931B8],BYTE +00
016F:00490DC4  JZ      00490DCF
016F:00490DC6  CMP      BYTE [00496AB3],02
016F:00490DCD  JZ      00490E00
016F:00490DCF  TEST    BYTE [00496D33],80
016F:00490DD6  JNZ      NEAR 00490E86                不跳
016F:00490DDC  TEST    BYTE [00496D33],10
016F:00490DE3  JZ      00490E00                  應該跳轉

016F:00490DE5  MOV      ECX,01
016F:00490DEA  CALL    0048E700              次數用完對話方塊
016F:00490DEF  TEST    EAX,EAX
016F:00490DF1  JZ      00490E00
016F:00490DF3  TEST    BYTE [00496D33],10
016F:00490DFA  JNZ      NEAR 00490E86

016F:00490E00  XOR      EDX,EDX
016F:00490E02  MOV      ECX,6D
016F:00490E07  MOV      ESI,00
016F:00490E0C  CALL    00491510
016F:00490E11  MOV      EDX,00496C90
016F:00490E16  MOV      ECX,EAX
016F:00490E18  MOV      [00496D1C],EAX
016F:00490E1D  CALL    0048D4E0
016F:00490E22  TEST    EAX,EAX
016F:00490E24  JZ      00490E37
016F:00490E26  MOV      EDX,0048D6C0
016F:00490E2B  MOV      ECX,00496C90
016F:00490E30  CALL    0048D680              註冊正確框,正確的註冊名和註冊碼

016F:00490E35  MOV      ESI,EAX
016F:00490E37  MOV      ECX,00496C90
016F:00490E3C  CALL    0048B200
016F:00490E41  MOV      EAX,[00496D1C]
016F:00490E46  MOV      EDI,[00497394]
016F:00490E4C  PUSH    EAX
016F:00490E4D  CALL    EDI
016F:00490E4F  PUSH    EAX
016F:00490E50  CALL    `KERNEL32!GlobalUnlock`
016F:00490E56  MOV      EAX,[00496D1C]
016F:00490E5B  PUSH    EAX
016F:00490E5C  CALL    EDI
016F:00490E5E  PUSH    EAX
016F:00490E5F  CALL    `KERNEL32!GlobalFree`
016F:00490E65  TEST    BYTE [00496D33],10
016F:00490E6C  JNZ      00490E86
016F:00490E6E  PUSH    BYTE +00
016F:00490E70  MOV      EAX,[00496C80]
016F:00490E75  PUSH    DWORD 8000
016F:00490E7A  PUSH    DWORD 0111
016F:00490E7F  PUSH    EAX
016F:00490E80  CALL    `USER32!SendMessageA`
016F:00490E86  MOV      EAX,ESI
016F:00490E88  POP      EDI
016F:00490E89  POP      ESI
              ret
             


子程式5:進入正確的萬能五筆程式,但進入前要判斷一下。


016F:0048E360  PUSH    ESI
016F:0048E361  PUSH    EDI
016F:0048E362  MOV      ESI,EDX
016F:0048E364  MOV      EDI,[ESP+0C]
016F:0048E368  MOV      EDX,[ECX+02]
016F:0048E36B  XOR      EDX,[ECX+06]
016F:0048E36E  XOR      EDX,[ECX+0A]
016F:0048E371  ADD      EDI,EDX
016F:0048E373  XOR      EDX,EDX
016F:0048E375  MOV      EAX,[ECX+06]
016F:0048E378  INC      EDX
016F:0048E379  XOR      [EDI+EDX*4-04],EAX
016F:0048E37D  INC      EDX
016F:0048E37E  MOV      EAX,[ECX+0A]
016F:0048E381  XOR      [EDI+EDX*4-04],EAX
016F:0048E385  CMP      EDX,BYTE +14
016F:0048E388  JL      0048E375
016F:0048E38A  MOV      ECX,[ESI]
016F:0048E38C  CALL    004915F0
016F:0048E391  MOV      DWORD [ESI],00
016F:0048E397  CMP      WORD [004931B8],BYTE +00
016F:0048E39F  JZ      0048E3AD                      要改
016F:0048E3A1  CMP      WORD [004931C0],BYTE +00
016F:0048E3A9  JZ      0048E3AD
016F:0048E3AB  CALL    EDI                          就是它,正確的程式在此處,TNND,找死我了
016F:0048E3AD  PUSH    BYTE +00
016F:0048E3AF  PUSH    DWORD 00493328
016F:0048E3B4  PUSH    DWORD 00493318
016F:0048E3B9  PUSH    BYTE +00
016F:0048E3BB  CALL    `USER32!MessageBoxA`
016F:0048E3C1  POP      EDI
016F:0048E3C2  POP      ESI
016F:0048E3C3  RET      04


好,總結以下,其實就是不斷的判斷障礙,

註冊對話方塊在 48e07b call的子程式中。
正確的程式程式碼藏在 48e3ab call的子程式中。

知道了這一點(也是最困難的一點),就容易對症下藥了。

其中要更改的地方有:
490d39
48e086 改為nop
48e2de
48e2e8
48e2f8
48e39f
48e3a9

當然不一定非得如此,只要能跳到48e3ab,其他的跳轉應該也行。

相關文章