本發(fā)明涉及信息安全技術領域,特別涉及一種對可執(zhí)行文件進行保護的方法和裝置。
背景技術:
在信息安全領域中,軟件作為一種寶貴的財富,軟件的安全性越來越受到單位、企業(yè)和個人的關注。軟件作為一種特殊的產品,由于其數字化的特征,從問世起就一直遭受盜版的困擾。盜版的存在不僅給軟件開發(fā)者造成了巨大的損失,也極大的阻礙了整個軟件行業(yè)的發(fā)展。
目前對于軟件中代碼的保護主要是基于應用層的軟件保護技術和基于硬件的保護方法。
常見的應用層的保護軟件有VMProtect虛擬機保護軟件等各種混淆器,對這種保護軟件的保護方式的分析完全可以在應用層進行,目前已經有各種破解插件可以利用,因此這種軟件保護技術的抗分析性較差。
基于硬件的保護方法主要是從程序文件中提取部分代碼到硬件保護裝置中,這樣軟件的一部分代碼在計算機中執(zhí)行,另外一部分在保護裝置中模擬執(zhí)行?;谟布谋Wo方法可以移植的代碼指令有限,受限于硬件的保護裝置的空間限制,移植的代碼的數量也有限。
技術實現要素:
有鑒于此,本發(fā)明的一個目的在于提供一種對可執(zhí)行文件的有效保護手段,以進一步提高軟件的安全性。
為此,本發(fā)明提供了一種對可執(zhí)行文件進行保護的方法,其包括:在運行可執(zhí)行文件時,所述可執(zhí)行文件中的預定代碼段的執(zhí)行過程中的至少部分過程不在應用層執(zhí)行而是在驅動層進行模擬執(zhí)行。
作為優(yōu)選,所述可執(zhí)行文件中預定位置處包括與實現所述預定代碼段的指令中的至少部分指令的功能對應的驅動層指令。
作為優(yōu)選,所述預定位置為所述可執(zhí)行文件中的預定數組或預定行。
作為優(yōu)選,所述至少部分指令中每條指令對應至少一條所述驅動層指令。
作為優(yōu)選,在所述可執(zhí)行文件中,所述至少部分指令被替換為包括與所述驅動層指令的調用相關的指令和/或函數在內的第一代碼段。
作為優(yōu)選,在運行所述可執(zhí)行文件時,應用層將所述驅動層指令發(fā)送至驅動層,并從驅動層接收相應的執(zhí)行結果。
作為優(yōu)選,通過以下步驟確定所述預定代碼段:分析所述可執(zhí)行文件中的多個函數,根據如下條件在所述多個函數中確定目標函數:對于實現所述目標函數的指令中的至少部分指令,存在功能對應的驅動層指令;將至少一個所述目標函數對應的代碼段確定為所述預定代碼段。
作為優(yōu)選,通過以下步驟確定所述預定代碼段:分析所述可執(zhí)行文件中的多個函數,在所述多個函數中將具有參數和返回值的函數確定為目標函數:將至少一個所述目標函數對應的代碼段確定為所述預定代碼段。
作為優(yōu)選,通過以下步驟確定所述預定代碼段:分析所述可執(zhí)行文件中的多個函數,在所述多個函數中將具有同一類型的參數和返回值的函數確定為目標函數:將至少一個所述目標函數對應的代碼段確定為所述預定代碼段。
本發(fā)明同時提供了一種對可執(zhí)行文件進行保護的裝置,包括:應用程序端,其配置為運行可執(zhí)行文件;驅動層模擬器,其配置為在可執(zhí)行文件運行時,對所述可執(zhí)行文件中的預定代碼段的執(zhí)行過程中的至少部分過程進行模擬執(zhí)行,其中,所述至少部分過程不在應用程序端執(zhí)行。
作為優(yōu)選,所述裝置還包括:處理單元,其配置為將與實現所述預定代碼段的指令中的至少部分指令的功能對應的驅動層指令寫入所述可執(zhí)行文件中預定位置處。
作為優(yōu)選,所述處理單元配置為將所述驅動層指令寫入所述可執(zhí)行文件中的預定數組或預定行處。
作為優(yōu)選,所述處理單元配置為,對于所述至少部分指令的每條指令,在所述預定位置寫入至少一條所述驅動層指令。
作為優(yōu)選,所述處理單元進一步配置為將所述可執(zhí)行文件中的所述至少部分指令替換為包括與所述驅動層指令的調用相關的指令和/或函數在內的第一代碼段。
作為優(yōu)選,所述處理單元進一步配置為在所述可執(zhí)行文件運行時將所述驅動層指令發(fā)送至所述驅動層模擬器,并從所述驅動層模擬器接收相應的執(zhí)行結果。
作為優(yōu)選,所述裝置還包括分析單元,其配置為分析所述可執(zhí)行文件中的多個函數,并將所述多個函數中的至少一個目標函數對應的代碼段確定為所述預定代碼段,其中,所述分析單元配置為根據如下條件確定所述目標函數:對于實現所述目標函數的指令中的至少部分指令,存在功能對應的驅動層指令。
作為優(yōu)選,所述裝置還包括分析單元,其配置為分析所述可執(zhí)行文件中的多個函數,并將所述多個函數中的至少一個目標函數對應的代碼段確定為所述預定代碼段,其中,所述分析單元配置為將具有參數和返回值的函數確定為所述目標函數。
作為優(yōu)選,所述裝置還包括分析單元,其配置為分析所述可執(zhí)行文件中的多個函數,并將所述多個函數中的至少一個目標函數對應的代碼段確定為所述預定代碼段,其中,所述分析單元配置為將具有同一類型的參數和返回值的函數確定為所述目標函數。
本發(fā)明在對可執(zhí)行文件進行保護時,將部分代碼或指令的執(zhí)行過程轉移至驅動層模擬執(zhí)行,這樣對軟件中代碼或指令的保護的對抗從應用層轉移到驅動層,進一步增加了調試難度,從而達到了保護軟件的目的。
附圖說明
圖1為本發(fā)明的對可執(zhí)行文件進行保護的方法的一個實施例的示意性流程圖;
圖2為本發(fā)明的對可執(zhí)行文件進行保護的方法的另一個實施例的部分示意性流程圖;
圖3為本發(fā)明的對可執(zhí)行文件進行保護的方法的又一個實施例的部分示意性流程圖;
圖4為本發(fā)明的對可執(zhí)行文件進行保護的方法的再一個實施例的部分示意性流程圖;
圖5為本發(fā)明的對可執(zhí)行文件進行保護的裝置的一個實施例的示意性框圖;
圖6為本發(fā)明的對可執(zhí)行文件進行保護的裝置的另一個實施例的示意性框圖;
圖7為本發(fā)明的對可執(zhí)行文件進行保護的裝置的又一個實施例的示意性框圖。
具體實施方式
下面參照附圖對本發(fā)明的具體實施方式進行詳細說明。本發(fā)明的對可執(zhí)行文件進行保護的方法可以支持例如.NET可執(zhí)行文件以及由C/C++編譯生成的32位或者64位的可執(zhí)行文件等。
圖1為本發(fā)明的對可執(zhí)行文件進行保護的方法的一個實施例的示意性流程圖。如圖1所示,本實施例的方法包括以下步驟:運行可執(zhí)行文件;在運行至所述可執(zhí)行文件的預定代碼段時,將預定代碼段的執(zhí)行過程中的至少一部分過程不在應用層執(zhí)行而是在驅動層進行模擬執(zhí)行;繼續(xù)運行所述可執(zhí)行文件。
預定代碼段為可執(zhí)行文件中待保護的代碼段,其可包括代碼或指令。預定代碼段可由用戶自行分析確定,也可以由客戶端軟件自動分析確定,或者由客戶端軟件對可執(zhí)行文件進行分析后向用戶提供能夠進行保護的多個代碼段以供用戶選定,用戶根據實際需要從中選定所需進行保護的代碼段作為預定代碼段。
在可執(zhí)行文件常規(guī)運行時,所有的代碼或指令均在應用層執(zhí)行。本發(fā)明的創(chuàng)新之處在于,將可執(zhí)行文件中預定代碼段的至少部分執(zhí)行過程不在應用層執(zhí)行,而是轉移至驅動層進行模擬執(zhí)行,驅動層在模擬執(zhí)行后可將執(zhí)行結果返回給應用層,如此可將可執(zhí)行文件中的預定執(zhí)行過程“隱藏”在驅動層執(zhí)行,要想破解可執(zhí)行文件中預定代碼的內容將變得十分困難。
本發(fā)明實施例的方法在運行可執(zhí)行文件時,將可執(zhí)行文件的預定代碼段(部分代碼或指令)的至少部分執(zhí)行過程轉移至驅動層進行模擬執(zhí)行,這樣對軟件中預定代碼或指令的保護的對抗從應用層轉移到驅動層,進一步增加了調試難度,能夠同時應對應用層保護軟件抗分析性差的問題和硬件保護方法容易受限的問題。應當理解的是,可執(zhí)行文件中可以包括多個上述的預定代碼段,從而在運行到每個預定代碼段處時均執(zhí)行上述過程。
在本發(fā)明一個實施例中,可將與可執(zhí)行文件中預定代碼段的指令中的至少部分指令的功能對應的驅動層指令寫入可執(zhí)行文件中的預定位置處。在該實施例中,預定代碼段可對應于與其實現相關的多個指令(或代碼),可將與其中的部分指令的功能對應的驅動層指令寫入可執(zhí)行文件中預定位置處,該預定位置可以是該部分指令原先所在行或其他行,或者也可以是可執(zhí)行文件中的預定數組處,例如一個新增的全局數組。
在本發(fā)明另一個實施例中,對于用于實現預定代碼段的指令中的至少部分指令中的每條指令,可能通過一條驅動層指令就能實現其功能,也可能通過兩條驅動層指令實現其功能。這里需要說明的是,驅動層指令可包括多種類型,對于某一類型的驅動層指令,可能一條驅動層指令的功能就能夠對應實現預定代碼段的部分指令中的一條指令,而對于另一類型的驅動層指令,可能需要兩條驅動層指令的功能才能對應實現預定代碼段的部分指令中的一條指令,具體對應關系由所選用的驅動層指令的類型而確定。
在本發(fā)明一個實施例中,可將實現上述預定代碼段的指令中的上述部分指令替換為包括與驅動層指令的調用相關的指令和/或函數在內的第一代碼段。如此可將與預定代碼段的執(zhí)行相關的指令中的至少部分指令完全隱藏,并且在可執(zhí)行文件運行時,通過與驅動層指令的調用相關的指令和/或函數來對驅動層指令進行調度,能夠例如將驅動層指令從應用層發(fā)送至驅動層,并從驅動層接收返回的執(zhí)行結果,從而在將上述的部分指令隱藏的同時能夠確??蓤?zhí)行文件的順利執(zhí)行。
圖2為本發(fā)明的對可執(zhí)行文件進行保護的方法的另一個實施例的部分示意性流程圖。
如圖2所示,本發(fā)明的對可執(zhí)行文件進行保護的方法的另一個實施例中在運行可執(zhí)行文件前,包括:分析所述可執(zhí)行文件中的多個函數,根據如下條件在所述多個函數中確定目標函數:對于實現所述目標函數的指令中的至少部分指令,存在功能對應的驅動層指令;將至少一個所述目標函數對應的代碼段確定為所述預定代碼段。
在本發(fā)明的實施例中,首先對可執(zhí)行文件中的多個函數進行分析,在多個函數中確定目標函數。目標函數的確定條件為,實現該目標函數的指令中的至少部分指令有驅動層指令的功能與之對應,即確定包括了能夠在驅動層模擬的指令的函數為目標函數,再將該目標函數對應的代碼段確定為待保護的預定代碼段。在確定了預定代碼段后,可執(zhí)行文件的運行過程與圖1所示相同。
圖3為本發(fā)明的對可執(zhí)行文件進行保護的方法的又一個實施例的部分示意性流程圖。
如圖3所示,本發(fā)明的對可執(zhí)行文件進行保護的方法的又一個實施例中在運行可執(zhí)行文件之前,包括:分析可執(zhí)行文件中的多個函數;在多個函數中將具有參數和返回值的函數確定為目標函數:將至少一個所述目標函數對應的代碼段確定為所述預定代碼段。
在本發(fā)明的實施例中,首先對可執(zhí)行文件中的多個函數進行分析,在多個函數中確定目標函數。目標函數的確定條件為,該目標函數具有參數、對參數的處理過程以及返回值,返回值即對參數的處理結果。即,確定了具備參數和返回值的函數為目標函數,再將該目標函數對應的代碼段確定為待保護的預定代碼段。在確定了預定代碼段后,可執(zhí)行文件的運行過程與圖1所示相同。
圖4為本發(fā)明的對可執(zhí)行文件進行保護的方法的再一個實施例的部分示意性流程圖。
如圖4所示,本發(fā)明的對可執(zhí)行文件進行保護的方法的又一個實施例中在運行可執(zhí)行文件之前,包括:分析可執(zhí)行文件中的多個函數,在所述多個函數中將具有同一類型的參數和返回值的函數確定為目標函數:將至少一個所述目標函數對應的代碼段確定為所述預定代碼段。
在本發(fā)明的實施例中,首先對可執(zhí)行文件中的多個函數進行分析,在多個函數中確定目標函數。目標函數的確定條件為,該目標函數具有參數、對參數的處理過程以及返回值,返回值即對參數的處理結果,并且參數和返回值為同一類型。即,確定了具備相同類型的參數和返回值的函數為目標函數,再將該目標函數對應的代碼段確定為待保護的預定代碼段。在確定了預定代碼段后,可執(zhí)行文件的運行過程與圖1所示相同。
下面結合一個示例性的.NET可執(zhí)行文件來說明本發(fā)明實施例對可執(zhí)行文件進行保護的方法的實現過程,該實施例以保護安裝有微軟Windows XP32位操作系統(tǒng)的系統(tǒng)環(huán)境為例,該示例性的.NET可執(zhí)行文件具體如下所示:
在所給出的示例性的.NET可執(zhí)行文件中包含Program類,Program中包含.ctor、Main、test_add、test_sub和test_mul等函數(或方法)。其中.ctor函數和Main函數中的返回值為void類型,兩者參數個數為0;test_add函數、test_sub函數和test_mul函數均包含2個int類型的參數,其對參數進行操作后得到的返回值也為int類型。經過分析,確定test_add函數、test_sub函數和test_mul函數可以在驅動層進行模擬。
下面以IL指令為例對實現test_add函數的指令進行說明:
{
IL_0000:nop
IL_0001:ldarg.0
IL_0002:ldarg.1
IL_0003:add
IL_0004:stloc.0
IL_0005:br.s IL_0007
IL_0007:ldloc.0
IL_0008:ret
}
上述用于實現test_add函數的IL指令中可以在驅動層模擬的指令為:
IL_0001:ldarg.0
IL_0002:ldarg.1
IL_0003:add
IL_0004:stloc.0
當用戶選定Program類中的test_add函數為目標函數時,將與上述四條IL指令的功能對應的驅動層指令(在本實施例中也稱為自定義指令)保存到可執(zhí)行文件中的預定位置處。這里給出所采用的驅動層指令的兩個例子。
驅動層指令的第一個例子可以包括:
vm_read_mem //讀取第一個參數
vm_push_imm //將參數入棧
vm_read_mem //讀取第二個參數
vm_push_imm //將參熟入棧
vm_add //相加
vm_pop //彈出棧頂垃圾數據
vm_write_mem //將結果保存
驅動層指令的第二個例子可以包括:
vm_get_context(相當于第一個例子中的vm_read_mem,vm_push_imm兩條指令)
vm_get_context
vm_add
vm_set_context(相當于第一個例子中的vm_pop,vm_write_mem兩條指令)
然后將上述的四條IL指令,即:
IL_0001:ldarg.0
IL_0002:ldarg.1
IL_0003:add
IL_0004:stloc.0
替換成包括了與驅動層指令的調用相關的代碼、指令和/或函數在內的以下代碼段:
System.Byte[]ab=new System.Byte[size];
System.Init(ab,...);//初始化自定義指令二進制編碼
object[]ao=new object[3];
ao[0]=arg.0;(arg.0--loc.0)//準備loc.0
ao[1]=arg.1;(arg.1--loc.1)//準備loc.1
ao[2]=loc.0;(loc.0--loc.2)//準備loc.2
call_driver_stub(ao,ab);
loc.0=ao[2];//將loc.2回寫到原方法的局部變量loc.0
在本實施例中,上面的代碼段中的ab中包含了自定義指令的二進制編碼。
下面對經過寫入驅動層指令和包括了與驅動層指令的調用相關的代碼、指令和/或函數在內的代碼段后的可執(zhí)行文件的執(zhí)行過程進行具體說明。
經安全處理后的.NET可執(zhí)行文件執(zhí)行到test_add函數的IL指令中上述替換的代碼段(即原先的上述四條指令位置處)時,通過System.Init(ab,...)設置ab中的自定義指令二進制編碼,應用層通過ao[0]=arg.0和ao[1]=arg.1設置了test_add函數的兩個參數的信息,通過ao[2]=loc.0指明在ao[2]中存儲要返回的結果,通過call_driver_stub函數調用驅動層模擬器。
驅動層模擬器接收到應用層傳遞的信息后,通過執(zhí)行vm_read_mem指令取得第一個參數的信息,通過vm_push_imm指令將第一個參數值壓入虛擬機堆棧;通過執(zhí)行vm_read_mem指令取得第二個參數的信息,通過vm_push_imm指令將第二個參數值壓入虛擬機堆棧;通過vm_add指令將堆棧中的兩個參數相加,并將結果入棧和標志寄存器入棧,通過vm_pop指令將標志寄存器彈出,通過vm_write_mem指令將結果保存在ao[2]地址處。
應用層通過指令loc.0=ao[2]獲得了執(zhí)行的結果,即得到了test_add函數對應的返回值,至此,完成了一次應用層和驅動層的交互,可執(zhí)行文件繼續(xù)執(zhí)行后續(xù)的指令和/代碼。
下面對當用戶需要對上述示例性的.NET可執(zhí)行文件中的test_sub函數在驅動層進行模擬時的處理過程進行說明。
對于test_sub方法,對應的IL指令為
{
IL_0000:nop
IL_0001:ldarg.0
IL_0002:ldarg.1
IL_0003:sub
IL_0004:stloc.0
IL_0005:br.s IL_0007
IL_0007:ldloc.0
IL_0008:ret
}
上述用于實現test_sub函數的IL指令中可以在驅動層模擬的指令為:
IL_0001:ldarg.0
IL_0002:ldarg.1
IL_0003:sub
IL_0004:stloc.0
當用戶選定Program類中的test_sub函數為目標函數時,將與上述四條IL指令的功能對應的驅動層指令保存到可執(zhí)行文件中的預定位置處。這里對test_sub函數的上述四條IL指令采用的驅動層指令可以是:
vm_read_mem //讀取第一個參數
vm_push_imm //將參數入棧
vm_read_mem //讀取第二個參數
vm_push_imm //將參熟入棧
vm_sub //相減
vm_pop //彈出棧頂垃圾數據
vm_write_mem //將結果保存
然后將上述的四條IL指令,即:
IL_0001:ldarg.0
IL_0002:ldarg.1
IL_0003:sub
IL_0004:stloc.0
替換成包括了與驅動層指令的調用相關的代碼、指令和/或函數在內的以下代碼段:
System.Byte[]ab=new System.Byte[size];
System.Init(ab,...);//初始化自定義指令二進制編碼
object[]ao=new object[3];
ao[0]=arg.0;(arg.0--loc.0)//準備loc.0
ao[1]=arg.1;(arg.1--loc.1)//準備loc.1
ao[2]=loc.0;(loc.0--loc.2)//準備loc.2
call_driver_stub(ao,ab);
loc.0=ao[2];//將loc.2回寫到原方法的局部變量loc.0
在對test_sub函數的部分指令進行驅動層模擬的實施例中,應用層與驅動層之間的互動與對test_add函數的部分指令進行驅動層模擬的實施例類似,在此不再贅述。
本發(fā)明實施例同時提供了一種用于對可執(zhí)行文件進行保護的裝置,下面參照圖5-7進行說明。
圖5為本發(fā)明的對可執(zhí)行文件進行保護的裝置的一個實施例的示意性框圖。
如圖5所示,本發(fā)明實施例的對可執(zhí)行文件進行保護的裝置包括:
應用程序端,其配置為運行可執(zhí)行文件;
驅動層模擬器,其配置為在可執(zhí)行文件運行時,對所述可執(zhí)行文件中的預定代碼段的執(zhí)行過程中的至少部分過程進行模擬執(zhí)行,其中,所述至少部分過程不在應用程序端執(zhí)行。
本發(fā)明實施例的裝置在應用程序端運行可執(zhí)行文件時,將可執(zhí)行文件的預定代碼段(部分代碼或指令)的至少部分執(zhí)行過程從應用程序端轉移至驅動層模擬器進行模擬執(zhí)行,這樣對軟件中預定代碼或指令的保護的對抗從應用層轉移到驅動層,進一步增加了調試難度,能夠同時應對應用層保護軟件抗分析性差的問題和硬件保護方法容易受限的問題。應當理解的是,可執(zhí)行文件中可以包括多個上述的預定代碼段,從而在運行到每個預定代碼段處時均執(zhí)行上述過程。
圖6為本發(fā)明的對可執(zhí)行文件進行保護的裝置的另一個實施例的示意性框圖。
在本發(fā)明一個實施例中,如圖6所示,裝置還可以包括處理單元,其可以配置為將與實現預定代碼段的指令中的至少部分指令的功能對應的驅動層指令寫入可執(zhí)行文件中預定位置處。在該實施例中,預定代碼段可對應于與其實現相關的多個指令(或代碼),處理單元可將與其中的部分指令的功能對應的驅動層指令寫入可執(zhí)行文件中預定位置處。該預定位置可以是該部分指令原先所在行或其他行,或者也可以是可執(zhí)行文件中的預定數組處,例如一個新增的全局數組。
在本發(fā)明一個實施例中,圖6所示的處理單元還可以配置為,對于實現預定代碼段的指令中的至少部分指令中的每條指令,在可執(zhí)行文件中的預定位置寫入至少一條驅動層指令。在本發(fā)明實施例中,對于用于實現預定代碼段的指令中的至少部分指令中的每條指令,可能通過一條驅動層指令就能實現其功能,也可能通過兩條驅動層指令實現其功能,具體由所選用的驅動層指令的類型而確定。
在本發(fā)明另一個實施例中,圖6所示的處理單元可以進一步配置為將實現可執(zhí)行文件中預定代碼段的指令中的至少部分指令替換為包括與驅動層指令的調用相關的指令和/或函數在內的第一代碼段。如此可將與預定代碼段的執(zhí)行相關的指令中的至少部分指令完全隱藏,并且在可執(zhí)行文件運行時,通過與驅動層指令的調用相關的指令和/或函數來對驅動層指令進行調度,能夠由處理單元使得驅動層指令從應用程序端發(fā)送至驅動層模擬器,并使得應用程序端從驅動層模擬器接收返回的相應執(zhí)行結果,從而在將上述的部分指令隱藏的同時能夠確??蓤?zhí)行文件的順利執(zhí)行。
圖7為本發(fā)明的對可執(zhí)行文件進行保護的裝置的又一個實施例的示意性框圖。
在本發(fā)明一個實施例中,如圖7所示,裝置還包括分析單元,其配置為分析所述可執(zhí)行文件中的多個函數,并將多個函數中的至少一個目標函數對應的代碼段確定為預定代碼段。分析單元可配置為基于不同的條件來確定目標函數。例如,分析單元可配置為根據如下條件確定所述目標函數:對于實現所述目標函數的指令中的至少部分指令,存在功能對應的驅動層指令?;蛘撸治鰡卧膳渲脼閷⒕哂袇岛头祷刂档暮瘮荡_定為目標函數。另外,分析單元還可以配置為將具有同一類型的參數和返回值的函數確定為目標函數。
本發(fā)明在對可執(zhí)行文件進行保護時,將部分代碼或指令的執(zhí)行過程轉移至驅動層模擬執(zhí)行,這樣對軟件中代碼或指令的保護的對抗從應用層轉移到驅動層,進一步增加了調試難度,從而達到了保護軟件的目的。
當然,以上所述是本發(fā)明的部分實施方式,應當指出,對于本技術領域的技術人員來說,在不脫離本發(fā)明原理的前提下,還可以做出若干改進和潤飾,這些改進和潤飾也視為落入本發(fā)明的保護范圍。