一、设计思路
软件推广与软件的防盗版是往往是矛盾的:推销软件时,极力推荐试用自己的产品,同时,为了保护自己的知识产权,又要努力防止产品不被非法复制。于是出现了共享软件的注册机制:未注册时,是演示版,注册并付款后,用户才获得软件的正式版。在用户注册后,许多公司的做法是向客户邮寄或电邮正式版软件,用户收到后必须重新安装软件。
为了兼顾上述两方面,笔者的思路是:软件公司向客户提供的注册码必须结合用户所在系统的特征信息的代码,这样,即使软件被复制,由于新环境的特征与原有环境特征不同,软件内部设计好的特征判定程序会拒绝系统执行正版软件的一些功能,而只执行演示版程序的功能。
关键是客户特征如何取得,并保证其唯一性。
较成功的做法是:采用用户计算机硬盘的产品序列号或网卡的MAC地址,因为这些代码重复的可能性极小,特别是后者,是全世界唯一的。用户在注册时,演示版程序的“注册”功能自动提取该特征信息,然后向软件销售商发送该信息,销售商获得该特征码后,用注册码生成器按一定算法对客户特征码进行变换,最后生成注册码,发送给用户,用户再用注册功能输入收到的注册码,软件自动升级为正式版。
在这种方法中,用户特征码到用户注册码的转换算法必须合理,保证转换之后的注册码也保持唯一性,同时,由于软件中也必须具有根据用户特征生成注册码并与用户从销售商处获得的注册码比较的功能,因此,转换算法必须有一定的复杂性以防止软件的注册机制被非法破解。
整个软件注册机制的过程和说明如下:
用户方 销售商
演示版软件 (1)分发演示软件
<stroke endarrow="block"></stroke><stroke endarrow="block"></stroke> (2) 特征码生成
(3)注册请求 注册码生成器
<stroke endarrow="block"></stroke><stroke endarrow="block"></stroke>
(5)发放注册码 (4)注册码生成
<stroke endarrow="block"></stroke>
<shapetype id="_x0000_t202" path="m,l,21600r21600,l21600,xe" o:spt="202" coordsize="21600,21600"><stroke joinstyle="miter"></stroke><path o:connecttype="rect" gradientshapeok="t"></path></shapetype><shape id="_x0000_s1037" style="MARGIN-TOP: 31.2pt; Z-INDEX: 12; LEFT: 0px; MARGIN-LEFT: 45pt; WIDTH: 66.9pt; POSITION: absolute; HEIGHT: 20.7pt; TEXT-ALIGN: left" type="#_x0000_t202" stroked="f" filled="f"><textbox></textbox></shape>
<wrap type="square"></wrap><stroke endarrow="block"></stroke> (6) 录入注册码
(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.
<wrapblock><shapetype id="_x0000_t75" path="m@4@5l@4@11@9@11@9@5xe" o:spt="75" coordsize="21600,21600" stroked="f" filled="f" o:preferrelative="t"><stroke joinstyle="miter"></stroke><formulas><f eqn="if lineDrawn pixelLineWidth 0"></f><f eqn="sum @0 1 0"></f><f eqn="sum 0 0 @1"></f><f eqn="prod @2 1 2"></f><f eqn="prod @3 21600 pixelWidth"></f><f eqn="prod @3 21600 pixelHeight"></f><f eqn="sum @0 0 1"></f><f eqn="prod @6 1 2"></f><f eqn="prod @7 21600 pixelWidth"></f><f eqn="sum @8 21600 0"></f><f eqn="prod @7 21600 pixelHeight"></f><f eqn="sum @10 21600 0"></f></formulas><path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f"></path><lock aspectratio="t" v:ext="edit"></lock></shapetype><shape id="_x0000_s1035" style="MARGIN-TOP: 31.2pt; Z-INDEX: 10; LEFT: 0px; MARGIN-LEFT: 63pt; WIDTH: 261pt; POSITION: absolute; HEIGHT: 179.4pt; TEXT-ALIGN: left" type="#_x0000_t75"><imagedata o:title="map1" src="file:///F:%5CDOCUME~1%5CADMINI~1%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image009.jpg"></imagedata><wrap type="topAndBottom"></wrap></shape></wrapblock> 将上述程序嵌入所发布的软件并略加修改,便可以向试用软件的用户提供注册的界面以及启动时的注册码校验。下图是注册功能的两个界面的示例:
<wrapblock><shape id="_x0000_s1036" style="MARGIN-TOP: 202.8pt; Z-INDEX: 11; LEFT: 0px; MARGIN-LEFT: 63pt; WIDTH: 270pt; POSITION: absolute; HEIGHT: 163.8pt; TEXT-ALIGN: left" type="#_x0000_t75"><imagedata o:title="map2" src="file:///F:%5CDOCUME~1%5CADMINI~1%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image011.jpg"></imagedata><wrap type="topAndBottom"></wrap></shape></wrapblock> 图一、特征码生成
图二、完成注册
三、注册码生成
用户向销售商反馈特征码并提出注册请求之后,软件销售商用注册码生成器生成用户的注册码,其过程仅仅是对用户提交的特征码进行一系列的变换。注册码生成器的源程序如下,有编程经验的朋友可以自行改变特征码到注册码的变换过程。
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))>
or (length(trim(edit3.text))>
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
j:=j-128; {限制在0-127之间}
ii:=i;
if j>=33 then
j:=j+33+ii; {限制在空格-127之间}
result:=result+char(j); {得到注册码}
end;
end;
end.
<wrapblock><shape id="_x0000_s1034" style="MARGIN-TOP: 23.4pt; Z-INDEX: 9; LEFT: 0px; MARGIN-LEFT: 54pt; WIDTH: 279pt; POSITION: absolute; HEIGHT: 132.6pt; TEXT-ALIGN: left" type="#_x0000_t75" o:allowincell="f"><imagedata o:title="getreg" src="file:///F:%5CDOCUME~1%5CADMINI~1%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image013.jpg"></imagedata><wrap type="topAndBottom"></wrap></shape></wrapblock> 该注册码生成器的软件界面如下:
图三、注册码生成器
四、软件自升级
用户在输入了正确的注册码之后,软件应由原来的演示版自动升级为正式版。设计程序的朋友都知道,这很简单:将用户输入的注册码保存在文件中,如>.INI文件,每次软件启动时读入该代码,同时,读取系统的特征码并按注册器相同的规则生成内部注册码,再与用户输入的注册码比较,若相同,则应开放系统所有功能(即自升级为正式版),否则,应按演示软件的特点屏蔽一些功能或加上时间限定。这部分的程序由于比较简单,在此不再列出。
|
相关推荐
这个是IOCP远程控制软件的模型,服务端运行后会自动发送本机信息到客户端,客户端采用IOCP重叠机制。 IOCP封装类(DLL)发布 主要是CIocpSrv"伪类",实际上还是调用的DLL, IOCP完成端口 IP所在地查询器 jpeglib_demo...
这个是IOCP远程控制软件的模型,服务端运行后会自动发送本机信息到客户端,客户端采用IOCP重叠机制。 IOCP封装类(DLL)发布 主要是CIocpSrv"伪类",实际上还是调用的DLL, IOCP完成端口 [1]---选择 - Select [2]异步...
这个是IOCP远程控制软件的模型,服务端运行后会自动发送本机信息到客户端,客户端采用IOCP重叠机制。 IOCP封装类(DLL)发布 主要是CIocpSrv"伪类",实际上还是调用的DLL, IOCP完成端口 IP所在地查询器 jpeglib_demo...
这个是IOCP远程控制软件的模型,服务端运行后会自动发送本机信息到客户端,客户端采用IOCP重叠机制。 IOCP封装类(DLL)发布 主要是CIocpSrv"伪类",实际上还是调用的DLL, IOCP完成端口 IP所在地查询器 jpeglib_demo...
这个是IOCP远程控制软件的模型,服务端运行后会自动发送本机信息到客户端,客户端采用IOCP重叠机制。 IOCP封装类(DLL)发布 主要是CIocpSrv"伪类",实际上还是调用的DLL, IOCP完成端口 IP所在地查询器 jpeglib_demo...
这个是IOCP远程控制软件的模型,服务端运行后会自动发送本机信息到客户端,客户端采用IOCP重叠机制。 IOCP封装类(DLL)发布 主要是CIocpSrv"伪类",实际上还是调用的DLL, IOCP完成端口 IP所在地查询器 jpeglib_demo...
课程内容和考试内容的对照 理解微软的MCSE长远考虑 理解微软出题的方式 使用本书帮助备考 在Internet上寻找对考试有帮助的信息 寻求微软认可的课程指导 寻找高质量的和三方帮助 寻找可利用的评估软件拷贝 ...
3.1.3 字符串的拷贝 37 3.1.4 字符串的连接 38 3.1.5 字符串的打印 38 3.2 内存与链表 40 3.2.1 内存的分配与释放 40 3.2.2 使用LIST_ENTRY 41 3.2.3 使用长长整型数据 43 3.3 自旋锁 44 3.3.1 使用自旋锁 ...
3.1.3 字符串的拷贝 37 3.1.4 字符串的连接 38 3.1.5 字符串的打印 38 3.2 内存与链表 40 3.2.1 内存的分配与释放 40 3.2.2 使用LIST_ENTRY 41 3.2.3 使用长长整型数据 43 3.3 自旋锁 44 3.3.1 使用自旋锁 ...
9-23 6.session⑤-session配置 session的gc机制 自定义session处理器 9-24 0.回顾 9-24 1.回顾2 9-24 2.php文件编程①-文件操作原理 如何获取文件信息 如何读文件 9-24 3.php文件编程②-如何写文件 拷贝文件 创建和...
9-23 6.session⑤-session配置 session的gc机制 自定义session处理器 9-24 0.回顾 9-24 1.回顾2 9-24 2.php文件编程①-文件操作原理 如何获取文件信息 如何读文件 9-24 3.php文件编程②-如何写文件 拷贝文件 创建和...
9-23 6.session⑤-session配置 session的gc机制 自定义session处理器 9-24 0.回顾 9-24 1.回顾2 9-24 2.php文件编程①-文件操作原理 如何获取文件信息 如何读文件 9-24 3.php文件编程②-如何写文件 拷贝文件 创建和...
9-23 6.session⑤-session配置 session的gc机制 自定义session处理器 9-24 0.回顾 9-24 1.回顾2 9-24 2.php文件编程①-文件操作原理 如何获取文件信息 如何读文件 9-24 3.php文件编程②-如何写文件 拷贝文件 创建和...
9-23 6.session⑤-session配置 session的gc机制 自定义session处理器 9-24 0.回顾 9-24 1.回顾2 9-24 2.php文件编程①-文件操作原理 如何获取文件信息 如何读文件 9-24 3.php文件编程②-如何写文件 拷贝文件 创建和...