利用硬體資訊實現共享軟體的安全註冊 (4千字)

看雪資料發表於2001-09-12

利用硬體資訊實現共享軟體的安全註冊

資訊產業部電子第二十二研究所青島分所 郎銳 
01-9-10 下午 12:50:48

--------------------------------------------------------------------------------


一、 引言

在網路相當發達的今天,一大批優秀的軟體湧現在網際網路上,我們可以根據需要隨意的下載、使用。這些軟體有一部分是免費的,使用者可以在免費的前提下無限期、不受限制的使用。但也有為數眾多的共享軟體是需要使用者註冊的,使用者可以免費使用一段時間,超過期限之後如果還未註冊,那麼將不能繼續使用軟體或是一些先進的、常用的功能將無法正常使用。只有使用者在完成註冊或交納一定的費用得到開發者反饋回的註冊碼之後方可正常使用。但現有的許多註冊方式是存在漏洞的,現在不少破解網站透過正常渠道購買回一個註冊碼之後將其公佈在其網站之上,更有甚者還提供有用於產成註冊碼的序號產生器。以上的種種行為侵犯了軟體開發者的智慧財產權,干擾了共享軟體的正常釋出。雖然國家也有保護智慧財產權的相關法律條文,但顯然在執行起來存在一定的難度,比如針對本文前面所述情況單是取證就相當困難。因此作為程式設計師的軟體開發者應當具有自我保護意識,利用自己的專業特長,透過程式控制來確保自己的每一個註冊碼只針對於一個軟體複製。本文將根據筆者的實際程式設計經驗,對一種結合物理硬體資訊的安全註冊方法的實現過程進行較全面的介紹。

二、 註冊源的採集

為了確保註冊碼的唯一性,在註冊源的採集上應當儘量選取一些唯一的、不易複製的軟、硬體資訊作為原始資訊。而硬體由於其不可複製性和物理唯一性成為了我們的首選目標,而且多數計算機配件在出廠時都有一個唯一的標識號,我們可以將其作為識別的依據。符合上述條件的標識號大致有硬碟的序列號、網路卡的序列號、BIOS中的主版序列號或主機出廠日期和標誌等幾種,考慮到硬體通用性、實現起來的難易程度以及系統安全性等多種因素以硬碟序列號為佳,因為網路卡隨說唯一性最好但不能保證每臺計算機都裝有網路卡,而ROM BIOS中F000H-FFFFH區域雖存有與硬體配置有關的資訊、F000H:FFF5H-F000H:FFFFH存有主機出廠日期和主機標誌值等引數,但在Windows 9x的保護模式下程式設計實現是比較困難的。雖然在Windows 9x保護模式下對硬碟序列號也不能按通常在DOS模式下的透過硬碟埠1F6H和1F7H直接讀取,但Windows API函式中提供的下面這個函式可以非常簡單的獲取到指定磁碟驅動器的序列號:

GetVolumeInformation("C:\\",NULL,NULL,&dwIDESerial,NULL,NULL,NULL,NULL);

第一個引數設為"C:\\"表示我們要讀取C盤驅動器的序列號。之所以選C盤,是因為我們不能保證使用者有多個分割槽,而C盤卻是每一個使用者都具有的。該函式成功呼叫完畢後,在DWORD型的變數dwIDESerial中就儲存了獲取到的32位長的磁碟序列號。註冊資訊採集到後,關鍵的問題就是如何讓使用者將其返回給開發者。一種較簡單的方法是把採集到的硬碟序列號與使用者輸入的註冊名經過位操作的簡單加密後存放到一個文字中透過郵件傳送給開發者。

三、 序號產生器的設計

開發人員得到從使用者返回的由硬碟序列號構成的註冊原始資訊後就要利用序號產生器生成註冊碼並反饋給使用者。一般來說,序號產生器要利用既定的位操作和不可逆演算法,生成使用者比較容易操作的字串註冊碼。在使用者方面的共享軟體裡也應有一個具有相同演算法的序號產生器用以動態計算以當前註冊名進行註冊的正確的註冊碼,然後對使用者輸入的註冊碼進行檢驗,如果不匹配則不予註冊。如果是從開發者反饋來的正確註冊碼,則透過標記配置檔案或是往登錄檔中寫入特定內容的鍵值以表明當前軟體是經過註冊的。而且共享軟體在每次執行時都要對使用者註冊碼進行實時檢測與判斷,這樣才能實現註冊限制功能。如果應用程式被複製到其他計算機上則會由於硬碟序列號的改變而導致註冊資訊的不匹配,因此仍然需要重新註冊,從而達到共享軟體的釋出目的。下面就是一段非常簡單的序號產生器實現程式碼:

開發者方:
//strSerial是由使用者返回的同註冊名進行過位運算的註冊源資訊
::strcpy(buf1,strSerial);
::strcpy(buf2,strName);
//再次進行位運算,取得硬碟序列號
for(int I=0;I<8;I++)
input[I]=buf1[I]^buf2[I];
//錯序與位操作,產生與註冊名有關的註冊碼
int Index[8]={7,5,3,1,6,4,2,0};
char Mask[8]={'Z','H','U','C','E','J','I','0'};
for(I=0;I<8;I++)
{
result[I]=input[Index[I]]^buf2[I];
result[I]=result[I]^Mask[I];
}
……

使用者方:
//根據輸入的字串計算出硬碟序列號
int Index[8]={7,5,3,1,6,4,2,0};
char Mask[8]={'Z','H','U','C','E','J','I','0'};
for(int I=0;I<8;I++)
{
input[I]=input[I]^buf2[I];
ouput[Index[I]]=input[I]^Mask[I];
}
dwSerialID=::atoll(output);//將序列號恢復成數值
//動態提取硬碟序列號
GetVolumeInformation("C:\\",NULL,NULL,&dwIDESerial,NULL,NULL,NULL,NULL);
If(dwSerialID==dwIDESerial)
{
……//註冊成功
}
else
{
……//註冊失敗
}

以上兩段程式碼僅用於舉例說明實現的方法,並未進行復雜的邏輯運算,在實際應用中應視共享軟體的自身價值、軟體實現的複雜程度等多種因素來決定採取多大的加密深度。即使對於一般的序號產生器也應加以2層以上的函式邏輯運算。對於共享軟體,不管其實現何種功能,最好採取線上註冊的方式,而且在同一個軟體系統中應有若干個註冊入口,只要一處註冊成功整個軟體就算註冊成功了。為了清晰的瞭解整個註冊過程,流程圖可以大致如下,並可根據具體做適當的調整:

小結:本文主要對共享軟體的安全註冊進行了討論。為了更方便、安全地實現對共享軟體的註冊可以大致遵循這樣幾個原則:選準註冊源、經常變動註冊演算法、加密註冊碼、管理好序號產生器防止外流、採用線上式的註冊方法。以上所述基本是筆者自己的實際經驗總結,由於能力有限,難免有所疏漏,應在具體程式設計中不斷對其加以改進完善。本文所引程式在Windows 98下由Microsoft Visual C++ 6.0編譯透過。

相關文章