• 标 题:FolderView注册部分的计算 (13千字)
  • 作 者:robot
  • 时 间:2001-5-27 6:02:26
  • 链 接:http://bbs.pediy.com

控件名称: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