本發明屬于系統安全技術領域,具體涉及一種驅動層防注入方法、裝置及客戶端。
背景技術:
異步過程調用(APC:asynchronous procedure call)是指函數在特定線程中被異步執行。在Microsoft Windows操作系統中,APC是一種并發機制,用于異步IO或者定時器。
客戶端程序的穩定性和安全性是必不可少的參考指標。某些第三方模塊會有漏洞(Bug)的存在,這些漏洞會通過APC的方式注入到其它客戶端程序,從而帶來客戶端程序的不穩定,由此帶來負面的用戶體驗和反饋。因此,如何減少第三方模塊注入給軟件所造成的影響便成了客戶端軟件穩定性中的一個不可或缺的環節。
現有技術中,尚未發現在驅動層攔截第三方模塊APC注入的技術。
技術實現要素:
因此,本發明提出一種驅動層防注入方法、裝置及客戶端。所述驅動層防注入方法包括如下步驟:
創建驅動層防注入動態鏈接庫,所述驅動層防注入動態鏈接庫包含第一鉤子函數和驅動層注入模塊名單;建立所述驅動層防注入動態鏈接庫與應用程序之間的靜態鏈接,以使得所述應用程序的主線程被建立時,所述驅動層防注入動態鏈接庫被首先調用,所述第一鉤子函數和所述驅動層注入模塊名單被加載;響應于所述應用程序的主線程對第三方模塊的加載,判斷所述被加載的第一鉤子函數返回的第三方模塊是否屬于所述驅動層注入模塊名單;若是,通過第一鉤子函數攔截所述返回的第三方模塊。
所述驅動層防注入裝置包括如下模塊:
驅動層防注入動態鏈接庫創建模塊,用于創建驅動層防注入動態鏈接庫,所述驅動層防注入動態鏈接庫包含第一鉤子函數和驅動層注入模塊名單;靜態鏈接建立模塊,用于建立應用程序與所述驅動層防注入動態鏈接庫之間的靜態鏈接,以使得當所述應用程序的主線程被建立時,所述驅動層防注入動態鏈接庫被首先調用,所述第一鉤子函數和所述驅動層注入模塊名單被加載;判斷模塊,用于判斷所述被加載的第一鉤子函數返回的模塊是否屬于所述驅動層注入模塊名單;攔截模塊,用于在被加載的第一鉤子函數返回的模塊屬于所述驅動層注入模塊名單時,攔截第一鉤子函數返回的所述模塊。
所述驅動層防注入客戶端包括前述的裝置。
本發明具有如下有益效果:本發明能夠在進程創建主線程時即對可能存在的驅動層注入進行識別和攔截,有效攔截驅動層的第三方模塊注入,從而提升系統的安全性和穩定性。
附圖說明
下面結合附圖對本發明的具體實施方式作進一步詳細的說明;
圖1是本發明實施例一提供的驅動層防異步過程調用注入方法流程圖。
圖2是本發明實施例一提供的驅動層防異步過程調用注入方法流程圖。
圖3是本發明實施例二提供的驅動層防異步過程調用注入方法流程圖。
圖4是本發明實施例三提供的防異步過程調用注入裝置結構示意圖。
圖5是本發明實施例三提供的獲取異步過程調用(APC)注入模塊名單模塊結構示意圖。
圖6是本發明實施例三提供的防異步過程調用動態鏈接庫創建模塊結構示意圖。
圖7是本發明實施例四提供的包含本發明裝置的通用計算機系統結構示意圖。
具體實施方式
為了使本技術領域的人員更好地理解本發明方案,下面將結合本發明實施例中的附圖,對本發明實施例中的技術方案進行清楚、完整地描述,顯然,所描述的實施例僅僅是本發明一部分的實施例,而不是全部的實施例。基于本發明中的實施例,本領域普通技術人員在沒有做出創造性勞動前提下所獲得的所有其他實施例,都應當屬于本發明保護的范圍。
本發明涉及的技術術語解釋如下:
ntdll.dll:該動態鏈接庫描述了windows本地NTAPI的接口。是重要的Windows NT內核級文件。當Windows啟動時,ntdll.dll就駐留在內存中特定的寫保護區域,使別的程序無法占用這個內存區域。ntdll.dll是Windows系統從ring3到ring0的入口。位于Kernel32.dll和user32.dll中的所有win32 API最終都是調用ntdll.dll中的函數實現的。ntdll.dll中的函數使用SYSENTRY進入ring0,函數的實現實體在ring0中。
user32.dll(Windows User API Client DLL):該動態鏈接庫是Windows用戶界面相關應用程序接口,用于包括Windows處理,基本用戶界面等特性,如創建窗口和發送消息。
kernel32.dll:該動態鏈接庫是Windows 9x/Me中非常重要的32位動態鏈接庫文件,屬于內核級文件。它控制著系統的內存管理、數據的輸入輸出操作和中斷處理,當Windows啟動時,kernel32.dll就駐留在內存中特定的寫保護區域,使別的程序無法占用這個內存區域。
上述三個動態鏈接庫都屬于系統動態鏈接庫,其不會被第三方模塊注入。
靜態鏈接:靜態鏈接的時候,載入代碼就會把程序會用到的動態代碼或動態代碼的地址確定下來,靜態庫的鏈接可以使用靜態鏈接,動態鏈接庫也可以使用靜態鏈接的方法鏈接導入庫。
動態鏈接方法:使用動態鏈接方式的程序并不在一開始就完成動態鏈接,而是直到真正調用動態庫代碼時,載入程序才計算(被調用的那部分)動態代碼的邏輯地址,然后等到某個時候,程序又需要調用另外某塊動態代碼時,載入程序又去計算這部分代碼的邏輯地址,所以,這種方式使程序初始化時間較短,但運行期間的性能比不上靜態鏈接的程序。
靜態鏈接與動態鏈接在運行時的比較:靜態庫和應用程序編譯在一起,在任何情況下都能運行,而動態庫是動態鏈接,顧名思義就是在應用程序啟動的時候才會鏈接,所以,當用戶的系統上沒有該動態庫時,應用程序就會運行失敗。
實施例一:
本實施例提供一種驅動層防異步過程調用(APC)注入方法,如圖1所示,方法包括如下步驟:
S101,獲取異步過程調用(APC)注入模塊名單。
S102,創建防異步過程調用動態鏈接庫(ApcRefuseInject.dll)。所述防異步過程調用注入動態鏈接庫中包含LdrLoadDLL的鉤子函數和APC注入模塊名單。在本實施例中,LdrLoadDLL即所述動態鏈接庫加載函數。
S103,建立與所述防異步過程調用注入動態鏈接庫的靜態鏈接。
S104,在創建主線程時,調用所述防異步過程調用動態鏈接庫,加載LdrLoadDLL的鉤子函數,獲取經過編譯的所述APC注入模塊名單。
S105,根據所述LdrLoadDLL的鉤子函數和APC注入模塊名單判斷是否存在APC注入模塊;若存在,攔截所述APC注入模塊。
在所述步驟S101中,獲取異步過程調用(APC)注入模塊名單,如圖2所示,該步驟進一步包含如下子步驟:
S1011,注冊驅動層映像加載回調函數。
在具體的實施過程中,驅動層映像加載回調函數可以通過PsSetLoadImageNonifyRoutine來注冊和加載回調。
S1012,根據所述驅動層映像加載回調函數判斷是否加載指定動態鏈接庫;若是,則進行藍屏調試。
S1013,分析藍屏dump,若奔潰的棧為KiUserApcDispatcher,則判斷所述動態鏈接庫為是通過驅動層APC注入的。
S1014,將所述模塊加入APC注入模塊名單。
在所述步驟S102中,創建防異步過程調用注入動態鏈接庫(ApcRefuseInject.dll),在創建ApcRefuseInject.dll的同時,還導出LdrLoadDLL的鉤子函數,所述APC注入模塊名單被編譯于LdrLoadDLL的鉤子函數中。該步驟還可能進一步包含如下子步驟:
S1021,僅基于ntdll.dll、user32.dll和kernel32.dll創建防異步過程調用注入動態鏈接庫(ApcRefuseInject.dll)。
在步驟S1021中,ApcRefuseInject.dll的建立僅依靠ntdll.dll、user32.dll和kernel32.dll建立是因為這三個動態鏈接庫為系統動態鏈接庫,依靠這三個動態鏈接庫建立的防異步過程調用注入動態鏈接庫只會調用系統模塊,而不會調用任何三方模塊,這就保證了ApcRefuseInject.dll本身不存在被三方模塊APC注入。
S1022,導出用于攔截APC注入的函數Hook_LdrLoadDll,該函數為LdrLoadDll的鉤子函數,用于獲取LdrLoadDll函數返回的加載模塊。
在具體的實施方式中,步驟S101獲取到的APC注入模塊名單被以二進制形式編譯到該模塊中。
在所述步驟S103中,建立與防異步過程調用注入動態鏈接庫(ApcRefuseInject.dll)之間的靜態鏈接。
建立靜態鏈接保證在主線程啟動時,防異步過程調用注入動態鏈接庫首先被調用,LdrLoadDll的鉤子函數優先于其他模塊被加載。
在所述步驟S104中,創建主線程,加載LdrLoadDLL的鉤子函數編譯所述黑名單。
由于與ApcRefuseInject.dll之間的靜態鏈接關系,當創建主線程時,該動態鏈接庫首先被調用,其中的LdrLoadDLL的鉤子函數被加載,編譯于鉤子函數中的APC注入模塊名單被編譯,通常是二進制的形式。由于ApcRefuseInject.dll僅依靠ntdll.dll、user32.dll和kernel32.dll建立,其不存在被APC注入的風險,通過其來對其他模塊是否被注入進行判斷也是安全的。
在所述步驟S105中,根據所述LdrLoadDLL的鉤子函數判斷是否存在APC注入模塊;若存在,攔截所述APC注入模塊。
判斷是否存在APC注入可以是一個比較的過程,該過程比較LdrLoadDLL的鉤子函數返回的模塊是否屬于APC注入模塊名單。但是該比較過程不能使用字符串比較函數,因為字符串比較函數會調用除ntdll.dll、user32.dll和kernel32.dll之外的動態鏈接庫,這會造成被第三方模塊APC注入的風險。具體的實施過程中,可以采用手動比較的方式來實現。
在本發明中,APC注入名單與傳統的病毒庫并不相同,其會被編譯于LdrLoadDLL函數的鉤子函數中,以例如二進制的形式存在。并且其與鉤子函數的返回值進行比較時,也不會使用系統的字符串比較函數,而使用手動設定的循環比較方式。
實施例二:
本實施例提供一種防異步過程調用(APC)注入裝置,如圖3所示,所述方法包括如下步驟:
S201,創建防異步過程調用動態鏈接庫(ApcRefuseInject.dll)。
所述防異步過程調用動態鏈接庫中包含LdrLoadDLL的鉤子函數和APC注入模塊名單。
APC注入模塊名單可以通過諸如藍屏調試的方式事先獲得。
步驟S201還可以進一步包含如下兩個子步驟:
S2021,僅基于ntdll.dll、user32.dll和kernel32.dll創建防異步過程調用注入動態鏈接庫(ApcRefuseInject.dll)。
在步驟S2021中,ApcRefuseInject.dll的建立僅依靠ntdll.dll、user32.dll和kernel32.dll建立是因為這三個動態鏈接庫為系統動態鏈接庫,依靠這三個動態鏈接庫建立的防異步過程調用注入動態鏈接庫只會調用系統模塊,而不會調用任何三方模塊,這就保證了ApcRefuseInject.dll本身不存在被三方模塊APC注入。
S2022,導出用于攔截APC注入的函數Hook_LdrLoadDll,該函數為LdrLoadDll的鉤子函數,用于獲取LdrLoadDll函數返回的加載模塊。
在具體的實施方式中,APC注入模塊名單被以二進制形式編譯到該模塊中。
S202,建立與所述防異步過程調用動態鏈接庫之間的靜態鏈接。
建立靜態鏈接保證在主線程啟動時,防異步過程調用注入動態鏈接庫首先被調用,LdrLoadDll的鉤子函數優先于其他模塊被加載。因為APC注入多數是發生在進程創建主線程的時候,所以必須在進程創建主線程的時候,加載鉤子函數,并對可能存在的APC注入進行判定和然后攔截。
S203,在創建主線程時,調用所述防異步過程調用動態鏈接庫,加載LdrLoadDLL的鉤子函數,獲取經過編譯的所述APC注入模塊名單。
由于與ApcRefuseInject.dll之間的靜態鏈接關系,當創建主線程時,該動態鏈接庫首先被調用,其中的LdrLoadDLL的鉤子函數被加載,編譯于鉤子函數中的APC注入模塊名單被編譯,通常是二進制的形式。由于ApcRefuseInject.dll僅依靠ntdll.dll、user32.dll和kernel32.dll建立,其不存在被APC注入的風險,通過其來對其他模塊是否被注入進行判斷也是安全的。
S204,根據所述LdrLoadDLL的鉤子函數和APC注入模塊名單判斷是否存在APC注入模塊;若存在,攔截所述APC注入模塊。
判斷是否存在APC注入可以是一個比較的過程,該過程比較LdrLoadDLL的鉤子函數返回的模塊是否屬于APC注入模塊名單。但是該比較過程不能使用字符串比較函數,因為字符串比較函數會調用除ntdll.dll、user32.dll和kernel32.dll之外的動態鏈接庫,這會造成被第三方模塊APC注入的風險。具體的實施過程中,可以采用手動比較的方式來實現。
在具體的實施過程中,手動比較方式包括建立循環函數,在所述循環函數的循環中逐一比較APC注入模塊名單與所述LdrLoadDLL的鉤子函數返回的模塊。
因為LdrLoadDLL的鉤子函數會返回如下值:
動態鏈接庫的路徑設置;
動態鏈接庫的屬性設置;
動態鏈接庫的名稱;
動態鏈接庫所引用的句柄。
建立一個循環函數,在單個循環中比較LdrLoadDLL的鉤子函數返回的動態鏈接庫與APC注入模塊名單中的一個APC諸如名稱,如果發現返回的動態鏈接庫名稱存在于名單中,則說明模塊存在APC注入,需要對注入進行攔截。
在具體的實施過程中,所述攔截所述APC注入模塊包括將所述LdrLoadDLL的鉤子函數中的動態鏈接庫的句柄設置為空,如此動態連接庫將不會被調用,對應的APC注入也被攔截。
在本發明中,APC注入名單與傳統的病毒庫并不相同,其會被編譯于LdrLoadDLL函數的鉤子函數中,以例如二進制的形式存在。并且其與鉤子函數的返回值進行比較時,也不會使用系統的字符串比較函數,而使用手動設定的循環比較方式。
實施例三:
本實施例提供一種防異步過程調用(APC)注入裝置,如圖4所示,所述裝置包括如下模塊:
APC注入模塊名單獲取模塊,用于獲取APC注入模塊名單,如圖5所示,其包括如下子模塊:
注冊子模塊,用語注冊驅動層映像加載回調函數。
藍屏調試子模塊,用于根據所述驅動層映像加載回調函數判斷是否加載指定動態鏈接庫;若是,則進行藍屏調試。
分析子模塊,用于分析藍屏dump,判斷奔潰的棧是否為KiUserApc-Dispatcher,若是,則判斷所述動態鏈接庫為是通過驅動層APC注入的。
將所述模塊加入APC注入模塊名單。
防異步過程調用動態鏈接庫創建模塊,用于創建防異步過程調用動態鏈接庫(ApcRefuseInject.dll),所述防異步過程調用動態鏈接庫包含LdrLoadDLL的鉤子函數和APC注入模塊名單。
該模塊創建防異步過程調用注入動態鏈接庫(ApcRefuseInject.dll),并且在創建ApcRefuseInject.dll的同時,還導出LdrLoadDLL的鉤子函數,APC注入模塊名單被編譯于LdrLoadDLL的鉤子函數中。如圖6所示,該模塊還可能進一步包含如下子模塊:
系統動態鏈接庫鏈接模塊,僅基于ntdll.dll、user32.dll和kernel32.dll創建防異步過程調用注入動態鏈接庫(ApcRefuseInject.dll)。
該子模塊的作用是ApcRefuseInject.dll僅依靠ntdll.dll、user32.dll和kernel32.dll建立。因為這三個動態鏈接庫為系統動態鏈接庫,依靠這三個動態鏈接庫建立的防異步過程調用注入動態鏈接庫只會調用系統模塊,而不會調用任何三方模塊,這就保證了ApcRefuseInject.dll本身不存在被三方模塊APC注入。
鉤子函數導出模塊,該子模塊的作用是導出用于攔截APC注入的函數Hook_LdrLoadDll,該函數為LdrLoadDll的鉤子函數,用于獲取LdrLoadDll函數返回的加載模塊。
在具體的實施方式中,APC注入模塊名單被以二進制形式編譯到該模塊中。
靜態鏈接建立模塊,用于建立與所述防異步過程調用動態鏈接庫之間的靜態鏈接。
建立靜態鏈接保證在主線程啟動時,防異步過程調用注入動態鏈接庫首先被調用,LdrLoadDll的鉤子函數優先于其他模塊被加載。
主線程創建模塊,用于創建主線程,調用所述防異步過程調用動態鏈接庫,加載LdrLoadDLL的鉤子函數,獲取經過編譯的所述APC注入模塊名單。
由于與ApcRefuseInject.dll之間的靜態鏈接關系,當創建主線程時,該動態鏈接庫首先被調用,其中的LdrLoadDLL的鉤子函數被加載,編譯于鉤子函數中的APC注入模塊名單被編譯,通常是二進制的形式。由于ApcRefuseInject.dll僅依靠ntdll.dll、user32.dll和kernel32.dll建立,其不存在被APC注入的風險,通過其來對其他模塊是否被注入進行判斷也是安全的。
在加載鉤子函數時,如果使用回調函數,則會有死鎖產生。在該步驟中,在進程創建主線程的時候加載LdrLoadDLL的鉤子函數,而不通過模塊加載回調LOAD_IMAGE_NOTIFY_ROUTINE來加載鉤子函數,能夠有效避免在加載回調過程的死鎖問題。
攔截模塊,根據所述LdrLoadDLL的鉤子函數和APC注入模塊名單判斷是否存在APC注入模塊;若存在,攔截所述APC注入模塊。
判斷是否存在APC注入可以是一個比較的過程,該過程比較LdrLoadDLL的鉤子函數返回的模塊是否屬于APC注入模塊名單。但是該比較過程不能使用字符串比較函數,因為字符串比較函數會調用除ntdll.dll、user32.dll和kernel32.dll之外的動態鏈接庫,這會造成被第三方模塊APC注入的風險。具體的實施過程中,可以采用手動比較的方式來實現。
在具體的實施過程中,手動比較方式包括建立循環函數,在所述循環函數的循環中逐一比較APC注入模塊名單與所述LdrLoadDLL的鉤子函數返回的模塊。
因為LdrLoadDLL的鉤子函數會返回如下值:
動態鏈接庫的路徑設置;
動態鏈接庫的屬性設置;
動態鏈接庫的名稱;
動態鏈接庫所引用的句柄。
建立一個循環函數,在單個循環中比較LdrLoadDLL的鉤子函數返回的動態鏈接庫與APC注入模塊名單中的一個APC諸如名稱,如果發現返回的動態鏈接庫名稱存在于名單中,則說明模塊存在APC注入,需要對注入進行攔截。
在具體的實施過程中,所述攔截所述APC注入模塊包括將所述LdrLoadDLL的鉤子函數中的動態鏈接庫的句柄設置為空,如此動態連接庫將不會被調用,對應的APC注入也被攔截。
在本發明中,APC注入名單與傳統的病毒庫并不相同,其會被編譯于LdrLoadDLL函數的鉤子函數中,以例如二進制的形式存在。并且其與鉤子函數的返回值進行比較時,也不會使用系統的字符串比較函數,而使用手動設定的循環比較方式。
實施例4:
本發明涉及的裝置可應用于客戶端中,所述客戶端可以是諸如臺式機、筆記本電腦、移動終端(例如智能手機)、ipad等。
當然,裝置也可應用于平臺中。或者,所述裝置或系統也可以軟件的形式運行于終端(客戶端)上。
圖7示出了上述裝置或系統或服務器的一種通用計算機系統結構。
上述計算機系統包括總線,處理器1、存儲器2、通信接口3、輸入設備4和輸出設備5通過總線相互連接。其中,總線在計算機系統各個部件之間傳送信息。
處理器1可以是通用處理器,例如通用中央處理器(CPU)、網絡處理器(Network Processor,簡稱NP)、微處理器等,也可以是特定應用集成電路(application-specific integrated circuit,ASIW),或一個或多個用于控制本發明方案程序執行的集成電路。還可以是數字信號處理器(DSP)、專用集成電路(ASIC)、現成可編程門陣列(FPGA)或者其他可編程邏輯器件、分立門或者晶體管邏輯器件、分立硬件組件。
處理器1可包括主處理器,還可包括基帶芯片、調制解調器等。存儲器2中保存有執行本發明技術方案的程序,還可以保存有操作系統和其他關鍵業務。具體地,程序可以包括程序代碼,程序代碼包括計算機操作指令。更具體的,存儲器2可以包括只讀存儲器(read-onlymemory,ROM)、可存儲靜態信息和指令的其他類型的靜態存儲設備、隨機存取存儲器(random access memory,RAM)、可存儲信息和指令的其他類型的動態存儲設備、磁盤存儲器、flash等等。
輸入設備4可包括接收用戶輸入的數據和信息的裝置,例如鍵盤、鼠標、攝像頭、掃描儀、光筆、語音輸入裝置、觸摸屏、計步器或重力感應器等。
輸出設備5可包括允許輸出信息給用戶的裝置,例如顯示屏、打印機、揚聲器等。
通信接口3可包括使用任何收發器一類的裝置,以便與其他設備或通信網絡通信,如以太網,無線接入網(RAN),無線局域網(WLAN)等。
處理器1執行存儲器2中所存放的程序、指令或者代碼,以及調用其他設備,并與操作系統交互或者調用操作系統中的部分指令,用于實現本發明實施例的如下各個步驟:
創建防異步過程調用動態鏈接庫(ApcRefuseInject.dll),所述防異步過程調用動態鏈接庫包含LdrLoadDLL的鉤子函數和APC注入模塊名單。
建立與所述防異步過程調用動態鏈接庫之間的靜態鏈接。
創建主線程,調用所述防異步過程調用動態鏈接庫,加載LdrLoadDLL的鉤子函數,獲取經過編譯的所述APC注入模塊名單。
根據所述LdrLoadDLL的鉤子函數和APC注入模塊名單判斷是否存在APC注入模塊;若存在,攔截所述APC注入模塊。
在一個具體實施過程中,方法還包括:獲取APC注入模塊名單。
在一個具體實施過程中,獲取APC注入名單包括如下步驟:
注冊驅動層映像加載回調函數;根據所述驅動層映像加載回調函數判斷是否加載指定動態鏈接庫;若是,則進行藍屏調試;分析藍屏dump,判斷奔潰的棧是否為指定棧,若是,則判斷所述動態鏈接庫為是通過驅動層APC注入的;將所述模塊加入APC注入模塊名單。
在一個具體實施過程中,所述防異步過程調用動態鏈接庫僅依靠ntdll.dll、user32.dll和kernel32.dll建立。
在一個具體實施過程中,在創建主線程時,LdrLoadDLL的鉤子函數先于其他模它被加載。
在一個具體實施過程中,所述根據所述LdrLoadDLL的鉤子函數和APC注入模塊名單判斷是否存在APC注入模塊步驟中,采用采用手動比較的方式判斷LdrLoadDLL的鉤子函數返回的模塊是否屬于APC注入模塊名單。
在一個具體實施過程中,所述的手動比較方法包括建立循環函數,在所述循環函數的循環中逐一比較APC注入模塊名單與所述LdrLoadDLL的鉤子函數返回的模塊。
在一個具體實施過程中,所述攔截所述APC注入模塊包括將所述LdrLoadDLL的鉤子函數中的動態鏈接庫的句柄設置為空。
專業人員還可以進一步意識到,結合本文中所公開的實施例描述的各示例的單元及算法步驟,能夠以電子硬件、計算機軟件或者二者的結合來實現,為了清楚地說明硬件和軟件的可互換性,在上述說明中已經按照功能一般性地描述了各示例的組成及步驟。這些功能究竟以硬件還是軟件方式來執行,取決于技術方案的特定應用和設計約束條件。專業技術人員可以對每個特定的應用來使用不同方法來實現所描述的功能,但是這種實現不應認為超出本發明的范圍。
結合本文中所公開的實施例描述的方法或算法的步驟可以直接用硬件、處理器執行的軟件模塊,或者二者的結合來實施。軟件模塊可以置于隨機存儲器(RAM)、內存、只讀存儲器(ROM)、電可編程ROM、電可擦除可編程ROM、寄存器、硬盤、可移動磁盤、WD-ROM、或技術領域內所公知的任意其它形式的存儲介質中。
對所公開的實施例的上述說明,使本領域專業技術人員能夠實現或使用本發明。對這些實施例的多種修改對本領域的專業技術人員來說將是顯而易見的,本文中所定義的一般原理可以在不脫離本發明的精神或范圍的情況下,在其它實施例中實現。因此,本發明將不會被限制于本文所示的這些實施例,而是要符合與本文所公開的原理和新穎特點相一致的最寬的范圍。