標籤:
文章轉載與看雪論壇.
我覺得,做一個殺毒軟體,大概要有以下的驅動程式。下面我給出了殺毒軟體的大致設計架構。
由於一些事情的存在,程式碼暫時不能上傳到看雪論壇上,以免引起日後產生不必要的法律糾紛。這裡還請各位朋友能夠原諒。
若有不對和不足的地方,還請見諒。
1)磁碟掃描電腦病毒。
一個掃描引擎主要包含:掃描規則設定、對象設定。
掃描規則設定主要是,允許使用者使用一個或全部規則對檔案進行掃描。
掃描對象設定主要是,允許使用者對要掃描的檔案的類型進行設定。
<1>判斷是否是PE 檔案格式。
若開啟的檔案不是PE 檔案格式規範,則給出提示資訊,讓使用者重新選擇要掃描的檔案。
若開啟的檔案是PE檔案格式規範,則:進行地址轉換。
RVA和地址進行相互轉換。
迴圈得到每個節的起始RVA(相對虛擬位址)、根據節的大小來計算出節的範圍。
比較程式入口的RVA(Address Of Entry Point),用來確定當前的節在哪個節區。
當RVA確定了以後,計算出它在該節中的位移量。
然後把這個位移量+該節在檔案中的位移量=入口地址在檔案中的確切地址。
<2>比較節的名稱。
一個PE檔案格式會存在有一個或多個的代碼節,也會有多個的非代碼節。在一般情況下,代碼節是唯讀不可寫的、非代碼節是可以寫的。如果某個非代碼節擁有了代碼節的屬性,那麼,這個節存在著代碼,或許是病毒代碼。
代碼節的屬性是60000020H,也就是可執行、可讀、節中包含代碼。如果某個節的節名不是: .text 、.code、.CODE,而它的屬性是60000020H,那麼可以認為,該節不是代碼節並且具有了代碼節的屬性,那麼它就是一個可疑的節。
可以通過IMAGE_SECTION_HEADER結構體的Name欄位迴圈讀出每個節的名字,若發現可疑之處,則可以把可疑的節設定為節名:.VIRUS或 .Virus等名字。
接著把該可疑的節的特徵儲存到資料庫裡面。可以設定一定的權值,通常在0.1—1之間。
這樣做目的是:為掃描引擎提供資料來源、提供校正的權值。
<3>檔案大小與最後一個節的尾位移量不相同。
一般情況下,檔案的最後一個節是檔案的結束,所以最後一個節相對於檔案頭的位移量應該和檔案的大小相同。如果不相同,可以認為,檔案被加入了其它的內容。那麼可以認為,這個檔案擁有可疑的代碼,這個檔案是病毒木馬檔案。
<4>檔案的進入點指向檔案頭、檔案尾、其它讓人出乎意料的地址。
一個PE檔案格式是由:檔案頭+節區組合而成。一個程式的進入點肯定要指向檔案的某個節區。否則,就是不正常的現象。那麼可以認為,這個檔案擁有可疑的代碼,這個檔案是病毒木馬檔案。
<5>節與節之間,它們的首地址和尾地址不是連續的。
兩個連續的節之間,不能有間隙。應當是首尾相連的。而一些病毒是按照自訂的方式來設定一些尺寸,這樣會造成了節和節之間產生了空隙,所以,可以認為,這個檔案是病毒木馬檔案。
<6>一個檔案,擁有2個以上的檔案頭。
病毒木馬程式附加在宿主檔案上,一般有3種形式。也就是說,病毒木馬程式修改了PE檔案的格式。
(1)病毒木馬附加在宿主檔案的後面。
(2)病毒木馬附加在宿主檔案裡面。
(3)病毒木馬附加在宿主檔案的前面。
那麼,可以認為,這個檔案是病毒木馬檔案。
<7>擷取Windows核心控制權。
一些程式會載入到C0001000H地址處,這樣可以使系統在運行本程式的時候,擷取核心的控制權。
我們安全衛士,可以迴圈讀出每個節區的記憶體位址RVA,並和C000000H比較,如果相同,那麼可以認為這個檔案是惡意的程式。
掃描演算法的設計。
在掃描演算法設計上,應當通過加如新的規則,來進行權值的校正。各條規則權值的校正可以通過演算法來完成、或人工修改的方式。
假設Y是掃描結果,
Y=1是權和大於規定值,則掃描為木馬病毒。
Y=0 是權和小於規定值,則不是木馬病毒。
公式Y=a+B1X1+B2X2+……….+BnXn
其中
Xi是:第i條規則的權值。
a是:整體誤差,由規則不全引起的誤差。
病毒日誌:
主要記錄:病毒檔案名稱、病毒來源、掃描等級、掃描日期、路徑掃描方式。
病毒掃描資料備份和恢複:
主要根據使用者的選擇,備份一些資料表,在需要的時候進行恢複。
病毒掃描記錄:
主要是儲存掃描後的掃描結果,為掃描引擎提供資料來源。
2)自我防護。
防止被惡意程式結束。
在32位Windows系統上,可以:
Hook掉 NtOpenProcess()、NtTerminateProcess()、ObReferenceObjectByHandle()
但,這些都不是最深層的函數,我們的安全衛士程式很容易被惡意程式結束掉。
因此,應該Inline Hook PspTerminateThreadByPointer(),防止進程被結束。
在64 位Windows系統上,可以:
調用Microsoft提供的核心功能 ObRegisterCallbacks()。利用提供的Callback函數指標來保護進程不被結束。
注意的事項:
在Windows7或更高版本的Windows系統裡面,Callback函數可以擁有64個。若一台電腦裡面的Callback函數多於64個,那麼Windows系統將不行掛載Callback函數。這時,需要替換Windows系統中的其它Callback函數。這些被替換的Callback函數可能是別的程式擁有的。
3)網路流量監控與管理。
監控電腦上的進程的連網情況。
如果要限制網路速度的快和慢, 可以截取網路資料包,然後做適當的丟包處理。
因為NDIS驅動程式,可以直接操控資料連結層的乙太網路資料包,可以使用NDIS驅動來進行丟包處理的操作。而進行資料包的丟棄處理,就是可以控制網路速度的快、慢。在程式碼裡,我們可以設計一些規則來決定什麼時候需要丟棄資料包、什麼時候不需要丟棄資料包。
由於NDIS不能夠得到進程的資訊。所以要配合TDI、WFP驅動來得到進程的資訊。
本地連接埠號碼、本地IP、遠程連接埠號碼、遠程IP、協議類型、進程路徑、進程ID號。如果,想擷取這些資訊,可以直接在WFP提供的回呼函數FWPM_LAYER_ALE_AUTH_CONNECT_V4裡面擷取。這個回呼函數的最後一個參數,可以指定一個值,用來允許存取還是攔截。
由於在Windows7或更高版本的Windows系統裡面,TDI技術已經被廢棄了,而使用了WFP技術來代替TDI技術。所以,在開發網路流量監控的時候,最好用上NDIS和WFP技術。
4)監控管理Windows檔案系統。
監控Windows系統上,檔案的開啟、建立、刪除、複製、粘貼、剪下、讀、寫 等狀態。
為了達到通用性,不論是在 32位Windows系統上,還是64位Windows系統上,都要使用MiniFilter檔案系統過濾驅動的開發技術,來監管檔案的這些狀態。不應該使用Hook SSDT的鉤子技術來監控管理檔案系統。
主要是:實現IRP_MJ_CREATE、IRP_MJ_READ、IRP_MJ_WRITE等這些IRP請求的
Pre和Post函數的代碼實現。並決定是否允許使用者操作、是否禁止。就是在代碼裡面設定:
STATUS_ACCESS_DENIED、STATUS_SUCCESS這樣的標誌。
5)監控管理Windows註冊表。
監控註冊表的索引值是否:開啟、建立、刪除、複製、粘貼、剪下、讀、寫 等狀態。
在32 位的Windows作業系統上:
在 WindowsXP以及更早的Windows作業系統上,在註冊表防護的時候,可以進行SSDT Hook的操作。 主要是Hook掉以下幾個核心功能:ZwSetValueKey、ZwCreateKey、ZwDeleteValueKey、ZwDeleteKey等等。因此,為了有效地管理註冊表,我們的安全衛士還應該Hook掉 KiFastCallEntry()函數。 這個函數是所有SSDT HooK函數的管理中轉站。 我們可以禁止別人來Hook一些函數。這樣可以有效地防止而已程式來操控註冊表。
在64位的Windows作業系統上:
在Windows7、Windows8或更高版本的Windows系統裡面,Microsoft 公司提供了註冊表專用的管理函數----CmRegisterCallback,我們可以用這個函數來監控註冊表。
需要說明的是:
在WindowsXP以及更早的Windows作業系統上,Microsoft公司沒有提供CmRegisterCallback核心功能,所以只能使用SSDT Hook的方式來管理註冊表。
在Windows7、Windows8或更高版本的Windows系統裡,不論是32位還是64位的Windows系統,都已經可以使用CmRegisterCallback函數了。
CmRegisterCallback函數,主要是提供了一個函數指標,在這個指標裡面來實現代碼,進行註冊表的監控管理。
CmRegisterCallback函數,和上面提到的自我防護一樣。 也需要注意Callback函數可以擁有的個數。若一台電腦裡面的Callback函數多於Windows作業系統所規定的個數,那麼
Windows系統將不行掛載Callback函數。這時,需要替換Windows系統中的其它Callback函數。這些被替換的Callback函數可能是別的程式擁有的。
6)沙箱。
沙箱其實就是一個Windows過濾檔案驅動,具體來說,就是你把要寫的東西寫到了硬碟上,但實際上並沒有寫到硬碟,而是到了一個轉存處,讀取內容需要判斷是沙箱開啟之前就存在的內容還是開沙箱之後寫入的內容,要分別從不同的地方讀取內容,重啟之後把轉存的地方清零。
在實現沙箱代碼的時候,要做以下幾個工作:
(1)檔案系統虛擬化
重新導向檔案目錄的路徑。
重新編寫一個Windows檔案系統,完全映射真實的Windows檔案系統。可以參考WDK 內建的例子FastFat工程代碼,並在此基礎上進行修改。
(2)註冊表虛擬化
重新導向註冊表相關索引值的路徑。
重新實現一個註冊表系統的驅動程式。完全映射真實的Windows註冊表。封裝註冊表操控的核心功能、定義通用的HIVE資料結構、
(3)核心對象虛擬化
主要是:突破單一實例程式在沙箱裡和沙箱外同時運行時的限制。比如一部分遊戲的多開限制。
(4)服務虛擬化
對於沙箱建立的服務進行虛擬化,主要作用是防止沙箱內的程式通過服務進程來穿透沙箱。
(5)視窗虛擬化
作用同核心對象虛擬化。
(6)DCOM虛擬化
使沙箱內進程的功能更加完善,比如ie瀏覽器在很多地方就使用了DCOM組件,如不進行虛擬化則ie有些功能會不正常。
(7)多沙箱支援
同時存在多個沙箱,每個沙箱互不干擾,彼此不知道對方的存在。
(8)日誌記錄
支援系統從WindowsXP到Windows8.1的32位和64位作業系統。
(9)Inline Hook、SSDT Hook、Shadow SSDT Hook、Object Hook
實現鉤子引擎。同時要確保能在 Windows x64操作提供上能夠正常使用。
(10)服務端進程
用來類比RPC通訊。實現所需要進行RPC互動的各種訊息。
沙箱的基礎架構:
沙箱在進程層級上操作。所有需要裝在沙箱中的東西都需要生存在進程中。最小的沙箱配置需要兩個進程:一個是許可權控制,稱為(代-理),和一個或者多個沙箱化的進程,稱為目標。在文檔和代碼當中,這兩個術語始終有精確的內涵。沙箱作為一個動態連結程式庫提供,必須連結到代-理和目標可執行程式中。
在沙箱中,代-理是一個瀏覽器進程。主要是:一個沙箱進程的許可權控制者/管理者。
代-理進程的任務有:
為每一個目標進程提供策略
產生目標進程
安置沙箱策略引擎服務
安置沙箱攔截管理器
安置沙箱IPC服務(發送到目標進程)
執行目標進程請求的策略允許的行為。
代-理進程必須在所有目標進程終止後才能終止。沙箱IPC是一個低層次的機制,它用來透明地發送來自於目標進程的特定的Windows API調用到代-理進程:這些調用被評估是否違反了策略。策略允許的調用被代-理進程執行,結果通過相同的IPC返回到目標進程。攔截管理器的工作是調整要通過IPC發送到代-理進程的Windows API調用。
沙箱的限制:
沙箱的核心依賴於四個windows機制提供的保護
(1)一個限制令牌
(2)Windows 工作物件
(3)Windows desktop對象
(4)限於Vista完整性層級
這些機制在保護OS上是非常高效的,它們的配置和使用者資料提供了:
所有的安全資源有一個比空安全性描述元更好的描述符。即:沒有未配置安全性的關鍵資源。
令牌:
擁有一個正常工作的進程的令牌和作業如何做限制。
在設計上,沙箱令牌不能保護下面的不安全資源:
掛載的FAT或者是FAT32卷:它們的安全性描述元實際上是空的。在目標進程上啟動並執行惡意軟體可以讀寫這些卷,只要它能猜到或者推出卷的路徑。
工作物件(Job Objects):
目標進程運行在一個Job對象下面。使用這個Windows機制,一些有趣的沒有傳統對象或者是安全性描述元的限制得以實施:
禁止使用SystemParametersInfo做使用者系統修改,函數可以切換滑鼠左右鍵,或者設定屏保逾時時間。
(1)禁止建立或者是切換案頭
(2)禁止修改使用者顯示配置例如解析度和主顯示器。
(3)不允許讀寫剪下板
(4)禁止廣播Windows訊息
(5)禁止設定全域鉤子
(6)禁止讀取全域Atom表
(7)禁止讀取Job對象外建立的User控制代碼
(8)一個活動進程限制(不允許建立子進程)
(9)每一個進程有自己的工作物件。使用工作物件,沙箱可以阻止
<1>過度使用CPU
<2>過度使用記憶體
<3>過度使用IO
目標進程自啟動:
目標進程啟動時不帶策略指定的限制。它們啟動時帶著與普通使用者進程非常相近的令牌。原因是,在進程啟動時,OS載入器要讀取許多資源,它們中的大部分確實沒有文檔描述而且任何時候也不能更改。同樣的,大多數應用程式使用標準的CRT(C執行階段程式庫)提供標準的開發工具。在進程啟動後,CRT還需要做初始化。
因此,在進程啟動的過程中實際上使用兩個令牌:鎖定令牌,是一個進程令牌;初始令牌,作為impersonation token設定到初始線程。
7)防止被調試。
一些惡意程式,可能會調試我們的安全衛士程式,來破壞、繞過安全衛士等等。被調試的程式可以檢測到自己是否被調試器附加了,如果探知自己正在被調試,肯定是有人試圖反組譯碼的方法破解自己。
(1)Windows API
Win32提供了兩個API函數, IsDebuggerPresent和CheckRemoteDebuggerPresent可以用來檢測當前進程是否正在被調試。
(2)查詢進程PEB的BeingDebugged標誌位
當進程被調試器所附加的時候,作業系統會自動化佈建這個標誌位,因此在程式裡定期查詢這個標誌位就可以了。
(3)查詢進程PEB的NtGlobal標誌位
當進程被調試的時候,作業系統除了修改BeingDebugged這個標誌位以外,NtDll中一些控制堆(Heap)操作的函數的標誌位就會被修改,因此也可以查詢這個標誌位。
(4)查詢進程堆的標誌位ForceFlags
只要進程被調試,進程在堆上分配的記憶體,在分配的堆的頭資訊裡,ForceFlags這個標誌位會被修改,因此可以通過判斷這個標誌位的方式來反調試。因為進程可以有很多的堆,因此只要檢查任意一個堆的頭資訊就可以了。
(5)作業系統,硬體虛擬化。
在電腦裡面,當電腦一開機的時候,BIOS就會上電自檢測。 而BIOS裡面有一個選項VT-X
當VT-X的狀態為Enable的時候,表示電腦可以進行硬體虛擬化的操作。
在代碼實現的時候,因為Windows驅動程式都是運行在Ring0層,調試、反調試的對抗也是直接在Ring0層進行的。
因此,許可權只要比Ring0層高,那麼就可以完全阻止其它程式來調試我們的程式。
目的:即使程式碼的實現方法眾所周知,其它任何軟體也無法探測到它。
硬體虛擬化的實現步驟:
<1>檢查當前電腦的CPU是否支援硬體虛擬化技術,使用彙編指令CPUID來查詢是否
CPUID.1:ECX.VMX[bit 5]=1,也就是VMX位結果是否為1。
設定CR4.VMXE[bit 13]=1,並且在記憶體中分配出VMXON地區和VMCS控制塊。它們都必須分配在4KB頁對齊的記憶體地區上。
<2>在驅動程式代碼裡面,通過組合語言指令VMXON來進入VMX Root模式,這樣就開啟了虛擬機器管理器的運行環境。然後使用VMLAUNCH指令,使目標系統正式運行在虛擬機器中。
<3>在程式碼裡面,調用Windows核心功能MmInitManager()、MmMapGuestKernelPages()、
MmMapGuestPages()等等來構建私人頁表。
<4>按照一般驅動的方法編寫代碼,來阻止調試。因為是比Ring0層更底層,所以可以非常有效地控制其它程式來調試。
windows安全行業功能體系