最近做了UKey加密中设计到USB设备. 因UKEy是用来加密和执行PC与项目间通信加密的介质.从作用范围来讲不是传统意义上U盘作为存储介质来使用.其实熟悉网银驱动DR应该了解.在网银系统安全上一个最基本需求就是动态即时监控通信PC驱动以及设备列表通信变化.当然包括我们加密存储介质在PC上USB插拔.
思路一.在WinFrom中通过拦截Windows 消息机制来实现. 类似定义MEssageForm窗体. 假如用鼠标左击一下窗体, 系统会收到一条 WM_LBUTTONDOWN 消息;当鼠标抬起, 系统又会收到 WM_LBUTTONUP 消息.系统收到消息后, 会告诉窗体发生的事情, 然后窗体再做出反应; 当然窗体能否做出反应要看窗体是否有相应的响应代码. 同样也可以把USB设备插拔事件通过重写窗体WndProc(Ref Message m)方法拦截并处理.
首先引入命名空间:
- using System.Management;
- using System.Threading;
- using System.Security.Permissions;
定义Device Management Event的枚举:
- public enum DeviceEvent : int
- {
- DBT_CONFIGCHANGECANCELED = 0x0019,
- DBT_CONFIGCHANGED=0x0018,
- DBT_CUSTOMEVENT=0x8006,
- DBT_DEVICEARRIVAL=0x8000,//USB Insert DEvice Statu
- DBT_DEVICEQUERYREMOVE=0x8001,
- DBT_DEVICEQUERYREMOVEFAILED=0x8002,
- DBT_DEVICEREMOVEPENDING=0x8003,//USB Revoing.
- DBT_DEVICEREMOVECOMPLETE=0x8004,//USB Remove Completed
- DBT_DEVICETYPESPECIFIC=0x8005,
- DBT_DEVNODES_CHANGED=0x0007,//Device List _Changed
- DBT_QUERYCHANGECONFIG=0x0017,
- DBT_USERDEFINED=0xFFFF
- }
其中涉及到USB设备插拔的是DEVICEREMOVEPENDING/DEVICEREMOVECOMPLETE[删除] DEVICEARRIVAL[插入设备] 重写WinFProc实现窗体上对Windows MEssage进行拦截并重新处理:
- [PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
- protected override void WndProc(ref Message m)
- {
- base.WndProc(ref m);
- DeviceEvent lEvent;
- lEvent = (DeviceEvent)m.WParam.ToInt32();
- switch (lEvent)
- {
- case DeviceEvent.DBT_DEVICEARRIVAL://[Insert]
- this.CheckDeviceStatus_Lable.BackColor = Color.Green;
- this.CheckDeviceStatus_Lable.Text = "----Connection Device!----";
- MessageBox.Show("Just Insert At Moment !", "Insert");
- break;
- case DeviceEvent.DBT_DEVICEREMOVECOMPLETE://[REmove]
- this.CheckDeviceStatus_Lable.BackColor = Color.Red;
- this.CheckDeviceStatus_Lable.Text = "------No Connection------";
- MessageBox.Show("Remove Complete At Moment!", "Remove");
- break;
- case DeviceEvent.DBT_DEVNODES_CHANGED://[Device List Have Changed]
- MessageBox.Show("Device List have been Changed!");
- break;
- default:
- break;
- }
- }
首先USB在进行插拔即时如果没有存储介质即Disk或是无驱动的方式可能不能触发DeviceEvent.DBT_DEVICEREMOVECOMPLETE 和 DeviceEvent.DBT_DEVICEARRIVAL插把事件. 但是一点是可以确认的是.PC端只要接受USB设备.PC识别之后设备列表肯定会发生变化. 如果不是加密Key. u盘的 盘符方式存在Disk存储介质.则没有问题.
当然需要移植这种基于From窗体系统Message拦截方法时发现这种可重用性就不高.换一种思路采用Windows底层方式WMI实现.
WMI以CIMOM为基础,CIMOM即公共信息模型对象管理器[Common Information Model Object Manager],是一个描述操作系统构成单元的对象数据库,为MMC和脚本程序提供了一个访问操作系统构成单元的公共接口。有了WMI,工具软件和脚本程序访问操作系统的不同部分时不需要使用不同的API;相反,操作系统的不同部分都可以插入WMI,工具软件和WMI可以方便地读写WMI.
WMI 可以产生的系统级事件的一些更有用。 每当创建 WMI 类的新实例 ; 例如对于激发称为 __instancecreationevent 事件__instancedeletionevent 时将触发一个实例将被删除. 当然USB插拔时同样获得这个系统事件:
- public void ControlUSBConnectionStatu()
- {
- ManagementEventWatcher getEventWatcher = null;
- WqlEventQuery getEventQuery = null;
- ManagementOperationObserver getObserver = new ManagementOperationObserver();
- //Bind to Loacl Machine and Watch the PortConnection
- ManagementScope getScope = new ManagementScope("root\\CIMV2");
- getScope.Options.EnablePrivileges = true;//set requeired
- try
- {
- getEventQuery = new WqlEventQuery();
- getEventQuery.EventClassName = "__InstanceOperationEvent";
- getEventQuery.WithinInterval = new TimeSpan(0, 0, 0, 1);
- getEventQuery.Condition = @"TargetInstance ISA 'Win32_DiskDrive' ";
- //[Disk must have DiskDrive fuck ]
- //Event Watcher [Test Event and semd informatio to this message and create new informtion .]
- getEventWatcher = new ManagementEventWatcher(getEventQuery);
- getEventWatcher.EventArrived += new EventArrivedEventHandler(getEventWatcher_EventArrived);
- getEventWatcher.Start();//Start Watch Event
- }
- catch (Exception se)
- { }
- finally
- {
- // getEventWatcher.Stop();
- }
- }
当发生USB插拔并成功监听到事件时处理方法:
- void getEventWatcher_EventArrived(object sender, EventArrivedEventArgs e)
- {
- ManagementBaseObject getBaseObject = (ManagementBaseObject)e.NewEvent;
- if ((getBaseObject.ClassPath.ClassName == "__InstanceCreationEvent"))
- {
- //Usb Inserted
- MessageBox.Show("USB Disk Inserted!");
- }
- else
- {
- //Usb Removed
- MessageBox.Show("USB Device Removed!");
- }
- }
如上在定义时设置一个Condition[条件]:存在Disk Driver 磁盘驱动.如果类似某些UKey不存在磁盘驱动同时也无存储介质 经过测试你会发现.加密的UKey插入 如上的WMI监听事件并不能扑捉到USB插拔. 但是针对这种方式我们还有一种更为彻底的方式就是USB插拔唯一可以确定在PC识别必然变化的因素是系统设备列表发生更新.
WMI处理监听:
- /// <summary>
- /// 监听USB Device设备插拔事件 完整操作.
- /// WMI Handle Event Change Device List chenkai
- /// </summary>
- public void RegisterDeviceWMIEventStatu()
- {
- try
- {
- //Device List HAve Changed And Send Message
- WqlEventQuery query = new WqlEventQuery("SELECT * FROM Win32_DeviceChangeEvent");
- ManagementEventWatcher watcher = new ManagementEventWatcher(query);
- watcher.EventArrived += new EventArrivedEventHandler(watcher_EventArrived);
- watcher.Start(); // Start listening for events
- }
- catch (Exception se)
- { }
- }
WMI监听处理函数:
- void watcher_EventArrived(object sender, EventArrivedEventArgs e)
- {
- string geteventtype = e.NewEvent.GetPropertyValue("EventType").ToString();
- ManagementBaseObject getEventObject = (ManagementBaseObject)e.NewEvent;
- if (getEventObject != null)
- {
- //close Operator
- this.CloseDeviceEqument();
- }
- }
其实这依然还是一种折中办法.因为导致PC端设备列表发生变化的因素有很多.如何判定是USB口发生设备变化.WMI依然没有让我们失望:
- //WMI Control The USB Device Change Statu And Send Message to When IT‘s Changed/
- public void ControlUSBDeviceSTatu()
- {
- try
- {
- WqlEventQuery query = new WqlEventQuery("select * from Win32_VolumeChangeEvent");
- ManagementEventWatcher getwatcher = new ManagementEventWatcher(query);
- getwatcher.EventArrived += new EventArrivedEventHandler(getwatcher_EventArrived);
- getwatcher.Start();
- }
- catch (Exception se)
- { }
- }
WMI在USB事情处理函数:
- void getwatcher_EventArrived(object sender, EventArrivedEventArgs e)
- {
- MessageBox.Show(e.NewEvent.GetText(TextFormat.Mof).ToString());
- }
这样来一来就可以清晰判定USB在插拔时所发生在系统PC端的变化通知给应用程序来进行处理.如何获得当前PC端 USB Driver列表.经过几番测试找到一种很好的方式获取全部的USB Driver信息:
- //Get ALL USB DRiver And Driver Property Fuck this shit。chenkai
- public static string[] AllInformation()
- {
- StringCollection propNames = new StringCollection();
- ManagementClass driveClass = new ManagementClass("Win32_USBController");
- PropertyDataCollection props = driveClass.Properties;
- foreach (PropertyData driveProperty in props)
- propNames.Add(driveProperty.Name);
- int idx = 0;
- ManagementObjectCollection drives = driveClass.GetInstances();
- string _s = string.Empty;
- List<string> harddisk = new List<string>();
- foreach (ManagementObject drv in drives)
- {
- idx++;
- _s = string.Format(" USB Driver({0}) Properties ", idx);
- harddisk.Add(_s);
- foreach (string strProp in propNames)
- {
- _s = string.Format("Property: {0}, Value: {1}", strProp, drv[strProp]);
- harddisk.Add(_s);
- }
- }
- string[] _ss = harddisk.ToArray();
- return _ss;
- }
WMI的更多体现是对Windows 交互中进一步封装和管理.
Can考资料:
Device ManageMent Events
System.Form.control.WinProc[]Method
System.Form.Control.Message[]Method