經過直接調用Kbdclass的回調函數KeyboardClassServiceCallback直接給上層發送鍵盤驅動。這個方法網上已經公開,參考Hook KeyboardClassServiceCallback實現鍵盤 Logger,其餘的還有不少,能夠到網上去查。 簡單說一下沒有公開的部分,就是按下和鬆開的模擬,已經擴展鍵的模擬。 模擬主要是構造KEYBOARD_INPUT_DATA結構,按下和鬆開的Flags分別對應KEY_MAKE、KEY_BREAK,而後調用KeyboardClassServiceCallback。這裏直接用的sudami的代碼,在此謝過,懶得改了。代碼以下: case IOCTL_KEY_DOWN : { if (ioBuf) { lKeyCode = *(ULONG*)ioBuf; dprintf("[KeyMouse] KeymouseDispatchDeviceControl IOCTL_KEY_DOWN = 0x%x/n", lKeyCode); dwSize = sizeof(KEYBOARD_INPUT_DATA); __asm { push eax mov kid.UnitId,0 ; 構造 KEYBOARD_INPUT_DATA mov eax,lKeyCode mov kid.MakeCode,ax mov kid.Flags,KEY_MAKE ;模擬按下 mov kid.Reserved,0 mov kid.ExtraInformation,0 lea eax,dwRet push eax lea eax,kid add eax,dwSize push eax lea eax,kid push eax push g_kbDeviceObject call orig_KeyboardClassServiceCallback ;利用 KeyboardClassServiceCallback 模擬按鍵 pop eax } status = STATUS_SUCCESS; } break; } case IOCTL_KEY_UP: { if (ioBuf) { lKeyCode = *(ULONG*)ioBuf; dprintf("[KeyMouse] KeymouseDispatchDeviceControl IOCTL_KEY_UP = 0x%x/n", lKeyCode); dwSize = sizeof(KEYBOARD_INPUT_DATA); __asm { push eax mov kid.UnitId,0 ; 構造 KEYBOARD_INPUT_DATA mov eax,lKeyCode mov kid.MakeCode,ax mov kid.Flags,KEY_BREAK ;模擬鬆開 mov kid.Reserved,0 mov kid.ExtraInformation,0 lea eax,dwRet push eax lea eax,kid add eax,dwSize push eax lea eax,kid push eax push g_kbDeviceObject call orig_KeyboardClassServiceCallback ;利用 KeyboardClassServiceCallback 模擬按鍵 pop eax } status = STATUS_SUCCESS; } break; } 擴展鍵的區別是按下和鬆開的Flags分別對應KEY_E0、KEY_E1。其餘和上面的同樣,這裏就不貼代碼出來了。主要說一下擴展鍵有哪幾個:(前面是MakeCode,後面表明按鈕) 0x1D-RIGHT CONTROL 0x38-RIGHT ALT 0x48-↑ 鍵 0x50-↓ 鍵 0x4b-← 鍵 0x4d-→ 鍵 0x5B-LEFT WIN 0x5C-RIGHT WIN 重點說一下鼠標的模擬,原理和鍵盤的同樣。查找驅動mouclass.sys中的MouseClassServiceCallback函數,而後獲取//Device//PointerClass0設備對象指針,構造MOUSE_INPUT_DATA結構,而後調用MouseClassServiceCallback。難點就在與構造MOUSE_INPUT_DATA結構上面。 typedef struct _MOUSE_INPUT_DATA { USHORT UnitId; USHORT Flags; union { ULONG Buttons; struct { USHORT ButtonFlags; USHORT ButtonData; }; }; ULONG RawButtons; LONG LastX; LONG LastY; ULONG ExtraInformation; } MOUSE_INPUT_DATA, *PMOUSE_INPUT_DATA; 經過調試操做系統調用MouseClassServiceCallback的參數,主要的標示有3個。 Flags標誌是標示鼠標的座標屬性(即相對座標、絕對座標等) ButtonFlags標誌是左右中鍵按下和鬆開的標誌 LastX是鼠標X座標,與Flags標誌有關 LastY是鼠標Y座標,與Flags標誌有關 其餘幾項能夠填0。 具體模擬代碼以下: case IOCTL_MOUSE_LEFT_BUTTON_DOWN: { MouseFlags = MOUSE_LEFT_BUTTON_DOWN; goto __MouseCallBack; } case IOCTL_MOUSE_LEFT_BUTTON_UP: { MouseFlags = MOUSE_LEFT_BUTTON_UP; goto __MouseCallBack; } case IOCTL_MOUSE_RIGHT_BUTTON_DOWN: { MouseFlags = MOUSE_RIGHT_BUTTON_DOWN; goto __MouseCallBack; } case IOCTL_MOUSE_RIGHT_BUTTON_UP: { MouseFlags = MOUSE_RIGHT_BUTTON_UP; goto __MouseCallBack; } case IOCTL_MOUSE_MIDDLE_BUTTON_DOWN: { MouseFlags = MOUSE_MIDDLE_BUTTON_DOWN; goto __MouseCallBack; } case IOCTL_MOUSE_MIDDLE_BUTTON_UP: { MouseFlags = MOUSE_MIDDLE_BUTTON_UP; __MouseCallBack: mid.UnitId = 0; mid.Flags = MOUSE_MOVE_RELATIVE; mid.Buttons = 0; mid.ButtonFlags = MouseFlags; mid.RawButtons = 0; mid.LastX = *((ULONG*)ioBuf); mid.LastY = *((ULONG*)ioBuf+1); mid.ExtraInformation = 0; InputDataStart = ∣ InputDataEnd = InputDataStart+1; orig_MouseClassServiceCallback( g_mouDeviceObject, InputDataStart, InputDataEnd, &InputDataConsumed ); status = STATUS_SUCCESS; break; } case IOCTL_MOUSE_MOVE_RELATIVE: { mid.Flags = MOUSE_MOVE_RELATIVE; //相對座標 goto __MouseMoveCallBack; } case IOCTL_MOUSE_MOVE_ABSOLUTE: { mid.Flags = MOUSE_MOVE_ABSOLUTE; //絕對座標 goto __MouseMoveCallBack; } case IOCTL_MOUSE_VIRTUAL_DESKTOP: { mid.Flags = MOUSE_VIRTUAL_DESKTOP; //虛擬桌面 __MouseMoveCallBack: mid.UnitId = 1; mid.Buttons = 0; mid.RawButtons = 0; mid.LastX = *((ULONG*)ioBuf); mid.LastY = *((ULONG*)ioBuf+1); mid.ExtraInformation = 0; InputDataStart = ∣ InputDataEnd = InputDataStart+1; orig_MouseClassServiceCallback( g_mouDeviceObject, InputDataStart, InputDataEnd, &InputDataConsumed ); status = STATUS_SUCCESS; break; } 驅動在windows XP SP2上測試經過。