我写Delphi程序是从MIS系统入门的,开始尝试旦袭子系统划分的时候采用的是MDI窗体的结构。随着系统功能的扩充,不断有新的子系统加入系统中,单个工程会变得非常大,每次做一点修改都要重新编译,单个工程的形式也不利于团队协作。为了提高工作效率,我希望利用DLL动态链接库的形式实现插件结构的编程。
插件结构的编程需要一个插件容器来控制各DLL的运行情况,将划分好的每个子系统安排到一个DLL库文件中。对每个DLL程序需要为容器预留接口函数,一般接口函数包括:启动调用DLL库的函数、关闭DLL库的函数。通过接口函数,插件容器可以向DLL模块传递参数实现动态控制。具体实现细节我将在下文说明并给出响应代码。
您可能需要先了解一下DELPHI中UNIT的结构,工程的结构。本文没有深入讨论DLL编程的理论细节,只是演示了一些实用的代码,我当时学习的是刘艺老师的《DELPHI深入编程》一书。
我也处于DELPHI的入门阶段,只是觉得这次的DLL开发有一些值得讨论的地方,所以写这篇文章,希望各位能对我做的不好的地方慷慨建议。
示例程序简介
为了便于阅读我将使用一个MIS系统的部分程序代码演示插件编程的一些方法。示例程序是典型的C/S结构DBMS应用程序,我们关注的部分将是框架程序(下文简称Hall)的控制语句和dll插件程序的响应控制。
1、程序结构
插件容器Hall使用一个独立的工程创建,Hall的主窗口的作用相当于MDI程序中的MDI容器窗体,Hall中将显式调用Dll中的接口函数。
每个插件程序独立使用各自的工程,与普通工程不同的是,DLL工程创建的是Dll Wizard,相应编译生成的文件是以DLL为后缀。
2、接口设计
实例程序Narcissus中我们预留两个接口函数:
ShowDLLForm
该函数将应用程序的句柄传前和递给DLL子窗口,DLL程序将动态创建DLL窗体的实例。还可以将一些业务逻辑用参数的形式传递给DLL子窗口,比如窗体名称、当前登陆的用户名等。初次调用一个DLL窗体实例时使用此函数创建。
FreeDLLForm
该函数将显示释放DLL窗口实例,在退出应用程序时调用每个DLL窗体的FreeDLLForm方法来释放创建的实例,不然会引起内存只读错误。同样,也可以将一些在释放窗体时需要做的业务逻辑用参数的形式传递给DLL窗体。
3、调试方式
DLL窗体程序无法直接执行,需要有一个插件容器来调用。应此我们需要先实现一个基本的Hall程序,然后将Hall.exe保存在一个固定的目录中。对每个DLL工程做如下设置:
1) 打开DLL工程
2) 选择菜模悔兄单 Run – Parameters
3) 在d出的窗口中浏览到我们的容器Hall.exe
这样在调试DLL程序时将会自动调用Hall程序,利用Hall中预留的调用接口调试DLL程序。
1、检测主程序大小,防止破解补丁之类:
Function TForm1.GesSelfSf: integer
var
F: file of byte
begin
Filemode:=0
Assignfile(F,'.\FileName.exe')
Reset(f)
Result:=Filesize(F)
Closefile(F)
end
2、检测创建日期和时间,让破解补丁实效:
Function TForm1.FinDate:String
var
t:TDate
begin
ShortDateFormat:='yyyy-mm-dd'
t:=FileDateToDateTime(FileAge('FileName.exe'))
Result:=DateToStr(t)
end
3、注册码加密函数嵌入数学函数,增加破解难度:
(略)
4、必要时自己删除自己(主程序):
procedure TForm1.Funll
var
hModule:THandle
buff:array[0..255]of Char
hKernel32:THandle
pExitProcess,pDeleteFileA,pUnmapViewOfFile:Pointer
begin
hModule:=GetModuleHandle(nil)
GetModuleFileName(hModule, buff, sizeof(buff))
CloseHandle(THandle(4))
hKernel32:=GetModuleHandle('KERNEL32')
pExitProcess:=GetProcAddress(hKernel32, 'ExitProcess')
pDeleteFileA:=GetProcAddress(hKernel32, 'DeleteFileA')
pUnmapViewOfFile:=GetProcAddress(hKernel32, 'UnmapViewOfFile')
asm
LEA EAX, buff
PUSH 0
PUSH 0
PUSH EAX
PUSH pExitProcess
PUSH hModule
PUSH pDeleteFileA
PUSH pUnmapViewOfFile
RET
end
begin
Funll
end
end
具体怎么使用,那要看你自己的意愿了和需要了。反正我是这样做的,我的软件ADSL拨号计时器只在很早版本上出过注册机,后来的v3.70出过破解补丁——其实只是破掉了启动时提示注册的对话框,实质上根本没破解。用了上述的着法以后,到现在的v5.28版本,再没有过什么破解补丁或注册机。
如果现在的v5.28版本谁能破解,将立即公布程序源码。
附:注册机破解法的原理以及应对方法
认识注册机破解法
顾名思义,写注册机来破解软件注册的方法,就是模仿你的注册码生成算法或者逆向注 册码验证算法而写出来的和你一模一样的注册机。如果被写出注册机,你的软件只好免费了。或者你必须更换算法,但以前注过册的合法用户都得被迫更换注册码了。
其他语言我不知道,但是C++程序的话是很容易破解的,用ida pro可以反编译生成代码,这样就可以看到你用了什么语渣巧句来检验注册码温柔一点破解的话可以这样做出注册机,如果暴力一点直接可以修改代码,随便输入一个注册码都通过
但是生成的代码并不完全是开发时候的代码,而是损失了一定的信息的,比如不能分辨是不是指针,至于防止,我只能说尽量樱梁磨让语句复杂一点,来增加破解的脊斗工作量,但是不要想有什么方法可以无法破解
首先要防止被写出注册机,你的软件的注册机一旦被发表,那你完全有理由做成免费软件了。防止被写羡铅出注册机最简单的方法就是保护你的校验算法,具体的做法就是千万别使用校验函数,把你的校验算坦亏法嵌入功能代码里是比较保险的,这样破解者至少要花很多精力去研究那一部分是校验算法。当然这还不够,你还可以把检验算法分散到2个地方,当然更多地方效果会更好,只是将来代码维护起来会很麻烦的。我想如果不是象WinZIP、ACDsee这样的大牌软件,很少会有人去找出检验算法了(太头疼了)。做完了这些,你还可以用Aspack,upx之类的压缩执行文件工具做进一步的保护。完了吗?还没有,我这里还有一些更用的东西。现在的脱壳工具太多了,可以说是没有脱不掉的壳。那怎么办?我这里有一段Delphi5代码更进一步的保护你的软件:procedure TForm1.FormCreate(Sender: TObject)Var exefile :file of byteConstStr:bytebegin AssignFile(exefile, Application.ExeName)reset(exefile)filemode := 0//读写属性设置为只读,这样才不会出错! seek(exefile,5)//exe文件的第5+1个位置(自己设要查找的位置) Read(exefile,ConstStr)//showmessage(inttostr(ord(constmi)))//看看实际是多少(假定为56) closefile(exefile)if ConstStr <>chr(56) then exit//如果第5+1个位置的值不是56退出(说明你的软件被改动了) end这段代码随时随地都可以加入,真的非常方便。不过你要注意的是,万一用户的机器染上了病毒怎么办。保护了检验算法,还要保护什么呢?校验算法只是让Cracker很难写出注册机,但是这还防止不了软件被破解(也就是常说的暴破)。暴破的原理很简单:你的软件写完后编译成可执行文件,当Cracker得到这个软件就可以进行反编译,得让派神到汇编代码。你的那段“If 检验不成功 Then ...”,就变成了cmp xx,xx,jp xx,xx。稍微改动一下变成cmp xx,xx,rop,rop,rop,rop。整个前面的校验算法也就作废了。我想应该是没有太好的方法,只是千万不要用明文比较。再想保护深一点就加入一些冗余代码,让Cracker在这堆代码里转的头晕脑涨,你的目的就达到了。最后,有些话不吐不快。1.(引用别人:)加密是救不了共享软件业的!在好的加密技术也有人能解开的!与其花费时间去加密,不如把自己软件的功能增强些!这样可能会有更多的人支持您的!!(整天跳出窗口是谁也烦了)! 2.我认为Cracker们其实挺可爱。欢迎分享,转载请注明来源:内存溢出
评论列表(0条)