【原创】OverNimble LocPlus 1.05注册算法全程详解(写给学VB算法者)
————手把手系列之四
【破解作者】 jackily
【作者主页】 http://estudy.ys168.com
【使用工具】 ollydbg、 untelock和偶的一双手(手动脱壳)
【破解平台】 Win9x/NT/2000/XP
【软件名称】 OverNimble LocPlus 1.05
【软件简介】 OverNimble LocPlus主要用于非资源格式的本地化,支持的种类包括非资源格式的 C 编译的程序中的 ASCII 字符串和 UniCode 字符串、非资源格式的 Delphi(C++ Builder)编译的程序的字符串、VB 编译的程序的字符串、文本格式的字符串等的提取及替换。未注册版本有一些功能(“VA英文和符号”、“VA非控制符”、“VA中文(GBK)”、“VA中文(BIG5)”、“VA完全中文”、“VA非保留区”、“VA非限制查找”方式的 ASCII 及 uniCode 查找)不能使用。
【加壳方式】tElock 0.98b1、PEBundle 2.0b5 - 3.0x 双层壳
【破解声明】 本破解纯以学习和交流为目的,偶得一点心得,愿与大家分享:)
--------------------------------------------------------------------------------
提起OverNimble LocPlus,大家可能很陌生,至少在真正接触它以前,我一直以为它是国外产品,但提到点睛字符串替换器,汉化界的朋友就非常熟悉了。其实二者是一回事。和狂风汉化百宝箱相类似,它最大的长处就是用于非资源格式字符串的本地化,而LocPlus做得更胜一筹,提供了更多的功能。在看雪精华4、5中侦探柯南、八鸟@和leeyam分别对其1.02版和1.04版做了分析,但采取的都是爆破方法,并没有深入到注册算法,而且他们对于关键代码的分析也存在着一些小BUG,因此本文一并指正出来,以免给初学者带来误导。
1.05版不仅增加了新功能,还在验证注册上稍做了改动,具体见分析过程。因此建议,在读本文前,先读一下侦探柯南、八鸟@和leeyam对1.02版和1.04版做的分析(参见看雪五周年收藏版),以便更好地理解本文。
和以往不同,这次倒过来写,先文字详述分析思路、过程和总结,代码分析放到最后的附录中,大家以交流心得为主,谁都不愿意,也没时间一句句地去读汇编代码,而且能读懂的也真不多,有兴趣的自己慢慢读吧。
读懂本文所必备的知识:
1. 汇编基础知识;
2. 听说过VB的浮点运算;
3. 听说过VB的数据在内存中的存放方式;
4. 了解如下VB内部函数的功能和参数调用(程序中将用到,先自行预习一下,代码分析中有讲解);
4.1 _vbavaradd
4.2 _vbavarsub
4.3 _vbaVarForInit、_vbaVarForNext
4.4 _vbaLenBstr
4.5 _vbaVarTstLe
4.6 rtcR8ValFromBstr
4.7 rtcVarBstrFromAnsi
4.8 rtcIsNumeric
这些天伏案成疾,背疼,找了个郎中,也偷学了一些疗法,这回随我出趟诊吧,医不好,不收费的。:)
第一步:出诊(查壳)
首先,当然是用PEID查壳了,发现tElock 0.98b1,用untelock很轻松地去掉第一层外衣。本想再用PEID查一下是什么程序编写的(本人习惯:脱完壳后,再查一次),嗯?!怎么出来个PEBundle 2.0b5 - 3.0x呢?!嘿,我的爆脾气又来了,第一次听说啊?用google一搜索,明白了,与其说PEBundle是一个壳,不如说是EXE压缩器。于是乎找遍了大江南北,楞没找到相应的脱壳机(本人一般很懒,要是有脱壳机,决不自己动手)。这家伙,象大姑娘上花轿似的,扭扭捏捏地,还穿了里三层外三层的?!没办法,用我的手来脱吧。只说一下要点,脱壳部分码见附录一。
这壳特简单。用ollydbg载入,忽略警告,进入后发现入口处的两个命令pushfd(9c)、pushad(60)非常典型,那我们就寻找popad和popfd,连在一起是619d。Ctrl+B搜索619d...,找到后,在紧接着的RETN 处下断。F9运行,被拦,F8单步跟过,又是60(pushad),此时地址是004473D0,顺着代码,一行行地快速下查,在0044753B处找到一个61(popad),紧接着是jmp 004027fc,下断。再来个F8跟过,此时看到了什么?典型的VB程序入口。用插件中的ollydump脱壳,轻松搞掂。
第二步:诊脉(查看注册校验方式)
打开脱壳后的locplus,点注册,弹出对话框,要求输入用户名和注册码?分别输入jackily和123456点确定,要求重启验证。这是1.05与以往版本不同之处。1.04以前版本有出错信息, 在ollydbg中可以查找到其地址,可以下断,因此其在输入注册码时,会直接检验一次,此时会有机会跟踪注册码。当然,每次重启时,它也都会重新校验注册码。而1.05不直接检验注册码,只在重启时检验,这给跟踪增加了一定的难度,是1.05的一大改进。
第三步:B超检查(动态调试)
既然是重启校验的方式,仔细想一下,无碍乎就是读key文件和读注册表。重新载入程序,点右键—“搜索”—“字符参考”。咦,只有稀稀啦啦的几个注册表项目树,并没有发现1.02和1.04版中出现的\Software\OverNimble\LocPlusRegUserName和RegCode项(注:在以前的版本中直接可查到具体的注册个子项),看来作者在反破解上下了点功夫。不过这点已经够了,说明注册码保存在注册表中了。那么如何下断呢?就断在HKEY_CURRENT_USER的地址上。为什么?我试出来的呗!以下过程请对照附录二的代码分析阅读。在00431a43下断,一步一步向下,发现经过计算,\Software\OverNimble\LocPlusRegUserName和RegCode项被解码出来,原来作者对这两个注册表项加密了。再经过N步跟踪,发现了一个重要信息,在00431a43和00431a71处的两个语句mov edx,eax中,eax存放着用户名和注册码的地址(个人认为,长时间的跟踪能力是大部分cracker所欠缺的,这是crack成功与否的关键)。再向下跟,就和1.04版以前的注册验证部分代码相似了。00431a81的call是关键算法,其中对输入的假码同“ONLocPlus"进行了循环计算(注意大小写),并得出新值,子调用中的算法详见附录二,在此不再述赘;00431a91是检验新值的长度,而非侦探柯南和leeyam所说的注册码长度,实际的注册码长度是26位,而这里是0xc,即12位,也就是说,通过重新计算,26位的注册码被转成12位新值;00431aad是检验新值是否为浮点数值,是就通过,否就失败;00431ac8是检验浮点数值的HEX值,也就是要求这个数值是大于0的,也非侦探柯南和leeyam所说的比较注册码;00431ad9是浮点数比较,[402050]中是程序既定值“9900000000.00000000”,因此,新算出的浮点值是“99.后接18个0”。这个写注册机时要用到。以上两点更正是需向读者说明的,以免造成学习过程中的误解。
第四步:开药方(编写注册机)
【破解总结】
一、用户名不参加注册计算,校验注册条件有三:
1、注册码运算后为12位数,即0xC;换句话说,注册码应该为26位。
2、注册码运算后应为数字,分析中会指出判断函数。
3、运算后的数字的HEX值应大于1 。
二、算法思路:
算法属于较特殊的变量比较一种,注册码第1、2位需取00,第3位开始,取12轮,每次取两个位(不用转换,已经认为是HEX值),和“ONLocPlus”的第一位开始(循环取值),每次取1个字母,进行异或。异或值是否小于前一对注册码值,如果是,用0xff减去异或值,再加上前一对注册码值,反之,用异或值减去前一对注册码值。如果前10轮结果值都等于0x30,并且11、12轮结果等于0x39,那么12轮结果转十进制并相连便是00000000099,此时注册码成功。(解释的我都有点糊涂了,能看懂吗?)
算法的数学表达式:
设x为注册码,y为符合条件值,a和b为变量,a=f1(x),b=f2(y),如果f3(a)=b,x为正确的。也就是说如果等式f3(f1(x))=f2(y)成立,x合法有效。
【算法注册机】
/* OverNimble LocPlus c语言注册机 */
/* 本注册机对以前版本也适用 */
/* 在Turboc 2.0 下调试通过 */
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
main()
{
char name[100]={0} ,s[]="ONLocPlus";
int i,j;
long unsigned c,code,k=0,m,t=0;
printf("OverNimble LocPlusB KeyGen by jackily 2005-1-18\n");
printf("Email:jackily_zhang@msn.com or jackily_zhang@yahoo.com.cn\n");
printf("please input name:");
scanf("%s",name);
printf("\nYour serial number is:00");
for (i=0;i<0xc;i++)
{ j=i;
for (k=0;k<0xff;k++)
{
code=k;
if (j>0x8) j-=0x9;
m=k^s[j];
if (t<=m) c=m-t;
else {c=0xff-t;c+=m;}
if (i<=0xa&&c==0x30) break;
if (i>0xa&&c==0x39) break;
}
t=code;
if (code<=0xf) printf("0%x",code);
else printf("%x",code);
}
}
--------------------------------------------------------------------------------
【内存注册机】
非明码比较,无法实现
【爆破地址】
小孩爬窗户的行为,都有钥匙了,还用吗?
【用户名、密码】
用户名:jackily
SN :007FE15EE171F14E0B4837292E
--------------------------------------------------------------------------------
附录一:脱壳分析(结合第一步阅读)
步骤一:
0044E000 L> 9C pushfd ; 程序进入点
0044E001 60 pushad
0044E002 E8 02000000 call LocPlus-.0044E009
0044E007 33C0 xor eax,eax
0044E009 8BC4 mov eax,esp
0044E00B 83C0 04 add eax,4
0044E00E 93 xchg eax,ebx
.........中间省略
0044E195 8D9D 0923400>lea ebx,dword ptr ss:[ebp+402309]
0044E19B 53 push ebx
0044E19C 6A 00 push 0
0044E19E FFD0 call eax
0044E1A0 FFA5 D628400>jmp dword ptr ss:[ebp+4028D6]
0044E1A6 61 popad ; 搜索到这里
0044E1A7 9D popfd
0044E1A8 68 D0734400 push LocPlus-.004473D0
0044E1AD C3 retn ; 下断
步骤二:
004473D0 60 pushad ;由44E1AD的retn而来
004473D1 BE 15604300 mov esi,LocPlus-.00436015
004473D6 8DBE EBAFFCF>lea edi,dword ptr ds:[esi+FFFCAFEB]
004473DC 57 push edi
004473DD 83CD FF or ebp,FFFFFFFF
004473E0 EB 10 jmp short LocPlus-.004473F2
004473E2 90 nop
...........中间省略
0044752E 8903 mov dword ptr ds:[ebx],eax
00447530 83C3 04 add ebx,4
00447533 ^ EB D8 jmp short LocPlus-.0044750D
00447535 FF96 447D040>call dword ptr ds:[esi+47D44]
0044753B 61 popad
0044753C - E9 BBB2FBFF jmp LocPlus-.004027FC ;下第二个断点
真正的程序入口:
004027FC 68 FC594000 push LocPlus-.004059FC ;oep,在此dump...
00402801 E8 EEFFFFFF call LocPlus-.004027F4 ;jmp to MSVBVM50.ThunRTMain
00402806 0000 add byte ptr ds:[eax],al
00402808 0000 add byte ptr ds:[eax],al
0040280A 0000 add byte ptr ds:[eax],al
0040280C 3000 xor byte ptr ds:[eax],al
0040280E 0000 add byte ptr ds:[eax],al
00402810 48 dec eax
00402811 0000 add byte ptr ds:[eax],al
00402813 0000 add byte ptr ds:[eax],al
00402815 0000 add byte ptr ds:[eax],al
00402817 0053 4A add byte ptr ds:[ebx+4A],dl
0040281A - E9 0B725CCE jmp CE9C9A2A
........以下代码省略
-------------------------------------------------------------------------------
附录二:代码分析(结合第三步阅读)
004319E0 55 push ebp
004319E1 8BEC mov ebp,esp
004319E3 83EC 14 sub esp,14
004319E6 68 C6224000 push <jmp.&MSVBVM50.__vbaExceptHandler>
004319EB 64:A1 000000>mov eax,dword ptr fs:[0]
004319F1 50 push eax
004319F2 64:8925 0000>mov dword ptr fs:[0],esp
004319F9 83EC 40 sub esp,40
004319FC 53 push ebx
004319FD 56 push esi
004319FE 57 push edi
004319FF 8965 EC mov dword ptr ss:[ebp-14],esp
00431A02 C745 F0 7820>mov dword ptr ss:[ebp-10],locplus-.004020>
00431A09 33F6 xor esi,esi
00431A0B 8975 F4 mov dword ptr ss:[ebp-C],esi
00431A0E 8975 F8 mov dword ptr ss:[ebp-8],esi
00431A11 8975 DC mov dword ptr ss:[ebp-24],esi
00431A14 8975 CC mov dword ptr ss:[ebp-34],esi
00431A17 8975 BC mov dword ptr ss:[ebp-44],esi
00431A1A 6A 01 push 1
00431A1C FF15 F8C4430>call dword ptr ds:[<&MSVBVM50.__vbaOnErro>; MSVBVM50.__vbaOnError
00431A22 66:8935 2C91>mov word ptr ds:[43912C],si
00431A29 68 38914300 push locplus-.00439138
00431A2E 8D45 CC lea eax,dword ptr ss:[ebp-34]
00431A31 50 push eax
00431A32 E8 F90E0000 call locplus-.00432930
00431A37 8D4D CC lea ecx,dword ptr ss:[ebp-34]
00431A3A 51 push ecx
00431A3B 8B3D 38C4430>mov edi,dword ptr ds:[<&MSVBVM50.__vbaStr>; MSVBVM50.__vbaStrVarMove
00431A41 FFD7 call edi
00431A43 8BD0 mov edx,eax ;eax存放着用户名地址
00431A45 B9 28914300 mov ecx,locplus-.00439128
00431A4A 8B35 18C7430>mov esi,dword ptr ds:[<&MSVBVM50.__vbaStr>; MSVBVM50.__vbaStrMove
00431A50 FFD6 call esi
00431A52 8D4D CC lea ecx,dword ptr ss:[ebp-34]
00431A55 8B1D 2CC4430>mov ebx,dword ptr ds:[<&MSVBVM50.__vbaFre>; MSVBVM50.__vbaFreeVar
00431A5B FFD3 call ebx
00431A5D 68 3C914300 push locplus-.0043913C
00431A62 8D55 CC lea edx,dword ptr ss:[ebp-34]
00431A65 52 push edx
00431A66 E8 C50E0000 call locplus-.00432930
00431A6B 8D45 CC lea eax,dword ptr ss:[ebp-34]
00431A6E 50 push eax
00431A6F FFD7 call edi
00431A71 8BD0 mov edx,eax ;eax存放着注册码地址
00431A73 8D4D DC lea ecx,dword ptr ss:[ebp-24]
00431A76 FFD6 call esi
00431A78 8D4D CC lea ecx,dword ptr ss:[ebp-34]
00431A7B FFD3 call ebx
00431A7D 8D4D DC lea ecx,dword ptr ss:[ebp-24]
00431A80 51 push ecx
00431A81 E8 0AFBFFFF call locplus-.00431590 ;关键算法call,必须跟进
00431A86 8BD0 mov edx,eax ;eax为新数值的地址
00431A88 8D4D DC lea ecx,dword ptr ss:[ebp-24]
00431A8B FFD6 call esi
00431A8D 8B55 DC mov edx,dword ptr ss:[ebp-24]
00431A90 52 push edx
00431A91 FF15 30C4430>call dword ptr ds:[<&MSVBVM50.__vbaLenBstr> ; 取新值的长度
00431A97 83F8 0C cmp eax,0C ;检验新值的长度是否为12位
00431A9A 75 6A jnz short locplus-.00431B06 ;跳走即失败
00431A9C 8D45 DC lea eax,dword ptr ss:[ebp-24]
00431A9F 8945 C4 mov dword ptr ss:[ebp-3C],eax
00431AA2 C745 BC 0840>mov dword ptr ss:[ebp-44],4008
00431AA9 8D4D BC lea ecx,dword ptr ss:[ebp-44]
00431AAC 51 push ecx
00431AAD FF15 8CC5430>call dword ptr ds:[<&MSVBVM50.rtcIsNumeric> ; 检验新值是否为浮点数值
00431AB3 66:85C0 test ax,ax ;是就通过
00431AB6 74 4E je short locplus-.00431B06 ;跳走即失败
00431AB8 8B55 DC mov edx,dword ptr ss:[ebp-24]
00431ABB 52 push edx
00431ABC FF15 58C7430>call dword ptr ds:[<&MSVBVM50.rtcR8ValFromBstr>];
00431AC2 FF15 00C7430>call dword ptr ds:[<&MSVBVM50.__vbaFpI4>] ; MSVBVM50.__vbaFpI4
00431AC8 8945 E0 mov dword ptr ss:[ebp-20],eax
00431ACB 83F8 01 cmp eax,1 ; 检验浮点数值的HEX值
00431ACE 7C 36 jl short locplus-.00431B06 ;跳走即失败
00431AD0 DB45 E0 fild dword ptr ss:[ebp-20]
00431AD3 DD5D A4 fstp qword ptr ss:[ebp-5C]
00431AD6 DD45 A4 fld qword ptr ss:[ebp-5C]
00431AD9 DC1D 5020400>fcomp qword ptr ds:[402050] ; 浮点数比较
00431ADF DFE0 fstsw ax ;[402050] 既定值“9900000000.00000000”
00431AE1 F6C4 41 test ah,41
00431AE4 74 20 je short locplus-.00431B06
00431AE6 66:C705 2C91>mov word ptr ds:[43912C],0FFFF
00431AEF FF15 DCC4430>call dword ptr ds:[<&MSVBVM50.__vbaExitPr>; MSVBVM50.__vbaExitProc
00431AF5 9B wait
00431AF6 68 281B4300 push locplus-.00431B28
00431AFB EB 21 jmp short locplus-.00431B1E
00431AFD 66:C705 2C91>mov word ptr ds:[43912C],0
00431B06 FF15 DCC4430>call dword ptr ds:[<&MSVBVM50.__vbaExitPr>; MSVBVM50.__vbaExitProc
00431B0C 9B wait
00431B0D 68 281B4300 push locplus-.00431B28
00431B12 EB 0A jmp short locplus-.00431B1E
00431B14 8D4D CC lea ecx,dword ptr ss:[ebp-34]
00431B17 FF15 2CC4430>call dword ptr ds:[<&MSVBVM50.__vbaFreeVa>; MSVBVM50.__vbaFreeVar
00431B1D C3 retn
00431B1E 8D4D DC lea ecx,dword ptr ss:[ebp-24]
00431B21 - FF25 54C7430>jmp dword ptr ds:[<&MSVBVM50.__vbaFreeStr>; MSVBVM50.__vbaFreeStr
00431B27 C3 retn
00431B28 8B4D E4 mov ecx,dword ptr ss:[ebp-1C]
00431B2B 64:890D 0000>mov dword ptr fs:[0],ecx
00431B32 5F pop edi
00431B33 5E pop esi
00431B34 5B pop ebx
00431B35 8BE5 mov esp,ebp
00431B37 5D pop ebp
00431B38 C3 retn
--------------------------------------------------------
关键算法,由00431a81跟进。
00431590 55 push ebp
00431591 8BEC mov ebp,esp
00431593 83EC 0>sub esp,0C
00431596 68 C62>push <jmp.&MSVBVM50.__vbaExceptHandler>
0043159B 64:A1 >mov eax,dword ptr fs:[0]
004315A1 50 push eax
004315A2 64:892>mov dword ptr fs:[0],esp
004315A9 81EC E>sub esp,0E0
004315AF A1 589>mov eax,dword ptr ds:[439158]
004315B4 53 push ebx
004315B5 56 push esi
004315B6 57 push edi
004315B7 8965 F>mov dword ptr ss:[ebp-C],esp
004315BA 33FF xor edi,edi
004315BC 50 push eax ; eax=001a7514,unicode "ONLocPlus"
004315BD C745 F>mov dword ptr ss:[ebp-8],locplus-.00402068
004315C4 897D D>mov dword ptr ss:[ebp-24],edi
004315C7 897D D>mov dword ptr ss:[ebp-2C],edi
004315CA 897D C>mov dword ptr ss:[ebp-3C],edi
004315CD 897D C>mov dword ptr ss:[ebp-40],edi
004315D0 897D B>mov dword ptr ss:[ebp-48],edi
004315D3 897D A>mov dword ptr ss:[ebp-54],edi
004315D6 897D A>mov dword ptr ss:[ebp-58],edi
004315D9 897D 9>mov dword ptr ss:[ebp-68],edi
004315DC 897D 8>mov dword ptr ss:[ebp-78],edi
004315DF 89BD 7>mov dword ptr ss:[ebp-88],edi
004315E5 89BD 6>mov dword ptr ss:[ebp-98],edi
004315EB 89BD 5>mov dword ptr ss:[ebp-A8],edi
004315F1 89BD 4>mov dword ptr ss:[ebp-B8],edi
004315F7 89BD 3>mov dword ptr ss:[ebp-C8],edi
004315FD 89BD 2>mov dword ptr ss:[ebp-D8],edi
00431603 89BD 1>mov dword ptr ss:[ebp-E8],edi
00431609 FF15 3>call dword ptr ds:[<&MSVBVM50.__vbaLenBstr>] ; 取"ONLocPlus"的长度放eax,为9
0043160F 8BC8 mov ecx,eax
00431611 FF15 9>call dword ptr ds:[<&MSVBVM50.__vbaI2I4>] ; MSVBVM50.__vbaI2I4
00431617 8B4D 0>mov ecx,dword ptr ss:[ebp+8]
0043161A BE 020>mov esi,2
0043161F 68 00D>push locplus-.0040D900 ; UNICODE "&H"
00431624 56 push esi
00431625 8B11 mov edx,dword ptr ds:[ecx]
00431627 8945 B>mov dword ptr ss:[ebp-4C],eax ; 把长度值9放入ebp-4c,在00431786会用到
0043162A 52 push edx ; 注册码地址
0043162B FF15 F>call dword ptr ds:[<&MSVBVM50.rtcLeftCharBstr> ; 取左边两个字符,
00431631 8B1D 1>mov ebx,dword ptr ds:[<&MSVBVM50.__vbaStrMove>; MSVBVM50.__vbaStrMove
00431637 8BD0 mov edx,eax
00431639 8D4D A>lea ecx,dword ptr ss:[ebp-54]
0043163C FFD3 call ebx ; 把宽型第1、2字符的地址放入ebp-54中 0043163E 50 push eax
0043163F FF15 8>call dword ptr ds:[<&MSVBVM50.__vbaStrCat>] ; &H和第1、2字符连在一起
00431645 8BD0 mov edx,eax
00431647 8D4D A>lea ecx,dword ptr ss:[ebp-58]
0043164A FFD3 call ebx ; 把1a76ac,&H和第1、2字符地址放入ebp-58
0043164C 50 push eax
0043164D FF15 5>call dword ptr ds:[<&MSVBVM50.rtcR8ValFromBstr> ; &&H和第1、2字符换成浮点数00431653 FF15 F>call dword ptr ds:[<&MSVBVM50.__vbaFpI2>] ; MSVBVM50.__vbaFpI2
00431659 8BD8 mov ebx,eax
0043165B 8D45 A>lea eax,dword ptr ss:[ebp-58]
0043165E 8D4D A>lea ecx,dword ptr ss:[ebp-54]
00431661 50 push eax
00431662 51 push ecx
00431663 56 push esi
00431664 FF15 A>call dword ptr ds:[<&MSVBVM50.__vbaFreeStrLis>; MSVBVM50.__vbaFreeStrList
0043166A 8B55 0>mov edx,dword ptr ss:[ebp+8] ; 注册码存放地址
0043166D 83C4 0>add esp,0C
00431670 89B5 6>mov dword ptr ss:[ebp-A0],esi ; ESI=0x2
00431676 89B5 5>mov dword ptr ss:[ebp-A8],esi
0043167C 8B02 mov eax,dword ptr ds:[edx]
0043167E 50 push eax ; 注册码存放地址给EAX
0043167F FF15 3>call dword ptr ds:[<&MSVBVM50.__vbaLenBstr>] ; 算注册码长度
00431685 8985 5>mov dword ptr ss:[ebp-B0],eax ; 长度应为0x1a,放入ebp-b0
0043168B B8 030>mov eax,3
00431690 8D8D 5>lea ecx,dword ptr ss:[ebp-A8]
00431696 8985 4>mov dword ptr ss:[ebp-B8],eax ; eax=0x3
0043169C 8985 4>mov dword ptr ss:[ebp-C0],eax
004316A2 8D95 4>lea edx,dword ptr ss:[ebp-B8]
004316A8 51 push ecx
004316A9 8D85 3>lea eax,dword ptr ss:[ebp-C8]
004316AF 52 push edx
004316B0 8D8D 1>lea ecx,dword ptr ss:[ebp-E8]
004316B6 50 push eax
004316B7 8D95 2>lea edx,dword ptr ss:[ebp-D8]
004316BD 51 push ecx
004316BE 8D45 D>lea eax,dword ptr ss:[ebp-24]
004316C1 52 push edx
004316C2 50 push eax
004316C3 89B5 3>mov dword ptr ss:[ebp-C8],esi
004316C9 FF15 E>call dword ptr ds:[<&MSVBVM50.__vbaVarForInit>; 和00431925中的call联合使用,相当于for循环语句
004316CF 3BC7 cmp eax,edi ;条件符合的话,eax=0,否=1
004316D1 0F84 5>je locplus-.00431932
004316D7 8D4D 9>lea ecx,dword ptr ss:[ebp-68]
004316DA 8D55 D>lea edx,dword ptr ss:[ebp-24]
004316DD BF 080>mov edi,8
004316E2 51 push ecx
004316E3 52 push edx
004316E4 C785 5>mov dword ptr ss:[ebp-B0],locplus-.0040D900 ; UNICODE "&H"
004316EE 89BD 4>mov dword ptr ss:[ebp-B8],edi ; edi=0x8
004316F4 8975 A>mov dword ptr ss:[ebp-60],esi ; esi=0x2
004316F7 8975 9>mov dword ptr ss:[ebp-68],esi
004316FA FF15 C>call dword ptr ds:[<&MSVBVM50.__vbaI4Var>] ; 转长整型
00431700 50 push eax ; 此处通过计算,每一循环取两个字符,下次是5,7,以此类推
00431701 8B45 0>mov eax,dword ptr ss:[ebp+8]
00431704 8B08 mov ecx,dword ptr ds:[eax]
00431706 51 push ecx ; 注册码地址
00431707 FF15 4>call dword ptr ds:[<&MSVBVM50.rtcMidCharBstr>>; 从EDX值处(=3、5、7等)取两个字符。
0043170D 8945 9>mov dword ptr ss:[ebp-70],eax ; 地址放入ebp-70
00431710 8D55 8>lea edx,dword ptr ss:[ebp-78] ; 内容值为0,下同
00431713 8D85 7>lea eax,dword ptr ss:[ebp-88]
00431719 52 push edx
0043171A 50 push eax
0043171B 897D 8>mov dword ptr ss:[ebp-78],edi ; edi=0x8
0043171E FF15 2>call dword ptr ds:[<&MSVBVM50.rtcTrimVar>] ; MSVBVM50.rtcTrimVar
00431724 8D8D 4>lea ecx,dword ptr ss:[ebp-B8]
0043172A 8D95 7>lea edx,dword ptr ss:[ebp-88]
00431730 51 push ecx ; ebp-b8 [ecx]=8
00431731 8D85 6>lea eax,dword ptr ss:[ebp-98]
00431737 52 push edx
00431738 50 push eax
00431739 FF15 D>call dword ptr ds:[<&MSVBVM50.__vbaVarAdd>] ; MSVBVM50.__vbaVarAdd
0043173F 8D4D A>lea ecx,dword ptr ss:[ebp-54]
00431742 50 push eax
00431743 51 push ecx
00431744 FF15 4>call dword ptr ds:[<&MSVBVM50.__vbaStrVarVal>>; 把&H和注册码连在一起
0043174A 50 push eax
0043174B FF15 5>call dword ptr ds:[<&MSVBVM50.rtcR8ValFromBstr>; 转浮点数
00431751 FF15 F>call dword ptr ds:[<&MSVBVM50.__vbaFpI2>] ; MSVBVM50.__vbaFpI2
00431757 8D4D A>lea ecx,dword ptr ss:[ebp-54] ; call 后ax随注册码在变
0043175A 8BF8 mov edi,eax ;VB够笨的,以上实际就是把假码从第3位开始,每次取2个字符,循环取完
0043175C FF15 5>call dword ptr ds:[<&MSVBVM50.__vbaFreeStr>] ; MSVBVM50.__vbaFreeStr
00431762 8D95 6>lea edx,dword ptr ss:[ebp-98]
00431768 8D85 7>lea eax,dword ptr ss:[ebp-88]
0043176E 52 push edx
0043176F 8D4D 8>lea ecx,dword ptr ss:[ebp-78]
00431772 50 push eax
00431773 8D55 9>lea edx,dword ptr ss:[ebp-68]
00431776 51 push ecx
00431777 52 push edx
00431778 6A 04 push 4
0043177A FF15 4>call dword ptr ds:[<&MSVBVM50.__vbaFreeVarLis>; 清空变量
00431780 8B45 C>mov eax,dword ptr ss:[ebp-40]
00431783 83C4 1>add esp,14
00431786 66:3B4>cmp ax,word ptr ss:[ebp-4C] ; 最早"ONLocPlus"的长度
0043178A 7D 0D jge short locplus-.00431799
0043178C 66:40 inc ax ; 计数器
0043178E 0F80 3>jo locplus-.004319D3
00431794 8945 C>mov dword ptr ss:[ebp-40],eax
00431797 EB 07 jmp short locplus-.004317A0
00431799 C745 C>mov dword ptr ss:[ebp-40],1
004317A0 0FBF4D>movsx ecx,word ptr ss:[ebp-40]
004317A4 8B15 5>mov edx,dword ptr ds:[439158] ; 地址01a7514,unicode "ONLocPlus"
004317AA 8D45 9>lea eax,dword ptr ss:[ebp-68]
004317AD 50 push eax
004317AE 51 push ecx ; ecx=1,2,3等,类推,
004317AF 52 push edx
004317B0 C745 A>mov dword ptr ss:[ebp-60],1
004317B7 8975 9>mov dword ptr ss:[ebp-68],esi ; esi=2
004317BA FF15 4>call dword ptr ds:[<&MSVBVM50.rtcMidCharBstr>>; 取"ONLocPlus”取ecx位值,循环
004317C0 8BD0 mov edx,eax
004317C2 8D4D A>lea ecx,dword ptr ss:[ebp-54]
004317C5 FF15 1>call dword ptr ds:[<&MSVBVM50.__vbaStrMove>] ; 地址放入ebp-54,0012f8dc
004317CB 50 push eax
004317CC FF15 6>call dword ptr ds:[<&MSVBVM50.rtcAnsiValueBst>; 分别转ascii,如"O"转换成HEX值,eax=0x4F
004317D2 33C7 xor eax,edi ;假码与取的值异或
004317D4 8D95 4>lea edx,dword ptr ss:[ebp-B8]
004317DA 8D4D C>lea ecx,dword ptr ss:[ebp-3C] ; 地址12f8f4
004317DD 66:898>mov word ptr ss:[ebp-B0],ax ; ax=异或后的值, 放入[ebp-b0]
004317E4 89B5 4>mov dword ptr ss:[ebp-B8],esi
004317EA FF15 1>call dword ptr ds:[<&MSVBVM50.__vbaVarMove>] ; MSVBVM50.__vbaVarMove
004317F0 8D4D A>lea ecx,dword ptr ss:[ebp-54]
004317F3 FF15 5>call dword ptr ds:[<&MSVBVM50.__vbaFreeStr>] ; MSVBVM50.__vbaFreeStr
004317F9 8D4D 9>lea ecx,dword ptr ss:[ebp-68]
004317FC FF15 2>call dword ptr ds:[<&MSVBVM50.__vbaFreeVar>] ; MSVBVM50.__vbaFreeVar
00431802 8D45 C>lea eax,dword ptr ss:[ebp-3C]
00431805 8D8D 5>lea ecx,dword ptr ss:[ebp-A8]
0043180B 50 push eax
0043180C 51 push ecx
0043180D 66:899>mov word ptr ss:[ebp-A0],bx ; bx=假码的第1位开始取值,每次2个
00431814 C785 5>mov dword ptr ss:[ebp-A8],8002
0043181E FF15 B>call dword ptr ds:[<&MSVBVM50.__vbaVarTstLe>] ; 比较是否ax<=bx
00431824 66:85C>test ax,ax ; 小于eax=0,否=FFFF
00431827 74 5A je short locplus-.00431883 ;小于跳,不小于不跳
00431829 8D95 5>lea edx,dword ptr ss:[ebp-A8]
0043182F 8D45 C>lea eax,dword ptr ss:[ebp-3C]
00431832 52 push edx
00431833 8D4D 9>lea ecx,dword ptr ss:[ebp-68]
00431836 50 push eax
00431837 51 push ecx
00431838 C785 6>mov dword ptr ss:[ebp-A0],0FF ; 赋值,0x0ff
00431842 89B5 5>mov dword ptr ss:[ebp-A8],esi
00431848 66:899>mov word ptr ss:[ebp-B0],bx
0043184F 89B5 4>mov dword ptr ss:[ebp-B8],esi
00431855 FF15 D>call dword ptr ds:[<&MSVBVM50.__vbaVarAdd>] ; MSVBVM50.__vbaVarAdd
0043185B 50 push eax
0043185C 8D95 4>lea edx,dword ptr ss:[ebp-B8]
00431862 8D45 8>lea eax,dword ptr ss:[ebp-78]
00431865 52 push edx
00431866 50 push eax
00431867 FF15 0>call dword ptr ds:[<&MSVBVM50.__vbaVarSub>] ; MSVBVM50.__vbaVarSub
0043186D 8BD0 mov edx,eax
0043186F 8D4D C>lea ecx,dword ptr ss:[ebp-3C]
00431872 FF15 1>call dword ptr ds:[<&MSVBVM50.__vbaVarMove>] ; MSVBVM50.__vbaVarMove
00431878 8D4D 9>lea ecx,dword ptr ss:[ebp-68]
0043187B FF15 2>call dword ptr ds:[<&MSVBVM50.__vbaFreeVar>] ; MSVBVM50.__vbaFreeVar
00431881 EB 2D jmp short locplus-.004318B0 ; 以上为不小于的话,ax+0xff-bx
00431883 8D4D C>lea ecx,dword ptr ss:[ebp-3C] ; 由431827跳来,
00431886 8D95 5>lea edx,dword ptr ss:[ebp-A8]
0043188C 51 push ecx
0043188D 8D45 9>lea eax,dword ptr ss:[ebp-68]
00431890 52 push edx
00431891 50 push eax
00431892 66:899>mov word ptr ss:[ebp-A0],bx
00431899 89B5 5>mov dword ptr ss:[ebp-A8],esi ; esi=0x2
0043189F FF15 0>call dword ptr ds:[<&MSVBVM50.__vbaVarSub>] ; MSVBVM50.__vbaVarSub
004318A5 8BD0 mov edx,eax ;小于则 bx-ax
004318A7 8D4D C>lea ecx,dword ptr ss:[ebp-3C]
004318AA FF15 1>call dword ptr ds:[<&MSVBVM50.__vbaVarMove>] ; MSVBVM50.__vbaVarMove
004318B0 8B4D B>mov ecx,dword ptr ss:[ebp-48]
004318B3 8D55 C>lea edx,dword ptr ss:[ebp-3C]
004318B6 52 push edx
004318B7 898D 6>mov dword ptr ss:[ebp-A0],ecx
004318BD C785 5>mov dword ptr ss:[ebp-A8],8
004318C7 FF15 C>call dword ptr ds:[<&MSVBVM50.__vbaI4Var>] ; MSVBVM50.__vbaI4Var
004318CD 50 push eax
004318CE 8D45 9>lea eax,dword ptr ss:[ebp-68]
004318D1 50 push eax
004318D2 FF15 2>call dword ptr ds:[<&MSVBVM50.rtcVarBstrFromA>; MSVBVM50.rtcVarBstrFromAnsi
004318D8 8D8D 5>lea ecx,dword ptr ss:[ebp-A8]
004318DE 8D55 9>lea edx,dword ptr ss:[ebp-68]
004318E1 51 push ecx
004318E2 8D45 8>lea eax,dword ptr ss:[ebp-78]
004318E5 52 push edx
004318E6 50 push eax
004318E7 FF15 D>call dword ptr ds:[<&MSVBVM50.__vbaVarAdd>] ; 此处需仔细研究
004318ED 50 push eax
004318EE FF15 3>call dword ptr ds:[<&MSVBVM50.__vbaStrVarMove>; MSVBVM50.__vbaStrVarMove
004318F4 8BD0 mov edx,eax
004318F6 8D4D B>lea ecx,dword ptr ss:[ebp-48] ; 得出数值放入ebp-48,最后连在一起需得000000000099,才正确
004318F9 FF15 1>call dword ptr ds:[<&MSVBVM50.__vbaStrMove>]
004318FF 8D4D 8>lea ecx,dword ptr ss:[ebp-78]
00431902 8D55 9>lea edx,dword ptr ss:[ebp-68]
00431905 51 push ecx
00431906 52 push edx
00431907 56 push esi
00431908 FF15 4>call dword ptr ds:[<&MSVBVM50.__vbaFreeVarLis>; MSVBVM50.__vbaFreeVarList
0043190E 83C4 0>add esp,0C
00431911 8D85 1>lea eax,dword ptr ss:[ebp-E8]
00431917 8D8D 2>lea ecx,dword ptr ss:[ebp-D8]
0043191D 8D55 D>lea edx,dword ptr ss:[ebp-24]
00431920 50 push eax
00431921 51 push ecx
00431922 52 push edx
00431923 8BDF mov ebx,edi
00431925 FF15 4>call dword ptr ds:[<&MSVBVM50.__vbaVarForNext>; 为下一循环作准备
0043192B 33FF xor edi,edi
0043192D ^ E9 9DF>jmp locplus-.004316CF
00431932 8B55 B>mov edx,dword ptr ss:[ebp-48]
00431935 8D4D D>lea ecx,dword ptr ss:[ebp-2C]
00431938 FF15 9>call dword ptr ds:[<&MSVBVM50.__vbaStrCopy>] ; MSVBVM50.__vbaStrCopy
0043193E 9B wait
0043193F 68 BD1>push locplus-.004319BD
00431944 EB 44 jmp short locplus-.0043198A
00431946 F645 F>test byte ptr ss:[ebp-4],4
0043194A 74 09 je short locplus-.00431955
0043194C 8D4D D>lea ecx,dword ptr ss:[ebp-2C]
0043194F FF15 5>call dword ptr ds:[<&MSVBVM50.__vbaFreeStr>] ; MSVBVM50.__vbaFreeStr
00431955 8D45 A>lea eax,dword ptr ss:[ebp-58]
00431958 8D4D A>lea ecx,dword ptr ss:[ebp-54]
0043195B 50 push eax
0043195C 51 push ecx
0043195D 6A 02 push 2
0043195F FF15 A>call dword ptr ds:[<&MSVBVM50.__vbaFreeStrLis>; MSVBVM50.__vbaFreeStrList
00431965 83C4 0>add esp,0C
00431968 8D95 6>lea edx,dword ptr ss:[ebp-98]
0043196E 8D85 7>lea eax,dword ptr ss:[ebp-88]
00431974 8D4D 8>lea ecx,dword ptr ss:[ebp-78]
00431977 52 push edx
00431978 50 push eax
00431979 8D55 9>lea edx,dword ptr ss:[ebp-68]
0043197C 51 push ecx
0043197D 52 push edx
0043197E 6A 04 push 4
00431980 FF15 4>call dword ptr ds:[<&MSVBVM50.__vbaFreeVarLis>; MSVBVM50.__vbaFreeVarList
00431986 83C4 1>add esp,14
00431989 C3 retn
0043198A 8D85 1>lea eax,dword ptr ss:[ebp-E8]
00431990 8D8D 2>lea ecx,dword ptr ss:[ebp-D8]
00431996 50 push eax
00431997 51 push ecx
00431998 6A 02 push 2
0043199A FF15 4>call dword ptr ds:[<&MSVBVM50.__vbaFreeVarLis>; MSVBVM50.__vbaFreeVarList
004319A0 8B35 2>mov esi,dword ptr ds:[<&MSVBVM50.__vbaFreeVar>; MSVBVM50.__vbaFreeVar
004319A6 83C4 0>add esp,0C
004319A9 8D4D D>lea ecx,dword ptr ss:[ebp-24]
004319AC FFD6 call esi
004319AE 8D4D C>lea ecx,dword ptr ss:[ebp-3C]
004319B1 FFD6 call esi
004319B3 8D4D B>lea ecx,dword ptr ss:[ebp-48]
004319B6 - FF25 5>jmp dword ptr ds:[<&MSVBVM50.__vbaFreeStr>] ; MSVBVM50.__vbaFreeStr
004319BC C3 retn
004319BD 8B4D E>mov ecx,dword ptr ss:[ebp-14]
004319C0 8B45 D>mov eax,dword ptr ss:[ebp-2C]
004319C3 5F pop edi
004319C4 5E pop esi
004319C5 64:890>mov dword ptr fs:[0],ecx
004319CC 5B pop ebx
004319CD 8BE5 mov esp,ebp
004319CF 5D pop ebp
004319D0 C2 040>retn 4 ; 跳回 00431a86
--------------------------------------------------------------------------------
为了更好地让大家了解和掌握VB注册算法,针对本文讲述的关键部分和最终注册机源码,将用几个问题来结束本文,算是读后思考题吧。回答问题请跟帖,希望管理员将此帖置顶,三天后将公布答案。
【思考题】
1.脱壳时,第一个断点后,F8单步跟过,又是60(pushad),为什么要顺着代码,一行行地下查,而不能用Ctrl+B搜索61(popad)?
2.004316c9、00431925中的_vbaVarForInit和_vbaVarForNext起何作用,是如何实现的?
3.0043181E_vbaVarTstLe在代码中起什么作用?
4.算法注册机第21行的(if (j>0x8) j-=0x9;)语句有何意义?28行的(t=code;)语句代表什么?
5.算法注册机第29行的(if (code<=0xf) printf("0%x",code);)与30行(else printf("%x",code);)语句有何区别?
后记:
1.05于2003年3月推出,增加了专用的对照文件编辑器、工具“偏移量转换器”、“文本编码查询”和“剪贴板繁简转换”,给用户提供了很大的便利条件。但至今本人未见该软件的注册机面世,不知是各位高手不屑一破,还是说其在算法上有一定的难度。因为要试用其全部功能,于是便尝试着分析了一下,本注册机向下兼容,也适合以前版本。
另外,再重申一次,本破解纯粹是技术交流。不为别的,因为这是我目前所见过的VB程序中,注册算法最隐蔽、最有特点的程序之一(也许我太孤陋寡闻),我对该软件的作者表示崇高的敬意。
同时,在此也感谢我的妻子emily长时间来对我的关心和理解,是她能容忍我不去写我的硕士毕业论文,却要和解密熬夜较劲的这种“不务正业”(引用她的口头禅)的行为。不要误会,我可不是学计算机的;本科是英语,硕士读经济,对电脑纯是业余爱好,but I like this game!
二零零五年元月二十三日
【版权声明】 本文纯属技术交流, 转载请注明作者并保持文章的完整, 谢谢!