【破文标题】一个外国人编写的名为ecGraph3D的三维控件的破解
【破文作者】zhuliang
【作者邮箱】huangzhuliang@sina.com
【破解工具】PEiD,OD,IDA,C32ASM
【破解平台】Windows XP
【软件大小】2.40 MB
【软件授权】国外软件/三维控件
【软件语言】英文
【原版下载】http://www.encoreconsulting.com.au/downloads/ecgraph3d-112-setup.exe
【保护方式】注册验证
【软件简介】ecGraph3D控件是一个能把给定的数据用三维的形式显示出来的控件,用它来显示一些统计数据可以说是相当的形象(如图1所示),能把数据直观地表现出来。
【破解声明】一点心得,愿与大家分享。 版权所有,转载注明来自看雪论坛!
【破解内容】
用ecGraph3D控件来显示一些统计数据可以说是相当的形象(如图1所示),ecGraph3D控件能把数据直观地表现出来,对于我们气象行业来说是一个相当有用的控件,因为,气象行业有大量的统计数据要显示和输出。
这个控件的使用也比较简单,它带有一个针对VB的帮助文档,告诉用户如何在VB中使用该控件。按理说,因为这个Active X控件不仅仅能在VB使用,也能在VC中使用,所以不仅要提供对VB的帮助文档也要提供对VC的使用文档的。但是它没提供针对VC的帮助文档,我想这可能是因为这个控件是用VB写的吧。
这个控件使用注册验证保护,注册版与未注册版的区别在于控件的右下角有没有个带链接的框(如图1和图2)。
图1未注册版
图2注册版
按照帮助文档上的说明,以从官方得到的注册码为参数调用RegisterecGraph3D方法,就可以把未注册版转变为注册版。帮助文档上对RegisterecGraph3D方法的说明如下。
RegisterecGraph3D Procedure (Sub)
Public Sub RegisterecGraph3D(S$)
Attempts to register this implementation of ecGraph using a registration key that can be obtained from www.encoreconsulting.com.au
If successful, this converts ecGraph from a demo version to a registered version, removing the demo message printed on each graph.
Parameter Type Description
S$ String S
See Also..
Registered
Example..
Call ecGraph3D1.RegisterecGraph3D(s)
按照它给出的例子,可以用下面的代码进行注册。
Const ecGraph3DRegistrationKey$="98765-,3210-ABCDE-01234-56789"
Private Sub Form_Load()
Dim k As Integer, KeyWords$
'****************************************************************************************
'*** Register all ecGraph3D controls on your form with your registration key obtained
'*** from www.encoreconsulting.com.au, otherwise it will function in Demo mode .
'****************************************************************************************
'in this demo program there are two ecGraph3D controls on the form: ecGraph3D1
Call ecGraph3D1.RegisterecGraph3D(ecGraph3DRegistrationKey$)
Me.Caption = "ecGraph3D - Simple demo"
Call Command1_Click(1)
End Sub
跟注册相关的随了RegisterecGraph3D方法外,还跟Registered属性有关。在VB中使用下面的代码可以知道是否已经注册。
Registered Property
Property Registered() As Boolean 'Read only
Returns True if this implementation of ecGraph has been successfully registered.
See Also..
RegisterecGraph3D Version
Example..
x = ecGraph3D1.Registered
看到这里,控件有一个属性Registered ,猜想控件有一个变量用于保存是否注册了的信息,要想验证是不是这样,可以通过跟踪来证实,如果真是这样的话,那么修改这个变量让这个变量恒为true就可以实现爆破了。而跟踪RegisterecGraph3D方法就可以得到它的注册算法了,思路就是这简单,下面进行操作。
由于本人不会用VB,就用VC写了一个小程序来访问控件的Registered属性和调用它的RegisterecGraph3D方法。先用VC创建一个基于对话框的MFC工程,然后依次点“Project”菜单 、“Add To Project”子菜单、“Components And Controls”命令,在弹出的对话框里选择ecGraph3D_ocx.ecGraph3D.lnk,如图3所示,再点“Insert”,这样便把该控件增加到工程中了,之后工程中多了一个C_ecGraph3D类,而在类中的函数声明中有下面两语句:
BOOL GetRegistered();
void RegisterecGraph3D(BSTR* S);
图3
这两个成员函数就分别对应着控件的Registered属性和它的RegisterecGraph3D方法,原来VB的Active X控件中的属性和方法是通过类的成员函数来实现的,题外话。呵呵。
对于COM里面某个函数的定位我参考了看雪论坛上的一篇文章《跟踪调试COM组件的接口》,思路是:由于在调用COM里面某个函数时,会由DispCallFunc去分发,然后再调用COM里面的函数,那么,我们就在它分发的时候先把它拦截下来,之后再单步跟入某个函数。关键函数:DispCallFunc,位于OLEAUT32.dll。
对于我写的这个程序也是一样,用OD载入生成的.exe文件,在DispCallFunc下断,然后,运行程序,断下来后,往下面看,执行到call ecx,如下图:
在这里F7跟进去后,经过一个跳转,便到达了GetRegistered()函数,这函数在IDA里如下图所示。
注意到这几条汇编语句:
.text:1103D7C7 mov cx, [esi+ecGraph3D.Registered]
.text:1103D7D1 mov [ebp+var_18], ecx
.text:1103D7DD mov eax, [ebp+pblRegistered]
.text:1103D7E0 mov cx, word ptr [ebp+var_18]
.text:1103D7E4 mov [eax], cx
看到这几句可以知道,控件真的如我们猜想的那样用一个变量(Registered)用来标识控件是否已注册,而这个变量的值是RegisterecGraph3D函数中被设置的,那么修改相应的汇编代码让这个变量恒为true就可以实现爆破了,而跟踪RegisterecGraph3D方法就可以得到它的注册算法。由于我不熟悉VB,而注册算法里用到了很多从MSVBM60.dll中导出的如__vbaI2I4、rtcMidCharBstr、rtcR8ValFromBstr、__vbaFpI2的函数,这些函数的功能是什么在MSDN里也没有介绍,要知道它的功能只能通过分析函数的代码,这样的工作不是我等菜鸟能做的,希望大侠分析出来后告诉我。在这里我只给出它的爆破方法,而不给出它的注册码,况且论坛也不希望我们在这里散布注册码。
用同样的方法可以定位RegisterecGraph3D函数,下面是其代码:
.text:11041760 RegisterecGraph3D proc near ; CODE XREF: .text:loc_110071F1 j
.text:11041760
.text:11041760 var_CC = dword ptr -0CCh
.text:11041760 var_C8 = dword ptr -0C8h
.text:11041760 var_C4 = dword ptr -0C4h
.text:11041760 var_C0 = dword ptr -0C0h
.text:11041760 var_BC = dword ptr -0BCh
.text:11041760 var_A8 = word ptr -0A8h
.text:11041760 var_90 = qword ptr -90h
.text:11041760 var_88 = dword ptr -88h
.text:11041760 var_84 = dword ptr -84h
.text:11041760 var_70 = dword ptr -70h
.text:11041760 var_68 = dword ptr -68h
.text:11041760 var_60 = dword ptr -60h
.text:11041760 var_50 = dword ptr -50h
.text:11041760 var_48 = dword ptr -48h
.text:11041760 var_40 = dword ptr -40h
.text:11041760 var_3C = dword ptr -3Ch
.text:11041760 var_38 = dword ptr -38h
.text:11041760 var_34 = dword ptr -34h
.text:11041760 var_30 = dword ptr -30h
.text:11041760 var_2C = dword ptr -2Ch
.text:11041760 v_short = dword ptr -28h
.text:11041760 v_str2 = dword ptr -24h
.text:11041760 v_str = dword ptr -20h
.text:11041760 var_1C = dword ptr -1Ch
.text:11041760 var_14 = dword ptr -14h
.text:11041760 var_10 = dword ptr -10h
.text:11041760 var_C = dword ptr -0Ch
.text:11041760 var_8 = dword ptr -8
.text:11041760 this = dword ptr 8
.text:11041760 pStrcode= dword ptr 0Ch ;这让我不明白了,
.text:11041760 arg_8 = dword ptr 10h ;返回明明是.text:110418CE retn 8
.text:11041760 arg_C = dword ptr 14h ;按理说不外就是两个参数吗
.text:11041760 arg_10 = dword ptr 18h ;为什么IDA分析出来有这么多参数的
.text:11041760 arg_14 = dword ptr 1Ch
.text:11041760 arg_18 = dword ptr 20h
.text:11041760 arg_1C = dword ptr 24h
.text:11041760 arg_20 = dword ptr 28h
.text:11041760
.text:11041760 push ebp
.text:11041761 mov ebp, esp
.text:11041763 sub esp, 14h
.text:11041766 push offset __vbaExceptHandler
.text:1104176B mov eax, large fs:0
.text:11041771 push eax
.text:11041772 mov large fs:0, esp
.text:11041779 sub esp, 24h
.text:1104177C push ebx
.text:1104177D push esi
.text:1104177E push edi
.text:1104177F mov [ebp+var_14], esp
.text:11041782 mov [ebp+var_10], offset dword_11003600
.text:11041789 xor edi, edi
.text:1104178B mov [ebp+var_C], edi
.text:1104178E mov [ebp+var_8], edi
.text:11041791 mov esi, [ebp+this]
.text:11041794 mov eax, [esi]
.text:11041796 push esi
.text:11041797 call dword ptr [eax+4] ; MSVBVM60.Zombie_AddRef
.text:1104179A mov [ebp+v_str], edi
.text:1104179D mov [ebp+v_str2], edi
.text:110417A0 mov [ebp+v_short], edi
.text:110417A3 push 1
.text:110417A5 call ds:__vbaOnError
.text:110417AB mov edx, offset aEcgraph3d ; "ecGraph3D"
.text:110417B0 lea ecx, [ebp+v_str]
.text:110417B3 mov ebx, ds:__vbaStrCopy
.text:110417B9 call ebx ; __vbaStrCopy
.text:110417BB mov ecx, [esi]
.text:110417BD lea edx, [ebp+v_short] ; 0 or -1
.text:110417C0 push edx
.text:110417C1 lea eax, [ebp+v_str]
.text:110417C4 push eax
.text:110417C5 mov edx, [ebp+pStrcode]
.text:110417C8 push edx
.text:110417C9 push esi
.text:110417CA call dword ptr [ecx+0A7Ch] ; sub_11072170
.text:110417D0 mov ax, word ptr [ebp+v_short]
.text:110417D4 mov [esi+ecGraph3D.Registered], ax
.text:110417DB lea ecx, [ebp+v_str]
.text:110417DE call ds:__vbaFreeStr
.text:110417E4 lea edi, [esi+ecGraph3D.m_strRegCode]
.text:110417EA mov ecx, [ebp+pStrcode]
.text:110417ED mov edx, [ecx]
.text:110417EF mov ecx, edi ; ecx=m_strRegCode
.text:110417F1 call ebx ; __vbaStrCopy
.text:110417F3 mov edx, [esi]
.text:110417F5 lea eax, [ebp+v_str]
.text:110417F8 push eax
.text:110417F9 push esi
.text:110417FA call dword ptr [edx+0A84h] ; sub_11072BB0
.text:11041800 mov edx, [ebp+v_str]
.text:11041803 mov [ebp+v_str], 0
.text:1104180A lea ecx, [ebp+v_str2]
.text:1104180D call ds:__vbaStrMove
.text:11041813 mov ecx, [esi]
.text:11041815 lea edx, [ebp+v_short]
.text:11041818 push edx
.text:11041819 lea eax, [ebp+v_str2]
.text:1104181C push eax
.text:1104181D mov edx, [edi]
.text:1104181F push edx
.text:11041820 push esi
.text:11041821 call dword ptr [ecx+0AB0h] ; sub_11075780
.text:11041827 mov ax, word ptr [ebp+v_short]
.text:1104182B mov [esi+ecGraph3D.m_dw_180], ax
.text:11041832 lea ecx, [ebp+v_str2]
.text:11041835 call ds:__vbaFreeStr
.text:1104183B mov ecx, [esi]
.text:1104183D push esi
.text:1104183E call dword ptr [ecx+9C4h] ; sub_1104B620
.text:11041844 test eax, eax
.text:11041846 jge short loc_11041890
.text:11041848 push 9C4h
.text:1104184D push offset nullsub_1
.text:11041852 push esi
.text:11041853 push eax
.text:11041854 call ds:__vbaHresultCheckObj
.text:1104185A jmp short loc_11041890
.text:1104185C ; ---------------------------------------------------------------------------
.text:1104185C
.text:1104185C loc_1104185C: ; DATA XREF: .text:11003620 o
.text:1104185C push (offset dword_110080FC+4)
.text:11041861 push (offset dword_1100C2F4+4)
.text:11041866 call ds:__vbaStrCat
.text:1104186C mov edx, eax
.text:1104186E lea ecx, [ebp+v_str]
.text:11041871 call ds:__vbaStrMove
.text:11041877 mov eax, [ebp+this]
.text:1104187A mov edx, [eax]
.text:1104187C lea ecx, [ebp+v_str]
.text:1104187F push ecx
.text:11041880 push eax
.text:11041881 call dword ptr [edx+984h]
.text:11041887 lea ecx, [ebp+v_str]
.text:1104188A call ds:__vbaFreeStr
.text:11041890
.text:11041890 loc_11041890: ; CODE XREF: RegisterecGraph3D+E6 j
.text:11041890 ; RegisterecGraph3D+FA j
.text:11041890 call ds:__vbaExitProc
.text:11041896
.text:11041896 loc_11041896: ; DATA XREF: .text:11003604 o
.text:11041896 push offset loc_110418B2
.text:1104189B jmp short locret_110418B1
.text:1104189D ; ---------------------------------------------------------------------------
.text:1104189D
.text:1104189D loc_1104189D: ; DATA XREF: .text:1100360C o
.text:1104189D lea edx, [ebp+v_str2]
.text:110418A0 push edx
.text:110418A1 lea eax, [ebp+v_str]
.text:110418A4 push eax
.text:110418A5 push 2
.text:110418A7 call ds:__vbaFreeStrList
.text:110418AD add esp, 0Ch
.text:110418B0 retn
.text:110418B1 ; ---------------------------------------------------------------------------
.text:110418B1
.text:110418B1 locret_110418B1: ; CODE XREF: RegisterecGraph3D+13B j
.text:110418B1 retn
.text:110418B2 ; ---------------------------------------------------------------------------
.text:110418B2
.text:110418B2 loc_110418B2: ; DATA XREF: RegisterecGraph3D:loc_11041896 o
.text:110418B2 mov eax, [ebp+this]
.text:110418B5 mov ecx, [eax]
.text:110418B7 push eax
.text:110418B8 call dword ptr [ecx+8]
.text:110418BB mov eax, [ebp+var_C]
.text:110418BE mov ecx, [ebp+var_1C]
.text:110418C1 mov large fs:0, ecx
.text:110418C8 pop edi
.text:110418C9 pop esi
.text:110418CA pop ebx
.text:110418CB mov esp, ebp
.text:110418CD pop ebp
.text:110418CE retn 8
.text:110418CE RegisterecGraph3D endp ; sp-analysis failed
上面的代码用C代码大致可表示为:
RegisterecGraph3D(CObject* this,char *pstrcode)
{
char* v_str; //v_str和v_str2应该都是像CString类的对象
char* v_str2; //对象只有一个成员,为指向字符串的指针
short v_short;
strcpy(v_str,"ecGrapgh3D");
sub_11072170(this,pstrcode,&v_str,&v_short);//call dword ptr [ecx+0A7Ch]
this->REGISTERED=v_short;
this->m_strRegCode=*pstrcode;
Free(v_str);
sub_11072BB0(this,&v_str);//call dword ptr [edx+0A84h]
sub_11075780(this,&this->m_strRegCode,&v_str2,&v_short);//call dword ptr [ecx+0AB0h]
this->m_dw_180=v_short;
free(v_str2);
if (sub_1104B620(this)<0)
{
vbahresultCheckObj(ecx,esi,&null_sub_1,0x9c4);
}
}
对我们来说关键的地方是下面这两个函数的调用,因为函数返回后,控件的成员变量马上被赋值。我们只要修改sub_11072170函数和sub_11075780函数的汇编代码,使函数返回后,变量v_short的值为TRUE。但可实现爆破了。
sub_11072170(this,pstrcode,&v_str,&v_short);//call dword ptr [ecx+0A7Ch]
this->REGISTERED=v_short;
sub_11075780(this,&this->m_strRegCode,&v_str2,&v_short);//call dword ptr [ecx+0AB0h]
this->m_dw_180=v_short;
跟进sub_11072170函数和sub_11075780函数,它们通过传进来的地址修改变量v_short的值的代码如下:
用C32ASM打开ecGraph3D.ocx文件,输入上面的机器码,如下图:
将保存后的ecGraph3D.ocx复制到C:\WINDOWS\system32下并覆盖原来的ecGraph3D.ocx文件,便实现爆破了。爆破后的控件如图2所示。附件里为爆破后的ecGraph3D.ocx文件。
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
上传的附件: