WinIO3.0调用键盘实践-winxp、win7、win10下32位64位都适用

目录

 

准备

步骤

第一步:Windows系统开启测试模式(针对64位系统,32系统不需要)

第二步:WinIo64.sys安装签名(针对64位系统,32系统不需要)

第三步:Java代码及c++代码实现

 第四步:执行代码


准备

开发环境:winxp、win7、win10 32位及64位

开发语言:Java和c++

必要文件:WinIo32.dll、WinIo64.dll、WinIo32.sys、WinIo64.sys

步骤

(注:有些步骤的详细做法非常简单,如果不明白请问度哥)

第一步:Windows系统开启测试模式(针对64位系统,32系统不需要)

开启测试模式:cmd执行命令:bcdedit /set testsigning on 然后重启,电脑右下角出现测试模式......

关闭测试模式:cmd执行命令:bcdedit /set testsigning off 然后重启,电脑右下角测试模式消失

参考链接如下:

win10:https://jingyan.baidu.com/article/72ee561a724b74e16138df1c.html
win7、winxp:https://jingyan.baidu.com/article/acf728fd21c3e7f8e510a3ef.html

第二步:WinIo64.sys安装签名(针对64位系统,32系统不需要)

1、打开 WinIO64.sys的属性框,翻到“数字签名”选项卡,点击“详细信息”

2、在新出来的对话框中点击“查看证书”

3、在又新出来的对话框中点击“安装证书”

4、点击“下一步”,然后选择“将所有的证书放入下列存储”

5、点击浏览,选择“受信任的根证书发布机构”

6、点击“下一步”,然后点击“完成”

7、在弹出的“安全性警告”对话框中选择“是”,才能导入成功

8、重启电脑

第三步:Java代码及c++代码实现

网上有很多人使用jnative实现的,这里使用jna实现。jnative是在jna的基础上封装的有局限性。以下是maven依赖:


   
      net.java.dev.jna
      jna
      4.4.0
   
   
      net.java.dev.jna
      jna-platform
      4.4.0
   
   
      org.apache.commons
      commons-lang3
      3.9
   

winio代码实现

import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.WString;
import com.sun.jna.win32.W32APIOptions;

/**
 * author songxq
 * date 2020/6/18
 * description
 */
public interface WinIo extends Library {

    /**
     * 系统架构32位或者64位
     */
    String ARCH = System.getProperty("os.arch");
    /**
     * 使用的winio版本
     */
    String WIN_IO_LIB_NAME = "x86".equals(ARCH) ? "WinIo32" : "WinIo64";

    WinIo INSTANCE = (WinIo) Native.loadLibrary(WIN_IO_LIB_NAME, WinIo.class, W32APIOptions.DEFAULT_OPTIONS);

    /**
     * PS/2键盘的命令端口
     */
    int CONTROL_PORT = 0x64;
    /**
     * PS/2键盘的数据端口
     */
    int DATA_PORT = 0x60;

    /**
     * 初始化winiolib库
     * @param path	驱动文件绝对路径
     * @return
     */
    boolean InitializeWinIo(WString path);

    /**
     * 释放资源及开辟的内存空间
     */
    void ShutdownWinIo();

    /**
     * 读数据
     * 98/ME系列使用GetPortVal  NT/2000/XP系列可以使用_inp/_inpw/_inpd
     * @param portAddr	io地址
     * @param pPortVal	指针变量
     * @param size 数据大小
     * @return
     */
    boolean GetPortVal(int portAddr, Pointer pPortVal, int size);

    /**
     * 写数据
     * @param portAddr	io地址
     * @param portVal	指针变量
     * @param size	数据大小
     * @return
     */
    boolean SetPortVal(int portAddr, int portVal, int size);
}

键盘调用代码


import com.sun.jna.Memory;
import com.sun.jna.Pointer;
import com.sun.jna.WString;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;

/**
 * author songxq
 * date 2020/6/18
 * description
 */
public class VirtualKB {

    private static final WinIo WIN_IO = WinIo.INSTANCE;

    private static final String WIN_BASE_SYSTEM32 = "C:\\Windows\\System32";

    private static final String WINIO_INSTALL_PATH = "C:\\INSTALLWINIO";

    private static final String WINIO_INSTALL_EXE = "C:\\INSTALLWINIO\\InstallWinIo.exe";

    private static final String WIN_32_SYS = "WinIo32.sys";

    private static final String WIN_64_SYS = "WinIo64.sys";

    //keyame
    public static final String Tab = "Tab";
    public static final String Esc = "Esc";
    public static final String Backspace = "Backspace";
    public static final String Enter = "Enter";
    public static final String LCtrl = "LCtrl";
    public static final String LShift = "LShift";
    public static final String RShift = "RShift";
    public static final String LAlt = "LAlt";
    public static final String Space = "Space";
    public static final String CapsLock = "CapsLock";
    public static final String F1 = "F1";
    public static final String F2 = "F2";
    public static final String F3 = "F3";
    public static final String F4 = "F4";
    public static final String F5 = "F5";
    public static final String F6 = "F6";
    public static final String F7 = "F7";
    public static final String F8 = "F8";
    public static final String F9 = "F9";
    public static final String F10 = "F10";
    public static final String F11 = "F11";
    public static final String F12 = "F12";
    public static final String NumLock = "NumLock";
    public static final String ScrollLock = "ScrollLock";


    static{
        String x86 = "x86";
        String driverName;
        if (x86.equals(WinIo.ARCH)) {
            driverName = WIN_BASE_SYSTEM32 + File.separator + WIN_32_SYS;
        } else {
            driverName = WIN_BASE_SYSTEM32 + File.separator + WIN_64_SYS;
        }
        if(!WIN_IO.InitializeWinIo(new WString(driverName))){
            installSys();
        }
    }

    /**
     * 等待缓冲区置空
     */
    private static void KBCWait4IBE() {
        int val;
        do {
            Pointer p = new Memory(8);
            if (!WIN_IO.GetPortVal(WinIo.CONTROL_PORT, p, 1)) {
                throw new RuntimeException("Cannot Get The Port!");
            }
            val = p.getInt(0);
        } while ((0x2 & val) > 0);
    }


    private static void down(int key) {
        KBCWait4IBE();
        WIN_IO.SetPortVal(WinIo.CONTROL_PORT, 0xd2, 1);
        KBCWait4IBE();
        WIN_IO.SetPortVal(WinIo.DATA_PORT, key, 1);
    }

    private static void up(int key) {
        KBCWait4IBE();
        WIN_IO.SetPortVal(WinIo.CONTROL_PORT, 0xd2, 1);
        KBCWait4IBE();
        WIN_IO.SetPortVal(WinIo.DATA_PORT, (key | 0x80), 1);
    }

    private static void press(String[] words, long firstSleepTime, long sleepTime) throws Exception{
        if (null == words || words.length == 0) {
            throw new IllegalArgumentException("words Is NULL Or Empty");
        }
        int minSleepTime = 50;
        if (sleepTime < minSleepTime) {
            throw new IllegalArgumentException("SleepTime Less Than 50 ms");
        }
        if (firstSleepTime > 0) {
            Thread.sleep(firstSleepTime);
        }
        for (String word : words) {
            Integer vk = VirtualKBMapping.VK_MAP.get(word);
            if (null == vk) {
                vk = VirtualKBMapping.NEED_SHIFT_VK.get(word);
            }
            if (null == vk) {
                throw new RuntimeException(word + " Not Support");
            }
            boolean needShift = word.length() == 1 && null != VirtualKBMapping.NEED_SHIFT_VK.get(word);
            if (needShift) {
                down(VirtualKBMapping.VK_MAP.get("LShift"));
            }
            down(vk);
            Thread.sleep(sleepTime);
            up(vk);
            if (needShift) {
                up(VirtualKBMapping.VK_MAP.get("LShift"));
            }
        }
    }

    /**
     * 键盘输入文本
     * @param content 文本
     * @param sleepTime 等待时间间隔
     */
    public static void inputStr(String content,long sleepTime) throws Exception {
        if (null == content || content.length() == 0) {
            throw new IllegalArgumentException("content Is NULL Or Empty");
        }
        char[] chars = content.toCharArray();
        for (int i=0;i

虚拟键盘映射代码


import org.apache.commons.lang3.StringUtils;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * author songxq
 * date 2020/6/18
 * description
 */
public class VirtualKBMapping {

    /**
     * 映射基本键map
     */
    static final Map VK_MAP = new HashMap<>();

    /**
     * 映射shift转换键map
     */
    static final Map NEED_SHIFT_VK = new HashMap<>();

    static {
        VK_MAP.put("Esc", 0x01);
        VK_MAP.put("1", 0x02);
        VK_MAP.put("2", 0x03);
        VK_MAP.put("3", 0x04);
        VK_MAP.put("4", 0x05);
        VK_MAP.put("5", 0x06);
        VK_MAP.put("6", 0x07);
        VK_MAP.put("7", 0x08);
        VK_MAP.put("8", 0x09);
        VK_MAP.put("9", 0x0a);
        VK_MAP.put("0", 0x0b);
        VK_MAP.put("-", 0x0c);
        VK_MAP.put("=", 0x0d);
        VK_MAP.put("Backspace", 0x0e);
        VK_MAP.put("Tab", 0x0f);
        VK_MAP.put("q", 0x10);
        VK_MAP.put("w", 0x11);
        VK_MAP.put("e", 0x12);
        VK_MAP.put("r", 0x13);
        VK_MAP.put("t", 0x14);
        VK_MAP.put("y", 0x15);
        VK_MAP.put("u", 0x16);
        VK_MAP.put("i", 0x17);
        VK_MAP.put("o", 0x18);
        VK_MAP.put("p", 0x19);
        VK_MAP.put("[", 0x1a);
        VK_MAP.put("]", 0x1b);
        VK_MAP.put("Enter", 0x1c);
        VK_MAP.put("LCtrl", 0x1d);
        VK_MAP.put("a", 0x1e);
        VK_MAP.put("s", 0x1f);
        VK_MAP.put("d", 0x20);
        VK_MAP.put("f", 0x21);
        VK_MAP.put("g", 0x22);
        VK_MAP.put("h", 0x23);
        VK_MAP.put("j", 0x24);
        VK_MAP.put("k", 0x25);
        VK_MAP.put("l", 0x26);
        VK_MAP.put(";", 0x27);
        VK_MAP.put("'", 0x28);
        VK_MAP.put("`", 0x29);
        VK_MAP.put("LShift", 0x2a);
        VK_MAP.put("\\", 0x2b);
        VK_MAP.put("z", 0x2c);
        VK_MAP.put("x", 0x2d);
        VK_MAP.put("c", 0x2e);
        VK_MAP.put("v", 0x2f);
        VK_MAP.put("b", 0x30);
        VK_MAP.put("n", 0x31);
        VK_MAP.put("m", 0x32);
        VK_MAP.put(",", 0x33);
        VK_MAP.put(".", 0x34);
        VK_MAP.put("/", 0x35);
        VK_MAP.put("RShift", 0x36);
        VK_MAP.put("LAlt", 0x38);
        VK_MAP.put("Space", 0x39);
        VK_MAP.put("CapsLock", 0x3a);
        VK_MAP.put("F1", 0x3b);
        VK_MAP.put("F2", 0x3c);
        VK_MAP.put("F3", 0x3d);
        VK_MAP.put("F4", 0x3e);
        VK_MAP.put("F5", 0x3f);
        VK_MAP.put("F6", 0x40);
        VK_MAP.put("F7", 0x41);
        VK_MAP.put("F8", 0x42);
        VK_MAP.put("F9", 0x43);
        VK_MAP.put("F10", 0x44);
        VK_MAP.put("NumLock", 0x45);
        VK_MAP.put("ScrollLock", 0x46);
        VK_MAP.put("F11", 0x57);
        VK_MAP.put("F12", 0x58);
    }

    static {
        NEED_SHIFT_VK.put("!", 0x02);
        NEED_SHIFT_VK.put("@", 0x03);
        NEED_SHIFT_VK.put("#", 0x04);
        NEED_SHIFT_VK.put("$", 0x05);
        NEED_SHIFT_VK.put("%", 0x06);
        NEED_SHIFT_VK.put("^", 0x07);
        NEED_SHIFT_VK.put("&", 0x08);
        NEED_SHIFT_VK.put("*", 0x09);
        NEED_SHIFT_VK.put("(", 0x0a);
        NEED_SHIFT_VK.put(")", 0x0b);
        NEED_SHIFT_VK.put("_", 0x0c);
        NEED_SHIFT_VK.put("+", 0x0d);
        NEED_SHIFT_VK.put("{", 0x1a);
        NEED_SHIFT_VK.put("}", 0x1b);
        NEED_SHIFT_VK.put(":", 0x27);
        NEED_SHIFT_VK.put("\"", 0x28);
        NEED_SHIFT_VK.put("~", 0x29);
        NEED_SHIFT_VK.put("|", 0x2b);
        NEED_SHIFT_VK.put("<", 0x33);
        NEED_SHIFT_VK.put(">", 0x34);
        NEED_SHIFT_VK.put("?", 0x35);
        NEED_SHIFT_VK.put("Q", 0x10);
        NEED_SHIFT_VK.put("W", 0x11);
        NEED_SHIFT_VK.put("E", 0x12);
        NEED_SHIFT_VK.put("R", 0x13);
        NEED_SHIFT_VK.put("T", 0x14);
        NEED_SHIFT_VK.put("Y", 0x15);
        NEED_SHIFT_VK.put("U", 0x16);
        NEED_SHIFT_VK.put("I", 0x17);
        NEED_SHIFT_VK.put("O", 0x18);
        NEED_SHIFT_VK.put("P", 0x19);
        NEED_SHIFT_VK.put("A", 0x1e);
        NEED_SHIFT_VK.put("S", 0x1f);
        NEED_SHIFT_VK.put("D", 0x20);
        NEED_SHIFT_VK.put("F", 0x21);
        NEED_SHIFT_VK.put("G", 0x22);
        NEED_SHIFT_VK.put("H", 0x23);
        NEED_SHIFT_VK.put("J", 0x24);
        NEED_SHIFT_VK.put("K", 0x25);
        NEED_SHIFT_VK.put("L", 0x26);
        NEED_SHIFT_VK.put("Z", 0x2c);
        NEED_SHIFT_VK.put("X", 0x2d);
        NEED_SHIFT_VK.put("C", 0x2e);
        NEED_SHIFT_VK.put("V", 0x2f);
        NEED_SHIFT_VK.put("B", 0x30);
        NEED_SHIFT_VK.put("N", 0x31);
        NEED_SHIFT_VK.put("M", 0x32);
    }

    /**
     * 返回所有支持的按键
     */
    public static String[] getSupportKeys() {
        String[] vkArray = VK_MAP.keySet().toArray(new String[0]);
        String[] needShiftVKArray = NEED_SHIFT_VK.keySet().toArray(new String[0]);
        String[] supportKeys = new String[vkArray.length + needShiftVKArray.length];
        System.arraycopy(vkArray, 0, supportKeys, 0, vkArray.length);
        System.arraycopy(needShiftVKArray, 0, supportKeys, vkArray.length, needShiftVKArray.length);
        return supportKeys;
    }

    /**
     * 返回是否支持按键
     */
    public static boolean isSupportKey(String key) {
        return StringUtils.join(Arrays.asList(VirtualKBMapping.getSupportKeys()),"").contains(key);
    }
}

 

 c++装载驱动代码可以生成为dll文件调用,也可生成为exe文件调用。这里编译为exe。

注:生成dll文件及exe文件的时候一定生成64位的文件(32位系统不需要这个)。

#include "stdafx.h"

#include  
#include  
#include  
#include 
#include 
#include 
#pragma comment (lib, "Advapi32.lib")
#pragma comment( linker, "/subsystem:windows /entry:mainCRTStartup" )

#define DRIVER_NAME "WinIo64"
#define DRIVER_PATH "C:\\Windows\\System32\\WinIo64.sys"

//装载NT驱动程序
BOOL LoadNTDriver(char* lpszDriverName, char* lpszDriverPath)
{
	char szDriverImagePath[256];
	//得到完整的驱动路径
	GetFullPathName(lpszDriverPath, 256, szDriverImagePath, NULL);

	BOOL bRet = FALSE;

	SC_HANDLE hServiceMgr = NULL;//SCM管理器的句柄
	SC_HANDLE hServiceDDK = NULL;//NT驱动程序的服务句柄

	//打开服务控制管理器
	hServiceMgr = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);

	if (hServiceMgr == NULL)
	{
		//OpenSCManager失败
		printf("OpenSCManager() Faild  ! \n");
		//printf(GetLastError());
		bRet = FALSE;
		goto BeforeLeave;
	}
	else
	{
		OpenSCManager成功
		printf("OpenSCManager() ok ! \n");
	}

	//创建驱动所对应的服务
	hServiceDDK = CreateService(hServiceMgr,
		lpszDriverName, //驱动程序的在注册表中的名字 
		lpszDriverName, // 注册表驱动程序的 DisplayName 值 
		SERVICE_ALL_ACCESS, // 加载驱动程序的访问权限 
		SERVICE_KERNEL_DRIVER,// 表示加载的服务是驱动程序 
		SERVICE_DEMAND_START, // 注册表驱动程序的 Start 值 
		SERVICE_ERROR_IGNORE, // 注册表驱动程序的 ErrorControl 值 
		szDriverImagePath, // 注册表驱动程序的 ImagePath 值 
		NULL,
		NULL,
		NULL,
		NULL,
		NULL);

	DWORD dwRtn;
	//判断服务是否失败
	if (hServiceDDK == NULL)
	{
		dwRtn = GetLastError();
		if (dwRtn != ERROR_IO_PENDING && dwRtn != ERROR_SERVICE_EXISTS)
		{
			//由于其他原因创建服务失败
			printf("CrateService() Faild ! \n");
			///printf(dwRtn);
			bRet = FALSE;
			goto BeforeLeave;
		}
		else
		{
			//服务创建失败,是由于服务已经创立过
			printf("CrateService() Faild Service is ERROR_IO_PENDING or ERROR_SERVICE_EXISTS! \n");
		}

		// 驱动程序已经加载,只需要打开 
		hServiceDDK = OpenService(hServiceMgr, lpszDriverName, SERVICE_ALL_ACCESS);
		if (hServiceDDK == NULL)
		{
			//如果打开服务也失败,则意味错误
			dwRtn = GetLastError();
			printf("OpenService() Faild  ! \n");
			//printf(dwRtn);
			bRet = FALSE;
			goto BeforeLeave;
		}
		else
		{
			printf("OpenService() ok ! \n");
		}
	}
	else
	{
		printf("CrateService() ok ! \n");
	}

	//开启此项服务
	bRet = StartService(hServiceDDK, NULL, NULL);
	if (!bRet)
	{
		DWORD dwRtn = GetLastError();
		if (dwRtn != ERROR_IO_PENDING && dwRtn != ERROR_SERVICE_ALREADY_RUNNING)
		{
			printf("StartService() Faild  ! \n" );
			//printf(dwRtn);
			bRet = FALSE;
			goto BeforeLeave;
		}
		else
		{
			if (dwRtn == ERROR_IO_PENDING)
			{
				//设备被挂住
				printf("StartService() Faild ERROR_IO_PENDING ! \n");
				bRet = FALSE;
				goto BeforeLeave;
			}
			else
			{
				//服务已经开启
				printf("StartService() Faild ERROR_SERVICE_ALREADY_RUNNING ! \n");
				bRet = TRUE;
				goto BeforeLeave;
			}
		}
	}
	bRet = TRUE;
	//离开前关闭句柄
BeforeLeave:
	if (hServiceDDK)
	{
		CloseServiceHandle(hServiceDDK);
	}
	if (hServiceMgr)
	{
		CloseServiceHandle(hServiceMgr);
	}
	return bRet;
}

//卸载驱动程序 
BOOL UnloadNTDriver(char * szSvrName)
{
	BOOL bRet = FALSE;
	SC_HANDLE hServiceMgr = NULL;//SCM管理器的句柄
	SC_HANDLE hServiceDDK = NULL;//NT驱动程序的服务句柄
	SERVICE_STATUS SvrSta;
	//打开SCM管理器
	hServiceMgr = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
	if (hServiceMgr == NULL)
	{
		//带开SCM管理器失败
		printf("OpenSCManager() Faild ! \n");
		//printf(GetLastError());
		bRet = FALSE;
		goto BeforeLeave;
	}
	else
	{
		//带开SCM管理器失败成功
		printf("OpenSCManager() ok ! \n");
	}
	//打开驱动所对应的服务
	hServiceDDK = OpenService(hServiceMgr, szSvrName, SERVICE_ALL_ACCESS);

	if (hServiceDDK == NULL)
	{
		//打开驱动所对应的服务失败
		printf("OpenService() Faild  ! \n");
		//printf(GetLastError());
		bRet = FALSE;
		goto BeforeLeave;
	}
	else
	{
		printf("OpenService() ok ! \n");
	}
	//停止驱动程序,如果停止失败,只有重新启动才能,再动态加载。 
	if (!ControlService(hServiceDDK, SERVICE_CONTROL_STOP, &SvrSta))
	{
		printf("ControlService() Faild %d !\n", GetLastError());
	}
	else
	{
		//打开驱动所对应的失败
		printf("ControlService() ok !\n");
	}
	//动态卸载驱动程序。 
	if (!DeleteService(hServiceDDK))
	{
		//卸载失败
		printf("DeleteSrevice() Faild %d !\n", GetLastError());
	}
	else
	{
		//卸载成功
		printf("DelServer:eleteSrevice() ok !\n");
	}
	bRet = TRUE;
BeforeLeave:
	//离开前关闭打开的句柄
	if (hServiceDDK)
	{
		CloseServiceHandle(hServiceDDK);
	}
	if (hServiceMgr)
	{
		CloseServiceHandle(hServiceMgr);
	}
	return bRet;
}


int main(int argc, char* argv[])
{
	//加载驱动
	BOOL bRet = LoadNTDriver(DRIVER_NAME, DRIVER_PATH);
	if (!bRet)
	{
		printf("install winio error\n");
		return 0;
	}
	//加载成功

	//printf("install winio successed!\n");
	//getch();


	//这时候你可以通过注册表,或其他查看符号连接的软件验证。 
	//printf("press any to unload the driver!\n");
	//getch();

	//卸载驱动
	//BOOL bRet = UnloadNTDriver(DRIVER_NAME);
	//if (!bRet)
	//{
	//	printf("unload winio error!\n");
	//	return 0;
	//}
	//printf("unload winio successed!\n");
	//return 0;
}

 第四步:执行代码

大家按照上述代码都写好后就是执行了。有人可能成功了,有人可能还不行。所以下面介绍下这个代码基本的运行逻辑。供大家自行调整bug。

windows系统开启测试模式后,winio64.sys安装签名后。

执行代码:

1、***首先执行装载winio64.sys驱动代码,就是c++生成的dll或者exe文件里的LoadNTDriver方法。(这一步必须有,网上大部分没有这一步,所以大部分你试了都不会成功。)

2、执行winio的初始化方法 InitializeWinIo

3、KBCWait4IBE方法等待0x64控制端口空闲

4、0x64控制端口空闲时SetPortVal发送命令到0x64端口,在发送按键对应的虚拟码到0x60端口即可

5、winio.ShutdownWinIo释放资源

6、winio64.sys驱动加载后,系统重启后需要重新加载(注意)

以上即是本人实践总结,欢迎留言交流。

 

你可能感兴趣的:(winio,c++,java,windows)