共享软件的注册加密法

3/8/2008来源:C/C++教程人气:6717

    Internet网络的迅速发展,为软件高效传播开辟更加广阔的天地。如国内闻名的金蜘蛛软件下载中心,就是一个典型的发布软件集散地。发布共享软件主要包括两种形式:日期限制形式和电子注册形式。日期限制形式答应下载软件的用户使用软件一段时间,如一个月等,假如用户认可该软件,可购买该软件的注册序列号继续使用;电子注册形式就是根据用户所用机器的硬件信息产生注册码,并在软件中对某些先进或常用功能进行限制,假如用户要使用其全部功能,必须将软件采集的有关硬件信息反馈给开发者,并交一定的注册费可获得该软件在自己机器中的注册码,才能正常使用。
    前一种形式很轻易给盗版者造成可乘之机,假如制作盗版者购买了一个注册序列号并公布于天下,则所有用户使用这个注册号都可进行正常使用;后者对用户来说注册手段稍显复杂些,对开发者来说也需要一定的编程真功夫,但其具有“八点锁紧”功能,防盗性却是不容置疑。本文根据自己的实践,将后者的实现过程介绍给想要制作发布共享软件的读者。
    一、注册源
    在WIN98/95的保护模式下,要根据硬件信息形成注册码可不是一件轻易的事,在实模式下可通过硬盘端口1F6H和1F7H直接读取硬盘的序列号等信息作为注册的数据源,但这一方法在保护模式下却被亮出了红牌。利用BIOS中的主板序列号、BIOS版本序列号或主机出厂日期和标志等,完全可以作为注册码的注册源。如ROMBIOS中F000H-FFFFH区域中就存在与硬件配置有关的信息,还可以采集其它一处或几处主板等的信息作为注册码的生产基地。例如可根据F000H:FFF5H-F000H:FFFFH 中存放的主机出厂日期和主机标志值,产生应用程序的注册码。由于计算机产品的更新换代比较快,而且所有用户使用的计算机不可能配置都完全相同,所以注册码产生的源也不会完全相同。而且这些硬件信息内容在任何操作系统下均完全相同,兼容性非常好,更不会因为操作系统的更新而造成注册功能失效。
    注册源确定之后,要害的问题就是共享软件安装程序如何采集注册源信息,并让用户将其返回给开发者。最简单的方法就是将采集到的注册源信息经过位操作加密后存放到一个文本中,形成注册码的数据源资料。这个注册源数据串可稍长一些,但不宜过长,使用户能够通过电子邮箱、电话或信件顺利转给开发者为宜。如笔者安装程序是用C语言编制的,假如将上述内存地址作为注册源,数据串文本文件名为KEYID.DOC,长度为20个字符。其示例代码如下:
    FILE  *fp2;
    unsigned int keyrom[9];
    unsigned char buff[0x410];
    unsigned char pathstmp[80];
    unsigned char path[80]={"C:\\WBCOOL"};
    unsigned int far *pt=(unsigned int far*)0xf000fff6L;
    ......
    outportb(0x21,0x2);
    strcpy(pathstmp,path);
    strcat(pathstmp,"\\");
    strcat(pathstmp,"KEYID.DOC");
    for(i=0;i<5;i++)
      keyrom[i]=(*(pt+i)+0x1818)^0x5858;//第一级加密算法
    sPRintf(buff,"KEYID:%04x%04x%04x%04x%04x",
      keyrom[0],keyrom[1],keyrom[2],keyrom[3],keyrom[4]);
    buff[0x1a]=0;
    if((fp2=fopen(pathstmp,"wb"))==NULL)
    {
      printf("FILE %s CREATE ERROR!",pathtmp);
    } else {
      fseek(fp2,0L,SEEK_SET);
      fprintf(fp2,"%s\xd\xa",buff);
      fclose(fp2);
    }
    outportb(0x21,0x0);
    
    二、注册机
    

    开发者得到用户提供的注册源数据之后,就需要利用注册机生成注册码并返回给用户。注册机利用既定的位操作和不可逆算法,形成用户比较轻易操作的字符串注册码,注册码的长度一般为8-16位为宜,用户只需注册一次就可以长期使用,所以注册码的长度不会影响用户的注册操作。当然注册机的算法应与共享软件中的算法部分基本相同。对于远程用户,注册机应该具有从键盘和内存两种取得注册源数据的功能,所以注册机的加密算法实际为两个分支:第一个分支是从键盘获取注册源数据后直接根据注册算法形成注册码的过程,是直接给远程用户反馈注册码的过程;第二个分支是直接从ROM BIOS中根据注册源算法取得注册源数据,再根据注册算法形成注册码的过程,是直接读取本地机注册码的。
    用户得到注册码后,根据共享发布软件的注册方法进行一次注册,应用程序会自动将这个注册码存放到软件的特定位置处,当应用程序被他人拷贝到其它机器中去后,由于注册码因不同机器而异,所以应用程序的功能或使用次数仍然受限,要在其它机器中使用该应用程序,还必须进行重新注册,达到共享软件发布目的。同时由于注册源数据的算法和注册码算法均可因人而异,因此这种方法非常可靠。本人实现的注册机带参数时接受键盘输入注册源;不带任何参数时从本地机器内直接采集注册源数据。我的注册机示例程序如下:
#include <conio.h>
#include <dos.h>
#include <io.h>
#include <dir.h>
#include <alloc.h>
#include <string.h>
#include <stdio.h>
#include <process.h>
#include <fcntl.h>
#include <ctype.h>
#include <stdlib.h>
unsigned char Buff[18];
unsigned char Buff1[18];
unsigned int  keyrom[9];
unsigned int sum,sum1,sumi,sumj;
unsigned int far *pt=(unsigned int far *)0xf000fff6L;
unsigned int i=0,j=0,m,imecom;
unsigned char p;
unsigned int  nn,nn1,nn2;
unsigned char rbuff[100],cc,cc1,cc2;
int fp;
void main(int argc,char *argv[])
{
  if(argc>=2){
    printf("KEYID:");
    scanf("%s",rbuff);//接受键盘输入远程注册源
    j=strlen(rbuff);
    if(j!=20) exit(1);
    for(i=0;i<20;i++){//读入20位注册源数据
      if((rbuff[i]>='a')&&(rbuff[i]<='f')) rbuff[i]&=0xdf;
      if((rbuff[i]>='A')&&(rbuff[i]<='F')) rbuff[i]-=0x37;
      else if((rbuff[i]>='0')&&(rbuff[i]<='9')) rbuff[i]-=0x30;
      else exit(1);
    }
    for(i=0;i<5;i++){//形成字符串
      cc1=rbuff[i*4]&0xf;
      cc2=rbuff[i*4+1]&0xf;
      cc=(cc1<<4)cc2;
      nn1=(unsigned int)cc;
      cc1=rbuff[i*4+2]&0xf;
      cc2=rbuff[i*4+3]&0xf;
      cc=(cc1<<4)cc2;
      nn2=(unsigned int)cc;
      nn=(nn1<<8)nn2;
      keyrom[i]=nn;
    }
    sum=0x1234;
    sum1=0x7456;
    for(sumj=0;sumj<4;sumj++){//形成16位注册码
      for(sumi=0;sumi<5;sumi++){
        sum+=keyrom[sumi];    //形成前4位码

        sum1+=keyrom[sumi];
      }
      sum^=0x1234<<sumj;      //进行移位异或处理
      sum1^=0x7456<<sumj;
      sprintf(Buff+4*sumj,"%04x"