push edx ; ObjectAttributes
push 0F000Fh ; DesiredAccess
lea eax, [ebp+Handle]
push eax ; DirectoryHandle
call ds:ZwOpenDirectoryObject ;枚举驱动对象目录
mov [ebp+var_78], eax
cmp [ebp+var_78], 0
jge short loc_1068C
1068C的汇编代码如下
loc_1068C: ; Tag
push 4B594244h
push 1000h ; NumberOfBytes
push 1 ; PoolType
call ds:ExAllocatePoolWithTag ;分配内存空间
mov [ebp+P], eax
push 4B594244h ; Tag
push 1000h ; NumberOfBytes
push 1 ; PoolType
call ds:ExAllocatePoolWithTag
mov [ebp+Context], eax
push 1000h ; size_t
push 0 ; int
mov ecx, [ebp+P]
push ecx ; void *
call memset
add esp, 0Ch
push 1000h ; size_t
push 0 ; int
mov edx, [ebp+Context]
push edx ; void *
call memset ;内存空间清 0,初始化
add esp, 0Ch
xor eax, eax
mov [ebp+var_54], eax
mov [ebp+var_50], eax
mov [ebp+var_4C], eax
mov [ebp+var_48], eax
mov [ebp+var_34], 0
mov dword_11510, 0
综合以上两段代码,可得知驱动在IRP_MJ_CREATE请求中分配内存空间,并对所有的驱
动对象进行了枚举,接下来的事情已经很明朗了:对每个驱动对象进行检查,匹配到特定的
驱动程序,过滤驱动程序是中间层的驱动程序,它通过把自身挂接在驱动层中或者挂接到其
他驱动程序上来拦截设备的I/O请求,通过IoAttachDevice或者IoAttachDeviceByPointer
实现自身的挂接。
push offset aKeyboardclass ; "KeyboardClass"
lea ecx, [ebp+String2]
push ecx ; DestinationString,传参
call ds:RtlInitUnicodeString
push 0 ; CaseInSensitive
lea edx, [ebp+String2]
push edx ; String2
mov eax, [ebp+String1]
push eax ; String1
call ds:RtlCompareUnicodeString
驱动通过 unicode编码比较keyboardclass字符,以此实现驱动对象的定位。
push offset aDeviceKeyboard ; "\\Device\\KeyboardClass0" 比较
keyboardclass0
push offset aDeviceKeyboa_1 ; \\Device\\KeyboardClass1 比较
keyboardclass1
push offset aDeviceKeyboa_0 ; "\\Device\\KeyboardClass2" 比较
keyboardclass2
作者在这里有一点值得商榷,他分别比较了keyboardClass0-2,keyboard0只支持 PS/2
键盘,如果附加到驱动层上也只能获得 PS/2 键盘的输入,而对 USB 键盘无能为力,USB 键 |