• 标 题:各位大哥,看看我的算法分析是否正确? (11千字)
  • 作 者:xuzhenhu
  • 时 间:2002-7-4 18:27:15
  • 链 接:http://bbs.pediy.com

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.注册码与用户名、公司名无关。