開發軟件的實踐中,通常將軟件分爲幾種版木:①release;②demo;③anti_copy:④register;⑤dog版本。release爲正常的無限制發行版本,後幾種受版權保護版本,其中demo版本爲限制時間或者功能的版本;anti_copy是防複製版本,只有安裝的版本才能使用,實現時安裝程序將某個動態庫放在指定的路徑下,程序運行時驗證該文件是否存在;register版本是用戶通過向軟件開發者提供軟件註冊申請碼,由軟件提供者生成註冊碼,返回給用戶,即通過軟件中提供的註冊碼驗證機制實現軟件系統功能的開放;dog版本通過硬件加密狗實現軟件的版權保護。
1 限制軟件部分功能
做法一是在軟件的功能菜單中將該菜單所對應的功能實現函數全部置空,這樣在執行該功能時會彈出提示對話框或者什麼動也沒有。做法二是爲了方便起見,直接將菜單的屬性設置爲變灰或者非激活狀態,這樣在運行系統時,該菜單項就會變灰或者沒有激活。這種方法雖然簡便,但是如果用Visual C++直接以資源方式打開可執行文件的話,就可以將將變灰或者非轍活狀態去掉,從而去掉軟件部分功能的限制。
2 限制軟件試用時間
這裏介紹記錄時間的時問限制方法。
2.1設置三個時間變量
起始時間:int nYear0,nMonth0,nDate0;
終止時間:int nYear,nMonth,nDate;
當前時間:int nYearCur,nMonthCur,nDateCur;
2.2初次運行時給上述變量的賦值
對於當前時間:
1.
SYSTEMTIME
stCur;
2.
GetSystemTnne(&stCur);
3.
nYearCUFstCur.wYear.nMonthCur=stCur.wMonth;
4.
nDateCur=stCur.wDay;
起始時間和終止時間的賦值是在程序第一次運行時將當前時間和預設的期限寫入某個文件當中,以後將這兩個時間同當前的系統時間進行比較,判斷軟件是否過期或者試用時間是否到期:
01.
String
sFn=
"c:\\muxuanshe.sys"
;
02.
FII.E
*fp=
fopen
(sFn,
"rb"
);
03.
{
04.
nDateO=nDateCur;
05.
nYear0=n
YearCur;
06.
nMonthO=nMonthCur;
07.
nDate=nDate0;
08.
nYear=nYear0;
09.
nMonth=nMonth0+1;
10.
if
(nMonth>12){
11.
nMonth-=12;
12.
nYcar++;
13.
}
//跨年度計算依次將起始時間、到期時間和當前時間及文件的字節數寫入c:\\muxuanshe
sys
14.
}
2.3比較時間
每次運行時比較當前時間與文件記錄中的時間,有兩種情況,一是判斷是否將系統系統時間提前:
if(IsPrcTime(nYear0,nMonth0,nDate0)||IsPreTime(nYear01d,nMo nthOld,nDateOJd)))其中nYearOld,nMonthOld,nDateOld爲上次運行的時間:
01.
BOOL
JsOverTime(
int
nYear,
int
nMonth,
int
nDate)
02.
{
03.
SYSTEMTIME
st;
04.
GetSysten/rime(&st);
05.
if
(st.wYear>nYear)
06.
return
TRUE;
07.
else
if
(st.wYearnMonth)
08.
return
TRUE;
09.
else
if
(st.wMonth==nMonth&&st.wDay>nDate)
10.
return
TRUE;
11.
return
FALSF;
12.
}
如果您前移了機器時間則將終止時間nYear=l並寫入c:\\muxuanshe.sys,軟件以後終止運行!
另一種情況是對於正常的剩餘時問計算:IsOverTime(nYear,nMonth,nDate),不再贅述,具體實現請參見示例代碼。
這裏介紹的方法主要是要注意存放時間的文件要保密,如果知道了時間存放位置,那麼時間限制就很容易被解除。也可以用其他更爲穩妥的方法將時間存放,如存放在註冊表中。
3根據機器碼實現軟件註冊
機器碼指與計算機硬件(CPU、網號、硬盤)有關的串號,如硬盤序列號、MAC地址等,編寫軟件的人常用機器碼作爲產生軟件序列號的依據,目的是區分用戶,確保自己的軟件使用受控,下面通過讀取用戶計算機硬盤卷序列號,經一定的加密算法進行換算後,返回給用戶一個產品註冊碼,由於硬盤卷序列號是唯一的,提供的產品註冊碼也是唯一的,用戶利用該註冊碼通過驗證後獲得軟件全部功能。
在筆者的編程實踐中發現有時候由於所使用的函數不正確,常常不能正確獲取硬盤的序列號,這裏就這一問題進行討論。
3.1不正確的序列號
利用GetVolumelnformation獲取的計算機硬盤卷序列號,不是正確的唯一序列號:
01.
void
CWJGISApp::Register()
02.
{
03.
DWORD
VolumeSerialNumber;
04.
GetVolumeInformation(
"c:\\"
,NULL,NULL,&VolumeSeriaINumber,NULL,NULL,NULL,NULL);
05.
char
charVolumeSerialNumber[l0];
06.
itoa(VolumeSerlalNumber,charVoIumeSerialNumber,10);
07.
CString
strTemp;
08.
strTemp.Format(
"%s"
,charVolumeSerialNumber);
09.
}
該函數獲取的序列號在硬盤格式化後會發生變化。
3.2正確獲取硬盤的序列號
正確獲取硬盤序列號代碼如下:
01.
//讀般硬盤序列號函數
02.
char
*
CGetHDSerial::GetHDSerial()
03.
{
04.
m_buffer[0]=
'\n'
;
05.
//得到當前操作系統版本
06.
OSVERSIONINFO
OSVersionInfo;
07.
OSVersionInfo.dwOSVersionInfoSize
=
sizeof
(OSVERSIONINFO);
08.
GetVersionEx(&OSVersionInfo);
09.
if
(OSVersionInfo.dwPlatformld
!= VER_PLATFORM_WIN32_NT)
10.
{
11.
//Windows
9x/ME下讀取硬盤序列號
12.
WORD
m_wWin9xl'HDSerial[256];
13.
Win9xReadHDSerial(m_wWin9xHDSerial);
14.
strcpy
(m_buffer,
WORDToChar(m _wWin9xHDSerial, 10, 19));
15.
}
16.
else
17.
{
18.
//Windows
NT/2000/XP下讀取硬盤序列弓
19.
DWORD
m_wWinNTHDSerial[256];
20.
//判斷是否有SCSI硬盤
21.
if
(!WinNTReadIDEHDSerial(m_wWinNTHDSerial))
22.
WinNTReadSCSIHDSerial(m_wWinNTHDSerial);
23.
strcpy
(m_buffer,DWORDToChar(m_wWinNTHDSerial,10,
19));
24.
}
25.
return
m_buffer;
26.
}
27.
//Windows
NT/2000/XP下讀取IDE硬盤序列號
28.
BOOL
CGetHDScriaI::WinNTReadIDEHDSerial(
DWORD
*
buffer)
29.
{
30.
BYTE
JdOutCmd
[
sizeof
(SENDCMDOUTPARAMS)+IDFNTIFY_BUFFER_SIZE
- 1];
31.
BOOL
bFlag
= FALSE;
32.
int
drive
= 0;
33.
Char
driveName[256];
34.
HANDLE
hPhysicalDrivelOCTL=0;
35.
36.
Sprintf(driveName,
"\\\.\\PhysicalDrive%d"
,drive);
37.
//Windows
NT/2000/XP 下創建文件需要管理員權限
38.
hPhysicalDriveIOCTL=CreateFile(driveName,GENERIC_READ|GENERIC_WRITE,
39.
FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,NULL);
40.
41.
if
(hPhysicalDriveIOCTL!=INVALID_HANDLE_VALUE)
42.
{
43.
GETVERSIONOUTPARAMS
VersionParams;
44.
DWORD
cbBytesReturned=0;
45.
//得到驅動器的I/O控制器版本
46.
memser((
void
*)&VersionParams,0,
sizeof
(VersionParams));
47.
if
(DeviceIoControl(hPhysicalDriveIOCTL,IOCTL_GET_VERSION,NULL,
48.
0,&VersionPaiams,
sizeof
(VersionParams),
sizeof
(VersionParams),
49.
&cbBytesReturned,NULL))
50.
{
51.
if
(VersionParams.bIDEDeviceMap>0)
52.
{
53.
BYTE
bIDCmd=0;
//IDE或者ATAPI識別命令
54.
SENDCMDINPARAMS
scip;
55.
//如果驅動器是光驅,採用命令IDE_ATAPI_IDENTIFY,command,
56.
否則採用命令IDE_ATA_IDENTIFY讀取驅動器信息
57.
bIDCmd=(VersionParams.bIDEDeviceMap>>drive&0x10)?
58.
IDE_ATAPI_IDENTIFY
: IDE_ATA_IDENTIFY;
59.
60.
memset
(&scip,0,
sizeof
(scip));
61.
memset
(IdOutCmd,0,
sizeof
(IdOutCmd));
62.
//獲取驅動器信息
63.
if
(WinNTGetIDEHDInfo(hPhysicalDrivelOCTL,&scip,(PSENDCMDOUTPARMS)&
64.
IdOutCmd,(
BYTE
)bIDCmd,(
BYTE
)drive,&cbBytesReturned))
65.
{
66.
int
m=0;
67.
USHORT
*pldSector=(
USHORT
*)((PSENDCMDOUTPARAMS)IdOutCmd)->bBuffer;
68.
for
(m=0;m<256;m++)
69.
buffer[m]=pIdSector[m];
70.
bFlag=TRUE;
//讀取硬盤信息成功
71.
}
72.
}
73.
}
74.
CloseHandle(hPhysicalDriyeIOCTL);
//關閉句柄
75.
}
76.
Return
bFlag;
77.
}
4 軟件版權保護方法調用
在程序初始化時,根據實際需要調用不同軟件保護方法,具體時間如下所示:
01.
BOOL
g_nSoftType=0;
//0,relese;1,demo;2
anti_copy;3 dog;
02.
BOOL
CTestApp::InitInstance()
03.
{
04.
if
(g_nSoftType==1){
05.
if
(DemoIsOverTime())
06.
return
FALSE;
07.
}
08.
else
if
(g_nSoftType==2){
09.
if
(!IsInstalledSoft())
10.
return
FALSE;
11.
}
12.
else
if
(g_nSoftType==3){
13.
if
(!Dog()){
14.
AfxMessageBox(“您沒有安裝軟件狗,請購買正版軟件。\n\n抱歉……”);
15.
return
FLASE;
16.
}
17.
}
18.
if
(!g_bDemo){
19.
CCommandLineInfo
cmdInfo;
20.
ParseCommandLine(cmdInfo);
21.
}
22.
}
以上簡單介紹了在Visual C++中實現軟件版權保護的方法,顯然,保護有效性從高到低依次爲硬件dog方法版本、註冊碼註冊方法、功能限制方法、時間限制方法,用戶可以根據工作實際需要進行選擇。