经过直接调用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上测试经过。