基于WinIO 3.0实现驱动级键盘模拟输入

一个业务场景需要使用驱动级的键盘模拟,折腾了2天,总结一下,为后人节省时间。

限制条件:

1.需要真实PC机,虚拟机不行

2.仅支持PS/2 键盘(指外接键盘,笔记本直接使用是没问题的)

实现:

关于WinIO没啥好说的,自行查阅吧。

直接上可执行代码,注意红色注释部分,网上很多资料这几个不对导致不能有正确结果

测试程序里扣出来的,请先行初始化调用InitializeWinIo();

#define KBC_CMD 0x64
#define KBC_DATA 0x60

void KBCWait4IBE()
{
 DWORD dwVal=0;

do
 {
  GetPortVal(KBC_CMD,&dwVal,1);
 }
 while(dwVal   &   0x00000002);     //其他条件均不正确

}

void KEY_DOWN(int vk_in)
{
 bool bRet  = false;
 unsigned int myscancode;
 myscancode=MapVirtualKey(BYTE(vk_in),0);
 KBCWait4IBE();
 bRet = SetPortVal(KBC_CMD,0xD2,1);
 KBCWait4IBE();
 bRet = SetPortVal(KBC_DATA,0xE2,1);
 KBCWait4IBE();
 bRet = SetPortVal(KBC_CMD,0xD2,1);
 KBCWait4IBE();
 bRet = SetPortVal(KBC_DATA,myscancode,1);
}

void KEY_UP(int vk_in)
{
 bool bRet  = false;
 unsigned myscancode;
 myscancode=MapVirtualKey(BYTE(vk_in),0);
 KBCWait4IBE();
 bRet = SetPortVal(KBC_CMD,0xD2,1);
 KBCWait4IBE();
 bRet = SetPortVal(KBC_DATA,0xE0,1);
 KBCWait4IBE();
 bRet = SetPortVal(KBC_CMD,0xD2,1);
 KBCWait4IBE();

bRet = SetPortVal(KBC_DATA,(myscancode|0x80),1); //此处需要与上0x80
}

void Key_Press(int vk_in)
{
//  sti() ;

KEY_DOWN(vk_in);
 Sleep(150);
 KEY_UP(vk_in);
 Sleep(150);
}

void InputString(CString &strInput)
{
 int nLen = strInput.GetLength();

for (int i = 0; i < nLen; i++)
 {
  short nKey = VkKeyScan(strInput.GetAt(i));    //注:由ASCII码转成按键码
  bool bShift = (nKey & 0x100);                 //shift键是否按下检查

long n = GetKeyState(VK_CAPITAL);             //Caps键是否按下检查

Key_Press(nKey);
 }

}

void CWinIOTestDlg::OnButton1()
{
 // TODO: Add your control notification handler code here

CString strInput;
 
  CWnd* pWnd =
  GetDlgItem( IDC_EDIT1 );

pWnd->GetWindowText(strInput);

Sleep(4000);     //可以不用,我测试时留时间给自己切换窗口用的

InputString(strInput);

}

void CWinIOTestDlg::OnCancel()
{
 // TODO: Add extra cleanup here
     ShutdownWinIo();
 CDialog::OnCancel();
}

另WinIO 3.0的32位系统代码有点问题,在某些密码输入控件下输入会抛特权指令异常(privileged instruction)

解决方法也很简单(自己找解决办法搞了一天),修改WinIO代码为如下所示,重新编译生成DLL即可

Port32.cpp

// ---------------------------------------------------- //
//                      WinIo v3.0                      //
//     Direct Hardware Access Under Windows //
//           Copyright 1998-2010 Yariv Kaplan           //
//               http://www.internals.com               //
// ---------------------------------------------------- //

#include <windows.h>
#include <winioctl.h>
#include <conio.h>
#include "port32.h"
#include "..\drv\winio_nt.h"
#include "winio.h"

bool _stdcall GetPortVal(WORD wPortAddr, PDWORD pdwPortVal, BYTE bSize)
{
 if (!IsWinIoInitialized)
 {
  return false;
 }

#ifdef _WIN64
 tagPortStruct PortStruct;
 DWORD dwBytesReturned;

PortStruct.bSize = bSize;
 PortStruct.wPortAddr = wPortAddr;

return DeviceIoControl(hDriver, IOCTL_WINIO_READPORT, &PortStruct, sizeof(PortStruct),
  pdwPortVal, sizeof(DWORD), &dwBytesReturned, NULL);

#elif _WIN32
 // If this is a 64 bit OS, we must use the driver to access I/O ports even if the application is 32 bit
 //if (g_Is64BitOS)
 {
  tagPortStruct PortStruct;
  DWORD dwBytesReturned;

PortStruct.bSize = bSize;
  PortStruct.wPortAddr = wPortAddr;

return DeviceIoControl(hDriver, IOCTL_WINIO_READPORT, &PortStruct, sizeof(PortStruct),
   pdwPortVal, sizeof(DWORD), &dwBytesReturned, NULL);
 }

#endif

return true;
}

bool _stdcall SetPortVal(WORD wPortAddr, DWORD dwPortVal, BYTE bSize)
{
 if (!IsWinIoInitialized)
 {
  return false;
 }

#ifdef _WIN64
 tagPortStruct PortStruct;
 DWORD dwBytesReturned;

PortStruct.bSize = bSize;
 PortStruct.dwPortVal = dwPortVal;
 PortStruct.wPortAddr = wPortAddr;

return DeviceIoControl(hDriver, IOCTL_WINIO_WRITEPORT, &PortStruct, sizeof(PortStruct),
  NULL, 0, &dwBytesReturned, NULL);
#elif _WIN32
 // If this is a 64 bit OS, we must use the driver to access I/O ports even if the application is 32 bit
 //if (g_Is64BitOS)
 {
  tagPortStruct PortStruct;
  DWORD dwBytesReturned;

PortStruct.bSize = bSize;
  PortStruct.dwPortVal = dwPortVal;
  PortStruct.wPortAddr = wPortAddr;

return DeviceIoControl(hDriver, IOCTL_WINIO_WRITEPORT, &PortStruct, sizeof(PortStruct),
   NULL, 0, &dwBytesReturned, NULL);
 }

#endif

return true;
}

基于WinIO 3.0实现驱动级键盘模拟输入的更多相关文章

  1. 谈谈基于OAuth 2.0的第三方认证 [下篇]

    从安全的角度来讲,<中篇>介绍的Implicit类型的Authorization Grant存在这样的两个问题:其一,授权服务器没有对客户端应用进行认证,因为获取Access Token的 ...

  2. 谈谈基于OAuth 2.0的第三方认证 [中篇]

    虽然我们在<上篇>分别讨论了4种预定义的Authorization Grant类型以及它们各自的适用场景的获取Access Token的方式,我想很多之前没有接触过OAuth 2.0的读者 ...

  3. 谈谈基于OAuth 2.0的第三方认证 [上篇]

    对于目前大部分Web应用来说,用户认证基本上都由应用自身来完成.具体来说,Web应用利用自身存储的用户凭证(基本上是用户名/密码)与用户提供的凭证进行比较进而确认其真实身份.但是这种由Web应用全权负 ...

  4. 基于Qt5.5.0的sql数据库、SDK_tts文本语音朗读的CET四六级单词背诵系统软件的编写V1.0

    作者:小波 QQ:463431476 请关注我的博客园:http://www.cnblogs.com/xiaobo-Linux/ 我的第二款软件:CET四六级单词背诵软件.基于QT5.5.0.sql数 ...

  5. 基于Qt5.5.0的sql,C++备忘录软件的编写

    我的第一个软件. 基于Qt5.5.0的 sql ,C++备忘录软件version1.0的编写 我用的Qt版本是5.5.0免配置编译器的版本,这里附上我使用的软件下载地址:http://download ...

  6. 基于Spark1.3.0的Spark sql三个核心部分

    基于Spark1.3.0的Spark sql三个核心部分: 1.可以架子啊各种结构化数据源(JSON,Hive,and Parquet) 2.可以让你通过SQL,saprk内部程序或者外部攻击,通过标 ...

  7. WebDriver基本API使用(基于Java)V1.0

    WebDriver基本API使用(基于Java)V1.0http://www.docin.com/p-803032877.html

  8. 自己编写的基于VC++6.0的串口调试软件,并贡献源程序!

    自己编写的基于VC++6.0的串口调试软件源程序! 程序下载链接: 点击打开链接

  9. 基于MyEclipse+9.0+++Tomcat+7.0的SSH+平台搭建

    基于MyEclipse+9.0+++Tomcat+7.0的SSH+平台搭建 http://wenku.baidu.com/view/96fbfe0f581b6bd97f19ea1d.html 用MyE ...

随机推荐

  1. 将td中文字过长的部分变成省略号显示的小技巧

    首先设置表格的样式table-layout:"fixed"再设置表格的宽度(这步必须) 最后再设置td样式的三个必要属性 代码如下: text-overflow: ellipsis ...

  2. python3颜色输出

    遇到一个项目,需求是在python3中,处理结果显示高亮加颜色,然后资料整理如下 ### 格式: \033[显示方式;前景色;背景色m 这里的格式是规定了m后面的输出字符颜色样式 说明: 前景色 背景 ...

  3. nginx 为什么要反向代理 影藏后端 高效连接(给nginx,他自己返回) 端口冲突解决 多个服务

    nginx 为什么要反向代理  影藏后端   高效连接(给nginx,他自己返回)  端口冲突解决  多个服务 单机使用反向代理可以根据不同url匹配到不同站点   rsync 的工作原理和应用实例 ...

  4. Python爬虫学习笔记(一)

    1.urllib2简介 urllib2的是爬取URL(统一资源定位器)的Python模块.它提供了一个非常简单的接口,使用urlopen函数.它能够使用多种不同的协议来爬取URL.它还提供了一个稍微复 ...

  5. JQ 报表插件 jquery.jqplot 使用

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <hea ...

  6. storm入门教程 第一章 前言

    转自:http://blog.linezing.com/?p=1847 storm:http://www.cnblogs.com/panfeng412/tag/Storm/ http://blog.l ...

  7. java ssh介绍(1)

    今年我一直在思考web开发里的前后端分离的问题,到了现在也颇有点心得了,随着这个问题的深入,再加以现在公司很多web项目的控制层的技术框架由struts2迁移到springMVC,我突然有了一个新的疑 ...

  8. WPF界面框架的设计

    http://www.cnblogs.com/baihmpgy/p/osgi_muinavtree_fx.html

  9. MySQL中的日期和时间函数

    常用日期函数如下: 函   数 功   能 CURDATE() 获取当前日期 CURTIME() 获取当前时间 NOW() 获取当前的日期和时间 UNIX_TIMESTAMP(date) 获取日期的U ...

  10. 如何使用C#操作WinAPI

    Windows API是对Windows操作系统的API函数,在C#中调用Windows API的实质是托管代码对非托管代码的调用. 主要使用的格式就是: using System.Runtime.I ...