8、加裁驅動,驅動與裝置
1)前面我們主要通過Driver Studio和KmdManager。現在了解一下程式加裁。
Windows NT式驅動是基于服務方式加載的,可以通過修改系統資料庫内容完成,也可以通過服務相關API完成。裝置驅動程式的動态加載主要由服務控制管理程式(Service Control Manager, SCM)系統元件完成,該元件可以啟動、停止和控制服務等。
具體加裁方法,參見 [1,3]。在這種情況下加載驅動需要調用OpenSCManager->CreateService->StartService,此時驅動會在服務管理器中注冊自己,但這往往顯得麻煩,我們還有一個不需要通過服務而直接加載驅動的方法,即使用ZwLoadDriver(這個函數通常是ring0中加載驅動時用,由于它被ntdll.dll導出,是以在ring3也可以用)進行直接加載。
及 http://hi.baidu.com/xlsdg/blog/item/93632681bf1ed4dabc3e1e97.html
2)裝置與符号連結
驅動程式和系統其他元件之間的互動是通過給裝置發送或者接受發給裝置的請求來互動的。換句話說,一個沒有任何裝置的驅動是不能按規範方式和系統互動的。當然也不會收到任何IRP,分發函數也失去了意義。
但并不意味着這樣的驅動程式不存在。如果一個驅動程式隻是想寫寫日志檔案、Hook某些核心函數或者是做一些其他的小動作,也可以不生成任何裝置,也不需要關心分發函數的設定。
如果驅動程式要和應用程式之間通信,則應該生成裝置。此外還必須為裝置生成應用程式可以通路的符号連結。下面的驅動程式生成了一個裝置,并設定了分發函數:
代碼
1 #include <ntifs.h>
2
3 NTSTATUS DriverEntry(
4
5 PDRIVER_OBJECT driver,
6
7 PUNICODE_STRING reg_path)
8
9 {
10
11 NTSTATUS status;
12
13 PDEVICE_OBJECT device;
14
15 // 裝置名
16
17 UNICODE_STRING device_name =
18
19 RTL_CONSTANT_STRING("\\Device\\MyCDO");
20
21 // 符号連結名
22
23 UNICODE_STRING symb_link =
24
25 RTL_CONSTANT_STRING("\\DosDevices\\MyCDOSL");
26
27 // 生成裝置對象
28
29 status = IoCreateDevice(
30
31 driver,
32
33 0,
34
35 device_name,
36
37 FILE_DEVICE_UNKNOWN,
38
39 0,
40
41 FALSE,
42
43 &device);
44
45 // 如果不成功,就傳回。
46
47 if(!NT_SUCCESS(status))
48
49 return status;
50
51 // 生成符号連結
52
53 status = IoCreateSymbolicLink(
54
55 &symb_link,
56
57 &device_name);
58
59 if(!NT_SUCCESS(status))
60
61 {
62
63 IoDeleteDevice(device);
64
65 return status;
66
67 }
68
69 // 裝置生成之後,打開初始化完成标記
70
71 device->Flags &= ~DO_DEVICE_INITIALIZING;
72
73 return status;
74
75 }
這個驅動成功加載之後,生成名為“\Device\MyCDO”的裝置。給這個裝置生成了一個符号連結名字“\DosDevices\MyCDOSL”。應用層可以通過打開這個符号連結來打開裝置,可以調用CreateFile就像打開檔案一樣打開。隻是路徑應該是“"\\.\ MyCDOSL”。“\\.\”意味後面是一個符号連結名(使用者态下),而不是普通檔案。請注意,由于C語言中斜杠要雙寫,是以正确的寫法應該是“ \\\\.\\”。
3)裝置的生成安全性限制
NTSTATUS
IoCreateDevice(
IN PDRIVER_OBJECT DriverObject,
IN ULONG DeviceExtensionSize,
IN PUNICODE_STRING DeviceName OPTIONAL,
IN DEVICE_TYPE DeviceType,
IN ULONG DeviceCharacteristics,
IN BOOLEAN Exclusive,
OUT PDEVICE_OBJECT *DeviceObject
);
第一個參數是生成這個裝置的驅動對象。
第二個參數DeviceExtensionSize非常重要;由于分發函數中得到的總是裝置的指針,當使用者需要在每個裝置上記錄一些額外的資訊(比如用于判斷這個裝置是哪個裝置的資訊、以及不同的實際裝置所需要記錄的實際資訊,比如網卡上資料包的流量、過濾器所綁定真實裝置指針等等),需要指定的裝置擴充區記憶體的大小。如果DeviceExtensionSize設定為非0,IoCreateDevice會配置設定這個大小的記憶體在 DeviceObject->DeviceExtension中。以後使用者就可以從根據DeviceObject-> DeviceExtension來獲得這些預先儲存的資訊。
DeviceName如前例,是裝置的名字。目前生成裝置,請總是生成在\Device\目錄下。是以前面寫的名字是“\Device\MyCDO”。
最後生成的裝置對象指針傳回到DeviceObject中。
這種裝置生成之後,必須有系統權限的使用者才能打開(比如管理者)。為了保證互動的成功與安全性,應該用服務程式與之互動,但是有時候必須用普通使用者打開裝置。必須用IoCreateDeviceSecure。
IoCreateDeviceSecure(
IN PCUNICODE_STRING DefaultSDDLString,
IN LPCGUID DeviceClassGuid,
OUT PDEVICE_OBJECT *DeviceObject)
這個函數增加了兩個參數(其他的沒變)。一個是DefaultSDDLString,這是一個用于描述權限的字元串。字元串“D:P(A;;GA;;;WD)”将滿足“人人皆可以打開”的需求。
<a href="http://msdn.microsoft.com/en-us/library/ff563667%28VS.85%29.aspx">http://msdn.microsoft.com/en-us/library/ff563667%28VS.85%29.aspx</a>
<a href="http://msdn.microsoft.com/en-us/library/ff548407%28VS.85%29.aspx">http://msdn.microsoft.com/en-us/library/ff548407%28VS.85%29.aspx</a>
另一個參數是一個裝置的GUID,随機手寫一個GUID。不要和其他裝置的GUID沖突。
// 随機手寫一個GUID
const GUID DECLSPEC_SELECTANY MYGUID_CLASS_MYCDO =
{0x26e0d1e0L, 0x8189, 0x12e0, {0x99,0x14, 0x08, 0x00, 0x22, 0x30, 0x19, 0x03}};
// 全使用者可讀寫權限
UNICODE_STRING sddl =
RLT_CONSTANT_STRING(L"D:P(A;;GA;;;WD)");
// 生成裝置
status = IoCreateDeviceSecure( DriverObject,
0,
&device_name,
FILE_DEVICE_UNKNOWN,
FILE_DEVICE_SECURE_OPEN,
FALSE,
&sddl,
(LPCGUID)&SFGUID_CLASS_MYCDO,
&device);
使用這個函數的時候,必須連接配接庫wdmsec.lib。
4)符号連結的使用者相關性
簡單的符号連結(還有一種使用GUID的符号連結)總是命名在\DosDevices\之下。但是實際上這會有一些問題。
比較進階的Windows系統(哪個版本的作業系統很難講,可能必須判定更新檔号),符号連結也帶有使用者相關性。如果一個普通使用者建立了符号連結 “\DosDevices\MyCDOSL”,那麼,其實其他的使用者是看不見這個符号連結的(除在DriverEntry中外,因為 DriverEntry總是在程序“System”中執行)。目前使用者總是取決于目前啟動目前程序的使用者。
解決方案是:任何使用者都可以生成全局符号連結,讓所有其他使用者都能看見。路徑“\DosDevices\MyCDOSL”改為“\DosDevices\Global\MyCDOSL”即可。
但是在不支援符号連結使用者相關性的系統上,生成“\DosDevices\Global\MyCDOSL”這樣的符号連結是一種錯誤。為此必須先判斷一下。
1 UNICODE_STRING device_name;
3 UNICODE_STRING symbl_name;
5 if (IoIsWdmVersionAvailable(1, 0x10))
7 {
9 // 如果是支援符号連結使用者相關性的版本的系統,用\DosDevices\Global.
11 RtlInitUnicodeString(&symbl_name, L"\\DosDevices\\Global\\SymbolicLinkName");
13 }
15 else
16
17 {
19 // 如果是不支援的,則用\DosDevices
21 RtlInitUnicodeString(&symbl, L"\\DosDevices\\SymbolicLinkName");
23 }
25 // 生成符号連結
27 IoCreateSymbolicLink(&symbl_name, &device_name);