某国产软件 - XX E-mail 邮差 的算法分析,感兴趣者请进! (32千字)
某国产软件 - 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
