FolderView注册部分的计算 (13千字)
控件名称:FolderView 3.0软件授权:共享软件
下载地址:http://www.filelibrary.com:8080/cgi-bin/registered/download/New_Files/n/150/fldrvw30.zip
该站点虽然免费下载,但需要密码,因此需要先注册一下
http://www.ssware.com/fldrview/fldrvw30.zip 到该站点下载时,需要代理才能下载
控件简介:FolderView is an ActiveX control that behaves like the left pane of Windows Explorer, showing all the files and folders on the system. Some of its features include context menus for items, the ability to execute shell commands, and automatic updating.
目标程序:FldrView.ocx,81408 bytes
破解工具:W32Dasm白金版,IDA Pro 4.15,Caspr v1.012
说明:本人想用VB编一个程序,需要用到只取得文件夹名称的控件,而VB中的Dirlist控件只能显示当前驱动器的文件夹,必须结合DriveList控件,但这样用起来又太不方便了,然人感觉太别扭,于是上网搜索,奋战了3个多小时,终于找到这两个满意的,确实比微软的那个强,但都需要注册,既然没有条件进行注册,那么就只好Crack了^_^
这个控件同样适用于Delphi、VC,用FI查看,判别不出来(我的FI有点老),估计是Aspack压缩,用Caspr v1.012成功去壳,再用FI查看,VC++6.0编的,这回可以用W32Dasm和IDA了,闲话少说,开始干,等等,忽然想到,W32Dasm对MFC函数支持不好,因此这回想用IDA试试,但用IDA反汇编后,还是出现了一个问题,输入注册码和显示注册是否成功部分并没有显示出来,而W32Dasm则很容易地显示出来了,以前没怎么用过IDA,不知道怎么把这段代码改成汇编格式,经过一段探索之后,终于解决,方法是跳到10006E99,从菜单中选择Edit-->Functions-->Create Function即可,下面为IDA反汇编的结果
.text:10006E99 sub_10006E99 proc near ; DATA XREF: .rdata:1000AB74
.text:10006E99 push esi
.text:10006E9A mov esi, ecx
.text:10006E9C push 1
.text:10006E9E call ?UpdateData@CWnd@@QAEHH@Z ; CWnd::UpdateData(int)
.text:10006EA3 mov eax, [esi+68h]
.text:10006EA6 cmp dword ptr [eax-8], 0
.text:10006EAA jz short loc_10006F17
.text:10006EAC mov ecx, [esi+64h]
.text:10006EAF cmp dword ptr [ecx-8], 0
.text:10006EB3 jz short loc_10006F17
.text:10006EB5 push eax
.text:10006EB6 push offset aUsername ; "Username"
.text:10006EBB call sub_10006917 ====> Username填入到注册表中
.text:10006EC0 push dword ptr [esi+64h]
.text:10006EC3 push offset aRegcode ; "Regcode"
.text:10006EC8 call sub_10006917 ====> Regcode填入到注册表中
.text:10006ECD mov ecx, [esi+60h]
.text:10006ED0 add esp, 10h
.text:10006ED3 push 1
.text:10006ED5 call ?SetModifiedFlag@COleControl@@QAEXH@Z ; COleControl::SetModifiedFlag(int)
.text:10006EDA mov eax, [esi+64h] ====> "Regcode"
.text:10006EDD mov ecx, [esi+68h] ====> "Username"
.text:10006EE0 push eax
.text:10006EE1 push ecx
.text:10006EE2 call sub_10006958 ====> 注册码的计算部分,见后面的分析
.text:10006EE7 pop ecx
.text:10006EE8 test eax, eax ====> eax为旗标
.text:10006EEA pop ecx
.text:10006EEB jz short loc_10006F09 ====> 等于0则注册码错误
.text:10006EED push 40h
.text:10006EEF push offset aRegistrationSu ; "Registration successful"
.text:10006EF4 push offset aThankYouForReg ; "Thank You for registering FolderView Ac"...
.text:10006EF9 mov ecx, esi
.text:10006EFB call ?MessageBoxA@CWnd@@QAEHPBD0I@Z ; CWnd::MessageBoxA(char const *,char const *,uint)
.text:10006F00 mov ecx, esi
.text:10006F02 call ?OnOK@CDialog@@MAEXXZ ; CDialog::OnOK(void)
.text:10006F07 pop esi
.text:10006F08 retn
.text:10006F09
.text:10006F09 loc_10006F09: ; CODE XREF: sub_10006E99+52j
.text:10006F09 push 10h
.text:10006F0B push offset aInvalidRegistr ; "Invalid registration code"
.text:10006F10 push offset aInvalidRegcode ; "Invalid Regcode. Please enter the corre"...
.text:10006F15 jmp short loc_10006F23
.text:10006F17
.text:10006F17 loc_10006F17: ; CODE XREF: sub_10006E99+11
.text:10006F17 ; sub_10006E99+1A
.text:10006F17 push 10h
.text:10006F19 push offset aEnterInformati ; "Enter information"
.text:10006F1E push offset aPleaseEnterThe ; "Please enter the username and registrat"...
.text:10006F23
.text:10006F23 loc_10006F23: ; CODE XREF: sub_10006E99+7C
.text:10006F23 mov ecx, esi
.text:10006F25 call ?MessageBoxA@CWnd@@QAEHPBD0I@Z ; CWnd::MessageBoxA(char const *,char const *,uint)
.text:10006F2A pop esi
.text:10006F2B retn
int __cdecl sub_10006958(int,int);
.text:10006958 sub_10006958 proc near ; CODE XREF: .text:10004249 .text:10004498
.text:10006958 ; 因为IDA没有将10006E99反编译出来,故这里代码参考没有列出来
.text:10006958 var_160 = qword ptr -160h
.text:10006958 var_158 = qword ptr -158h
.text:10006958 var_14C = byte ptr -14Ch
.text:10006958 var_20 = qword ptr -20h
.text:10006958 var_18 = qword ptr -18h
.text:10006958 var_10 = qword ptr -10h
.text:10006958 var_8 = qword ptr -8
.text:10006958 arg_0 = dword ptr 8 ====> "Username"
.text:10006958 arg_4 = dword ptr 0Ch ====> "Regcode"
.text:10006958
.text:10006958 push ebp
.text:10006959 mov ebp, esp
.text:1000695B sub esp, 14Ch
.text:10006961 fld ds:dbl_1000A900 ====> 双击此处可知dbl_1000A900=56
.text:10006967 push esi
.text:10006968 mov esi, [ebp+arg_0]
.text:1000696B fstp [ebp+var_18]
.text:1000696E fldz
.text:10006970 push esi
.text:10006971 fstp [ebp+var_10]
.text:10006974 call strlen ====> Username的长度
.text:10006979 pop ecx
.text:1000697A xor ecx, ecx
.text:1000697C test eax, eax
.text:1000697E jle short loc_100069B1
.text:10006980 movsx edx, byte ptr [esi]
.text:10006983 mov [ebp+arg_0], edx
.text:10006986 fild [ebp+arg_0] ====> st0=第1个Username字符
.text:10006989 movsx edx, byte ptr [ecx+esi] ====> 取1个Username字符
.text:1000698D mov [ebp+arg_0], edx
.text:10006990 inc ecx
.text:10006991 fild [ebp+arg_0]
.text:10006994 cmp ecx, eax
.text:10006996 fadd st, st(1) ====> st0=[ebp+arg_0],st1=Username(1)
.text:10006998 fmul [ebp+var_18]
.text:1000699B fadd [ebp+var_10]
.text:1000699E fstp [ebp+var_10]
.text:100069A1 fld [ebp+var_18]
.text:100069A4 fadd ds:dbl_1000A8F8 ====> dbl_1000A8F8=2
.text:100069AA fstp [ebp+var_18]
.text:100069AD jl short loc_10006989
10006989-100069AD的计算过程:
for i=1 to strlen(Username);Code1=Code1+(Username(1)+Username(i))*(56+(i-1)*2);next
.text:100069AF fstp st
.text:100069B1 fld [ebp+var_10]
.text:100069B4 fadd ds:dbl_1000A8F0 ====> dbl_1000A8F0=3419821
.text:100069BA push offset aEqualizer ; "equalizer"
.text:100069BF fst [ebp+var_10] ====> 令RegCode1=Code1+3419821
.text:100069C2 fstp [ebp+var_8]
.text:100069C5 call strlen ====> "equalizer"的长度
.text:100069CA pop ecx
.text:100069CB xor ecx, ecx
.text:100069CD test eax, eax
.text:100069CF jle short loc_100069F0
.text:100069D1 movsx edx, byte ptr [esi]
.text:100069D4 push edi
.text:100069D5 movsx edi, byte ptr [ecx+offset aEqualizer] ; "equalizer"
.text:100069DC add edi, edx
.text:100069DE inc ecx
.text:100069DF mov [ebp+arg_0], edi
.text:100069E2 cmp ecx, eax
.text:100069E4 fild [ebp+arg_0]
.text:100069E7 fsubr [ebp+var_8]
.text:100069EA fstp [ebp+var_8]
.text:100069ED jl short loc_100069D5
100069D5-100069ED的计算过程:
for i=1 to strlen("equalizer");Code2=Code2+Username(1)+"equalizer"(i);next
RegCode2=RegCode1-Code2
.text:100069EF pop edi
.text:100069F0 fld [ebp+var_8]
.text:100069F3 fsub ds:dbl_1000A8F0
.text:100069F9 push esi
.text:100069FA fst [ebp+var_8]
100069D5-100069ED的计算过程:
RegCode2=RegCode2-3419821
.text:100069FD fadd [ebp+var_18]
.text:10006A00 fstp [ebp+var_20]
.text:10006A03 call strlen
.text:10006A08 pop ecx
.text:10006A09 xor ecx, ecx
.text:10006A0B test eax, eax
.text:10006A0D jle short loc_10006A37
.text:10006A0F fld [ebp+var_18]
.text:10006A12 fadd ds:dbl_1000A8E8 ====> dbl_1000A8E8=1
====> st0=(56+2*strlen(Username))+1
.text:10006A18 movsx edx, byte ptr [ecx+esi]
.text:10006A1C mov [ebp+arg_0], edx
.text:10006A1F inc ecx
.text:10006A20 fild [ebp+arg_0]
.text:10006A23 cmp ecx, eax
.text:10006A25 fmul st, st(1)
.text:10006A27 fadd [ebp+var_20]
.text:10006A2A fsub ds:dbl_1000A8E0 ====> dbl_1000A8E0=5
.text:10006A30 fstp [ebp+var_20]
.text:10006A33 jl short loc_10006A18
100069D5-100069ED的计算过程:
RegCode3=RegCode2+(56+2*strlen(Username))
for i=1 to strlen(Username);RegCode3=RegCode3+Username(i)*((56+2*strlen(Username))+1)-5;next
.text:10006A35 fstp st
.text:10006A37 fld [ebp+var_20]
.text:10006A3A push ecx
.text:10006A3B push ecx
.text:10006A3C fstp [esp+158h+var_158]
.text:10006A3F fld [ebp+var_8]
.text:10006A42 push ecx
.text:10006A43 push ecx
.text:10006A44 fstp [esp+160h+var_160]
.text:10006A47 fld [ebp+var_10]
.text:10006A4A call _ftol
.text:10006A4F push eax
.text:10006A50 lea eax, [ebp+var_14C]
.text:10006A56 push offset aX_0f_0f ; "%X-%.0f-%.0f" ====> 注册码格式("0XRegCode1-RegCode2-RegCode3")
.text:10006A5B push eax
.text:10006A5C call ds:sprintf
.text:10006A62 push [ebp+arg_4]
.text:10006A65 lea eax, [ebp+var_14C]
.text:10006A6B push eax
.text:10006A6C call strcmp ====> 注册码比较
.text:10006A71 add esp, 24h
.text:10006A74 neg eax
.text:10006A76 sbb eax, eax
.text:10006A78 pop esi
.text:10006A79 inc eax ====> 结果放到eax
.text:10006A7A leave
.text:10006A7B retn
.text:10006A7B sub_10006958 endp
参数值:
.rdata:1000A8E0 dbl_1000A8E0 dq 5.0 ; DATA XREF: sub_10006958+D2
.rdata:1000A8E8 dbl_1000A8E8 dq 1.0 ; DATA XREF: sub_10006958+BA
.rdata:1000A8F0 dbl_1000A8F0 dq 3.419821e6 ; DATA XREF: sub_10006958+5C
.rdata:1000A8F8 dbl_1000A8F8 dq 2.0 ; DATA XREF: sub_10006958+4C
.rdata:1000A900 dbl_1000A900 dq 5.6e1 ; DATA XREF: sub_10006958+9
总结:注册码由3部分组成:(分别为RegCode1、RegCode2、RegCode3)
RegCode1=3419821+求和((用户名的第1个字符+用户名各字符的ASCII值)*(56+2*用户名各字符的位置))
RegCode2=RegCode1-3419821-求和(用户名的第1个字符+"equalizer"各字符的ASCII值)+(56+2*用户名长度+1)
RegCode3=求和((RegCode2+56+2*用户名长度)+用户名各字符的ASCII值*(56+2*用户名长度+1)-5)
注册码的第1部分用16进制显示,第2、3部分用十进制显示,各部分之间用"-"连上
注册器已做成
后记:IDA和W32Dasm相比较,各有各的优点,W32Dasm比较简单,上手快,字符串参考窗非常实用,可以说就是专为Cracker定制,但对于MFC函数支持不足,并且有一些如本例子的参数(在rdata段)并不能显示出来,要想得出注册码的计算过程,需要结合SoftICE,要想修改程序代码进行暴破,还须结合HIEW、HexWorkshop、UE等;而IDA相对来说就难懂一些,但它支持MFC函数,这样程序读起来就要容易,另外,就向本程序那样,查看注册码的计算参数很容易,当然,它的功能不止这些。对于一个程序,要想破解它,应该结合具体情况来选择不同的反编译器,通常首先选择W32Dasm——容易、直观,而对于象由VC++等编译的程序以及注册部分有内部参数计算的,最好还是用IDA,以上是我的浅见,不当指出请予指出。
2001.05.26 15:00
