WinIo64驱动级别的键盘模拟(java) - Go语言中文社区

WinIo64驱动级别的键盘模拟(java)


    最近因为爬虫登录的网站加了密码控件,尝试了很多方法都不能破解(该控件屏蔽了虚拟软键盘),寻找资料中发现了winIo这么工具,十几年前的东西了,它的官网貌似也处于游离状态,使用中也出现了很多问题,便以此mark一下。

    最开始从这里获取到了winIo32实现驱动级键盘事件,但使用的是JNative(目前只支持32位),同时winIO32在64位的OS下运行有问题(本人测试过可能过程中有没考虑到的原因,此文略过)所以采用winIo64+JNA来实现键盘的驱动级模拟。

    在开始前,先申明一下所需要的环境和设备(本文主要在window7 64位环境下测试):

1.WinIo64.dll 和 WinIo64.sys(下载请见上面winIo32实现驱动级键盘事件的附件key文件夹

2.因为WinIo库允许Windows应用程序中直接对I/O端口和物理内存进行存取操作,目前从网上找到的资料winio能模拟PS/2键盘输入(串口键盘),但USB设备的模拟暂时资料不详,所以此次以PS/2键盘模拟为例(必须链接PS/2键盘,否者模拟无效)。

3.WinIo64.sys签名:64位版本的Windows只加载设备驱动程序,这些驱动程序由一个公共CA签发的代码签名证书签署,如Verisign、Thawte等。WinIo64 除非获得了代码签名证书,否则系统不能部署在生产机器上。

    a.开启测试模式

           1)管理员模式运行cmd

           2)在命令行输入:bcdedit /set TESTSIGNING ON

           3)重启电脑,桌面右下角会出现测试模式。

    b.完成winIO64的签名认证:

           1.打开 WinIO64.sys的属性框,翻到“数字签名”选项卡,点击“详细信息”
            2.在新出来的对话框中点击“查看证书”
            3.在又新出来的对话框中点击“安装证书”
            4.点击“下一步”,然后选择“将所有的证书放入下列存储”
            5.点击浏览,选择“受信任的根证书发布机构”

4.需要jna相关的jar,自行下载。本示例jdk:1.8 64位。

接下来,贴出代码:

    

import java.awt.AWTException;
import java.awt.Robot;
import java.awt.event.KeyEvent;
import java.util.HashMap;
import java.util.Map;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.ie.InternetExplorerDriver;

import com.sun.jna.Native;
import com.sun.jna.win32.StdCallLibrary;

public class Selenium {
	private Robot robot = null;//此处用robot去移动鼠标,可忽略
	public static final int CONTROL_PORT = 0x64;
	public static final int DATA_PORT = 0x60;
	
	public static final Map<String,Integer> map=new HashMap();
		
	public Selenium(){
		try {
			robot = new Robot();
		} catch (AWTException e) {
			e.printStackTrace();
		}
	} 
	
	static{
		map.put("0", KeyEvent.VK_0);
		map.put("1", KeyEvent.VK_1);
		map.put("2", KeyEvent.VK_2);
		map.put("3", KeyEvent.VK_3);
		map.put("4", KeyEvent.VK_4);
		map.put("5", KeyEvent.VK_5);
		map.put("6", KeyEvent.VK_6);
		map.put("7", KeyEvent.VK_7);
		map.put("8", KeyEvent.VK_8);
		map.put("9", KeyEvent.VK_9);
		map.put("a", KeyEvent.VK_A);
		map.put("b", KeyEvent.VK_B);
		map.put("c", KeyEvent.VK_C);
		map.put("d", KeyEvent.VK_D);
		map.put("e", KeyEvent.VK_E);
		map.put("f", KeyEvent.VK_F);
		map.put("g", KeyEvent.VK_G);
		map.put("h", KeyEvent.VK_H);
		map.put("i", KeyEvent.VK_I);
		map.put("j", KeyEvent.VK_J);
		map.put("k", KeyEvent.VK_K);
		map.put("l", KeyEvent.VK_L);
		map.put("m", KeyEvent.VK_M);
		map.put("n", KeyEvent.VK_N);
		map.put("o", KeyEvent.VK_O);
		map.put("p", KeyEvent.VK_P);
		map.put("q", KeyEvent.VK_Q);
		map.put("r", KeyEvent.VK_R);
		map.put("s", KeyEvent.VK_S);
		map.put("t", KeyEvent.VK_T);
		map.put("u", KeyEvent.VK_U);
		map.put("v", KeyEvent.VK_V);
		map.put("w", KeyEvent.VK_W);
		map.put("x", KeyEvent.VK_X);
		map.put("y", KeyEvent.VK_Y);
		map.put("z", KeyEvent.VK_Z);
		map.put("Tab", KeyEvent.VK_TAB);
		map.put("Space", KeyEvent.VK_SPACE);
		map.put("Shift", KeyEvent.VK_SHIFT);
		map.put("Cntl", KeyEvent.VK_CONTROL);
		map.put("Alt", KeyEvent.VK_ALT);
		map.put("F1",KeyEvent.VK_F1);
		map.put("F2",KeyEvent.VK_F2);
		map.put("F3",KeyEvent.VK_F3);
		map.put("F4",KeyEvent.VK_F4);
		map.put("F5",KeyEvent.VK_F5);
		map.put("F6",KeyEvent.VK_F6);
		map.put("F7",KeyEvent.VK_F7);
		map.put("F8",KeyEvent.VK_F8);
		map.put("F9",KeyEvent.VK_F9);
		map.put("F10",KeyEvent.VK_F10);
		map.put("F11",KeyEvent.VK_F11);
		map.put("F12",KeyEvent.VK_F12);
		
	}
	//使用User32库里面键位值转换
	public interface User32 extends StdCallLibrary{
		User32 Instance = (User32)Native.loadLibrary("User32",User32.class);
		int MapVirtualKeyA(int key, int type);
	}
	//此处是winIo使用关键
	public interface WinIo extends StdCallLibrary{
		WinIo Instance = (WinIo)Native.loadLibrary("WinIo64",WinIo.class);		
		boolean InitializeWinIo();
		boolean GetPortVal(int portAddr, int pPortVal, int size);
		boolean SetPortVal(int portAddr, int portVal, int size) ;
		void ShutdownWinIo();
	}
	//将虚拟键位值转成扫描码
	public static int toScanCode(String key){
		try {
			return User32.Instance.MapVirtualKeyA(map.get(key).intValue(),0);
		} catch (Exception e) {
			return 0;
		}
	}
	
	
	public static void KBCWait4IBE() throws Exception{
		int val=0;
		do {
			if(!WinIo.Instance.GetPortVal(CONTROL_PORT,val, 1)){
				System.err.println("Cannot get the Port");
			}
			
		} while ((0x2&val)>0);			
	}
	
	public static void KeyDown(int key) throws Exception{
		KBCWait4IBE();
		WinIo.Instance.SetPortVal(WinIOAPI.CONTROL_PORT,0xD2,1);
		KBCWait4IBE();
		WinIo.Instance.SetPortVal(WinIOAPI.DATA_PORT,key,1);
	}
	
	public static void KeyUp(int key) throws Exception{
		KBCWait4IBE();
		WinIo.Instance.SetPortVal(WinIOAPI.CONTROL_PORT,0xD2,1);
		KBCWait4IBE();
		WinIo.Instance.SetPortVal(WinIOAPI.DATA_PORT,(key|0x80),1);		
	}
	
	public void mouseDemo() throws InterruptedException{
		robot.mouseMove(500, 290);
		Thread.sleep(650);
		robot.mousePress(KeyEvent.BUTTON1_MASK);
		Thread.sleep(150);
		robot.mouseRelease(KeyEvent.BUTTON1_MASK);
		Thread.sleep(999);
		System.out.println("鼠标点击完毕");
	}
	
	public static void main(String[] args) throws Exception{  


		//System.setProperty("webdriver.ie.driver", "D:/IEDriverServer.exe");
		//WebDriver dr = new InternetExplorerDriver();
		// 打开网站
		//dr.get("https://www.hao123.com");
		// 获取源代码
		//System.out.println("--"+dr.getPageSource());
		
		//Selenium se = new Selenium();
		
		//se.mouseDemo();
		
		System.out.println("winIO64初始化是否成功:"+WinIo.Instance.InitializeWinIo());//此处应该有判断,只有初始化成功才可继续往下走,否者直接终止
		Thread.sleep(1000);
		String s="helloworld";
		for (int i = 0; i < s.length(); i++) {
			KeyDown(toScanCode(""+s.charAt(i)));
			Thread.sleep(10);
			KeyUp(toScanCode(""+s.charAt(i)));
			Thread.sleep(200);
		}
		WinIo.Instance.ShutdownWinIo();
		

		// 关闭
		//System.out.println(dr.getPageSource());
        //Thread.sleep(20000);  
        //dr.quit();  
}
}

说明:代码中有使用selenium工具,一种自动化网页测试的工具,可自行注释掉,不影响执行,关于代码中scancode可以自行查找相关资料。

关于代码中如果winIO64初始化失败的问题,首先检查2个winio的文件路径是否正确,我习惯放在jdk的java/bin下,其次执行这段代码必须是管理员的权限,用IDE的童靴请自行用管理员启动IDE。

结语:

本方法仅适用于个人需求,对于上生产环境使用作用不大,而且涉及的问题较多,主要是得有ps/2键盘鄙视

2018-05-16 add:无意中发现笔记本上的键盘就是PS/2敲打,呵呵呵呵呵!!!


版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/geanwan/article/details/80310041
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2021-06-14 13:58:32
  • 阅读 ( 502 )
  • 分类:

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢