首先得说不是我这篇文章经典,还是说这个算法过程是一个非常经典案例! 大鸟飞过~~~~~~
尽管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去描述。脚踏实地非常重要
[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法