自动填密码大家可能都不莫生,最有名的应该是 按键精灵 只要是一个可以输入的地方都可以能过按键精灵来完成输入.我今天要讲的是使用 winio/winring0来完成类似的功能
如果要自动填充密码方式基本上有 消息级的模拟 和 驱动级的模拟,
消息级的模拟如 C# 直接使用 SendKeys 就可以完成 API下可以使用 SendMessage完成 即有了这个神器为什么还要用三方?
答案:现在一些网都使用了ActiveX安全插件,如网银,支付宝,等,还有我们上一次说到的 翼支付和手机支付 它们基本上屏蔽了 SendMessage 有些就算可以使用但是不能得到正确的加密数据.还有更可气的是 在服务器远程操作中手动输入都不能输入密码.
驱动级的就是硬盘的模拟 模拟键盘,大牛们可以直接操作 I/O 我这里讲的是使用三方类库来完成,
第一个是 winIO 在XP时候我一直使用它,但到了 win7+64位模式下使用有点小问题,winIO 64位下驱动数字签名有点问题不能直接运行,需要将 win7转到测试模式下,安装数字证书而用程序还要在测试模式使用,如果是自己有可以凑合着,如果是给客户去使用,客户绝对会说你脑残,我运行个程序还要调这调那,当然是不愿意了.
我现在就以 32位模式下来演示如何使用 winIO,首先是下载winIO 最新版本为 3.0 网官下载地址 http://www.internals.com/
解压后,得到上图所示的文件 这个地方有用的 就是最后4个文件其它的是源文件和例子帮助文件之类的,
跟据系统的不同来使用不同的文件 如果是 32位的就使用32结尾的两个.呵呵 直接把这两个放到你开发目录下的 bin/release 或 bin/debug下面就行了
然后就是调用
public class WinIO { public const int KBC_KEY_CMD = 0x64;//输入键盘按下消息的端口 public const int KBC_KEY_DATA = 0x60;//输入键盘弹起消息的端口 [DllImport"WinIo32.dll")] public static extern bool InitializeWinIo); [DllImport"WinIo32.dll")] public static extern bool GetPortValIntPtr wPortAddr, out int pdwPortVal, byte bSize); [DllImport"WinIo32.dll")] public static extern bool SetPortValuint wPortAddr, IntPtr dwPortVal, byte bSize); [DllImport"WinIo32.dll")] public static extern byte MapPhysToLinbyte pbPhysAddr, uint dwPhysSize, IntPtr PhysicalMemoryHandle); [DllImport"WinIo32.dll")] public static extern bool UnmapPhysicalMemoryIntPtr PhysicalMemoryHandle, byte pbLinAddr); [DllImport"WinIo32.dll")] public static extern bool GetPhysLongIntPtr pbPhysAddr, byte pdwPhysVal); [DllImport"WinIo32.dll")] public static extern bool SetPhysLongIntPtr pbPhysAddr, byte dwPhysVal); [DllImport"WinIo32.dll")] public static extern void ShutdownWinIo); [DllImport"user32.dll")] public static extern int MapVirtualKeyuint Ucode, uint uMapType); private WinIO) { IsInitialize = true; } public static void Initialize) { if InitializeWinIo)) { KBCWait4IBE); IsInitialize = true; } } public static void Shutdown) { if IsInitialize) ShutdownWinIo); IsInitialize = false; } private static bool IsInitialize { get; set; } ///等待键盘缓冲区为空 private static void KBCWait4IBE) { int dwVal = 0; do { bool flag = GetPortValIntPtr)0x64, out dwVal, 1); } while dwVal & 0x2) > 0); } /// 模拟键盘标按下 public static void KeyDownKeys vKeyCoad) { if !IsInitialize) return; int btScancode = 0; btScancode = MapVirtualKeyuint)vKeyCoad, 0); KBCWait4IBE); SetPortValKBC_KEY_CMD, IntPtr)0xD2, 1); KBCWait4IBE); SetPortValKBC_KEY_DATA, IntPtr)0x60, 1); KBCWait4IBE); SetPortValKBC_KEY_CMD, IntPtr)0xD2, 1); KBCWait4IBE); SetPortValKBC_KEY_DATA, IntPtr)btScancode, 1); } /// 模拟键盘弹出 public static void KeyUpKeys vKeyCoad) { if !IsInitialize) return; int btScancode = 0; btScancode = MapVirtualKeyuint)vKeyCoad, 0); KBCWait4IBE); SetPortValKBC_KEY_CMD, IntPtr)0xD2, 1); KBCWait4IBE); SetPortValKBC_KEY_DATA, IntPtr)0x60, 1); KBCWait4IBE); SetPortValKBC_KEY_CMD, IntPtr)0xD2, 1); KBCWait4IBE); SetPortValKBC_KEY_DATA, IntPtr)btScancode | 0x80), 1); } }
上面这个类也是网上搜出来的,感觉前辈们的分享.此处只模拟了键盘的 按下和弹起
使用实例
String pass = "123456"; foreach char chr in pass) { WinIO.KeyDownKeys)chr); Thread.CurrentThread.Join100); WinIO.KeyUpKeys)chr); Thread.CurrentThread.Join100); } Thread.CurrentThread.Join100); WinIO.Shutdown);
这个地方按下的时候,稍停下,弹起也一样
这样的话 winIO 的调用就完成了
另一个神器就是 WinRing0 这个是一个开源的项目,可以通杀 32 64位系统, 不需要为驱动安装数字签名,自从发现了这个以后,我所有的需要自动填密码的项目都使用了它
虽说开源,但是这个在网上的使用文档还是比较少,有的都是自带的一些文档和使用实例没有特殊意义的例子,说实话,这项目的找了好久才找到下载地址,大家如需要就留个邮箱,
我看到后就发给你
我们打开 release目录,
复制相关的文件到你的工作开发目录下.
sourcesampleCsOpenLibSys.cs 找到这个cs文件,这个是官方的所有的功能的封装,包括 I/O PCI CPU 等操作.把它加到我们的工程项目中
新建一个类 WinRing 代码如下
using System; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Text; using OpenLibSys; class WinRing { public enum Key { ABSOLUTE = 0x8000, LEFTDOWN = 2, LEFTUP = 4, MIDDLEDOWN = 0x20, MIDDLEUP = 0x40, MOVE = 1, RIGHTDOWN = 8, RIGHTUP = 0x10, VIRTUALDESK = 0x4000, VK_A = 0x41, VK_ADD = 0x6b, VK_B = 0x42, VK_BACK = 8, VK_C = 0x43, VK_CANCEL = 3, VK_CAPITAL = 20, VK_CLEAR = 12, VK_CONTROL = 0x11, VK_D = 0x44, VK_DECIMAL = 110, VK_DELETE = 0x2e, VK_DIVIDE = 0x6f, VK_DOWN = 40, VK_E = 0x45, VK_END = 0x23, VK_ESCAPE = 0x1b, VK_EXECUTE = 0x2b, VK_F = 70, VK_F1 = 0x70, VK_F10 = 0x79, VK_F11 = 0x7a, VK_F12 = 0x7b, VK_F2 = 0x71, VK_F3 = 0x72, VK_F4 = 0x73, VK_F5 = 0x74, VK_F6 = 0x75, VK_F7 = 0x76, VK_F8 = 0x77, VK_F9 = 120, VK_G = 0x47, VK_H = 0x48, VK_HELP = 0x2f, VK_HOME = 0x24, VK_I = 0x49, VK_INSERT = 0x2d, VK_J = 0x4a, VK_K = 0x4b, VK_L = 0x4c, VK_LBUTTON = 1, VK_LEFT = 0x25, VK_M = 0x4d, VK_MBUTTON = 4, VK_MENU = 0x12, VK_N = 0x4e, VK_NEXT = 0x22, VK_NULTIPLY = 0x6a, VK_NUM0 = 0x30, VK_NUM1 = 0x31, VK_NUM2 = 50, VK_NUM3 = 0x33, VK_NUM4 = 0x34, VK_NUM5 = 0x35, VK_NUM6 = 0x36, VK_NUM7 = 0x37, VK_NUM8 = 0x38, VK_NUM9 = 0x39, VK_NUMLOCK = 0x90, VK_NUMPAD0 = 0x60, VK_NUMPAD1 = 0x61, VK_NUMPAD2 = 0x62, VK_NUMPAD3 = 0x63, VK_NUMPAD4 = 100, VK_NUMPAD5 = 0x65, VK_NUMPAD6 = 0x66, VK_NUMPAD7 = 0x67, VK_NUMPAD8 = 0x68, VK_NUMPAD9 = 0x69, VK_O = 0x4f, VK_P = 80, VK_PAUSE = 0x13, VK_PRINT = 0x2a, VK_PRIOR = 0x21, VK_Q = 0x51, VK_R = 0x52, VK_RBUTTON = 2, VK_RETURN = 13, VK_RIGHT = 0x27, VK_S = 0x53, VK_SCROLL = 0x91, VK_SELECT = 0x29, VK_SEPARATOR = 0x6c, VK_SHIFT = 0x10, VK_SNAPSHOT = 0x2c, VK_SPACE = 0x20, VK_SUBTRACT = 0x6d, VK_T = 0x54, VK_TAB = 9, VK_U = 0x55, VK_UP = 0x26, VK_V = 0x56, VK_W = 0x57, VK_X = 0x58, VK_Y = 0x59, VK_Z = 90, WHEEL = 0x800, XDOWN = 0x80, XUP = 0x100 } static OpenLibSys.Ols ols = null; [DllImport"user32.dll")] public static extern int MapVirtualKeyuint Ucode, uint uMapType); public static Boolean init) { ols = new OpenLibSys.Ols); return ols.GetStatus) == uint)Ols.Status.NO_ERROR; } private static void KBCWait4IBE) { byte dwVal = 0; do { ols.ReadIoPortByteEx0x64, ref dwVal); } while dwVal & 0x2) > 0); } public static void KeyDownChar ch) { int btScancode = MapVirtualKeyuint)Key)ch, 0); KBCWait4IBE); ols.WriteIoPortByte0x64, 0xd2); KBCWait4IBE); ols.WriteIoPortByte0x60, byte)btScancode); } public static void KeyUpChar ch) { int btScancode = MapVirtualKeyuint)Key)ch, 0); KBCWait4IBE); ols.WriteIoPortByte0x64, 0xd2); KBCWait4IBE); ols.WriteIoPortByte0x60, byte)btScancode | 0x80)); } }
也只是模拟了 按下和弹起 以下为调用方式
String pwd = "123456"; foreach char chr in pwd) { WinRing.init); WinRing.KeyDownchr); Thread.Sleep100); WinRing.KeyUpchr); } Thread.CurrentThread.Join100);
到此 这两个类库的使用就介绍完了,但是在真正项目中可能会遇到各种问题,这就需我们的经验和处理问题的能力了.
注:这两个类库有一个通病就是不支持 USB键盘的模拟.估计是我没有研究出来吧
–幸福海
博客地址:http://www.cnblogs.com/ningqhai/
–幸福海
微信号:ningqhai