一、设计思路 软件推广与软件的防盗版是往往是矛盾的:推销软件时,极力推荐试用自己的产品,同时,为了保护自己的知识产权,又要努力防止产品不被非法复制。于是出现了共享软件的注册机制:未注册时,是演示版,注册并付款后,用户才获得软件的正式版。在用户注册后,许多公司的做法是向客户邮寄或电邮正式版软件,用户收到后必须重新安装软件。 为了兼顾上述两方面,笔者的思路是:软件公司向客户提供的注册码必须结合用户所在系统的特征信息的代码,这样,即使软件被复制,由于新环境的特征与原有环境特征不同,软件内部设计好的特征判定程序会拒绝系统执行正版软件的一些功能,而只执行演示版程序的功能。 关键是客户特征如何取得,并保证其唯一性。 较成功的做法是:采用用户计算机硬盘的产品序列号或网卡的MAC地址,因为这些代码重复的可能性极小,特别是后者,是全世界唯一的。用户在注册时,演示版程序的“注册”功能自动提取该特征信息,然后向软件销售商发送该信息,销售商获得该特征码后,用注册码生成器按一定算法对客户特征码进行变换,最后生成注册码,发送给用户,用户再用注册功能输入收到的注册码,软件自动升级为正式版。 在这种方法中,用户特征码到用户注册码的转换算法必须合理,保证转换之后的注册码也保持唯一性,同时,由于软件中也必须具有根据用户特征生成注册码并与用户从销售商处获得的注册码比较的功能,因此,转换算法必须有一定的复杂性以防止软件的注册机制被非法破解。 整个软件注册机制的过程和说明如下:
用户方 销售商 演示版软件 (1)分发演示软件 (2) 特征码生成 (3)注册请求 注册码生成器
(5)发放注册码 (4)注册码生成
(1)、软件销售商向用户分发演示软件 (2)、用户运行演示程序、用软件注册功能生成特征码 (3)、用户将特征码通过Email等形式反馈给销售商,请求注册 (4)、销售商用注册码生成器,根据用户反馈的特征码生成注册码 (5)、销售商向用户通过Email等形式发放注册码 (6)、用户在演示程序中输入获得的注册码,用注册功能录入注册码,演示程序根据注册码生成规则生成内部注册码,再与用户录入的注册码比较,若相等,则软件自升级为正式版,否则,继续以演示软件形式运行。 二、客户特征码的获取 在Delphi中,获取用户计算机的网卡MAC地址可通过Windows中NetBIOS的API调用来完成,得到地址后,作适当变换再作为用户特征码。实现这一过程的程序如下: unit mac; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, NB30, StdCtrls; type TNBLanaResources = (lrAlloc, lrFree); type PMACAddress = ^TMACAddress; TMACAddress = array[0..5] of Byte; type TForm1 = class(TForm) Label1: TLabel; Edit1: TEdit; Button1: TButton; Button2: TButton; function GetMACAddress(LanaNum: Byte; MACAddress: PMACAddress): Byte; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.DFM} //GetMACAddress—获取网卡MAC地址的函数 //其中:LanaNum取值为0-n,指哪一个网卡 // MACAddress为获取的MAC地址值 function TForm1.GetMACAddress(LanaNum: Byte; MACAddress: PMACAddress): Byte; var AdapterStatus: PAdapterStatus; {网卡状态变量} StatNCB: PNCB; {网络控制块变量} begin New(StatNCB); ZeroMemory(StatNCB, SizeOf(TNCB)); {分配网络控制块空间} StatNCB.ncb_length := SizeOf(TAdapterStatus) + 255 * SizeOf(TNameBuffer); GetMem(AdapterStatus, StatNCB.ncb_length); try with StatNCB^ do begin ZeroMemory(MACAddress, SizeOf(TMACAddress)); ncb_buffer := PChar(AdapterStatus); ncb_callname := '* ' + #0; ncb_lana_num := Char(LanaNum); ncb_command := Char(NCBASTAT); NetBios(StatNCB); {调用NetBIOS功能} Result := Byte(ncb_cmd_cplt); if Result = NRC_GOODRET then {获取地址,存放到变量} MoveMemory(MACAddress, AdapterStatus, SizeOf(TMACAddress)); end; finally FreeMem(AdapterStatus); {释放空间} Dispose(StatNCB); end; end;
procedure TForm1.Button1Click(Sender: TObject); var LanaNum: Byte; MACAddress: PMACAddress; RetCode: Byte; begin LanaNum := 0; New(MACAddress); try RetCode := GetMACAddress(LanaNum, MACAddress); {调用函数,获取MAC地址} if RetCode = NRC_GOODRET then begin Edit1.Text := Format('%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x', [MACAddress[0]+11, MACAddress[1]+12, MACAddress[2]+13, {作适当变换} MACAddress[3]+14, MACAddress[4]+15, MACAddress[5]]+16); end else begin Beep; Edit1.Text := 'Error'; ShowMessage('GetMACAddress Error! RetCode = $' + IntToHex(RetCode, 2)); end; finally Dispose(MACAddress); end; end;
procedure TForm1.Button2Click(Sender: TObject); begin form1.close; end; end.
图二、完成注册
三、注册码生成 用户向销售商反馈特征码并提出注册请求之后,软件销售商用注册码生成器生成用户的注册码,其过程仅仅是对用户提交的特征码进行一系列的变换。注册码生成器的源程序如下,有编程经验的朋友可以自行改变特征码到注册码的变换过程。 unit main; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Label1: TLabel; Label3: TLabel; Button1: TButton; Button2: TButton; Edit1: TEdit; Label2: TLabel; Edit2: TEdit; Label4: TLabel; Edit3: TEdit; Edit4: TEdit; Label5: TLabel; Edit5: TEdit; Label6: TLabel; Edit6: TEdit; procedure Button2Click(Sender: TObject); procedure Button1Click(Sender: TObject); function GenRegCode(source: string): string; private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.DFM}
procedure TForm1.Button2Click(Sender: TObject); begin form1.close; end;
procedure TForm1.Button1Click(Sender: TObject); var regcode: string; begin if (length(trim(edit1.text))><4) or (length(trim(edit2.text))><4) or (length(trim(edit3.text))><4) then begin application.MessageBox('客户提交的特征码无效,必须为3个4位!', '错误信息',mb_ok); exit; end; regcode:=genregcode(trim(edit1.text)+trim(edit2.text)+trim(edit3.text)); edit4.text:=copy(regcode,1,4); edit5.text:=copy(regcode,5,4); edit6.text:=copy(regcode,9,4); end;
function TForm1.GenRegCode(source: string): string; var cusstr,mystr: array [0..12] of char; {密钥} i: integer; ii,j,k: byte; begin strpcopy(cusstr,source); mystr[0]:='T'; mystr[1]:='h'; mystr[2]:='i'; mystr[3]:='s'; mystr[4]:='a'; mystr[5]:='T'; mystr[6]:='e’; {密钥} mystr[7]:='s'; mystr[8]:='t'; mystr[9]:='1'; mystr[10]:='2'; mystr[11]:='3'; k:=0; for i:=1 to 12 do k:=k xor ord(cusstr[i-1]); {特征异或和} result:=''; for i:=1 to 12 do begin j:=ord(mystr[i-1]) xor ord(cusstr[12-i]); {每字节与密钥字节异或} j:=j xor k; {再与累加和异或} j:=abs(j); {取其绝对值} if j<127 then j:=j-128; {限制在0-127之间} ii:=i; if j>=33 then j:=j+33+ii; {限制在空格-127之间} result:=result+char(j); {得到注册码} end; end; end.
图三、注册码生成器
四、软件自升级 用户在输入了正确的注册码之后,软件应由原来的演示版自动升级为正式版。设计程序的朋友都知道,这很简单:将用户输入的注册码保存在文件中,如>.INI<文件,每次软件启动时读入该代码,同时,读取系统的特征码并按注册器相同的规则生成内部注册码,再与用户输入的注册码比较,若相同,则应开放系统所有功能(即自升级为正式版),否则,应按演示软件的特点屏蔽一些功能或加上时间限定。这部分的程序由于比较简单,在此不再列出。
|
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1821051