各位大哥,看看我的演算法分析是否正確? (11千字)

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

SpamKiller2.90版的演算法分析

作者:Batman
   
0167:00498109  CALL      00404068
0167:0049810E  MOV      [EBP-0C],EAX
0167:00498111  CMP      DWORD PTR [EBP-0C],10  // 比較註冊碼是否是16位
0167:00498115  JNZ      00498372  // 不是就跳轉出錯(不能跳)
0167:0049811B  MOV      EAX,[EBP-04]
0167:0049811E  CMP      BYTE PTR [EAX+04],2D  // 比較註冊碼第五位是否是“-”
0167:00498122  JNZ      00498372  // 不是就跳轉出錯(不能跳)
0167:00498128  MOV      EAX,[EBP-04]
0167:0049812B  CMP      BYTE PTR [EAX+09],2D  // 比較註冊碼第十位是否是“-”
0167:0049812F  JNZ      00498372  // 不是就跳轉出錯(不能跳)
0167:00498135  MOV      EBX,00000011
0167:0049813A  MOV      ESI,004EF4DC
0167:0049813F  LEA      EDX,[EBP-14]
0167:00498142  MOV      EAX,[ESI]
0167:00498144  CALL      00487CE4
0167:00498149  MOV      EDX,[EBP-14]
0167:0049814C  MOV      EAX,[EBP-04]
0167:0049814F  CALL      00404178  // 比較註冊碼是否是“003E-9124-7E3E39”(黑名單)
0167:00498154  JZ        00498372  // 是就跳轉出錯(不能跳)
0167:0049815A  ADD      ESI,04
0167:0049815D  DEC      EBX
0167:0049815E  JNZ      0049813F  // 反覆跳轉數次
0167:00498160  XOR      EDX,EDX
0167:00498162  PUSH      EBP
0167:00498163  PUSH      00498368
0167:00498168  PUSH      DWORD PTR FS:[EDX]
0167:0049816B  MOV      FS:[EDX],ESP
0167:0049816E  MOV      EBX,00000001
0167:00498173  JMP      00498191  // 向下跳轉
0167:00498175  MOV      EAX,[EBP-04]
0167:00498178  CMP      BYTE PTR [EBX+EAX-01],2D
0167:0049817D  JNZ      00498190
0167:0049817F  LEA      EAX,[EBP-04]
0167:00498182  MOV      ECX,00000001
0167:00498187  MOV      EDX,EBX
0167:00498189  CALL      004042B0  // 這裡的CALL去除註冊碼中的“-”
0167:0049818E  JMP      00498191
0167:00498190  INC      EBX
0167:00498191  MOV      EAX,[EBP-04]  // 跳到這裡
0167:00498194  CALL      00404068
0167:00498199  CMP      EBX,EAX
0167:0049819B  JLE      00498175  // 反覆跳轉數次,以去除註冊碼中的“-”
0167:0049819D  MOV      EAX,[EBP-04]
0167:004981A0  CALL      00404068
0167:004981A5  MOV      [EBP-0C],EAX
0167:004981A8  CMP      DWORD PTR [EBP-0C],0E  // 比較去除“-”後的註冊碼是否是14位
0167:004981AC  JZ        004981BB  // 是就跳轉(要跳)
0167:004981AE  XOR      EAX,EAX
0167:004981B0  POP      EDX
0167:004981B1  POP      ECX
0167:004981B2  POP      ECX
0167:004981B3  MOV      FS:[EAX],EDX
0167:004981B6  JMP      00498372
0167:004981BB  XOR      ECX,ECX  // 跳到這裡,ECX清零(即ECX=0)
0167:004981BD  MOV      EAX,[EBP-0C]  // 將註冊碼的位數(即14)送給EAX(已去除“-”)
0167:004981C0  DEC      EAX  // EAX=14-1=13
0167:004981C1  TEST      EAX,EAX  // 測試EAX
0167:004981C3  JLE      004981D8
0167:004981C5  MOV      EBX,00000001  // 將01送給EBX(即EBX=01
0167:004981CA  MOV      EDX,[EBP-04]  // 將去除“-”的註冊碼送給EDX
0167:004981CD  MOVZX    EDX,BYTE PTR [EBX+EDX-01]  // 依次註冊碼字元的十六進位制值給EDX
0167:004981D2  ADD      ECX,EDX  // ECX=ECX+EDX ,將註冊碼的前13位字元的十六進位制值相加,結果存入ECX
0167:004981D4  INC      EBX  // EBX加1
0167:004981D5  DEC      EAX  // EAX-1
0167:004981D6  JNZ      004981CA  // 不相等則跳(反覆跳轉13次,也就是將註冊碼的前13位字元的十六進位制值相加,結果存入ECX)
0167:004981D8  MOV      EAX,ECX  // 將註冊碼的前13位字元的十六進位制值相加的值送給EAX
0167:004981DA  MOV      ECX,0000000A  // ECX=0A
0167:004981DF  CDQ
0167:004981E0  IDIV      ECX  // EAX除以ECX,餘數放入DL
0167:004981E2  ADD      DL,30  // DL=DL(即餘數)+30
0167:004981E5  MOV      EAX,[EBP-04]
0167:004981E8  MOV      ECX,[EBP-0C]
0167:004981EB  CMP      DL,[ECX+EAX-01]  // 比較DL中的字元與註冊碼的最後一位是否相等
0167:004981EF  JNZ      0049835E  // 不相等就跳轉出錯(不能跳)
0167:004981F5  XOR      ECX,ECX  //ECX=0
0167:004981F7  MOV      EBX,00000001  // EBX=1
0167:004981FC  MOV      EAX,[EBP-04]  // 將去除“-”的註冊碼送給EAX
0167:004981FF  MOVZX    EAX,BYTE PTR [EBX+EAX-01]  // 依次註冊碼字元的十六進位制值給EAX
0167:00498204  ADD      ECX,EAX  // ECX=ECX+EAX ,將註冊碼的前5位字元的十六進位制值相加,結果存入ECX
0167:00498206  INC      EBX  // EBX加1
0167:00498207  CMP      EBX,06  // 比較EBX與6是否相等
0167:0049820A  JNZ      004981FC  // 不相等則跳(反覆跳轉5次,也就是將註冊碼的前5位字元的十六進位制值相加,結果存入ECX)
0167:0049820C  MOV      EAX,ECX // 將註冊碼的前5位字元的十六進位制值相加的值送給EAX
0167:0049820E  MOV      ECX,0000000A  // ECX=0A
0167:00498213  CDQ
0167:00498214  IDIV      ECX  // EAX除以ECX,餘數放入DL
0167:00498216  ADD      DL,30  // DL=DL(即餘數)+30
0167:00498219  MOV      EAX,[EBP-04]
0167:0049821C  MOV      ECX,[EBP-0C]
0167:0049821F  CMP      DL,[ECX+EAX-02]  // 比較DL中的字元與註冊碼的最後第二位是否相等
0167:00498223  JNZ      0049835E  // 不相等就跳轉出錯(不能跳)
0167:00498229  LEA      EAX,[EBP-1C]
0167:0049822C  PUSH      EAX
0167:0049822D  MOV      ECX,00000003
0167:00498232  MOV      EDX,00000006
0167:00498237  MOV      EAX,[EBP-04]
0167:0049823A  CALL      00404270
0167:0049823F  MOV      ECX,[EBP-1C]
0167:00498242  LEA      EAX,[EBP-18]
0167:00498245  MOV      EDX,004983BC
0167:0049824A  CALL      004040B4
0167:0049824F  MOV      EAX,[EBP-18]
0167:00498252  CALL      00409878  // EAX中的是去掉“-”後註冊碼的第6、7、8位註冊碼組成的字元(如註冊碼是1234,那麼EAX=1234)
0167:00498257  MOV      EBX,EAX  // 將這些字元給EBX
0167:00498259  MOV      CX,0012
0167:0049825D  MOV      DX,000C
0167:00498261  MOV      AX,07CC
0167:00498265  CALL      0040A9CC
0167:0049826A  CALL      00402B18
0167:0049826F  ADD      EBX,EAX  // EAX=8A59,EBX=去掉“-”後註冊碼的第6、7、8位註冊碼組成的字元 + 8A59
0167:00498271  MOV      CX,0001
0167:00498275  MOV      DX,000A
0167:00498279  MOV      AX,07CD
0167:0049827D  CALL      0040A9CC  // 下面要在SoftICE中下“WF”指令開啟浮點視窗
0167:00498282  MOV      [EBP-20],EBX  // 將所得的值送給[EBP-20]
0167:00498285  FILD      DWORD PTR [EBP-20]  // 將該值的十進位制值放入浮點暫存器ST0,這裡原ST0中的值35704將移到ST1
0167:00498288  FCOMPP  // ST0與ST1中的值相比較
0167:0049828A  FSTSW  AX
0167:0049828C  SAHF
0167:0049828D  JBE      0049835E  // 小於、等於35704則跳轉(不能跳)
0167:00498293  MOV      CX,0001
0167:00498297  MOV      DX,0001
0167:0049829B  MOV      AX,07DA
0167:0049829F  CALL      0040A9CC
0167:004982A4  MOV      [EBP-24],EBX  // 將所得的值送給[EBP-20]
0167:004982A7  FILD      DWORD PTR [EBP-24]  // 將該值的十進位制值放入浮點暫存器ST0,這裡原ST0中的值40179將移到ST1
0167:004982AA  FCOMPP  // ST0與ST1中的值相比較
0167:004982AC  FSTSW  AX
0167:004982AE  SAHF
0167:004982AF  JAE      0049835E  // 大於、等於40179則跳轉(不能跳)
0167:004982B5  LEA      EAX,[EBP-2C]
0167:004982B8  PUSH      EAX
0167:004982B9  MOV      ECX,00000004
0167:004982BE  MOV      EDX,00000009
0167:004982C3  MOV      EAX,[EBP-04]
0167:004982C6  CALL      00404270
0167:004982CB  MOV      ECX,[EBP-2C]
0167:004982CE  LEA      EAX,[EBP-28]
0167:004982D1  MOV      EDX,004983BC
0167:004982D6  CALL      004040B4
0167:004982DB  MOV      EAX,[EBP-28]  // 將去除“-”的註冊碼的第9,10,11,12位的字元給EAX(如註冊碼是1234,那麼EAX=1234)
0167:004982DE  CALL      00409878
0167:004982E3  PUSH      EAX
0167:004982E4  MOV      EAX,000081FA  // EAX=81FA
0167:004982E9  POP      EDX  // EDX就是註冊碼的第9,10,11,12位的字元
0167:004982EA  SUB      EAX,EDX  // EAX減去EDX,值放入EAX
0167:004982EC  CMP      EAX,01  比較EAX是否小於己於1
0167:004982EF  JL        0049835E  // 小於就跳轉(不能跳)
0167:004982F1  CMP      EAX,00002710  // 比較EAX是否大於2710
0167:004982F6  JG        0049835E  // 大於就跳轉(不能跳)
0167:004982F8  LEA      EAX,[EBP-34]
0167:004982FB  PUSH      EAX
0167:004982FC  MOV      ECX,00000005
0167:00498301  MOV      EDX,00000001
0167:00498306  MOV      EAX,[EBP-04]
0167:00498309  CALL      00404270
0167:0049830E  MOV      ECX,[EBP-34]  // 將去除“-”的註冊碼的第1,2,3,4,5位的字元給EAX(如註冊碼是12345,那麼EAX=12345)
0167:00498311  LEA      EAX,[EBP-30]
0167:00498314  MOV      EDX,004983BC
0167:00498319  CALL      004040B4
0167:0049831E  MOV      EAX,[EBP-30]
0167:00498321  CALL      00409878
0167:00498326  MOV      EBX,EAX  // EBX=註冊碼的第1,2,3,4,5位的字元
0167:00498328  MOV      EAX,EBX  // EAX=註冊碼的第1,2,3,4,5位的字元
0167:0049832A  MOV      ECX,000003E8  // ECX=03E8
0167:0049832F  CDQ
0167:00498330  IDIV      ECX  // EAX除以ECX,商放入EAX
0167:00498332  MOV      ECX,EAX  // 將商送給ECX
0167:00498334  MOV      EAX,EBX  // EAX=註冊碼的第1,2,3,4,5位的字元
0167:00498336  MOV      EBX,000003E8  // ECX=03E8
0167:0049833B  CDQ
0167:0049833C  IDIV      EBX  // EAX除以EBX,餘數放入EDX
0167:0049833E  MOV      EAX,EDX  // 將餘數送給EAX
0167:00498340  DEC      ECX  // ECX減1
0167:00498341  SUB      ECX,45  // ECX減去45
0167:00498344  JB        0049834E  // 有進位則跳
0167:00498346  ADD      ECX,-0A
0167:00498349  SUB      ECX,0C
0167:0049834C  JAE      0049835E
0167:0049834E  CMP      EAX,64  // 比較餘數是否小於或等於64
0167:00498351  JLE      0049835A  // 是就跳轉(可以跳轉)
0167:00498353  CMP      EAX,000003E7  // 比較餘數是否等於03E7
0167:00498358  JNZ      0049835E  // 不相等就跳(不能跳)
0167:0049835A  MOV      BYTE PTR [EBP-05],01  // 這裡是關鍵,前面比較有錯誤將不經過這行,[EBP-05]=1
0167:0049835E  XOR      EAX,EAX  // EAX=0
0167:00498360  POP      EDX
0167:00498361  POP      ECX
0167:00498362  POP      ECX
0167:00498363  MOV      FS:[EAX],EDX
0167:00498366  JMP      00498372  // 這裡跳轉
0167:00498368  JMP      0040352C
0167:0049836D  CALL      00403888
0167:00498372  XOR      EAX,EAX  // 跳到這裡,EAX=0
0167:00498374  POP      EDX
0167:00498375  POP      ECX
0167:00498376  POP      ECX
0167:00498377  MOV      FS:[EAX],EDX
0167:0049837A  PUSH      004983A9
0167:0049837F  LEA      EAX,[EBP-34]
0167:00498382  MOV      EDX,00000004
0167:00498387  CALL      00403E0C
0167:0049838C  LEA      EAX,[EBP-1C]
0167:0049838F  MOV      EDX,00000004
0167:00498394  CALL      00403E0C
0167:00498399  LEA      EAX,[EBP-04]
0167:0049839C  CALL      00403DE8
0167:004983A1  RET  // 按F10一下,跳到下面
0167:004983A2  JMP      004037E0
0167:004983A7  JMP      0049837F
0167:004983A9  MOV      AL,[EBP-05]  // 跳到這裡,AL=[EBP-05],如經過了上面的關鍵行,那麼EAX=1(註冊成功),否則EAX=0(註冊失敗)。
0167:004983AC  POP      EDI
0167:004983AD  POP      ESI
0167:004983AE  POP      EBX
0167:004983AF  MOV      ESP,EBP
0167:004983B1  POP      EBP
0167:004983B2  RET

【演算法總結】
1.註冊碼必須是16位,並且第五、第十位必須是“-”;
2.註冊碼不能與“003E-9124-7E3E39”相同;
3.去掉“-”後註冊碼的位數必須是14位,即註冊碼中除了第5,10位外,不能再出現“-”;
4.將去掉“-”後註冊碼的前13位字元的十六進位制值相加,再除於“0A”後的餘數加上30(十六進位制)所得的十六進位制值相對應的字元就是最後一位註冊碼;
5.將去掉“-”後註冊碼的前5位字元的十六進位制值相加,再除於“0A”後的餘數加上30所得的十六進位制值相對應的字元就是最後第二位註冊碼;
6.去掉“-”後註冊碼的第6、7、8位註冊碼組成的字元,加上“8A59”後所得的值的十進位制值要大於“35704”,但要小於“40179”;
7.“81FA”減去去掉“-”後註冊碼的第9、10、11、12位註冊碼組成的字元的差要大於或等於1,但小於2710;
8.將去掉“-”後註冊碼的前5位所組成的字元除於“03E8”,商要小於等於“45”,餘數要麼小於或等於“64”,要麼等於“03E7”;
9.註冊碼與使用者名稱、公司名無關。

相關文章