现有软件加密基本都是采用各种硬件系列号作为加密依据,实现的是一机一码制,在采用硬件系列号作为加密依据之前,先要了解下各种硬件系列号的情况。这样有利于选择软件加密依据,防止注册码可以在多台计算机上使用。
获取硬盘系列号
硬盘系列号是生产厂家在硬盘出厂之前就写入到硬盘中不可以修改的系列号,也就是所谓的出厂系列号或是物理系列号,该系列号一旦写入就不可以进行修改,并且是唯一的,但有些硬盘厂家生产的硬盘没有这个系列号,也就是说系列号为空。硬盘出厂系列号与硬盘分区卷的系列号的区别在于:卷的系列号可以修改,并且只要一重新格式化,该系列号就会改变;而硬盘出厂系列号是不可修改的,格式化以后系列号不会被改变。
如果采用分区卷的系列号作为加密依据,其一,只要购买一个注册码,其他的计算机只要修改卷的系列号就可以成为软件的正式用户;其二,如果用户重新格式化过分区,那么就要重新给用户发送新的系列号,因为没有确切的证据,也不知道用户是否真的格式化过分区还是使用另外的计算机的分区系列号来获取注册码。所以为了避免出现一码多机可用和引起不必要的麻烦,建议在实际加密过程中不要使用硬盘卷的分区系列号作为加密依据,而应该采用硬盘出厂系列号作为软件的加密依据。
虽然不使用卷的系列号作为加密依据,但这里也来看看怎么获取磁盘分区卷的系列号?其实很简单,只要调用 API函数 GetVolumeInformation 就可以得到磁盘分区卷的系列号。 API 函数 GetVolumelnformation 在 MSDN 中的函数原型如下:
BOOL GetVolumelnformation(
LPCTSTR lpRootPathName, //指向文件系统根的路径字符串
LPTSTR IpVolumeNameBuffer, //接收返回的卷名的缓冲区
DWORD nVolumeNameSize, //上述缓冲区的长度
LPDWORD pVolumeSerialNumber, //接收卷序列号的整数变量的地址
LPDWORD pMaimumComponenilength, //接收卷上最大文件路径长度的整数变量的地址
LPDWORD IpFileSystemFlagx, 1/接收卷文件系统标志的整数变量的地址
LPTSTR ipFilSystemNameBufer, //接收返回的卷的文件系统名的缓冲区0
DWORD nFileSystemNameSsize //上述缓冲区的长度
)
示例代码如下:
//获取指定磁盘分区的卷系列号
function GetDiskvo1 (Driver:String): DWORD;
var
volumeSerialNumber : DWORD;
MaximumComponentLength : DWORD;
FileSystemFlags :DWORD;
beqin
if Driver length(Driver)] =':' then
Driver :=Driver + ‘\’
GetVolumeInformation(PChar (Driver), nil,0,@VolumeSerialNumber,
MaximumComponentlength,
FileSystemFlags, nil,0);
Resul t:= (VolumeSeria1Number);
end;
procedure TForm1.Button1click(sender; Tobject);
begin
Label1.caption:-IntToHex(GetDiskVo1('c:V9),8);
end;
获取硬盘的出厂系列号还要考虑到硬盘的接口类型,在这里只介绍 IDE 接口的和 SCSI 接口的。首先看看要获取硬盘系列号所需要的几个 API 函数:
BOOL DeviceloControl(
HANDLE hDevice, //设备句柄
DWORD dwloControlCode, //控制代码
LPVOID IpInBufer, //指向包含操作所需的数据的缓冲区指针
DWORD nInBufferSize, //lpInBuffer 参数指向的缓冲区的大小
LPVOID IpOutBufer, //指向用来接收输出数据的缓冲区
DWORD nOuBuferSize, //指向用来接收输出数据的缓冲区
LPDWORD ipBytesRethurned //指向变量用于返回缓冲区数据的数量
LPOVERLAPPED IpOverlaped //指向 OVERLAPPED 结构
);
HANDLE CreateFile(
LPCTSTR IpFileName, //指向文件名
DWORD dwDesiredAccess, //访问模式(读或写)
DWORD dwShareMode, //共享模式
LPSECURITY_ATTRIBUTES ipSecurityAttributes,
//指向安全属性
DWORD dwCreationDisposition, //如何创建文件
DWORD dwFlagsAndAtributes, //文件属性
HANDLE hTemplateFile //文件模板句柄
获取硬盘出厂系列号的完整示例代码如下:
unit DiskserialUnit;
interface
uses
Windows; SysUtils;
function GetHddserial: string;
implementation
function GetIdeDiskserialNumber: String;
type
TSrbIoControl = packed record
HeaderLength :ULONG;
Signature Array[0..7] of Char;
Timeout ULONG;
Controlcode:ULONG;
ReturnCode ULONG;
Length :ULONG;
end;
SRB_IO_CONTROL = TSrbIoControl;
PSrbIoControl =^TSrbIoControl;
TIDERegs = packed record bFeaturesReg :Byte;
bsectorCountReg :Byte;
bsectorNumberReg : Byte;
bcylLowReg :Byte;
bcylHighReg :Byte;
bDriveHeadReg :Byte;
bcommandReg: Byte;
bReserved:Byte;
end;
IDEREGS=TIDERegs;
PIDEREGS=^TIDERegs;
TsendcndInParams = packed record
CBuffersize : DWORD;
irDriveRegs:TIDERegs;
bdriveNumber : Byte;
bReserved:Arraylo..2] of byte;
dwReserved:Array10..31 of DWORD;
bBuffer : Array[0..0] of Byte
end;
SENDCMDINPARAMS= TSendCmdInParams; PSendCmdInParams=TSendCmdInParams;
TIdSector = packed record
wGenConfig :Word;
wNumCyls : Word;
wReserved :Word;
wNumHeads :Word;
wBytesPerTrack: Word;
wBytesPerSector :Word;
wSectorsPerTrack : Word;
wVendorUnique :Array10..2] of word;
sSerialNumber : Arraylo..19] of Char;
WBufferType :Word;
wBuffersize :Word;
wEccsize :Word;
sFirmwareRev :Array[0..7] of char;
sMode1Number : Array[0..39] of Char;
WMoreVendorUnique :Word;
wDoublewordIo:Word;
wcapabilities :Word;
wReserved1 : Word;
wPIOTiming:word;
WDMATiming:word;
wBS: Word1;
WNumcurrentcyla:Word;
wNumcurrentHeads:Word;
wNumcurrentSectorsPerTrack:Word;
ulCurrentSectorCapacity : ULONG;
ulTotalAddressableSectors:ULONG:
wSingleWordDMA:Word;
sMultiWordDMA:Word;
bReserved:Array[0..127] of byte;
end;
PIdsector = ^TIdSector;
const
IDEID_FUNCTION -=SECI
IDENTIFY BUFFER SIZE =512;
DFP RECEIVE DRIVE DATA =$0007c088:
IOCTL SCSI MINIPORT =$0004d008;
IOCTL SCSI MINIPORT_IDENTIFY =$001b0501;
Datasito =sizeof(TSendomdInParams)-1+IDENTIFY BUFFER_SIZE; ButfferSize=Sizeof(SRB_IO_CONTROL)+DataSize;
W9xbuffersize=IOENTIFYBUFER_SIZE+16;
var
hDevice : THandler
cbbytenReturned : DWORD;
pInData: PSendCmdInParams;
poutData : Pointer; // PSendCndInParama;
Bufter : Array[0..Buffersize-1] of Byte;
srbcontrol : Tsrblocontrol absolute buffers;
procedure Changonyteorder( var patat size t Integer )
var
ptr : PChar;
i :Integer;
c : Char;
begin
//判断操作系统
//获取SCSI接口句柄
end;
function ScsiHddSerialNumber:String;
{$ALIGN ON}
Type
end;
begin
end;
function GetHddSerial:string
var
NumTry:Byte;
FinalStr:String;
begin
NumTry := 1;
Repeat
Case NumTry of
1:FinalStr:= ScsiHddSerialNumber;
2:FinalStr:= GetIdeDiskSerialNumber;
3:FinalStr:=’Error’;
End;
Inc(NumTry);
Until(FinalStr <> ‘’) or (NumTry > 4);
Result := FinalStr;
end;
end.
在实际加密过程中,不建议使用CPU序列号和网卡的MAC地址作为加密依据,因为相同型号的CPU的序列号相同,并且,MAC地址可以更改,以硬盘出厂序列号作为加密依据是比较好的选择。