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


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/mergerly/archive/2009/11/19/4838655.aspx

上传的附件 KeyMouse.zip