標籤:
開發軟體的實踐中,通常將軟體分為幾種版木:①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初次運行時給上述變數的賦值
對於目前時間:
SYSTEMTIME stCur;
2.GetSystemTnne(&stCur);
3.nYearCUFstCur.wYear.nMonthCur=stCur.wMonth;
4.nDateCur=stCur.wDay;
起始時間和終止時間的賦值是在程式第一次運行時將目前時間和預設的期限寫入某個檔案當中,以後將這兩個時間同當前的系統時間進行比較,判斷軟體是否到期或者試用時間是否到期:
view sourceprint?01.String sFn=“c:\muxuanshe.sys”;
02.FII.E *fp=fopen(sFn,“rb”);
03.{
nDateO=nDateCur;
nYear0=n YearCur;
nMonthO=nMonthCur;
nDate=nDate0;
nYear=nYear0;
nMonth=nMonth0+1;
if(nMonth>12){
nMonth-=12;
nYcar++;
}//跨年度計算依次將起始時間、到期時間和目前時間及檔案的位元組數寫入c:\muxuanshe sys
14.}
2.3比較時間
每次運行時比較目前時間與檔案記錄中的時間,有兩種情況,一是判斷是否將系統系統時間提前:
if(IsPrcTime(nYear0,nMonth0,nDate0)||IsPreTime(nYear01d,nMo nthOld,nDateOJd)))其中nYearOld,nMonthOld,nDateOld為上次啟動並執行時間:
view sourceprint?01.BOOL JsOverTime(int nYear,int nMonth,int nDate)
02.{
SYSTEMTIME st;
GetSysten/rime(&st);
if(st.wYear>nYear)
return TRUE;
else if(st.wYearnMonth)
return TRUE;
else if(st.wMonth==nMonth&&st.wDay>nDate)
return TRUE;
return FALSF;
12.}
如果您前移了機器時間則將終止時間nYear=l並寫入c:\muxuanshe.sys,軟體以後終止運行!
另一種情況是對於正常的剩餘時問計算:IsOverTime(nYear,nMonth,nDate),不再贅述,具體實現請參見範例程式碼。
這裡介紹的方法主要是要注意存放時間的檔案要保密,如果知道了時間存放位置,那麼時間限制就很容易被解除。也可以用其他更為穩妥的方法將時間存放,如存放在註冊表中。
3根據機器碼實現軟體註冊
機器碼指與電腦硬體(CPU、網號、硬碟)有關的串號,如硬碟序號、MAC地址等,編寫軟體的人常用機器碼作為產生軟體序號的依據,目的是區分使用者,確保自己的軟體使用受控,下面通過讀取使用者電腦硬碟卷序號,經一定的密碼編譯演算法進行換算後,返回給使用者一個產品註冊碼,由於硬碟卷序號是唯一的,提供的產品註冊碼也是唯一的,使用者利用該註冊碼通過驗證後獲得軟體全部功能。
在筆者的編程實踐中發現有時候由於所使用的函數不正確,常常不能正確擷取硬碟的序號,這裡就這一問題進行討論。
3.1不正確的序號
利用GetVolumelnformation擷取的電腦硬碟卷序號,不是正確的唯一序號:
view sourceprint?01.void CWJGISApp::Register()
02.{
DWORD VolumeSerialNumber;
GetVolumeInformation(“c:\“,NULL,NULL,&VolumeSeriaINumber,NULL,NULL,NULL,NULL);
char charVolumeSerialNumber[l0];
itoa(VolumeSerlalNumber,charVoIumeSerialNumber,10);
CString strTemp;
strTemp.Format(“%s”,charVolumeSerialNumber);
09.}
該函數擷取的序號在硬碟格式化後會發生變化。
3.2正確擷取硬碟的序號
正確擷取硬碟序號代碼如下:
view sourceprint?01.
//讀般硬碟序號函數
char* CGetHDSerial::GetHDSerial()
{
m_buffer[0]=‘\n‘;
//得到當前作業系統版本
OSVERSIONINFO OSVersionInfo;
OSVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&OSVersionInfo);
if(OSVersionInfo.dwPlatformld != VER_PLATFORM_WIN32_NT)
{
//Windows 9x/ME下讀取硬碟序號
WORD m_wWin9xl‘HDSerial[256];
Win9xReadHDSerial(m_wWin9xHDSerial);
strcpy (m_buffer, WORDToChar(m _wWin9xHDSerial, 10, 19));
}
else
{
//Windows NT/2000/XP下讀取硬碟序列弓
DWORD m_wWinNTHDSerial[256];
//判斷是否有SCSI硬碟
if (!WinNTReadIDEHDSerial(m_wWinNTHDSerial))
WinNTReadSCSIHDSerial(m_wWinNTHDSerial);
strcpy (m_buffer,DWORDToChar(m_wWinNTHDSerial,10, 19));
}
return m_buffer;
}
//Windows NT/2000/XP下讀取IDE硬碟序號
BOOL CGetHDScriaI::WinNTReadIDEHDSerial(DWORD* buffer)
{
BYTE JdOutCmd [sizeof(SENDCMDOUTPARAMS)+IDFNTIFY_BUFFER_SIZE - 1];
BOOL bFlag = FALSE;
int drive = 0;
Char driveName[256];
HANDLE hPhysicalDrivelOCTL=0;
Sprintf(driveName,“\.\PhysicalDrive%d”,drive);
//Windows NT/2000/XP 下建立檔案需要管理員權限
hPhysicalDriveIOCTL=CreateFile(driveName,GENERIC_READ|GENERIC_WRITE,
39.FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,NULL);
if(hPhysicalDriveIOCTL!=INVALID_HANDLE_VALUE)
{
GETVERSIONOUTPARAMS VersionParams;
DWORD cbBytesReturned=0;
//得到磁碟機的I/O控制器版本
memser((void*)&VersionParams,0,sizeof(VersionParams));
if(DeviceIoControl(hPhysicalDriveIOCTL,IOCTL_GET_VERSION,NULL,
48.0,&VersionPaiams,sizeof(VersionParams),sizeof(VersionParams),
&cbBytesReturned,NULL))
{
if(VersionParams.bIDEDeviceMap>0)
{
BYTE bIDCmd=0;//IDE或者ATAPI識別命令
SENDCMDINPARAMS scip;
//如果磁碟機是光碟機,採用命令IDE_ATAPI_IDENTIFY,command,
56.否則採用命令IDE_ATA_IDENTIFY讀取磁碟機資訊
bIDCmd=(VersionParams.bIDEDeviceMap?drive&0x10)?
58.IDE_ATAPI_IDENTIFY : IDE_ATA_IDENTIFY;
memset(&scip,0,sizeof(scip));
memset(IdOutCmd,0,sizeof(IdOutCmd));
//擷取磁碟機資訊
if(WinNTGetIDEHDInfo(hPhysicalDrivelOCTL,&scip,(PSENDCMDOUTPARMS)&
64.IdOutCmd,(BYTE)bIDCmd,(BYTE)drive,&cbBytesReturned))
{
int m=0;
USHORTpldSector=(USHORT)((PSENDCMDOUTPARAMS)IdOutCmd)->bBuffer;
for(m=0;m<256;m++)
buffer[m]=pIdSector[m];
bFlag=TRUE; //讀取硬碟資訊成功
}
}
}
CloseHandle(hPhysicalDriyeIOCTL); //關閉控制代碼
}
Return bFlag;
}
4 軟體著作權保護方法調用
在程式初始化時,根據實際需要調用不同軟體保護方法,具體時間如下所示:
view sourceprint?01.BOOL g_nSoftType=0;//0,relese;1,demo;2 anti_copy;3 dog;
02.BOOL CTestApp::InitInstance()
03.{
if(g_nSoftType==1){
if(DemoIsOverTime())
return FALSE;
}
else if(g_nSoftType==2){
if(!IsInstalledSoft())
return FALSE;
}
else if(g_nSoftType==3){
if(!Dog()){
AfxMessageBox(“您沒有安裝軟體狗,請購買正版軟體。\n\n抱歉……”);
return FLASE;
}
}
if(!g_bDemo){
CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);
}
22.}
以上簡單介紹了在Visual C++中實現軟體著作權保護的方法,顯然,保護有效性從高到低依次為硬體dog方法版本、註冊碼註冊方法、功能限制方法、時間限制方法,使用者可以根據工作實際需要進行選擇。
如何使用vc++限制軟體功能