五筆輸入通1.x註冊演算法分析 (10千字)

看雪資料發表於2015-11-15

某輸入通1.34註冊演算法分析

軟體網站:http://openinput.126.com/
破解工具:TRW
作者:Maomao[CCG]
日期:2002-7-15
軟體介紹:
    **輸入通是一個綜合性的、能夠滿足使用者多種輸入要求的軟體,使用者即可以掛接任意的形碼方案作為形碼輸入法,如五筆輸入,也可以用作拼音輸入法,拼音輸入支援字、詞、句間的無縫轉換,系統會根據使用者輸入的拼音由一定的演算法自動選出最可能的漢字,免去使用者逐字逐詞進行選擇的麻煩,提高了拼音輸入的效率。

宣告:
    這款軟體是國產軟體輸入法中比較優秀的軟體之一,註冊費用也比較合理,希望大家支援國產軟體。本人寫此文的目的僅在於幫助大家提高程式分析的能力,希望大家理解支援配合.

開啟此輸入法,選擇註冊,任意輸入29位註冊碼,下斷點bpx hmemcpy,然後按“註冊”,程式中斷,按幾次F12和F10(用pmodule會失敗),會來到Zwsrt的領空,這時會看到下面的程式碼:

0177:00C0E95F  PUSH    BYTE +01
0177:00C0E961  PUSH    EAX    <=====假碼
0177:00C0E962  CALL    00C0E3A0<======註冊演算法的call
0177:00C0E967  LEA      ECX,[ESP+0C]
0177:00C0E96B  MOV      [00C2B33A],EAX  <===EAx是返回值
0177:00C0E970  PUSH    ECX
0177:00C0E971  PUSH    DWORD 80000002
0177:00C0E976  CALL    00C014C0
0177:00C0E97B  TEST    EAX,EAX    <=====這裡比較
0177:00C0E97D  JZ      00C0E994    <=====跳走就完了

用F8跟進C0E962 的call,一路無話,來到這裡:

0177:00C0E431  MOV      AX,[EBP+00]<====EBP開始的記憶體中存放的就是機器碼了,每四位一段,共六段,十六進位制,這裡取第一段的四位數
0177:00C0E435  SHL      EAX,1 2 <====左移一位,相當於乘以2
0177:00C0E437  MOV      [ESP+10],EAX
0177:00C0E43B  MOV      [EBP+00],AX<====低四位放回
0177:00C0E43F  XOR      EAX,EAX
0177:00C0E441  MOV      AX,[EBP+02] <====取第二段
0177:00C0E445  LEA      EAX,[EAX+EAX*2]<====乘以3
0177:00C0E448  SHL      EAX,1<====再左移一位(乘以2)
0177:00C0E44A  MOV      [ESP+10],EAX
0177:00C0E44E  MOV      [EBP+02],AX<====低四位放回(相當於乘以6,取低四位)
0177:00C0E452  XOR      EAX,EAX
0177:00C0E454  MOV      AX,[EBP+04]<====取第三段
0177:00C0E458  LEA      EAX,[EAX+EAX*4]<====乘以5
0177:00C0E45B  MOV      [ESP+10],EAX
0177:00C0E45F  MOV      [EBP+04],AX<====低四位放回
0177:00C0E463  XOR      EAX,EAX
0177:00C0E465  MOV      AX,[EBP+06]<====取第四段
0177:00C0E469  SHL      EAX,02<====再左移二位(乘以4)
0177:00C0E46C  MOV      [ESP+10],EAX
0177:00C0E470  MOV      [EBP+06],AX<====低四位放回
0177:00C0E474  XOR      EAX,EAX
0177:00C0E476  MOV      AX,[EBP+08]<====取第五段
0177:00C0E47A  LEA      EAX,[EAX+EAX*8]<====乘以9
0177:00C0E47D  MOV      [ESP+10],EAX
0177:00C0E481  MOV      [EBP+08],AX<====低四位放回
0177:00C0E485  XOR      EAX,EAX
0177:00C0E487  MOV      AX,[EBP+0A]<====取第六段
0177:00C0E48B  LEA      ECX,[EAX*8+00000000]<====乘以8
0177:00C0E492  SUB      ECX,EAX<====再減去自己(相當於完成乘以7)
0177:00C0E494  XOR      EAX,EAX
0177:00C0E496  MOV      [ESP+10],ECX
0177:00C0E49A  MOV      AX,[EBP+00]<====取第一段運算結果
0177:00C0E49E  MOV      [EBP+0A],CX <====低四位放回
0177:00C0E4A2  MOV      ECX,EAX
0177:00C0E4A4  MOV      EAX,[ESP+10]
0177:00C0E4A8  AND      EAX,FFFF  <====取得第六段運算結果
0177:00C0E4AD  LEA      EDX,[EAX+EAX*2]<====第六段*3
0177:00C0E4B0  LEA      EAX,[EDX+ECX*2]<==== 加 第一段*2
0177:00C0E4B3  MOV      [ESP+10],EAX
0177:00C0E4B7  MOV      [EBP+0A],AX<====低四位放回第六段
0177:00C0E4BB  XOR      EAX,EAX
0177:00C0E4BD  XOR      ECX,ECX
0177:00C0E4BF  MOV      AX,[EBP+04]<====取第三段運算結果
0177:00C0E4C3  MOV      CX,[EBP+08]<====取第五段運算結果
0177:00C0E4C7  LEA      EAX,[ECX+EAX*2]<====第五段+第三段*2
0177:00C0E4CA  MOV      [ESP+10],EAX
0177:00C0E4CE  MOV      [EBP+08],AX<====低四位放回第五段
0177:00C0E4D2  CMP      [ESP+80],EBX
0177:00C0E4D9  JZ      NEAR 00C0E5EA
小結:
假設我的機器碼是:38DF-F3D0-D5CE-C4C4-7D81-5874
從左往右依次為第  ①  ②  ③  ④  ⑤  ⑥ 段儲存於EBP中,上面這段程式完成以下的執行:
①=(①*2)&0xffff
②=(②*6)&0xffff
③=(③*5)&0xffff
④=(④*4)&0xffff
⑤=((⑤*9)&0xffff+③*2)&0xffff
⑥=((⑥*7)&0xffff+①*2)&0xffff

這樣六段合起來就是註冊碼了,但沒有任何跡像表明這就是註冊碼,因為下面還有一大段程式碼,比較有意思,是校驗:

0177:00C0E5FA  MOV      EDX,[ESP+18]
0177:00C0E5FE  LEA      EDI,[ESP+40]
0177:00C0E602  OR      ECX,BYTE -01
0177:00C0E605  XOR      EAX,EAX
0177:00C0E607  LEA      ESI,[ESP+2C]
0177:00C0E60B  REPNE SCASB
0177:00C0E60D  NOT      ECX
0177:00C0E60F  SUB      EDI,ECX
0177:00C0E611  MOV      [ESP+20],ESI
0177:00C0E615  MOV      EAX,ECX
0177:00C0E617  MOV      ESI,EDI
0177:00C0E619  MOV      EDI,[ESP+20]
0177:00C0E61D  SHR      ECX,02
0177:00C0E620  REP MOVSD
0177:00C0E622  MOV      ECX,EAX
0177:00C0E624  AND      ECX,BYTE +03
0177:00C0E627  CMP      EBX,BYTE +02<======EBX是計數器,記錄上次操作的段
0177:00C0E62A  REP MOVSB
0177:00C0E62C  JNL      00C0E63C<===========如果當前操作的段>2,則跳到下面轉換
0177:00C0E62E  LEA      ECX,[ESP+24]
0177:00C0E632  XOR      EAX,EAX
0177:00C0E634  MOV      AX,[EDX]<==========不轉換(1、2段)
0177:00C0E637  PUSH    BYTE +10
0177:00C0E639  PUSH    ECX
0177:00C0E63A  JMP      SHORT 00C0E653
0177:00C0E63C  MOV      AX,[EDX]  <==========3-6段需要轉換
0177:00C0E63F  LEA      ECX,[ESP+24]
0177:00C0E643  IMUL    AX,AX,BYTE +39<============乘以0x39
0177:00C0E647  AND      EAX,FFFF<============取低四位
0177:00C0E64C  PUSH    BYTE +10
0177:00C0E64E  MOV      [ESP+14],EAX
0177:00C0E652  PUSH    ECX
0177:00C0E653  PUSH    EAX
0177:00C0E654  CALL    `MSVCRT!_ltoa`<============轉成字串
0177:00C0E65A  OR      ECX,BYTE -01
0177:00C0E65D  LEA      EDI,[ESP+30]
0177:00C0E661  XOR      EAX,EAX
0177:00C0E663  ADD      ESP,BYTE +0C
0177:00C0E666  REPNE SCASB
0177:00C0E668  NOT      ECX
0177:00C0E66A  DEC      ECX
0177:00C0E66B  LEA      EDI,[ESP+45]
0177:00C0E66F  MOV      EDX,ECX
0177:00C0E671  OR      ECX,BYTE -01
0177:00C0E674  REPNE SCASB
0177:00C0E676  NOT      ECX
0177:00C0E678  SUB      EDI,ECX
0177:00C0E67A  LEA      ESI,[ESP+EDX+24]
0177:00C0E67E  MOV      EAX,ECX
0177:00C0E680  MOV      [ESP+20],ESI
0177:00C0E684  MOV      ESI,EDI
0177:00C0E686  MOV      EDI,[ESP+20]
0177:00C0E68A  SHR      ECX,02
0177:00C0E68D  REP MOVSD
0177:00C0E68F  MOV      ECX,EAX
0177:00C0E691  MOV      EAX,04
0177:00C0E696  AND      ECX,BYTE +03
0177:00C0E699  SUB      EAX,EDX
0177:00C0E69B  REP MOVSB
0177:00C0E69D  MOV      [ESP+10],EAX
0177:00C0E6A1  LEA      EDX,[ESP+EAX+2C]
0177:00C0E6A5  LEA      EDI,[ESP+24]
0177:00C0E6A9  OR      ECX,BYTE -01
0177:00C0E6AC  XOR      EAX,EAX
0177:00C0E6AE  REPNE SCASB
0177:00C0E6B0  NOT      ECX
0177:00C0E6B2  SUB      EDI,ECX
0177:00C0E6B4  MOV      EAX,ECX
0177:00C0E6B6  MOV      ESI,EDI
0177:00C0E6B8  MOV      EDI,EDX
0177:00C0E6BA  SHR      ECX,02
0177:00C0E6BD  REP MOVSD
0177:00C0E6BF  MOV      ECX,EAX
0177:00C0E6C1  XOR      EAX,EAX
0177:00C0E6C3  AND      ECX,BYTE +03
0177:00C0E6C6  REP MOVSB
0177:00C0E6C8  LEA      EDI,[ESP+2C]
0177:00C0E6CC  OR      ECX,BYTE -01
0177:00C0E6CF  REPNE SCASB
0177:00C0E6D1  MOV      EAX,[ESP+1C]
0177:00C0E6D5  NOT      ECX
0177:00C0E6D7  SUB      EDI,ECX
0177:00C0E6D9  MOV      EDX,ECX
0177:00C0E6DB  MOV      ESI,EDI
0177:00C0E6DD  MOV      EDI,EAX
0177:00C0E6DF  ADD      EAX,BYTE +05
0177:00C0E6E2  SHR      ECX,02
0177:00C0E6E5  REP MOVSD
0177:00C0E6E7  MOV      ECX,EDX
0177:00C0E6E9  MOV      [ESP+1C],EAX
0177:00C0E6ED  AND      ECX,BYTE +03
0177:00C0E6F0  INC      EBX
0177:00C0E6F1  REP MOVSB     
  以上這些程式碼完成各段的變換(3-6段*0x39),再轉成字串,不足四位高位補0,並連線
0177:00C0E6F3  MOV      ECX,[ESP+18]
0177:00C0E6F7  ADD      ECX,BYTE +02
0177:00C0E6FA  CMP      EBX,BYTE +06
0177:00C0E6FD  MOV      [ESP+18],ECX
0177:00C0E701  JL      NEAR 00C0E5FA<============取下一段進行運算
0177:00C0E707  LEA      EAX,[ESP+54]
0177:00C0E70B  MOV      BYTE [ESP+71],00
0177:00C0E710  PUSH    EAX<============全部轉換好的SN(小寫)
0177:00C0E711  MOV      DWORD [00C291C0],1234
0177:00C0E71B  CALL    `USER32!CharUpperA`<============轉成大寫
    如果你到這裡看到註冊碼,以為成功,那就大錯特錯了!這是作者的高明之處。暫且把這裡
得到串叫做校驗碼1。

接下來這段將得到的正確註冊進行如下變換,得到校驗碼2。
0177:00C0E759  MOV      EAX,EBP
0177:00C0E75B  MOV      ECX,06
0177:00C0E760  ADD      WORD [EAX],BYTE +34<====每段+0x34
0177:00C0E764  ADD      EAX,BYTE +02
0177:00C0E767  DEC      ECX
0177:00C0E768  JNZ      00C0E760
0177:00C0E7A8  MOV      EAX,EBP
0177:00C0E7AA  MOV      ECX,06
0177:00C0E7AF  ADD      WORD [EAX],0200<====每段+0x200
0177:00C0E7B4  ADD      EAX,BYTE +02
0177:00C0E7B7  DEC      ECX
0177:00C0E7B8  JNZ      00C0E7AF

這裡開始校驗了:

0177:00C0E7BA  MOV      EBX,[00C211D8]
0177:00C0E7C0  XOR      ESI,ESI
0177:00C0E7C2  MOV      EDI,EDX
0177:00C0E7C4  MOV      AX,[EBP+00]<=======校驗碼2
0177:00C0E7C8  ADD      AX,1000<=======加0x1000
0177:00C0E7CC  CMP      ESI,BYTE +02<=======第1、2段不比較
0177:00C0E7CF  MOV      [EBP+00],AX
0177:00C0E7D3  JNL      00C0E7E5<=======跳到校驗
0177:00C0E7D5  AND      EAX,FFFF
0177:00C0E7DA  IMUL    EAX,ESI<=======乘以(當前段數-1)
0177:00C0E7DD  SHL      EAX,1<=======乘以2
0177:00C0E7DF  MOV      [ESP+10],EAX<=======留到下次使用
0177:00C0E7E3  JMP      SHORT 00C0E81E
0177:00C0E7E5  MOV      EAX,[EDI]
0177:00C0E7E7  LEA      ECX,[ESP+10]
0177:00C0E7EB  PUSH    ECX
0177:00C0E7EC  LEA      EDX,[ESP+28]
0177:00C0E7F0  PUSH    DWORD 00C2384C
0177:00C0E7F5  PUSH    EDX
0177:00C0E7F6  MOV      BYTE [ESP+34],00
0177:00C0E7FB  MOV      [ESP+30],EAX
0177:00C0E7FF  CALL    EBX
0177:00C0E801  MOV      EAX,[ESP+1C]
0177:00C0E805  MOV      ECX,[00C291C0]
0177:00C0E80B  ADD      EAX,ECX <=======校驗碼1加0x1234
0177:00C0E80D  XOR      ECX,ECX
0177:00C0E80F  MOV      [ESP+1C],EAX
0177:00C0E813  MOV      CX,[EBP+00]
0177:00C0E817  ADD      ESP,BYTE +0C
0177:00C0E81A  CMP      EAX,ECX <=======與校驗碼2比較
0177:00C0E81C  JNZ      00C0E851  <=======跳走說明校驗失敗!
0177:00C0E81E  INC      ESI
0177:00C0E81F  ADD      EDI,BYTE +05
0177:00C0E822  ADD      EBP,BYTE +02
0177:00C0E825  CMP      ESI,BYTE +06
0177:00C0E828  JL      00C0E7C4 <=====繼續下一位校驗

  作者這一段看似無用的校驗,卻非常有用,既是障眼法又增加了跟蹤的難度,讓你搞不清他的比較方法,如果你在上面看到工某暫存器中有註冊碼,自以為成功,那你就上當了。只有多觀察分析比較思考(有點像說教),相信你能很快成為高手。 如果本文能對你學習破解有所幫助,我的目的就達到了:)

Maomao[CCG]
2002-7-15

相關文章