關(guān)于保護(hù)您的應(yīng)用程序的建議
VMProtect 是保護(hù)應(yīng)用程序代碼免遭分析和破解的可靠工具,但只有在正確構(gòu)建應(yīng)用程序內(nèi)保護(hù)機(jī)制并且沒有可能破壞整個(gè)保護(hù)的典型錯(cuò)誤的情況下才能最有效地使用,讓我們一起來(lái)看看為您的程序開發(fā)提供良好保護(hù)的三大關(guān)鍵要素。
>注冊(cè)程序
許多開發(fā)人員在設(shè)計(jì)自己的應(yīng)用程序注冊(cè)過(guò)程時(shí)犯的一個(gè)典型錯(cuò)誤是將整個(gè)注冊(cè)密鑰檢查封裝到一個(gè)單獨(dú)的函數(shù)中,該函數(shù)還返回一個(gè)易于理解的值:
function CheckRegistration(const RegNumber: String): Boolean; begin if RegNumber='123' then Result:=True else Result:=False; end; procedure TForm1.Button1Click(Sender: TObject); begin ... if not CheckRegistration(RegNumber) then exit; Application.CreateForm(TForm2, Form2); Form2.ShowModal; ... end;
使用這種方法,入侵者甚至不需要了解密鑰檢查算法。他可以簡(jiǎn)單地修改檢查程序開頭的代碼,使其始終返回正確的注冊(cè)密鑰值:
function CheckRegistration(const RegNumber: String): Boolean; begin Result:=True; exit; ... end;
一種更有效的密鑰校驗(yàn)方法是將正確性校驗(yàn)嵌入到程序的主要運(yùn)行邏輯中,使注冊(cè)密鑰校驗(yàn)算法與調(diào)用過(guò)程算法密不可分。我們還建議將操作邏輯與注冊(cè)碼檢查程序“混合”起來(lái),以便在繞過(guò)檢查時(shí)使程序失敗。對(duì)于上面的示例,這可以按如下方式完成:
function CheckRegistration(const RegNumber: String): Boolean; begin if RegNumber='123' then begin Application.CreateForm(TForm2, Form2); Result:=True end else Result:=False; end; procedure TForm1.Button1Click(Sender: TObject); begin ... Form2:=nil; if not CheckRegistration(RegNumber) then exit; Form2.ShowModal; ... end;
如果 CheckRegistration 函數(shù)是這樣實(shí)現(xiàn)的,入侵者將不得不分析注冊(cè)碼檢查的所有細(xì)節(jié)的代碼,以便繞過(guò)它。如果此應(yīng)用程序受 VMProtect 保護(hù),則建議對(duì) CheckRegistration 函數(shù)和 TForm1.Button1Click 過(guò)程進(jìn)行虛擬化。為了使黑客攻擊更加復(fù)雜,您可以打開“超級(jí)”保護(hù)模式以結(jié)合代碼變異和后續(xù)虛擬化。
>檢查注冊(cè)碼
開發(fā)人員犯的另一個(gè)嚴(yán)重錯(cuò)誤是注冊(cè)密鑰檢查的錯(cuò)誤實(shí)施。通常將輸入的密鑰與正確的值進(jìn)行簡(jiǎn)單比較。破解者可以通過(guò)跟蹤字符串比較函數(shù)的參數(shù)輕松匹配密鑰的正確值:
var ValidRegNumber: String; ... function CheckRegistration(const RegNumber: String): Boolean; begin if RegNumber=ValidRegNumber then Result:=True else Result:=False; end;
為避免這種情況,我們建議比較密鑰的哈希值,而不是它們的實(shí)際值。哈希函數(shù)是不可逆的,所以破解者無(wú)法從哈希中檢索到真正的密鑰值,并且必須花費(fèi)更多的時(shí)間來(lái)研究程序,因?yàn)楝F(xiàn)在需要分析更多的代碼片段,而不僅僅是注冊(cè)密鑰檢查程序:
var ValidRegNumber: String; ... function CheckRegistration(const RegNumber: String): Boolean; begin if RegNumber=ValidRegNumber then Result:=True else Result:=False; end;
當(dāng)使用 VMProtect 保護(hù)應(yīng)用程序時(shí),應(yīng)處理 HashPJW 和 CheckRegistration 函數(shù)以使黑客的活動(dòng)復(fù)雜化。
>保存檢查結(jié)果
通常,即使是在注冊(cè)程序上花費(fèi)大量時(shí)間的開發(fā)人員也不會(huì)適當(dāng)注意保護(hù)注冊(cè)程序的結(jié)果。下面的示例使用全局變量來(lái)存儲(chǔ)和控制調(diào)用序列號(hào)檢查過(guò)程之前應(yīng)用程序的注冊(cè)狀態(tài)。對(duì)于入侵者來(lái)說(shuō),找到一個(gè)全局變量是小菜一碟——他只是比較注冊(cè)前后的數(shù)據(jù)段。順便說(shuō)一下,流行的 ArtMoney 程序使用相同的原理。
var IsRegistered: Boolean; ... procedure TForm1.Button1Click(Sender: TObject); begin ... if not IsRegistered then IsRegistered:=CheckRegistration(RegNumber); if not IsRegistered then exit; ... end;
為避免這種情況,我們建議將與程序注冊(cè)相關(guān)的所有檢查結(jié)果存儲(chǔ)在動(dòng)態(tài)內(nèi)存中。在這種情況下,在注冊(cè)之前和之后掃描數(shù)據(jù)段以查找修改后的內(nèi)存塊變得毫無(wú)用處。這是一個(gè)非常簡(jiǎn)單的示例,演示如何將結(jié)果存儲(chǔ)在動(dòng)態(tài)分配的內(nèi)存中:
type PBoolean = ^Boolean; var IsRegistered: PBoolean; ... procedure TForm1.Button1Click(Sender: TObject); begin ... if not IsRegistered^ then IsRegistered^:=CheckRegistration(RegNumber); if not IsRegistered^ then exit; ... end; ... initialization New(IsRegistered);
這些是使用內(nèi)置保護(hù)機(jī)制的最簡(jiǎn)單方法。注冊(cè)程序、注冊(cè)密鑰檢查和存儲(chǔ)結(jié)果的實(shí)際實(shí)現(xiàn)僅限于開發(fā)人員的創(chuàng)造力。無(wú)論如何,您應(yīng)該在開發(fā)自己的保護(hù)機(jī)制時(shí)了解這些潛在的錯(cuò)誤以避免它們。
以上便是本篇文章的分享,如果您有任何疑問或者想獲取更多產(chǎn)品試用/授權(quán)/價(jià)格信息,請(qǐng)點(diǎn)擊VMProtect了解。