一、共享==免费?
随着inte.net大行其道,“共享+注册”模式日渐成为程序员发布自己软件的主要手段,但是随之而来的破解手段也越来越高明。如何保护自己的劳动成果不被暴力破解或修改?用md5摘要值验证是一个很常用的方法。
md5作为一个公开算法,实现的方法很多,比如开源软件、windows自带的api等,c++ builder和delphi中集成的indy里面也有现成的md5控件。用api实现md5虽然效率高,但是毕竟太繁琐,具体方法可以参阅msdn上crypt开头的那几个函数说明。用c++ builder的md5控件虽然方便,但是速度较慢,而且只能处理以’\0’结尾的字符串,所以要用这个控件还需要我们对待验证数据做一些预处理。预处理的关键在于把较重要的内容挑出来计算,这样一方面可以去除’\0’,另一方面可以极大减少待验证内容的长度,只计算关键代码的摘要值。
二、源程序祥解
先要说明的是网上和borland help里面对indy md5控件介绍很少,这段程序基本上是我自己摸索的结果,在c++ biulder 6.0和indy 6.0下运行正常。
先在indy misc中拖一个md5控件,假设其name为cipher,程序如下:
/*
md5计算函数 by daydreamer 2004-04
功能:对文件名为fname的文件计算16个字节长的md5值,放在result里面
输入:指向文件名的指针char *fname
输出:md5值放在result指向的缓冲区里面
返回值:如果正确计算出md5值则返回true,否则返回false
*/
bool md5( char* fname, char *result)
{
unsigned int i=0; //用于记录读出文件的大小
bool flag=false; //正确计算md的话则置标记
static ansistring ss; //用于临时存放得到的md5值
char *buffer=new char[myfile_size]; //用于读取目标文件,文件大小不能超过myfile_size
tfilestream *tt=new tfilestream(fname,fmopenread); //用于读取目标文件的全部内容,使用此方法简单一点,也可以用标准的createfile()读取
i=tt->read(buffer,myfile_size); //i中保存实际读取的字节数
if ((i)&&(i!=1)) //如果读出字节数不为0或1,则进行处理
{ i=i-1; //最后一个字节必须留出,供结束符使用
_asm{ //这一段汇编主要是用来对文件预处理
mov ecx,i; //置计数器
mov ebx,buffer; //源地址指针
mov edx,buffer; //目的地址指针
l1: mov al, [ebx]; //取一个字节,因为如果文件过大会极大降低速度,所以必须以较细粒度过滤源串
cmp al,0x70; //只对大于0x70和小于0x91的字节进行摘要
jb l2 ; //因为主要的转移指令(jz,jnz)、空操作指令(nop)等都大于0x70小于0x91
cmp al,0x91; //也可以换成更宽松的条件,但至少应该把0x00滤掉,因为它被视为结束符
jnb l2 ;
mov [edx],al ; //符合条件的字节保存起来等待验证
inc edx;
l2: inc ebx;
dec ecx;
jnz l1;
mov byte ptr [edx+1],0; //在最后置结束符’\0’
}
cipher->reset(); //每次使用该控件之前应该重置其内部的一些参数
cipher->autocompleteinput=false; // 只有调用completedinput() 时才得到结果
cipher->codestring(buffer); //输入预处理过的数据
ss=cipher->completedinput(); //输入完毕,得到摘要码
if(ss.length()=md5_lenghth) //如果摘要码正常(即为16位),则保存之
{ flag=true; //置正确标志
memcpy(result,ss.c_str(),16); //把结果放入result
} // end if
}// end if
delete tt;
delete[] buffer;
return flag;}
调用的时候可以用application->exename.c_str()当作fname传入,注意在c++ biulder中直接run的话这会引起异常,这没关系,发布出来的程序不会有问题。此处为了简明,在汇编代码中没有保存和恢复寄存器,使用时可以加上,或者发布时把optionsèadvanced complier中的register variables设为none即可。
三、使用方法
利用md5值来保护共享软件的方法有很多,最简单的比如先把正常的执行模块的md5摘要值静态保存在外部文件中(比如包含在注册文件中),每次运行时计算自身的md5并与之比较,从而判断是否被修改。高深一点的比如用正确的md5来还原正确的入口地址,或者参与注册码/机器码计算。最好是加上自身md5验证之后再用asprotect或aspack之类的压缩软件加上壳,这样一旦cracker用脱壳软件脱壳,软件将不会正常执行,对于很多crack newbie来说十有八九会怀疑脱壳失败,进而放弃。
其实软件保护与破解永远是魔道相长的一对矛盾,无论怎么严密的防范,肯定有人能破。我们要做的只是把大量的菜鸟cracker挡在门外,如果不幸被高手盯上,那么恭喜你:这说明你的软件真的很有价值。
Java Asp PHP .Net XML C/C++ CGI VB Jsp J2ee J2se J2me EJB Servlet Tomcat Resin Struts Weblogic Eclipse ANT GUI JMS Web servise IDEA Webphere Hibernate Spring Jboss Applet Swing Socket Javamail Perl Ajax P2P 安全 模式 框架 测试 开源 游戏
Windows XP Windows 2000 Windows 2003 Windows Me Windows 9.x Linux UNIX 注册表 操作系统 服务器 应用服务器