余彥 萬毅
摘 要: 作為最常用的軟件保護(hù)方式之一,序列號保護(hù)面臨著最多的攻擊者的研究。破解者主要的攻擊過程分為黑盒階段,動態(tài)分析階段,靜態(tài)分析階段和編輯階段。動態(tài)分析可以理解成一個遵循“定位保護(hù)代碼-修改二進(jìn)制代碼-測試”的破解循環(huán)。從該破解循環(huán)入手,提出一種新的程序架構(gòu),在校驗代碼之前加入某種規(guī)則決定是否進(jìn)行校驗,并將其嵌入主程序的不同位置,形成的對主程序的校驗位置的組合有2N種,這可為軟件提供更有效的保護(hù)措施。
關(guān)鍵詞: 軟件保護(hù); 序列號; 動態(tài)分析; 軟件破解
中圖分類號:TP311.1 文獻(xiàn)標(biāo)志碼:A 文章編號:1006-8228(2015)05-22-04
Abstract: As one of the most commonly used method of software protection, serial number protection is facing up to the crackers' research. The main process of software attacking is divided into black box stage, dynamic analysis stage, static analysis stage and editing stage. Dynamic analysis stage can be understood as a follow "positioning the protection code-modify the binary code-test" of the work cycle. From the work cycle of dynamic analysis stage, we put forward a new program architecture, by adding certain rules before deciding whether to execute the code for checking serial number, and to embed them into the main program for n times, so there are 2n different kinds of combinations of the code for checking serial number to form. Thus the software can be protected more effectively.
Key words: software protection; serial number; dynamic analysis; software cracking
0 引言
在計算機(jī)軟件技術(shù)高速發(fā)展的今天,軟件產(chǎn)品早已作為知識產(chǎn)權(quán)受到法律保護(hù)。可是在我國,即使有各種各樣的法律,軟件被盜版問題依然很嚴(yán)重。根據(jù)商業(yè)軟件聯(lián)盟(Business Software Alliance)公布的調(diào)查報告[1]顯示,2013年的盜版軟件安裝率為74%,雖然較前幾年(2011:77%,2009:79%,2007:84%)有所下降,但依然處于非常高的比例,據(jù)該調(diào)查報告顯示,盜版軟件的商業(yè)價值達(dá)到87億美元。因此,軟件保護(hù)技術(shù)的研究依然是熱點課題。
軟件保護(hù)技術(shù)中最常見的是序列號保護(hù)技術(shù)。針對序列號保護(hù),本文提出了一種新的程序架構(gòu),其關(guān)鍵是將校驗的代碼隨機(jī)多次嵌入主程序的不同位置,而校驗代碼之前加入某種規(guī)則決定是否進(jìn)行授權(quán)校驗,使得程序可以根據(jù)不同運行狀態(tài)而進(jìn)入不同位置的校驗代碼段,從而增加盜版者的破解難度。
1 序列號保護(hù)機(jī)制原理
作為最常見的軟件保護(hù)模型,序列號保護(hù)[2]的結(jié)構(gòu)如圖1所示。每次程序開始運行時,需要先校驗保存在本地的序列號。如果校驗未通過,如序列號不正確或序列號有效期已過,則要求用戶輸入合法的序列號,否則不允許進(jìn)入受保護(hù)的主程序。當(dāng)校驗通過,程序便處于合法運行狀態(tài),可以使用受保護(hù)的功能或算法等。
[啟動程序][用戶程序][校驗序列號] [進(jìn)入主程序][程序結(jié)束][輸入序列號] [T][F]
圖1 序列號校驗流程
對于獲得了序列號的用戶來說,校驗過程是透明的,用戶只需要輸入從軟件廠商購買的序列號,校驗過程由本地程序自動完成[3]。校驗過程可用如下公式表示。
⑴ 軟件廠商獲得用戶信息后計算序列號:
序列號=F(用戶信息)
⑵ 用戶獲得序列號后在本地進(jìn)行校驗:
用戶信息=G(序列號)
購買者如果隨意將用戶信息和對應(yīng)的序列號非法分發(fā)給其他未授權(quán)使用者,軟件廠商無法禁止其使用。因此本文采取硬件信息作為用戶信息,如此,即使序列號被非法分發(fā),也因為硬件不同而無法在不同的機(jī)器上使用,從而可以更好的保護(hù)軟件。
2 破解者的主要攻擊方法
整個破解的過程可以分為若干個階段,在最初的幾個階段中,破解者的任務(wù)主要是分析程序,試圖弄明白程序的內(nèi)部結(jié)構(gòu)及其行為模式。而在后面幾個階段,破解者則會使用前幾個階段中獲得的信息,按具體需要對程序進(jìn)行修改。我們把破解過程大致分為四個階段[4]。
⑴ 黑盒階段
在黑盒分析階段,破解者并不了解程序的內(nèi)部構(gòu)造,對其而言,程序就是一個“黑盒”。破解者會試圖給程序輸入一些數(shù)據(jù),并觀察程序的輸出,然后根據(jù)程序的行為做出某些推斷。
⑵ 動態(tài)分析階段
在動態(tài)分析階段,破解者開始分析程序的內(nèi)部行為,雖然這時他仍然會執(zhí)行程序,但是他這時會記錄在輸入不同的數(shù)據(jù)后,程序會執(zhí)行哪些不同的部分。
⑶ 靜態(tài)分析階段
為了更好的理解程序的作用,破解者在動態(tài)分析過后會直接分析代碼本身,這就是靜態(tài)分析。
⑷ 編輯階段
前三個階段的工作使得破解者可以弄清楚他所關(guān)心的算法,找到了秘鑰所在。但如果破解者還需要對程序進(jìn)行修改,例如刪除檢查軟件序列號部分的代碼,或者是抹除程序中用來標(biāo)識用戶信息的指紋水印等,則需要驚醒這個步驟對原程序進(jìn)行編輯。
動態(tài)分析中的破解循環(huán),對于破解者來說,對一個程序進(jìn)行動態(tài)分析是需要遵循“定位保護(hù)代碼-修改二進(jìn)制代碼-測試”的破解循環(huán)來工作。如圖2所示,在定位保護(hù)代碼的階段,破解者需要找到程序的保護(hù)代碼(比如校驗序列號的代碼段)在程序中的位置,并且在接下來的修改階段對其進(jìn)行一系列的修改使程序能按其方式來運行。對二進(jìn)制代碼進(jìn)行的修改包括去除舊的指令,增加新的指令以及對原有指令進(jìn)行修改。最后,破解者還要測試經(jīng)過修改后的程序是否能按照其意愿進(jìn)行工作,否則將進(jìn)行下一次破解循環(huán)。本文提出的程序結(jié)構(gòu)就是從破解循環(huán)入手,增加其動態(tài)分析程序的阻力,通過增加程序運行時的不確定性讓程序在每次獨立運行時都會動態(tài)的選擇不同的執(zhí)行路徑,讓破解者無法輕易找到序列號的校驗代碼所在。
圖3是采用objdump工具對作者的程序進(jìn)行反匯編得到的結(jié)果。圖3左側(cè)是未經(jīng)過修改的程序,MainWindow::core()是一個函數(shù),用于代表程序的主體部分,其地址為0x00405040。圖片左側(cè)下方的內(nèi)容是軟件的序列號校驗?zāi)K其中的一段。進(jìn)入程序主體部分之前,需要經(jīng)過序列號的校驗。這段匯編代碼中有一條判斷語句:test %al,%al,其功能是如果用戶輸入的序列號通過了校驗,那么就進(jìn)入主程序部分(地址0x00405040)繼續(xù)執(zhí)行,否則就跳轉(zhuǎn)至程序的結(jié)束部分的地址(0x004059b0)??梢钥闯?,對軟件的保護(hù)依賴于序列號的校驗是否成功。如果攻擊者對程序先進(jìn)行反匯編,然后找到這段控制序列號校驗邏輯的代碼,將其的跳轉(zhuǎn)邏輯修改成無論序列號校驗是否成功都跳轉(zhuǎn)至程序的主體部分繼續(xù)執(zhí)行,那么序列號的校驗?zāi)K也就無法對軟件提供保護(hù)了。如圖3右下方代碼段所示,將匯編程序跳轉(zhuǎn)邏輯修改后,無論序列號校驗的結(jié)果如何,程序始終都會執(zhí)行MainWindow::core()(在修改過的程序中該函數(shù)的地址為0x00404fd0)。也就是說,如果通過動態(tài)分析的手段找出了軟件的序列號校驗的代碼并對其功能進(jìn)行修改,那么即使不知道序列號校驗的算法,也可以直接繞過序列號校驗的部分直接非法的使用該軟件。
3 一種新的抵抗動態(tài)分析的軟件模式
如前文所述,破解者在動態(tài)分析階段會試圖找出程序的序列號校驗?zāi)K,并修改其邏輯已獲得非法使用程序的目的。動態(tài)分析主要是遵循“定位保護(hù)代碼-修改二進(jìn)制代碼-測試”的破解循環(huán)來工作的,其中最重要的環(huán)節(jié)就是定位二進(jìn)制代碼,如果破解者無法順利定位序列號校驗部分的代碼,也就無法針對其進(jìn)行攻擊。傳統(tǒng)的商業(yè)軟件對于程序的保護(hù)一般是將程序的序列號校驗部分放在程序的最開始,這樣,攻擊者跟蹤程序的運行步驟不久后比較容易找出程序的校驗?zāi)K。本系統(tǒng)的設(shè)計主要目的是提高破解者對代碼動態(tài)分析的難度,并且輔助以注冊碼的安全生成機(jī)制而提高軟件的安全性。
防止動態(tài)分析的手段,從動態(tài)分析階段入手,我們提出了以下更具復(fù)雜性和隨機(jī)性的機(jī)制來保護(hù)軟件。
⑴ 增加程序中校驗序列號的次數(shù),也就是說,不僅僅在軟件安裝時校驗序列號,而在軟件的使用過程中可以嵌入多段校驗序列號的代碼。
⑵ 校驗序列號時不采用函數(shù)調(diào)用的方式,而是直接將代碼嵌入到需要校驗序列號的位置,這樣一來,攻擊者無法通過函數(shù)的調(diào)用頻率來分析該函數(shù)是否是校驗序列號的函數(shù)。
⑶ 在校驗的代碼段前增加一個開關(guān),這個開關(guān)的狀態(tài)決定了是否進(jìn)入校驗代碼段。如果開關(guān)的狀態(tài)可以隨機(jī)化,那么對于整個程序來說,不同位置的校驗狀態(tài)組合結(jié)果也就是隨機(jī)的。開關(guān)的狀態(tài)可以由開發(fā)人員自己決定,例如使用主程序的某個變量來決定,或者使用當(dāng)前的時間,還可以將二者結(jié)合某個隨機(jī)值運算而成。加入這種機(jī)制后,如果在主程序代碼段內(nèi)嵌入了N段校驗代碼,對于整個程序的校驗位置的組合來說理論上有2N種狀態(tài)。這種隨機(jī)性的加入使得代碼的破解難度呈指數(shù)級增加。
在設(shè)計開關(guān)時,我們提出三種方法。第一種是取系統(tǒng)的時間,根據(jù)其奇偶性作為開關(guān)的值;第二種是取系統(tǒng)中一個叫做State_Output_Counts的全局變量的值,State_Output_Counts是軟件中用于記錄程序運行狀態(tài)語句輸出次數(shù)的變量,根據(jù)其奇偶性作為開關(guān)的值;第三種是將系統(tǒng)當(dāng)前時間和上述State_Output_Counts變量結(jié)合起來進(jìn)行異或計算,根據(jù)得到的結(jié)果的奇偶性作為開關(guān)變量的值。每次決定具體使用哪一種方法之前取隨機(jī)數(shù),根據(jù)隨機(jī)數(shù)的值對3求模,根據(jù)其結(jié)果決定使用哪一種開關(guān)。具體代碼如下:
r=rand();
seconds=time(NULL);
r=r%3;
switch (r)
{ case 0:Check_Switch=seconds;break;
case 1: Check_Switch=State_Output_counts; break;
case 2: Check_Switch=seconds^State_Output_Counts; bresk;
}
⑷ 將校驗序列號的代碼和程序的運算模塊結(jié)合起來,將校驗序列號的代碼段嵌入程序的運算模塊內(nèi),并且根據(jù)序列號校驗的結(jié)果決定運算模塊的結(jié)果是否正確,如果通過校驗代碼的驗證后,運算模塊可以正常使用。如果序列號校驗不通過,則可以通過校驗?zāi)K傳遞給運算模塊一個錯誤的變量值使運算模塊失效或者輸出錯誤的結(jié)果。攻擊者很難發(fā)現(xiàn)運算模塊發(fā)生錯誤,而攻擊者如果采用修改二進(jìn)制代碼的方式繞過校驗代碼部分,運算模塊也無法使用,也就起到了保護(hù)程序的作用。如果再結(jié)合第⑶步所描述的方法,運算模塊中的序列號校驗代碼不一定每次都會執(zhí)行,因此在序列號不合法時運算模塊的功能有時會產(chǎn)生正確的結(jié)果而有時又會產(chǎn)生錯誤的結(jié)果,更加迷惑攻擊者。當(dāng)序列號不正確時,程序并不會提示用戶序列號錯誤,而是直接給出錯誤的運算結(jié)果,因此攻擊者很難分析出序列號校驗代碼段的位置。
例如,原始代碼在主程序中完成一個加法功能的語句a+b,我們將其更改成為一個函數(shù)int Add(int a,int b),并且將序列號校驗的代碼嵌入其中,如果序列號校驗通過就正常的返回兩個參數(shù)的和,如果序列號校驗不通過,并不會有錯誤提示,但是返回值會是兩個參數(shù)的乘積,如此一來,攻擊者無法找到校驗的位置,也無法發(fā)現(xiàn)最終的運算結(jié)果是一個錯誤的答案。具體代碼如下:
int Add(int a,int b)
{ switch (Prog_State)
{ case true: return a+b;break;
case false: return a*b;break;
}
}
具體實現(xiàn)中,本文在主程序代碼中嵌入了5次校驗序列號的代碼,理論上應(yīng)該有25種校驗狀態(tài)的組合。當(dāng)校驗不通過時,計算結(jié)果產(chǎn)生了錯誤,也從另一個方面阻止了軟件的非法使用。
4 系統(tǒng)設(shè)計和實現(xiàn)
如圖4所示,該架構(gòu)中客戶在程序開始時先獲得用戶ID,本系統(tǒng)中的用戶ID采用CPUID與MAC地址組合的方式生成。得到用戶ID后進(jìn)入客戶端的序列號校驗?zāi)K。校驗通過以后,可以進(jìn)入主程序,序列號的校驗部分是由開發(fā)人員無規(guī)律隨機(jī)的分散在主程序代碼中的,校驗代碼段之前會有一個開關(guān)決定進(jìn)入或是跳過校驗代碼,開關(guān)的狀態(tài)可以由多種變量的狀態(tài)決定。
對于服務(wù)器端,在用戶需要注冊時可以通過通信模塊接收用戶ID并通過序列號生成模塊計算出序列號并返回給用戶,并將用戶ID和生成的序列號保存在服務(wù)器本身的數(shù)據(jù)庫中。
4.1 序列號申請模塊
服務(wù)器計算出序列號的過程可用公式:序列號=F(用戶ID)來表示。其中用戶ID代表了用戶的個人信息,可以是電話號碼或者是銀行卡號等信息。但這些信息很容易被重復(fù)使用并且無法保證是否是用戶本人,本文采取提取用戶機(jī)器的硬件序列號(CPU ID和MAC地址)作為用戶ID來保證其惟一性和不可傳播性。由于用戶的硬件基本上不會隨便更換,因此可以保證用戶在使用軟件的過程中不會因此產(chǎn)生麻煩。公式中F代表的是根據(jù)用戶ID生成序列號所使用的算法,本文中使用的是MD5消息摘要算法。
序列號申請模塊主要分為生成用戶ID和序列號的生成與驗證兩個部分。
4.1.1 生成用戶ID的方式
本文采用了CPU ID和MAC地址共同作為用戶ID,但是在獲得了CPU ID和網(wǎng)卡MAC地址后需要構(gòu)造一個可靠的用戶ID,若是簡單的將其連接必然會造成安全性上的欠缺,又因為通用的MD5算法是公開的,因此如果對用戶ID 的構(gòu)成方式進(jìn)行復(fù)雜化則可以迷惑攻擊者無法輕易的推測出用戶ID 的構(gòu)造方式。本文通過采取將CPU ID和MAC地址交叉組合的方式,并在其后添加一個附加的自定義字串。例如CPU ID為abcdefgh而MAC地址為12345678則構(gòu)成的用戶ID為a1b2c3d4e5f6g7h803914256。
4.1.2 序列號的生成與驗證
本文采用MD5消息摘要算法來生成序列號。MD5算法的特點[5]包括:易于從原始信息計算出MD5值,而從MD5值無法逆推算出原始數(shù)據(jù),任意長的數(shù)據(jù)計算后得出的MD5值都是固定長度的。對于序列號的生成過程和校驗過程在計算上是同一個過程??蛻舳藱C(jī)器先在機(jī)器內(nèi)計算出自己的用戶ID并將其發(fā)送給服務(wù)器端,當(dāng)服務(wù)器端收到了用戶ID后根據(jù)收到的用戶ID計算其MD5值,并以此作為合法的序列號返回給用戶。如果用戶收到了序列號后,再在本地重復(fù)這一過程,根據(jù)同一個公式去計算本地的用戶ID是否與所得到的序列號相同。
4.2 程序運行結(jié)果
程序運行結(jié)果如圖5所示。程序左側(cè)的文本框采用獨立線程每隔三秒會顯示程序是否運行在合法狀態(tài),即使破解者找到了注冊序列號的位置繞過了最初注冊時的驗證,但是每次運行程序時,隨機(jī)出現(xiàn)的校驗位置的狀態(tài)組合都不一樣,如果攻擊者并不知曉序列號而只是繞過了驗證部分,則在此處無法再次通過驗證因此程序提示用戶使用的是未注冊版本,進(jìn)而可以保護(hù)主程序無法輕易的被破解和非法使用。程序下方還顯示了當(dāng)前五個開關(guān)的狀態(tài),可以看出,當(dāng)前的開關(guān)狀態(tài)為“10110”,也就是說,主程序中的有五個位置需要進(jìn)行序列號校驗,而在程序運行完一次后只有第一個、第三個和第四個位置發(fā)生了校驗,而第二個和第五個位置的校驗代碼并沒有運行。多次運行得到的開關(guān)狀態(tài)并不相同,具有隨機(jī)性。
5 結(jié)束語
本文提出了一種新的抵抗動態(tài)分析的軟件保護(hù)模型,并在LINXU平臺下采用QT和C++編程實現(xiàn)了該系統(tǒng),經(jīng)過實驗驗證能完整地提供序列號保護(hù)所需的功能,并較傳統(tǒng)序列號保護(hù)方式更具有復(fù)雜性和隨機(jī)性。該系統(tǒng)可以較好地抵御攻擊者對程序的動態(tài)分析過程。該程序結(jié)構(gòu)簡單,卻能大大增加攻擊者的破解難度和破解代價,并且其結(jié)構(gòu)的復(fù)雜度可以自己控制。因此,該系統(tǒng)具有較好的實用性和應(yīng)用前景。本系統(tǒng)還有需要改進(jìn)的地方,如太過于頻繁的驗證可能影響計算的性能,用戶如果更換硬件則需要更換序列號等問題,這些將是下一步需要研究的問題。
參考文獻(xiàn):
[1] Business Software Alliance. The Compliance Gap BSA GLOBAL SOFTWARE SURVEY[R/OL].Washington, DC: Business Software Alliance, 2014. [2014-06].http://globalstudy.bsa.org/2013/downloads/studies/2013GlobalSurvey_Study_en.pdf
[2] 許旭,潘志剛.一種基于一機(jī)一碼的軟件激活序列號生成方案[J].浙江科技學(xué)院學(xué)報,2010.4.
[3] 龐啟寧.一種基于注冊碼的軟件加密算法[J].通信與廣播電視,2008.2.
[4] Christian Collberg,Jasvir Nagra,Surreption Software[M].人民郵電出版社,2012.
[5] 許琪.MD5加密算法的研究[J].福建電腦,2014.3.