首页
社区
课程
招聘
[旧帖] [转帖]反汇编写完美的注册机(本人十分想来看雪学习希望给一个邀请码) 0.00雪花
发表于: 2010-1-9 16:36 1735

[旧帖] [转帖]反汇编写完美的注册机(本人十分想来看雪学习希望给一个邀请码) 0.00雪花

2010-1-9 16:36
1735
首先得说不是我这篇文章经典,还是说这个算法过程是一个非常经典案例! 大鸟飞过~~~~~~  
  
  尽管Delphi开发RAD很方便,但有时候要用它写一个完美的注册机不容易, 比如上一篇VB算法破文,
  因为在Delphi找不到和VB程序的ASC函数完全一样功能的函数,导致注册机不能支持中文。
  再如这一篇破文,反汇编中 IMUL 指令在大数相乘操作后会结果有两个,保存在EAX和EDX中,
  然而如何在Delphi里获得EDX的结果,由于个人技术问题,暂时还是个謎 ~~ ,
  还好,这并不妨碍写注册机,因为Delphi“完美”支持 ASM 嵌入,从而把这个问题给绕过去了,看操作 ~~
  
  老样子,输入假码后bp MessageBoxA 可以断下。来到主算法过程。

引用
  0040DEF0  PUSH -1                                         ;  主算法过程
  0040DEF2  PUSH Ace_DVD_.00466376                          ;  SE 处理程序安装
  0040DEF7  MOV EAX,DWORD PTR FS:[0]
  0040DEFD  PUSH EAX
  0040DEFE  MOV DWORD PTR FS:[0],ESP
  0040DF05  SUB ESP,570
  0040DF0B  PUSH EBX
  0040DF0C  PUSH EBP
  0040DF0D  PUSH ESI
  0040DF0E  MOV ESI,ECX
  0040DF10  PUSH EDI
  0040DF11  LEA ECX,DWORD PTR SS:[ESP+10]
  0040DF15  CALL
  0040DF1A  LEA EBP,DWORD PTR DS:[ESI+120]
  0040DF20  LEA EAX,DWORD PTR SS:[ESP+10]
  0040DF24  PUSH EAX
  0040DF25  MOV ECX,EBP
  0040DF27  MOV DWORD PTR SS:[ESP+58C],0
  0040DF32  CALL ;  读取邮件名
  0040DF37  MOV ECX,DWORD PTR SS:[ESP+10]
  0040DF3B  MOV EAX,DWORD PTR DS:[ECX-8]
  0040DF3E  CMP EAX,40                                      ;  邮件名长度和64比较
  0040DF41  JG Ace_DVD_.0040E186                            ;  不能大于64位
  0040DF47  CMP EAX,3
  0040DF4A  JL Ace_DVD_.0040E186                            ;  也不能小于3位
  0040DF50  PUSH 40                                         ;  字符 @
  0040DF52  LEA ECX,DWORD PTR SS:[ESP+14]
  0040DF56  CALL   ;  类似于Delphi的Pos函数,查@的位置
  0040DF5B  OR EBX,FFFFFFFF
  0040DF5E  CMP EAX,EBX
  0040DF60  JE Ace_DVD_.0040E189                            ;  如果邮件中没有@字符则失败
  0040DF66  MOV DL,BYTE PTR DS:[4B06CC]
  0040DF6C  MOV ECX,10
  0040DF71  XOR EAX,EAX
  0040DF73  LEA EDI,DWORD PTR SS:[ESP+3D]
  0040DF77  MOV BYTE PTR SS:[ESP+3C],DL
  0040DF7B  PUSH 40
  0040DF7D  REP STOS DWORD PTR ES:[EDI]
  0040DF7F  LEA EAX,DWORD PTR SS:[ESP+40]
  0040DF83  MOV ECX,EBP
  0040DF85  PUSH EAX
  0040DF86  CALL
  0040DF8B  LEA ECX,DWORD PTR SS:[ESP+14]
  0040DF8F  CALL
  0040DF94  LEA ECX,DWORD PTR SS:[ESP+14]
  0040DF98  LEA EDI,DWORD PTR DS:[ESI+160]
  0040DF9E  PUSH ECX
  0040DF9F  MOV ECX,EDI
  0040DFA1  MOV BYTE PTR SS:[ESP+58C],1
  0040DFA9  CALL ;  读取假码
  0040DFAE  MOV ECX,DWORD PTR SS:[ESP+14]
  0040DFB2  MOV EAX,DWORD PTR DS:[ECX-8]
  0040DFB5  TEST EAX,EAX
  0040DFB7  JE Ace_DVD_.0040E148                            ;  假码没填跳OVER
  0040DFBD  CMP EAX,1D                                      ;  假码必须是29位
  0040DFC0  JNZ Ace_DVD_.0040E148
  0040DFC6  PUSH EAX                                        ; /maxlen
  0040DFC7  LEA EDX,DWORD PTR SS:[ESP+20]                   ; |
  0040DFCB  PUSH ECX                                        ; |src
  0040DFCC  PUSH EDX                                        ; |dest
  0040DFCD  CALL DWORD PTR DS:[<&MSVCRT.strncpy>]           ; \strncpy
  0040DFD3  LEA EAX,DWORD PTR SS:[ESP+28]
  0040DFD7  LEA ECX,DWORD PTR SS:[ESP+48]
  0040DFDB  PUSH EAX
  0040DFDC  PUSH ECX
  0040DFDD  MOV BYTE PTR SS:[ESP+4D],0
  0040DFE2  CALL Ace_DVD_.0040DE50                          ;  核心算法
  0040DFE7  ADD ESP,14
  0040DFEA  TEST EAX,EAX
  0040DFEC  JE Ace_DVD_.0040E148                            ;  关键跳转,跳走失败
  0040DFF2  MOV EBX,DWORD PTR DS:[<&MSVCRT.sprintf>]        ;  msvcrt.sprintf
  0040DFF8  LEA EDX,DWORD PTR SS:[ESP+3C]
  0040DFFC  PUSH EDX                                        ; /<%s>
  0040DFFD  LEA EAX,DWORD PTR SS:[ESP+384]                  ; |
  0040E004  PUSH Ace_DVD_.0049015C                          ; |format = "License to %s."
  0040E009  PUSH EAX                                        ; |s
  0040E00A  CALL EBX                                        ; \sprintf
  0040E00C  ADD ESP,0C
  0040E00F  LEA ECX,DWORD PTR SS:[ESP+380]
  0040E016  PUSH 40
  0040E018  PUSH Ace_DVD_.00490150                          ;  ASCII "Thank you."
  0040E01D  PUSH ECX
  0040E01E  MOV ECX,ESI
  0040E020  CALL ;  弹出注册成功信息框
  0040E025  LEA EDX,DWORD PTR SS:[ESP+180]
  0040E02C  PUSH 0FF                                        ; /BufSize = FF (255.)
  0040E031  PUSH EDX                                        ; |Buffer
  0040E032  CALL DWORD PTR DS:[<&KERNEL32.GetWindowsDirecto>; \GetWindowsDirectoryA
  0040E038  LEA EDI,DWORD PTR SS:[ESP+180]                  ;  获得系统目录
  0040E03F  OR ECX,FFFFFFFF
  0040E042  XOR EAX,EAX
  0040E044  REPNE SCAS BYTE PTR ES:[EDI]
  0040E046  NOT ECX
  0040E048  DEC ECX
  0040E049  CMP BYTE PTR SS:[ESP+ECX+17F],5C
  0040E051  JE SHORT Ace_DVD_.0040E06B
  0040E053  LEA EDI,DWORD PTR SS:[ESP+180]
  0040E05A  OR ECX,FFFFFFFF
  0040E05D  XOR EAX,EAX
  0040E05F  REPNE SCAS BYTE PTR ES:[EDI]
  0040E061  MOV AX,WORD PTR DS:[48F2C4]
  0040E067  MOV WORD PTR DS:[EDI-1],AX
  0040E06B  LEA ECX,DWORD PTR SS:[ESP+180]
  0040E072  LEA EDX,DWORD PTR SS:[ESP+280]
  0040E079  PUSH ECX
  0040E07A  PUSH Ace_DVD_.0048F2B0                          ;  ASCII "%sAceDVDBackup.ini"
  0040E07F  PUSH EDX
  0040E080  CALL EBX
  0040E082  ADD ESP,0C
  0040E085  LEA EAX,DWORD PTR SS:[ESP+280]
  0040E08C  PUSH 0                                          ; /hTemplateFile = NULL
  0040E08E  PUSH 80                                         ; |Attributes = NORMAL
  0040E093  PUSH 2                                          ; |Mode = CREATE_ALWAYS
  0040E095  PUSH 0                                          ; |pSecurity = NULL
  0040E097  PUSH 1                                          ; |ShareMode = FILE_SHARE_READ
  0040E099  PUSH 40000000                                   ; |Access = GENERIC_WRITE
  0040E09E  PUSH EAX                                        ; |FileName
  0040E09F  CALL DWORD PTR DS:[<&KERNEL32.CreateFileA>]     ; \CreateFileA
  0040E0A5  MOV CL,BYTE PTR DS:[4B06CC]
  0040E0AB  MOV EBP,EAX
  0040E0AD  MOV BYTE PTR SS:[ESP+80],CL
  0040E0B4  MOV ECX,3F
  0040E0B9  XOR EAX,EAX
  0040E0BB  LEA EDI,DWORD PTR SS:[ESP+81]
  0040E0C2  REP STOS DWORD PTR ES:[EDI]
  0040E0C4  STOS WORD PTR ES:[EDI]
  0040E0C6  STOS BYTE PTR ES:[EDI]
  0040E0C7  LEA EDX,DWORD PTR SS:[ESP+1C]
  0040E0CB  LEA EAX,DWORD PTR SS:[ESP+3C]
  0040E0CF  PUSH EDX
  0040E0D0  PUSH EAX
  0040E0D1  LEA ECX,DWORD PTR SS:[ESP+88]
  0040E0D8  PUSH Ace_DVD_.0049012C                          ;  ASCII "TestCode=1User=%s#UniCode=%s#"
  0040E0DD  PUSH ECX
  0040E0DE  CALL EBX
  0040E0E0  LEA EDI,DWORD PTR SS:[ESP+90]
  0040E0E7  OR ECX,FFFFFFFF
  0040E0EA  XOR EAX,EAX
  0040E0EC  ADD ESP,10
  0040E0EF  REPNE SCAS BYTE PTR ES:[EDI]
  0040E0F1  NOT ECX
  0040E0F3  LEA EDX,DWORD PTR SS:[ESP+18]
  0040E0F7  PUSH 0                                          ; /pOverlapped = NULL
  0040E0F9  DEC ECX                                         ; |
  0040E0FA  PUSH EDX                                        ; |pBytesWritten
  0040E0FB  LEA EAX,DWORD PTR SS:[ESP+88]                   ; |
  0040E102  PUSH ECX                                        ; |nBytesToWrite
  0040E103  PUSH EAX                                        ; |Buffer
  0040E104  PUSH EBP                                        ; |hFile
  0040E105  CALL DWORD PTR DS:[<&KERNEL32.WriteFile>]       ; \WriteFile
  0040E10B  PUSH EBP                                        ; /hObject
  0040E10C  CALL DWORD PTR DS:[<&KERNEL32.CloseHandle>]     ; \CloseHandle
  0040E112  MOV ECX,ESI
  0040E114  MOV DWORD PTR DS:[4A8E6C],1
  0040E11E  CALL
  0040E123  MOV ECX,ESI
  0040E125  CALL
  0040E12A  LEA ECX,DWORD PTR SS:[ESP+14]
  0040E12E  MOV BYTE PTR SS:[ESP+588],0
  0040E136  CALL
  0040E13B  MOV DWORD PTR SS:[ESP+588],-1
  0040E146  JMP SHORT Ace_DVD_.0040E1BF
  0040E148  PUSH 40
  0040E14A  PUSH Ace_DVD_.00490124                          ;  ASCII "Sorry"
  0040E14F  PUSH Ace_DVD_.00490100                          ;  ASCII "Invalid Email or Code.          "
  0040E154  MOV ECX,ESI
  0040E156  CALL
  0040E15B  PUSH Ace_DVD_.004B06CC
  0040E160  MOV ECX,EBP
  0040E162  CALL
  0040E167  PUSH Ace_DVD_.004B06CC
  0040E16C  MOV ECX,EDI
  0040E16E  CALL
  0040E173  LEA ECX,DWORD PTR SS:[ESP+14]
  0040E177  MOV BYTE PTR SS:[ESP+588],0
  0040E17F  CALL
  0040E184  JMP SHORT Ace_DVD_.0040E1B8
  0040E186  OR EBX,FFFFFFFF
  0040E189  PUSH 40
  0040E18B  PUSH Ace_DVD_.00490124                          ;  ASCII "Sorry"
  0040E190  PUSH Ace_DVD_.00490100                          ;  ASCII "Invalid Email or Code.          "
  0040E195  MOV ECX,ESI
  0040E197  CALL
  0040E19C  PUSH Ace_DVD_.004B06CC
  0040E1A1  MOV ECX,EBP
  0040E1A3  CALL
  0040E1A8  PUSH Ace_DVD_.004B06CC
  0040E1AD  LEA ECX,DWORD PTR DS:[ESI+160]
  0040E1B3  CALL
  0040E1B8  MOV DWORD PTR SS:[ESP+588],EBX
  0040E1BF  LEA ECX,DWORD PTR SS:[ESP+10]
  0040E1C3  CALL
  0040E1C8  MOV ECX,DWORD PTR SS:[ESP+580]
  0040E1CF  POP EDI
  0040E1D0  POP ESI
  0040E1D1  POP EBP
  0040E1D2  POP EBX
  0040E1D3  MOV DWORD PTR FS:[0],ECX
  0040E1DA  ADD ESP,57C
  0040E1E0  RETN

主算法过程读取用户名和假码,保证用户名的长度在 [3 ,64] 之间,
  然后验证邮件地址里有没有@,否则提示出错;
  再对比假码的长度是不是等于29,否则提示出错;
  符合要求之后进入核心CALL
  0040DFE2  CALL Ace_DVD_.0040DE50                          ;  核心算法
  进行进一步验证。
  验证成功后把注册码保存在 系统目录下的 AceDVDBackup.ini 文件中。结束。
  
  F7进入核心算法看看:

引用
  0040DE50  PUSH EBX                                        ;  核心算法
  0040DE51  PUSH EBP
  0040DE52  MOV EBP,DWORD PTR SS:[ESP+C]                    ;  邮件,记为Em
  0040DE56  PUSH ESI
  0040DE57  PUSH EDI
  0040DE58  MOV EDI,EBP
  0040DE5A  OR ECX,FFFFFFFF
  0040DE5D  XOR EAX,EAX
  0040DE5F  XOR EBX,EBX
  0040DE61  XOR ESI,ESI
  0040DE63  REPNE SCAS BYTE PTR ES:[EDI]
  0040DE65  NOT ECX
  0040DE67  DEC ECX
  0040DE68  TEST ECX,ECX
  0040DE6A  JLE SHORT Ace_DVD_.0040DE86
  0040DE6C  /MOVSX EDX,BYTE PTR DS:[ESI+EBP]                ;  EDX= ord(Em[n])
  0040DE70  |MOV EAX,EDX                                    ;  EAX = EDX
  0040DE72  |MOV EDI,6F                                     ;  EDI = $6F
  0040DE77  |SHL EAX,4                                      ;  EAX = EAX shl 4
  0040DE7A  |ADD EAX,EDX                                    ;  EAX = EAX + EDX
  0040DE7C  |CDQ
  0040DE7D  |IDIV EDI
  0040DE7F  |ADD EBX,EDX                                    ;  EBX = EBX + (EAX mod EDI)
  0040DE81  |INC ESI                                        ;  INC(ESI)
  0040DE82  |CMP ESI,ECX                                    ;  到达最后一位了吗?
  0040DE84  \JL SHORT Ace_DVD_.0040DE6C                     ;  未到达则继续循环,循环结果EBX记为 A1
  0040DE86  MOV EAX,EBX                                     ;  EAX = A1
  0040DE88  MOV EBP,DWORD PTR SS:[ESP+18]
  0040DE8C  IMUL EAX,EBX                                    ;  EAX = A1 * A1, 结果记为 A2
  0040DE8F  XOR ESI,ESI                                     ;  ESI = n (计数器初始化为0)
  0040DE91  MOV EDI,EAX                                     ;  EDI = A2 (保存起来后面用)
  0040DE93  LEA EBX,DWORD PTR DS:[EAX+B]                    ;  EBX = EAX + 11,结果记为 A3
  0040DE96  /MOV EAX,ESI                                    ;  EAX = 计数器n
  0040DE98  |MOV ECX,6                                      ;  ECX = 6
  0040DE9D  |CDQ
  0040DE9E  |IDIV ECX                                       ;  EAX mod ECX
  0040DEA0  |CMP EDX,5                                      ;  余数和5比较
  0040DEA3  |JE SHORT Ace_DVD_.0040DECA                     ;  相等跳走
  0040DEA5  |MOV EAX,EDI                                    ;  EAX = A2
  0040DEA7  |MOV ECX,5                                      ;  ECX = 5
  0040DEAC  |CDQ
  0040DEAD  |IDIV ECX                                       ;  A2 mod 5
  0040DEAF  |MOV EDX,DWORD PTR DS:[EDX*4+4900EC]            ;  根据余数来选择子CALL
  0040DEB6  |MOV DWORD PTR DS:[4B06E4],EDX
  0040DEBC  |MOV AL,BYTE PTR DS:[ESI+EBP]                   ;  AL = 假码[n],入EAX低位
  0040DEBF  |PUSH EAX                                       ;  EAX 入栈
  0040DEC0  |PUSH EBX                                       ;  A3  入栈
  0040DEC1  |CALL EDX                                       ;  核心验证过程
  0040DEC3  |ADD ESP,8
  0040DEC6  |TEST EAX,EAX
  0040DEC8  |JE SHORT Ace_DVD_.0040DEE0                     ;  EAX返回0则验证失败
  0040DECA  |INC ESI                                        ;  计数器n递增
  0040DECB  |SUB EDI,0B                                     ;  EDI = EDI - 11;
  0040DECE  |SUB EBX,11                                     ;  EBX = EBX - 17
  0040DED1  |CMP ESI,1D                                     ;  ESI 和 29 比较
  0040DED4  \JL SHORT Ace_DVD_.0040DE96                     ;  小于继续循环
  0040DED6  POP EDI
  0040DED7  POP ESI
  0040DED8  POP EBP
  0040DED9  MOV EAX,1                                       ;  标志位赋值为1,注册成功
  0040DEDE  POP EBX
  0040DEDF  RETN
  0040DEE0  POP EDI
  0040DEE1  POP ESI
  0040DEE2  POP EBP
  0040DEE3  XOR EAX,EAX                                     ;  标志位赋值为0,注册失败
  0040DEE5  POP EBX
  0040DEE6  RETN

小结一下核心算法过程:
  1、读取邮件,记为 Em,然后通过第一处循环,
     for n:=1 to Length(Em) do
      累加 (ord(Em[n]) shl 4 + ord(Em[n])) mod $6F 的值。结果记为 A1
  2、A1 * A1,结果记为 A2
  3、A2 + 11,结果记为 A3
  4、开始第二处循环进行验证注册码了。
     for n:=1 to $1D do
     begin
        (1). 逢6的倍数位( i mod 6 = 0),跳到第(3)步;
        (2). A2 mod 5 的结果进行选择性调用子CALL过程,验证假码每一位是否正确;如果有一位不正确,跳走失败。
        (3) A2 := A2 - $B;   A3 := A3 - $11;
     end;
  
  可知第4步循环中第(2)小步很关键,每个进入看看。

引用
  0040DD60  MOV ECX,DWORD PTR SS:[ESP+4]                    ;  ECX = A3   [余数为0时CALL这个]
  0040DD64  MOV EAX,78787879
  0040DD69  IMUL ECX                                        ;  EAX = A3 * $78787879
  0040DD6B  MOV EAX,EDX                                     ;  EAX = EDX
  0040DD6D  SAR EAX,3                                       ;  EAX sar 3
  0040DD70  MOV ECX,EAX                                     ;  ECX = EAX
  0040DD72  SHR ECX,1F                                      ;  ECX = ECX shr $1F
  0040DD75  ADD EAX,ECX                                     ;  EAX = EAX + ECX
  0040DD77  MOV ECX,0A                                      ;  ECX = 10
  0040DD7C  CDQ
  0040DD7D  IDIV ECX                                        ;  EDX = EAX div ECX
  0040DD7F  MOV CL,BYTE PTR SS:[ESP+8]                      ;  CL = ord(假码[n])
  0040DD83  XOR EAX,EAX                                     ;  EAX = 0
  0040DD85  ADD DL,30                                       ;  DL = DL + $30
  0040DD88  CMP DL,CL                                       ;  真假码在此比较
  0040DD8A  SETE AL                                         ;  相等则通过,否则注册失败
  0040DD8D  RETN
  0040DD8E  NOP
  0040DD8F  NOP
  0040DD90  MOV ECX,DWORD PTR SS:[ESP+4]                    ;  ECX = A3  [余数为1时CALL这个]
  0040DD94  MOV EAX,B21642C9
  0040DD99  IMUL ECX                                        ;  EAX = A3 * $B21642C9
  0040DD9B  MOV EAX,EDX                                     ;  EAX = EDX
  0040DD9D  ADD EAX,ECX                                     ;  EAX = EAX + ECX
  0040DD9F  SAR EAX,4                                       ;  EAX = EAX sar 4
  0040DDA2  MOV ECX,EAX                                     ;  ECX = ECX
  0040DDA4  SHR ECX,1F                                      ;  ECX = ECX shr $1F
  0040DDA7  ADD EAX,ECX                                     ;  EAX = EAX + ECX
  0040DDA9  MOV ECX,0A                                      ;  ECX = 10
  0040DDAE  CDQ
  0040DDAF  IDIV ECX                                        ;  EAX mod ECX
  0040DDB1  MOV CL,BYTE PTR SS:[ESP+8]                      ;  指向假码
  0040DDB5  XOR EAX,EAX                                     ;  EAX = 0
  0040DDB7  ADD DL,30                                       ;  DL = DL + $30
  0040DDBA  CMP DL,CL                                       ;  真假码在此比较
  0040DDBC  SETE AL
  0040DDBF  RETN
  0040DDC0  MOV ECX,DWORD PTR SS:[ESP+4]                    ;  [余数为2时CALL这个]
  0040DDC4  MOV EAX,4EC4EC4F                                ;  下面的大同小异,不做注释
  0040DDC9  IMUL ECX
  0040DDCB  MOV EAX,EDX
  0040DDCD  SAR EAX,2
  0040DDD0  MOV ECX,EAX
  0040DDD2  SHR ECX,1F
  0040DDD5  ADD EAX,ECX
  0040DDD7  MOV ECX,1A
  0040DDDC  CDQ
  0040DDDD  IDIV ECX
  0040DDDF  MOV CL,BYTE PTR SS:[ESP+8]
  0040DDE3  XOR EAX,EAX
  0040DDE5  ADD DL,41
  0040DDE8  CMP DL,CL                                       ;  真假码在此比较
  0040DDEA  SETE AL
  0040DDED  RETN
  0040DDEE  NOP
  0040DDEF  NOP
  0040DDF0  MOV ECX,DWORD PTR SS:[ESP+4]                    ;  [余数为3时CALL这个]
  0040DDF4  MOV EAX,92492493                                ;  下面的大同小异,不做注释
  0040DDF9  IMUL ECX
  0040DDFB  MOV EAX,EDX
  0040DDFD  ADD EAX,ECX
  0040DDFF  SAR EAX,2
  0040DE02  MOV ECX,EAX
  0040DE04  SHR ECX,1F
  0040DE07  ADD EAX,ECX
  0040DE09  MOV ECX,1A
  0040DE0E  CDQ
  0040DE0F  IDIV ECX
  0040DE11  MOV CL,BYTE PTR SS:[ESP+8]
  0040DE15  XOR EAX,EAX
  0040DE17  ADD DL,41
  0040DE1A  CMP DL,CL                                       ;  真假码在此比较
  0040DE1C  SETE AL
  0040DE1F  RETN
  0040DE20  MOV ECX,DWORD PTR SS:[ESP+4]                    ;  [余数为4时CALL这个]
  0040DE24  MOV EAX,6BCA1AF3                                ;  下面的大同小异,不做注释
  0040DE29  IMUL ECX
  0040DE2B  MOV EAX,EDX
  0040DE2D  SAR EAX,3
  0040DE30  MOV ECX,EAX
  0040DE32  SHR ECX,1F
  0040DE35  ADD EAX,ECX
  0040DE37  MOV ECX,1A
  0040DE3C  CDQ
  0040DE3D  IDIV ECX
  0040DE3F  MOV CL,BYTE PTR SS:[ESP+8]
  0040DE43  XOR EAX,EAX
  0040DE45  ADD DL,41
  0040DE48  CMP DL,CL                                       ;  真假码在此比较
  0040DE4A  SETE AL
  0040DE4D  RETN

难题在这部分遇到:每一个子CALL里面都有一个这样的指令。

引用
  0040DD64  MOV EAX,78787879                                ;  来一个大数
  0040DD69  IMUL ECX                                        ;  EAX = ECX * $78787879 (ECX也不小)
  0040DD6B  MOV EAX,EDX                                     ;  EAX = EDX

执行完 IMUL ECX 后,寄存器EAX和EDX都有一个值,在Delphi里,用 * 号运算后得到的是寄存器EAX的值,但不知道EDX的值怎么获得。
  为了不浪费时间,暂时不去研究这个问题了,干脆用嵌入汇编来搞定,不费吹灰之力!
  最后看源代码吧。
  
  [完美Delphi注册码 *支持中文邮件名* --------- 有中文邮件名的吗?? -_-!! ]

引用
//这个函数可以使得注册机支持中文及各种奇怪字符注册
  function MOVSX(A: Byte): integer;
  begin
        if A and $80 = 0 then Result:= A
        else Result:= $FFFFFF00 or A;
  end;
  
  function KeyGen(Em: string): string;
  var
      n, Len: integer;
      Flag: boolean;
      A1, A2, A3, A4: integer;
      Sn: string;
  begin
      Len:= Length(Em);
      if (Len<=3) or (Len>=64) then
      begin
          Result:='邮件名长度不对';
          Exit;
      end;
      Flag:=False;
      for n:= 1 to Len do
          if Em[n] = '@' then Flag:=True;
      if Not Flag then
      begin
          Result:='邮件地址必须含有字符@';
          Exit;
      end;
      A1 := 0;
      for n := 1 to Len  do
      begin
          A1 := A1 + (MOVSX(ord(Em[n])) shl 4 + MOVSX(ord(Em[n]))) mod $6F;
      end;
      A2 := A1 * A1;
      A3 := A2 + $B;
      Sn := '';
      for n := 0 to 28 do
      begin
          if n mod 6 = 5 then
          begin
              Sn := Sn + '-'; //用其它符号也可以
              A2 := A2 - $B;
              A3 := A3 - $11;
              continue;
          end;
          case (A2 mod 5) of
              0:
                  asm
                      XOR EDX,EDX  //必须先把EAX清空
                      MOV ECX, A3
                      MOV EAX,$78787879
                      IMUL ECX
                      MOV EAX,EDX   //这一句在Delphi里不知道怎么表达
                      SAR EAX,3     //还有Delphi里没有 SAR指令,还是用汇编简洁。
                      MOV ECX,EAX
                      SHR ECX,$1F
                      ADD EAX,ECX
                      MOV ECX,<# WebPartBody #>A
                      CDQ
                      IDIV ECX
                      ADD EDX,$30
                      MOV A4, EDX
                  end;
              1:
                  asm
                      XOR EDX,EDX  
                      MOV ECX, A3
                      MOV EAX, $B21642C9
                      IMUL ECX
                      MOV EAX,EDX
                      ADD EAX,ECX
            SAR EAX,4
                      MOV ECX,EAX
                      SHR ECX,$1F
                      ADD EAX,ECX
                      MOV ECX,<# WebPartBody #>A
                      CDQ
                      IDIV ECX
                      ADD EDX,$30
                      MOV A4, EDX
                  end;
  
              2:
                  asm
                      XOR EDX,EDX
                      MOV ECX, A3
                      MOV EAX,$4EC4EC4F
                     IMUL ECX
                      MOV EAX,EDX
                      SAR EAX,2
                      MOV ECX,EAX
                      SHR ECX,$1F
                      ADD EAX,ECX
                      MOV ECX,$1A
                      CDQ
                      IDIV ECX
                      ADD EDX,$41
                      MOV A4, EDX
                  end;
  
              3:
                  asm
                      XOR EDX,EDX  
                      MOV ECX, A3
                      MOV EAX,$92492493
                      IMUL ECX
                      MOV EAX,EDX
                      ADD EAX,ECX
                      SAR EAX,2
                      MOV ECX,EAX
                      SHR ECX,$1F
                      ADD EAX,ECX
                      MOV ECX,$1A
                      CDQ
                      IDIV ECX
                      ADD DL,$41
                      MOV A4, EDX
                  end;
              4:
                  asm
                      XOR EDX,EDX
                      MOV ECX, A3
                      MOV EAX,$6BCA1AF3
                      IMUL ECX
                      MOV EAX,EDX
                      SAR EAX,3
                      MOV ECX,EAX
                      SHR ECX,$1F
                      ADD EAX,ECX
                      MOV ECX,$1A
                      CDQ
                      IDIV ECX
                      ADD DL,$41
                      MOV A4, EDX
                  end;
          end; //End the Case;
  
          Sn := Sn + Chr(A4);
          A2 := A2 - $B;
          A3 := A3 - $11;
      end;
      Result := Sn;
  end;

提供几组经上述代码计算出来的结果吧:
  
  邮  件:BeyondMe@UpK.cn
  注册码:64JQX-9FER8-ASK59-GD14R-X79NH
  
  邮  件:BeyondMe@一蓑烟雨.cn
  注册码:ZSE82-GY47Q-R12MH-77HVE-2DJX9
  
  邮  件:Futuring@126.com
  注册码:ZCO70-QH45Q-B00LS-65HGO-0CUH9
  
  由于感觉这个算法非常经典,于是做了个API版本音乐注册机,用FCG的模板修改了一下,比较喜欢。

  写在最后:
  尽管已经写了近50篇精华算法破文(感谢版主支持),突然感觉自己还处于起步状态,需要了解的东西还很多。
  起码SAR指令还要去查一下怎么用Delphi去描述。脚踏实地非常重要

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 0
支持
分享
最新回复 (3)
雪    币: 43
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
汇编不是很懂,无法看明白
2010-1-10 13:18
0
雪    币: 36
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
真的很好 谢谢分享
2010-1-10 13:59
0
雪    币: 45
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
谢谢分享,,,
2010-1-10 15:11
0
游客
登录 | 注册 方可回帖
返回
//