C# winIO32位,64位的使用(运行时要用管理员身份)
下载地址:http://www.internals.com/utilities/WinIo.zip
一个按键的消息产生流程如下:
1)硬件中断/硬件端口数据
WinIO能模拟,或者修改IDT是在这一层
2)键盘Port驱动(USB or PS/2)
Filter驱动在此
KeyboardClassServiceCallback也在这一层被调用
3)kbdclass驱动
处理键盘布局和键盘语言
4)Windows内核边界(zwCreate/zwReadFile)
———————-(系统调用)———————-
5)Windows内核边界(zwCreate/zwReadFile)
6)csrss.exe的win32k!RawInputThread读取,完成scancode和vk的转换
SetWindowHook工作在这里(全局)
kbd_event工作在这里
7)csrss.exe调用DispatchMessage等函数分发消息
SetWindowHook工作在这里(进程)
PostMessage和SendMessage在这里
8)各个进程处理消息
winIO可以模拟最底层的按键消息,借此可以绕过没有从消息循环读取消息的安全控件。在这只讲下64位系统下的用法,我的系统是win10 64位企业版。
1.64位系统,C#使用WinIO64
需要的文件:WinIo64.dll,WinIo64.sys
a.首先安装WinIo64.sys的数字签名,
由于winIO64只有测试版的签名,我们需要把windows的测试模式打开。
win键+R cmd:bcdedit /set testsigning on
b.将整两个文件复制到跟exe同一目录。
c.c#代码
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace WinIOTest
{
public class WinIO
{
private const int KBC_KEY_CMD = 0x64;
private const int KBC_KEY_DATA = 0x60;
public static extern bool InitializeWinIo();
public static extern bool GetPortVal(IntPtr wPortAddr, out int pdwPortVal, byte bSize);
public static extern bool SetPortVal(uint wPortAddr, IntPtr dwPortVal, byte bSize);
public static extern byte MapPhysToLin(byte pbPhysAddr, uint dwPhysSize, IntPtr PhysicalMemoryHandle);
public static extern bool UnmapPhysicalMemory(IntPtr PhysicalMemoryHandle, byte pbLinAddr);
public static extern bool GetPhysLong(IntPtr pbPhysAddr, byte pdwPhysVal);
public static extern bool SetPhysLong(IntPtr pbPhysAddr, byte dwPhysVal);
public static extern void ShutdownWinIo();
public static extern int MapVirtualKey(uint Ucode, uint uMapType);
private WinIO()
{
IsInitialize = true;
}
public static void Initialize()
{
if (InitializeWinIo())
{
KBCWait4IBE();
IsInitialize = true;
}
else
MessageBox.Show("Load WinIO Failed!");
}
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);
}
}
}
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
[*]7
[*]8
[*]9
[*]10
[*]11
[*]12
[*]13
[*]14
[*]15
[*]16
[*]17
[*]18
[*]19
[*]20
[*]21
[*]22
[*]23
[*]24
[*]25
[*]26
[*]27
[*]28
[*]29
[*]30
[*]31
[*]32
[*]33
[*]34
[*]35
[*]36
[*]37
[*]38
[*]39
[*]40
[*]41
[*]42
[*]43
[*]44
[*]45
[*]46
[*]47
[*]48
[*]49
[*]50
[*]51
[*]52
[*]53
[*]54
[*]55
[*]56
[*]57
[*]58
[*]59
[*]60
[*]61
[*]62
[*]63
[*]64
[*]65
[*]66
[*]67
[*]68
[*]69
[*]70
[*]71
[*]72
[*]73
[*]74
[*]75
[*]76
[*]77
[*]78
[*]79
[*]80
[*]81
[*]82
[*]83
[*]84
[*]85
[*]86
[*]87
[*]88
[*]89
[*]90
[*]91
[*]92
[*]93
[*]94
[*]95
[*]96
[*]97
[*]98
[*]99
[*]100
[*]101
[*]102
[*]103
[*]104
[*]105
[*]106
[*]107
使用:
WinIO.Initialize(); // 注册
WinIO.KeyDown(Keys.A); // 按下A
WinIO.KeyUp(Keys.A); // 松开A
WinIO.Shutdown(); // 用完后注销
[*]1
[*]2
[*]3
[*]4
2.64位系统,C#使用WinIO32
切换成WinIO32,只需要改成,WinIo32.dll复制到exe同一目录,运行时要用管理员身份。其他与winIO64一致。
运行时要用管理员身份
运行时要用管理员身份
运行时要用管理员身份
运行时要用管理员身份
运行时要用管理员身份
文档来源:51CTO技术博客https://blog.51cto.com/smallfa/3184083
页:
[1]