代碼保護(hù)軟件 VMProtect 用戶手冊(cè): 保護(hù)應(yīng)用程序的三大要素
VMProtect 是一種很可靠的工具,可以保護(hù)應(yīng)用程序代碼免受分析和破解,但只有在應(yīng)用程序內(nèi)保護(hù)機(jī)制正確構(gòu)建且沒有可能破壞整個(gè)保護(hù)的嚴(yán)重錯(cuò)誤的情況下,才能實(shí)現(xiàn)最好的效果。 讓我們一起來看看為應(yīng)用程序提供良好保護(hù)的關(guān)鍵要素。
>注冊(cè)程序
許多開發(fā)人員在設(shè)計(jì)自己的應(yīng)用程序注冊(cè)過程時(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;
使用這種方法,入侵者甚至不需要理解密鑰檢查算法。他可能只是在檢查過程的開頭修改代碼,就可使其始終返回正確的注冊(cè)密鑰值:
function CheckRegistration(const RegNumber: String): Boolean; begin Result:=True; exit; ... end;
檢查密鑰的一種更有效的方法是將檢查的正確性嵌入到程序的主要操作邏輯中,使得注冊(cè)密鑰檢查的算法不能與調(diào)用過程的算法分離。我們還建議將操作邏輯與注冊(cè)密鑰檢查過程“混合”,以便在繞過檢查時(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;
如果這樣來實(shí)現(xiàn)CheckRegistration的功能,入侵者想要繞過它的話,就必須分析所有細(xì)節(jié)中的注冊(cè)密鑰檢查代碼。如果此應(yīng)用程序受VMProtect保護(hù),則建議同時(shí)虛擬化CheckRegistration函數(shù)和TForm1.Button1Click過程。 為了使黑客更難破解程序,你可以打開“Ultra”保護(hù)模式,將代碼突變和虛??擬化結(jié)合起來。
>檢查注冊(cè)碼
開發(fā)人員常犯的另一個(gè)錯(cuò)誤是注冊(cè)密鑰檢查的錯(cuò)誤實(shí)現(xiàn)。輸入的密鑰通常只是與正確的值進(jìn)行比較。通過跟蹤字符串比較函數(shù)的參數(shù),cracker可以輕松匹配密鑰的正確值:
var ValidRegNumber: String; ... function CheckRegistration(const RegNumber: String): Boolean; begin if RegNumber=ValidRegNumber then Result:=True else Result:=False; end;
為避免這種情況,我們建議比較密鑰的哈希值,而不是實(shí)際值。哈希函數(shù)是不可逆的,因此破解者無法從哈希中檢索真正的密鑰值,并且必須花費(fèi)更多的時(shí)間來研究程序,因?yàn)楝F(xiàn)在需要分析更多的代碼片段,而不僅僅是注冊(cè)密鑰檢查過程:
var HashOfValidRegNumber: Longint; ... // Peter Weinberger's PJW hashing algorithm example of use function HashPJW(const Value: String): Longint; var I:Integer; G:Longint; begin Result:=0; for I:=1 to Length(Value) do begin Result:=(Result shl 4)+Ord(Value[I]); G:=Result and $F0000000; if G<>0 then Result:=(Result xor (G shr 24)) xor G; end; end; function CheckRegistration(const RegNumber: String): Boolean; begin if HashPJW(RegNumber)=HashOfValidRegNumber then Result:=True else Result:=False; end; ... initialization HashOfValidRegNumber:=HashPJW(ValidRegNumber); end.
使用VMProtect保護(hù)應(yīng)用程序時(shí),應(yīng)使用 HashPJW 和 CheckRegistration 功能,讓黑客更難入侵。
>保存檢查結(jié)果
通常,即使在注冊(cè)程序上花費(fèi)大量時(shí)間的開發(fā)人員也很少注意保護(hù)注冊(cè)程序的結(jié)果。下面的示例在調(diào)用序列號(hào)檢查過程之前使用全局變量來存儲(chǔ)和控制應(yīng)用程序的注冊(cè)狀態(tài)。 對(duì)于入侵者來說,找到一個(gè)全局變量是件小事 - 他只需要在注冊(cè)之前和之后比較數(shù)據(jù)段。順便說一下,流行的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è)之前和之后掃描修改的存儲(chǔ)塊的數(shù)據(jù)段是無用的。這是一個(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)造性。無論如何,你應(yīng)該知道這些常見錯(cuò)誤,避免在開發(fā)自己的保護(hù)機(jī)制時(shí)出現(xiàn)這種錯(cuò)誤。
VMProtect 在線訂購有優(yōu)惠噢~ 立即購買正版VMProtect>>>