自動填密碼大家可能都不莫生,最有名的應該是 按鍵精靈 只要是一個可以輸入的地方都可以能過按鍵精靈來完成輸入.我今天要講的是使用 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 GetPortVal(IntPtr wPortAddr, out int pdwPortVal, byte bSize);
[DllImport("WinIo32.dll")]
public static extern bool SetPortVal(uint wPortAddr, IntPtr dwPortVal, byte bSize);
[DllImport("WinIo32.dll")]
public static extern byte MapPhysToLin(byte pbPhysAddr, uint dwPhysSize, IntPtr PhysicalMemoryHandle);
[DllImport("WinIo32.dll")]
public static extern bool UnmapPhysicalMemory(IntPtr PhysicalMemoryHandle, byte pbLinAddr);
[DllImport("WinIo32.dll")]
public static extern bool GetPhysLong(IntPtr pbPhysAddr, byte pdwPhysVal);
[DllImport("WinIo32.dll")]
public static extern bool SetPhysLong(IntPtr pbPhysAddr, byte dwPhysVal);
[DllImport("WinIo32.dll")]
public static extern void ShutdownWinIo();
[DllImport("user32.dll")]
public static extern int MapVirtualKey(uint 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 = GetPortVal((IntPtr)0x64, out dwVal, 1);
}
while ((dwVal & 0x2) > 0);
}
/// 模擬鍵盤標按下
public static void KeyDown(Keys vKeyCoad) {
if (!IsInitialize) return;
int btScancode = 0;
btScancode = MapVirtualKey((uint)vKeyCoad, 0);
KBCWait4IBE();
SetPortVal(KBC_KEY_CMD, (IntPtr)0xD2, 1);
KBCWait4IBE();
SetPortVal(KBC_KEY_DATA, (IntPtr)0x60, 1);
KBCWait4IBE();
SetPortVal(KBC_KEY_CMD, (IntPtr)0xD2, 1);
KBCWait4IBE();
SetPortVal(KBC_KEY_DATA, (IntPtr)btScancode, 1);
}
/// 模擬鍵盤彈出
public static void KeyUp(Keys vKeyCoad) {
if (!IsInitialize) return;
int btScancode = 0;
btScancode = MapVirtualKey((uint)vKeyCoad, 0);
KBCWait4IBE();
SetPortVal(KBC_KEY_CMD, (IntPtr)0xD2, 1);
KBCWait4IBE();
SetPortVal(KBC_KEY_DATA, (IntPtr)0x60, 1);
KBCWait4IBE();
SetPortVal(KBC_KEY_CMD, (IntPtr)0xD2, 1);
KBCWait4IBE();
SetPortVal(KBC_KEY_DATA, (IntPtr)(btScancode | 0x80), 1);
}
}
上面這個類也是網上搜出來的,感覺前輩們的分享.此處只模擬了鍵盤的 按下和彈起
使用實例
String pass = "123456";
foreach (char chr in pass) {
WinIO.KeyDown((Keys)chr);
Thread.CurrentThread.Join(100);
WinIO.KeyUp((Keys)chr);
Thread.CurrentThread.Join(100);
}
Thread.CurrentThread.Join(100);
WinIO.Shutdown();
這個地方按下的時候,稍停下,彈起也一樣
這樣的話 winIO 的調用就完成了
另一個神器就是 WinRing0 這個是一個開源的項目,可以通殺 32 64位系統, 不需要為驅動安裝數字簽名,自從發現了這個以後,我所有的需要自動填密碼的項目都使用了它
雖說開源,但是這個在網上的使用文檔還是比較少,有的都是自帶的一些文檔和使用實例沒有特殊意義的例子,說實話,這項目的找了好久才找到下載地址,大家如需要就留個郵箱,
我看到後就發給你
我們打開 release目錄,
復制相關的文件到你的工作開發目錄下.
source\sample\Cs\OpenLibSys.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 MapVirtualKey(uint 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.ReadIoPortByteEx(0x64, ref dwVal);
}
while ((dwVal & 0x2) > 0);
}
public static void KeyDown(Char ch) {
int btScancode = MapVirtualKey((uint)(Key)ch, 0);
KBCWait4IBE();
ols.WriteIoPortByte(0x64, 0xd2);
KBCWait4IBE();
ols.WriteIoPortByte(0x60, (byte)btScancode);
}
public static void KeyUp(Char ch) {
int btScancode = MapVirtualKey((uint)(Key)ch, 0);
KBCWait4IBE();
ols.WriteIoPortByte(0x64, 0xd2);
KBCWait4IBE();
ols.WriteIoPortByte(0x60, (byte)(btScancode | 0x80));
}
}
也只是模擬了 按下和彈起 以下為調用方式
String pwd = "123456";
foreach (char chr in pwd) {
WinRing.init();
WinRing.KeyDown(chr);
Thread.Sleep(100);
WinRing.KeyUp(chr);
}
Thread.CurrentThread.Join(100);
到此 這兩個類庫的使用就介紹完了,但是在真正項目中可能會遇到各種問題,這就需我們的經驗和處理問題的能力了.
注:這兩個類庫有一個通病就是不支持 USB鍵盤的模擬.估計是我沒有研究出來吧
--幸福海
博客地址:http://www.cnblogs.com/ningqhai/