某国产软件 - XX E-mail 邮差 的算法分析
这篇文章可以说是受人之托,基本上可以有所交待了。不过看过了ppp621等大侠写的文章后,发表得有点心虚,和那些文章相比,这片太小儿科了!:)
该软件无壳无反无防,是典型的“三无产品”,这东西分析起来简直是太爽了。:)跟踪流程基本上没费多大劲,主要是写注册机时想了好一会儿.....
由 fi 得知是采用 delphi 编写,那么理所当然的就用 DeDe 喽。
我的机器码为572463 =
$8BC2F
假定我们填的注册码为 WWWWW-XXXXX-YYYYY-ZZZZZ (至于为什么这么填,跟到后面就全知道了)
我们很 EZ 地来到这里:
* Reference to: sysutils.StrToInt(System.AnsiString):System.Integer;
|
0048ED3D E8E2A0F7FF
call 00408E24
0048ED42 8BD0
mov edx, eax
0048ED44
B98D000000 mov ecx, $0000008D
0048ED49 8B45FC
mov eax, [ebp-$04]
* Reference to : TRegisterDlg._PROC_0048E36C()
|
0048ED4C E81BF6FFFF
call 0048E36C //关键Call。跟踪时要注意注册标志 bl 的赋值情况
0048ED51 8BD8
mov ebx, eax
* Reference to pointer to GlobalVar_0049D9A8
|
0048ED53 A148CB4900
mov eax, dword ptr [$0049CB48]
* Reference to field GlobalVar_0049D9A8.OFFS_0054
|
0048ED58 885854
mov [eax+$54], bl
* Reference to pointer to GlobalVar_0049D9A8
|
0048ED5B A148CB4900
mov eax, dword ptr [$0049CB48]
0048ED60 84DB
test bl, bl
0048ED62 752C
jnz 0048ED90 //这意味着什么大家都清楚吧?
*^_^*
0048ED64 8D45F8
lea eax, [ebp-$08]
* Possible String Reference to:
'无效的注册码! '
|
0048ED67 BA04EE4800
mov edx, $0048EE04
* Reference to: system.@LStrLAsg;
|
0048ED6C E8AF4FF7FF
call 00403D20
0048ED71 6A30
push $30
0048ED73 8B45F8
mov eax, [ebp-$08]
于是乎,又很 EZ 地来到这里:
////////////////////////////////////////////////////////////////////////////////
//////////////// 0048E36C call
Start ////////////////
////////////////////////////////////////////////////////////////////////////////
0048E36C 55
push ebp
0048E36D 8BEC
mov ebp, esp
0048E36F
51 push
ecx
0048E370 B90E000000
mov ecx, $0000000E
0048E375 6A00
push $00
0048E377 6A00
push $00
0048E379 49
dec ecx
0048E37A 75F9
jnz 0048E375
0048E37C
874DFC xchg
[ebp-$04], ecx
0048E37F 53
push ebx
0048E380 56
push
esi
0048E381 57
push edi
0048E382 894DF4
mov [ebp-$0C], ecx
0048E385
8955F8 mov
[ebp-$08], edx
0048E388 8945FC
mov [ebp-$04], eax
0048E38B 8B45FC
mov eax, [ebp-$04]
* Reference to: system.@LStrAddRef;
|
0048E38E E8295DF7FF
call 004040BC
0048E393
33C0 xor
eax, eax
0048E395 55
push ebp
* Possible String Reference
to: '閚N?胫奅骭^[嬪]?
|
0048E396 6829E84800
push $0048E829
***** TRY
|
0048E39B
64FF30 push
dword ptr fs:[eax]
0048E39E 648920
mov fs:[eax], esp
0048E3A1 C645F300
mov byte ptr [ebp-$0D],
$00
0048E3A5 8B45FC
mov eax, [ebp-$04]
* Reference to: system.@LStrLen:Integer;
|
0048E3A8 E85B5BF7FF
call 00403F08
0048E3AD 83F814
cmp eax, +$14
//注册码是否填写完整(20位)
0048E3B0 0F8543040000
jnz 0048E7F9
0048E3B6 8D45DC
lea eax, [ebp-$24]
0048E3B9
8B55FC mov
edx, [ebp-$04]
* Reference to: system.@LStrLAsg;
|
0048E3BC
E85F59F7FF call 00403D20
-----------------------------------------------------------------------------
* Reference to: sysutils.Now:System.TDateTime;
//有一点反跟踪意思。但太简单,故不算在反跟踪里面。:)
|
0048E3C1 E8BABAF7FF
call 00409E80
0048E3C6
83C4F8 add
esp, -$08
0048E3C9 DD1C24
fstp qword ptr [esp]
0048E3CC 9B
wait
0048E3CD
8D55CC lea
edx, [ebp-$34]
* Possible String Reference to: 'hhnnss'
//取得系统时间 20:00:35 --> 200035
|
0048E3D0
B844E84800 mov eax, $0048E844
* Reference to: Unit_00407C78.Proc_0040AAC0
|
0048E3D5
E8E6C6F7FF call 0040AAC0
0048E3DA 8B45CC
mov eax, [ebp-$34]
* Reference to: sysutils.StrToInt(System.AnsiString):System.Integer;
|
0048E3DD E842AAF7FF
call 00408E24
0048E3E2 8BF0
mov esi, eax
0048E3E4
BB01000000 mov ebx, $00000001
0048E3E9 83FE0A
cmp esi, +$0A
0048E3EC 7C59
jl 0048E447
0048E3EE 8B45DC
mov eax, [ebp-$24]
* Reference to: system.@LStrLen:Integer;
|
0048E3F1 E8125BF7FF
call 00403F08
0048E3F6 85C0
test eax, eax
0048E3F8
7E2E jle
0048E428
* Reference to: sysutils.Now:System.TDateTime;
|
0048E3FA E881BAF7FF call
00409E80
0048E3FF 83C4F8
add esp, -$08
0048E402 DD1C24
fstp qword ptr [esp]
0048E405 9B
wait
0048E406 8D55C8
lea edx, [ebp-$38]
* Possible String Reference
to: 'hhnnss' //再次取得系统时间 20:00:37 -->
200037
|
0048E409 B844E84800
mov eax, $0048E844
* Reference to: Unit_00407C78.Proc_0040AAC0
|
0048E40E E8ADC6F7FF
call 0040AAC0
0048E413 8B45C8
mov eax, [ebp-$38]
* Reference
to: sysutils.StrToInt(System.AnsiString):System.Integer;
|
0048E416
E809AAF7FF call 00408E24
0048E41B 2BC6
sub eax, esi
0048E41D 83F80A
cmp eax, +$0A
//计算运行时间,不得大于 10 秒
0048E420 0F8FD3030000
jnle 0048E7F9 //这是绝对不能跳的
0048E426
EB1F jmp
0048E447
0048E428 8B45DC
mov eax, [ebp-$24]
* Reference to: system.@LStrLen:Integer;
|
0048E42B E8D85AF7FF
call 00403F08
0048E430 3BD8
cmp ebx, eax
0048E432
7D13 jnl
0048E447
0048E434 8D45D8
lea eax, [ebp-$28]
0048E437 50
push eax
0048E438
B901000000 mov ecx, $00000001
0048E43D 8BD3
mov edx, ebx
0048E43F 8B45DC
mov eax, [ebp-$24]
*
Reference to: system.@LStrCopy;
|
0048E442 E8C95CF7FF
call 00404110
0048E447 43
inc
ebx
0048E448 81FBF5010000 cmp
ebx, $000001F5 //将以上时间比较过程重复 500 次
0048E44E 7599
jnz 0048E3E9
//可 r fl z 跳过
0048E450 BB01000000
mov ebx, $00000001
---------------------
注册码应在 'A' - 'Z' 范围内 ---------------------
0048E455 8D45C4
lea eax, [ebp-$3C]
0048E458 50
push eax
0048E459 B901000000
mov ecx, $00000001
0048E45E 8BD3
mov edx,
ebx
0048E460 8B45DC
mov eax, [ebp-$24]
* Reference to: system.@LStrCopy;
|
0048E463 E8A85CF7FF
call 00404110
0048E468 8B45C4
mov eax, [ebp-$3C]
0048E46B
BA54E84800 mov edx, $0048E854
* Reference to: system.@LStrCmp;
|
0048E470 E8A35BF7FF
call 00404018
0048E475
0F877E030000 jnbe 0048E7F9
0048E47B 8D45C0 lea
eax, [ebp-$40]
0048E47E 50
push eax
0048E47F B901000000
mov ecx, $00000001
0048E484
8BD3 mov
edx, ebx
0048E486 8B45DC
mov eax, [ebp-$24]
* Reference to: system.@LStrCopy;
|
0048E489 E8825CF7FF
call 00404110
0048E48E 8B45C0
mov eax, [ebp-$40]
0048E491
BA60E84800 mov edx, $0048E860
* Reference to: system.@LStrCmp;
|
0048E496 E87D5BF7FF
call 00404018
0048E49B
0F8258030000 jb 0048E7F9
0048E4A1 43
inc ebx
0048E4A2 83FB15
cmp ebx, +$15
0048E4A5
75AE jnz
0048E455
0048E4A7 8D45D8
lea eax, [ebp-$28]
0048E4AA 8B55FC
mov edx, [ebp-$04]
* Reference to: system.@LStrLAsg;
|
0048E4AD E86E58F7FF
call 00403D20
0048E4B2
8D45DC lea
eax, [ebp-$24]
* Reference to: system.@LStrClr(String);
|
0048E4B5 E8CE57F7FF call
00403C88
0048E4BA BB01000000
mov ebx, $00000001
-------------------- 将注册码倒置
----------------------
最终效果: WWWWWXXXXXYYYYYZZZZZ --> ZZZZZYYYYYXXXXXWWWWW
0048E4BF 8D45BC
lea eax, [ebp-$44]
0048E4C2 50
push eax
0048E4C3
BA14000000 mov edx, $00000014
0048E4C8 2BD3
sub edx, ebx
0048E4CA 42
inc edx
0048E4CB
B901000000 mov ecx, $00000001
0048E4D0 8B45D8
mov eax, [ebp-$28]
* Reference to: system.@LStrCopy;
|
0048E4D3 E8385CF7FF call
00404110
0048E4D8 8B55BC
mov edx, [ebp-$44]
0048E4DB 8D45DC
lea eax, [ebp-$24]
* Reference to: system.@LStrCat;
|
0048E4DE E82D5AF7FF
call 00403F10
0048E4E3
43 inc
ebx
0048E4E4 83FB15
cmp ebx, +$15
0048E4E7 75D6
jnz 0048E4BF
0048E4E9 8D45D8 lea
eax, [ebp-$28]
0048E4EC 8B55DC
mov edx, [ebp-$24]
* Reference to:
system.@LStrLAsg;
|
0048E4EF E82C58F7FF
call 00403D20
0048E4F4 8D45DC
lea eax, [ebp-$24]
* Reference to: system.@LStrClr(String);
|
0048E4F7 E88C57F7FF
call 00403C88
0048E4FC
BB01000000 mov ebx, $00000001
-------------------- 将字符串首尾交叉 ----------------------
最终效果:
ZZZZZYYYYYXXXXXWWWWW --> ZXZXZXZXZXYWYWYWYWYW
如果填入的字母都不相同,效果会更强烈些。
:-)
0048E501 FF75DC
push dword ptr [ebp-$24]
0048E504 8D45B8
lea eax, [ebp-$48]
0048E507 50
push eax
0048E508 B901000000
mov ecx, $00000001
0048E50D
8BD3 mov
edx, ebx
0048E50F 8B45D8
mov eax, [ebp-$28]
* Reference to: system.@LStrCopy;
|
0048E512 E8F95BF7FF
call 00404110
0048E517 FF75B8
push dword ptr [ebp-$48]
0048E51A
8D45B4 lea
eax, [ebp-$4C]
0048E51D 50
push eax
0048E51E 8D530A
lea edx, [ebx+$0A]
0048E521 B901000000 mov
ecx, $00000001
0048E526 8B45D8
mov eax, [ebp-$28]
* Reference to:
system.@LStrCopy;
|
0048E529 E8E25BF7FF
call 00404110
0048E52E FF75B4
push dword ptr [ebp-$4C]
0048E531 8D45DC
lea eax, [ebp-$24]
0048E534 BA03000000
mov edx, $00000003
* Reference to:
system.@LStrCatN;
|
0048E539 E88A5AF7FF
call 00403FC8
0048E53E 43
inc ebx
0048E53F
83FB0B cmp
ebx, +$0B
0048E542 75BD
jnz 0048E501
0048E544 8D45D8
lea eax, [ebp-$28]
* Reference to: system.@LStrClr(String);
|
0048E547 E83C57F7FF
call 00403C88
0048E54C
BB01000000 mov ebx, $00000001
------------ Sorry,我不知道该怎么概括,只好细说了 ---------------
最终效果:ZXZXZXZXZXYWYWYWYWYW
--> '2522232021181916171414111291078212219'
0048E551 8D7B40
lea edi, [ebx+$40]
0048E554 83FF51
cmp edi, +$51
0048E557 7E03
jle 0048E55C
0048E559
83EF10 sub
edi, +$10
0048E55C 8D45D4
lea eax, [ebp-$2C]
0048E55F 50
push eax
0048E560 B901000000 mov
ecx, $00000001
0048E565 8BD3
mov edx, ebx
0048E567 8B45DC
mov eax, [ebp-$24]
* Reference to: system.@LStrCopy;
//下面这个Call是从字符串里取出一个字符
|
0048E56A E8A15BF7FF
call 00404110
0048E56F 8B45D4
mov eax, [ebp-$2C]
0048E572 8A00
mov al, byte ptr [eax]
0048E574 8BF0
mov esi, eax
0048E576 81E6FF000000 and
esi, $000000FF //得到字符的ASCII值
0048E57C 8D55B0
lea edx, [ebp-$50]
0048E57F 8BC6
mov eax, esi
0048E581 2BC7
sub eax, edi
// 这里注意 EDI 的变化规律:
从 $41 - $51 依次循环
* Reference to: sysutils.IntToStr(System.Integer):System.AnsiString;overload;
//数字变字符
|
0048E583 E830A8F7FF
call 00408DB8
0048E588 8B55B0
mov edx, [ebp-$50]
0048E58B
8D45D8 lea
eax, [ebp-$28]
* Reference to: system.@LStrCat;
//看看名字就知道,下面的这个Call是连接字符串的
|
0048E58E
E87D59F7FF call 00403F10
0048E593 43
inc ebx
0048E594 83FB15
cmp ebx, +$15
// 循环取完字符串的每一位
0048E597 75B8
jnz 0048E551
0048E599 8D45DC
lea eax, [ebp-$24]
0048E59C 8B55D8
mov edx, [ebp-$28]
* Reference to: system.@LStrLAsg;
|
0048E59F E87C57F7FF call
00403D20
0048E5A4 BB01000000
mov ebx, $00000001
---------------- 连接后的字串每一位应在
'0' - '9' 范围内 ----------------------
这就要求我们输入的注册码为了减少麻烦应该都取靠后的字母。
如果比较靠前,则字串可能会含有负数,导致无法通过检测。
0048E5A9 8D45AC
lea eax, [ebp-$54]
0048E5AC 50
push eax
0048E5AD
B901000000 mov ecx, $00000001
0048E5B2 8BD3
mov edx, ebx
0048E5B4 8B45DC
mov eax, [ebp-$24]
*
Reference to: system.@LStrCopy;
|
0048E5B7 E8545BF7FF
call 00404110
0048E5BC 8B45AC
mov eax, [ebp-$54]
0048E5BF BA6CE84800 mov
edx, $0048E86C
* Reference to: system.@LStrCmp;
|
0048E5C4
E84F5AF7FF call 00404018
0048E5C9 0F872A020000 jnbe
0048E7F9 //一跳就玩完了
0048E5CF 8D45A8 lea
eax, [ebp-$58]
0048E5D2 50
push eax
0048E5D3 B901000000
mov ecx, $00000001
0048E5D8
8BD3 mov
edx, ebx
0048E5DA 8B45DC
mov eax, [ebp-$24]
* Reference to: system.@LStrCopy;
|
0048E5DD E82E5BF7FF
call 00404110
0048E5E2 8B45A8
mov eax, [ebp-$58]
0048E5E5
BA78E84800 mov edx, $0048E878
* Reference to: system.@LStrCmp;
|
0048E5EA E8295AF7FF
call 00404018
0048E5EF
0F8204020000 jb 0048E7F9
0048E5F5 43
inc ebx
0048E5F6 83FB15
cmp ebx, +$15
//只取前 20 个字符
0048E5F9 75AE
jnz 0048E5A9
0048E5FB
33F6 xor
esi, esi
0048E5FD BB01000000
mov ebx, $00000001
0048E602 8D45A4 lea eax, [ebp-$5C]
0048E605 50 push eax
0048E606 B901000000 mov ecx, $00000001
0048E60B 8BD3 mov edx, ebx
0048E60D 8B45DC mov eax, [ebp-$24]
* Reference to: system.@LStrCopy;
|
0048E610 E8FB5AF7FF call 00404110
0048E615 8B45A4 mov eax, [ebp-$5C]
* Reference to: sysutils.StrToInt(System.AnsiString):System.Integer; //字符变数字
|
0048E618 E807A8F7FF call 00408E24
0048E61D 03F0 add esi, eax //将前18个字符累加至ESI
0048E61F 43 inc ebx
0048E620 83FB13 cmp ebx, +$13
0048E623 75DD jnz 0048E602
0048E625 8BDE mov ebx, esi
0048E627 81E301000080 and ebx, $80000001 //除极端情况(数字字符全为0)外,EBX大都等于1
0048E62D 7905 jns 0048E634
0048E62F 4B dec ebx
0048E630 83CBFE or ebx, -$02
0048E633 43 inc ebx
0048E634 8D45A0 lea eax, [ebp-$60]
0048E637 50 push eax
0048E638 B901000000 mov ecx, $00000001 //传入 Lstrcopy 的三个参数
0048E63D BA13000000 mov edx, $00000013
0048E642 8B45DC mov eax, [ebp-$24]
* Reference to: system.@LStrCopy;
|
0048E645 E8C65AF7FF call 00404110
0048E64A 8B45A0 mov eax, [ebp-$60]
* Reference to: sysutils.StrToInt(System.AnsiString):System.Integer;
|
0048E64D E8D2A7F7FF call 00408E24
0048E652 3BD8 cmp ebx, eax //这一句也就基本上要求了数字串的第19位'1'
0048E654 0F859F010000 jnz 0048E7F9
0048E65A 33F6 xor esi, esi
0048E65C BB01000000 mov ebx, $00000001
---------------- 将数字串中前 18 位每个数字 3 倍的个位数进行累加 ----------------------
最终效果:'2522232021181916171414111291078212219' --> '252223202118191617' -->
(2 * 3) mod 10 + (5 * 3) mod 10 +(2 * 3) mod 10 + .... + (7 * 3) mod 10 = 85
0048E661 8D459C lea eax, [ebp-$64]
0048E664 50 push eax
0048E665 B901000000 mov ecx, $00000001
0048E66A 8BD3 mov edx, ebx
0048E66C 8B45DC mov eax, [ebp-$24]
* Reference to: system.@LStrCopy;
|
0048E66F E89C5AF7FF call 00404110
0048E674 8B459C mov eax, [ebp-$64]
* Reference to: sysutils.StrToInt(System.AnsiString):System.Integer;
|
0048E677 E8A8A7F7FF call 00408E24
0048E67C 8D0440 lea eax, [eax+eax*2] // X * 3
0048E67F B90A000000 mov ecx, $0000000A
0048E684 99 cdq
0048E685 F7F9 idiv ecx
0048E687 03F2 add esi, edx // 个位数相加
0048E689 43 inc ebx
0048E68A 83FB13 cmp ebx, +$13 // 取前18位
0048E68D 75D2 jnz 0048E661
------------------------ 再求累加和的个位数 --------------------------
最终效果:85 mod 10 = 5
0048E68F 8BC6 mov eax, esi
0048E691 B90A000000 mov ecx, $0000000A
0048E696 99 cdq
0048E697 F7F9 idiv ecx
0048E699 8BDA mov ebx, edx
0048E69B 8D4598 lea eax, [ebp-$68]
0048E69E 50 push eax
0048E69F B901000000 mov ecx, $00000001
0048E6A4 BA14000000 mov edx, $00000014
0048E6A9 8B45DC mov eax, [ebp-$24]
* Reference to: system.@LStrCopy;
|
0048E6AC E85F5AF7FF call 00404110
0048E6B1 8B4598 mov eax, [ebp-$68]
* Reference to: sysutils.StrToInt(System.AnsiString):System.Integer;
|
0048E6B4 E86BA7F7FF call 00408E24
0048E6B9 3BD8 cmp ebx, eax //累加和的个位数('5')应和数字串的第20位相等
0048E6BB 0F8538010000 jnz 0048E7F9
0048E6C1 8D45E0 lea eax, [ebp-$20]
0048E6C4 50 push eax
0048E6C5 B903000000 mov ecx, $00000003
0048E6CA BA10000000 mov edx, $00000010
0048E6CF 8B45DC mov eax, [ebp-$24]
* Reference to: system.@LStrCopy; // Lstrcopy(string,10,3) = '617'
| 不过根据后来的跟踪,
0048E6D2 E8395AF7FF call 00404110 好像这次取出的字符串无关紧要
0048E6D7 8D45EC lea eax, [ebp-$14]
* Reference to: system.@LStrClr(String);
|
0048E6DA E8A955F7FF call 00403C88
0048E6DF 8D45E8 lea eax, [ebp-$18]
* Reference to: system.@LStrClr(String);
|
0048E6E2 E8A155F7FF call 00403C88
0048E6E7 8D45E4 lea eax, [ebp-$1C]
* Reference to: system.@LStrClr(String);
|
0048E6EA E89955F7FF call 00403C88
0048E6EF BB01000000 mov ebx, $00000001
------------ Sorry,我又不知道该怎么说了,看最终效果吧 ---------------
最终效果:'2522232021181916171414111291078212219' -->
'252' + '223' + '202' + '118' + '191' -->
'22211'(第一位) + '52019'(第二位) + '23281' (第三位)
0048E6F4 8D4594 lea eax, [ebp-$6C]
0048E6F7 50 push eax
0048E6F8 8BC3 mov eax, ebx
0048E6FA 48 dec eax
0048E6FB 8D3440 lea esi, [eax+eax*2]
0048E6FE 8BD6 mov edx, esi
0048E700 42 inc edx
0048E701 B901000000 mov ecx, $00000001
0048E706 8B45DC mov eax, [ebp-$24]
* Reference to: system.@LStrCopy;
|
0048E709 E8025AF7FF call 00404110
0048E70E 8B5594 mov edx, [ebp-$6C]
0048E711 8D45EC lea eax, [ebp-$14]
* Reference to: system.@LStrCat;
|
0048E714 E8F757F7FF call 00403F10
0048E719 8D4590 lea eax, [ebp-$70]
0048E71C 50 push eax
0048E71D 8BD6 mov edx, esi
0048E71F 83C202 add edx, +$02
0048E722 B901000000 mov ecx, $00000001
0048E727 8B45DC mov eax, [ebp-$24]
* Reference to: system.@LStrCopy;
|
0048E72A E8E159F7FF call 00404110
0048E72F 8B5590 mov edx, [ebp-$70]
0048E732 8D45E8 lea eax, [ebp-$18]
* Reference to: system.@LStrCat;
|
0048E735 E8D657F7FF call 00403F10
0048E73A 8D458C lea eax, [ebp-$74]
0048E73D 50 push eax
0048E73E 8BD6 mov edx, esi
0048E740 83C203 add edx, +$03
0048E743 B901000000 mov ecx, $00000001
0048E748 8B45DC mov eax, [ebp-$24]
* Reference to: system.@LStrCopy;
|
0048E74B E8C059F7FF call 00404110
0048E750 8B558C mov edx, [ebp-$74]
0048E753 8D45E4 lea eax, [ebp-$1C]
* Reference to: system.@LStrCat;
|
0048E756 E8B557F7FF call 00403F10
0048E75B 43 inc ebx
0048E75C 83FB06 cmp ebx, +$06 //共循环5次,每次取出3个字符
0048E75F 7593 jnz 0048E6F4
0048E761 8B45E0 mov eax, [ebp-$20]
* Reference to: sysutils.StrToInt(System.AnsiString):System.Integer;
|
0048E764 E8BBA6F7FF call 00408E24
0048E769 BEE7030000 mov esi, $000003E7
0048E76E 2BF0 sub esi, eax // 999 - 617 = 382 = $17E
0048E770 8B45EC mov eax, [ebp-$14]
* Reference to: sysutils.StrToInt(System.AnsiString):System.Integer;
|
0048E773 E8ACA6F7FF call 00408E24
0048E778 BF9F860100 mov edi, $0001869F
0048E77D 2BF8 sub edi, eax // 99999 - 22211 = 77788 = $12FDC
0048E77F 8B45E8 mov eax, [ebp-$18]
* Reference to: sysutils.StrToInt(System.AnsiString):System.Integer;
|
0048E782 E89DA6F7FF call 00408E24
0048E787 BB9F860100 mov ebx, $0001869F
0048E78C 2BD8 sub ebx, eax // 99999 - 52019 = 47980 = $BB6C
0048E78E 8B45E4 mov eax, [ebp-$1C]
* Reference to: sysutils.StrToInt(System.AnsiString):System.Integer;
|
0048E791 E88EA6F7FF call 00408E24
0048E796 BA9F860100 mov edx, $0001869F
0048E79B 2BD0 sub edx, eax // 99999 - 23281 = 76718 = $12BAE
0048E79D 8955D0 mov [ebp-$30], edx
0048E7A0 8BC3 mov eax, ebx
0048E7A2 B964000000 mov ecx, $00000064
0048E7A7 99 cdq
0048E7A8 F7F9 idiv ecx
0048E7AA 8BCA mov ecx, edx
0048E7AC 2BF1 sub esi, ecx
0048E7AE 8BC3 mov eax, ebx
0048E7B0 BE64000000 mov esi, $00000064
0048E7B5 99 cdq
0048E7B6 F7FE idiv esi // 47980 ÷ 100 = 479 ... 80
0048E7B8 8BF0 mov esi, eax
0048E7BA 8BC6 mov eax, esi
0048E7BC 2BC1 sub eax, ecx
0048E7BE 7906 jns 0048E7C6 // 若商小于余数,则商+1000(反正不能出现负数)
0048E7C0 81C6E8030000 add esi, $000003E8
0048E7C6 2BF1 sub esi, ecx
0048E7C8 3B75F4 cmp esi, [ebp-$0C] //关键判断:比较399(= 479 - 80)和$8D(常量)
0048E7CB 752C jnz 0048E7F9 //跳则死,不跳则活。
0048E7CD 8BF7 mov esi, edi
0048E7CF 8BC6 mov eax, esi
0048E7D1 2BC3 sub eax, ebx // $12FDC - $BB6C = $7470
0048E7D3 7906 jns 0048E7DB // 若商小于余数,则商+100000(反正不能出现负数)
0048E7D5 81C6A0860100 add esi, $000186A0
0048E7DB 2BF3 sub esi, ebx
0048E7DD 8B45F8 mov eax, [ebp-$08]
0048E7E0 B90A000000 mov ecx, $0000000A
0048E7E5 99 cdq
0048E7E6 F7F9 idiv ecx
0048E7E8 8945F8 mov [ebp-$08], eax //机器码:572463 idiv 10 = 57246 =$DF9E
0048E7EB 3B75F8 cmp esi, [ebp-$08] //关键判断:比较$7470(= $12FDC - $BB6C)和$DF9E
0048E7EE 7509 jnz 0048E7F9 //跳则死,不跳则活。
0048E7F0 8B45D0 mov eax, [ebp-$30]
0048E7F3 2BC7 sub eax, edi
0048E7F5 C645F301 mov byte ptr [ebp-$0D], $01 //到此处写入注册成功标志
0048E7F9 33C0 xor eax, eax
0048E7FB 5A pop edx
0048E7FC 59 pop ecx
0048E7FD 59 pop ecx
0048E7FE 648910 mov fs:[eax], edx
****** FINALLY //异常处理,释放单元,不去管它。
|
* Possible String Reference to: '奅骭^[嬪]?
|
0048E801 6830E84800 push $0048E830
0048E806 8D458C lea eax, [ebp-$74]
0048E809 BA11000000 mov edx, $00000011
* Reference to: system.@LStrArrayClr;
|
0048E80E E89954F7FF call 00403CAC
0048E813 8D45D4 lea eax, [ebp-$2C]
0048E816 BA07000000 mov edx, $00000007
* Reference to: system.@LStrArrayClr;
|
0048E81B E88C54F7FF call 00403CAC
0048E820 8D45FC lea eax, [ebp-$04]
* Reference to: system.@LStrClr(String);
|
0048E823 E86054F7FF call 00403C88
0048E828 C3 ret
0048E829 E96E4EF7FF jmp 0040369C
0048E82E EBD6 jmp 0048E806
****** END
|
0048E830 8A45F3 mov al, byte ptr [ebp-$0D] //将注册标志赋予AL,返回供后面调用
0048E833 5F pop edi
0048E834 5E pop esi
0048E835 5B pop ebx
0048E836 8BE5 mov esp, ebp
0048E838 5D pop ebp
0048E839 C3 ret
-------------------------0048E36C call End-----------------------------------------
写得挺长,但分析的确是比较快的。现在总结一下注册码比较流程:
机器码:572463 =$8BC2F
注册码:WWWWW-XXXXX-YYYYY-ZZZZZ
WWWWWXXXXXYYYYYZZZZZ ---> ZZZZZYYYYYXXXXXWWWWW ---> ZXZXZXZXZXYWYWYWYWYW --->
'2522232021181916171414111291078212219' ---> '252223202118191617' --->
'252' + '223' + '202' + '118' + '191' ---> '22211' + '52019' + '23281' --->
1、99999 - 52019 = 47980 ÷ 100 = 479 ... 80 ---> 要求 479 - 80 等于常量 141 = &8D
99999 - 85798 = 14201
2、99999 - 22211 = 77788 - 47980 = 29808 ---> 要求与机器码:572463 idiv 10 = 57246相等
下面该写注册机了:
首先应该知道,对注册码的 20 位进行穷举是不太现实的。那么我们是不是有办法减少穷举的位数呢。我想了一些办法,去掉了些无关紧要的
位数,但还是比较大,效率很低,估计软件的作者是不会使用的。:)我们必须另辟蹊径。
由上面的注册流程可知,最重要的部分是那个数字串('2522232021181916171414111291078212219')。一般情况下,该串的长度是大于20位的,
除非在极端情况(比如'11111111111111111111',此时注册码反转交叉后应该是类似这个样子:'BCDEFGHIJKLMNOPQRSTU')下。而最核心的只
有15位数字,用7、8位注册码就可产生。这就意味着注册码的某些位数可以忽略不计。而在这15位数字中,又有5位没有参与关键判断(指的是
0048E7C8、0048E7EB两处判断),这样我们又可舍弃 5 位数字。
假设我们需要的两个 5 位数分别为 M(对应例子中的22211) 和 N(对应例子中的52019)。由流程我们可以看到,真正的注册码要求:(
99999 - N ) ÷ 100 = P ... Q , P - Q = 141 ,
∴ P = Q + 141
∴ 99999 - N = 100 * P + Q = 101 * Q + 14100
∴ N = 99999 - ( 101 * Q + 14100 ) = 85899 - 101 * Q
又∵ 99999 - M - (99999 - N) = 99999 - 14100 - 101 * Q - M = 57246
∴ M = 99999 - 14100 - 101 * Q - 57246 = 28653 - 101 * Q
这样,我们用一位变量和机器码便表示出了两个 5 位数。第三个 5 位数由于没起什么作用,所以我们不妨设它为 11111。
例如:
令Q = 1,则
N = 85899 - 101 * 1 = 85798
M = 28653 - 101 * 1 = 28552
于是15位的字串就是 281851571591281;
又∵ 第16-18位没有什么限制,所以就取随便取个212;
第19位通常状况下为1(见0048E627);
第20位的值等于数字串前18位('281851571591281212')每个数字三倍和的个位数(∵((a mod n) +(b mod n)) mod n = (a+b) mod n),此
时为7;
∴该数字串为 '28185157159128121217'
然后,我们对数字分组。分组的原则就是,让后面的数尽量的小。因为 'Z' 的 ASCII 值为90,而到后面加上的数会很大(比如83、84等),
容易超出界限。不够20 组可再补齐。补齐原则同上。再分别对每一组数字一次加上65、66、67、……、85,如下:
2 8 18 5 15 7 15 9 12 8 12 12 1 7 1 1 1 1 1 1
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
67 74 85 73 84 77 86 81 85 82 87 88 78 85 80 81 82 83 84 85
C J U I T M V Q U R W X N U P Q R S T U
这样,CJUITMVQURWXNUPQRSTU ---> CUTVUWNPRTJIMQRXUQSU ---> USQUX-RQMIJ-TRPNW-UVTUC
再附上注册机源码(Delphi 6 + WinXP Pro 下调试通过),一切OK。
procedure TForm1.Button1Click(Sender: TObject);
var
Machinecode,N,Tmp,i:Integer;
Tmpstr,tmpstr1,tmpstr2:Str