监控USB设备插拔

  • Post author:
  • Post category:其他



最近做了UKey加密中设计到USB设备. 因UKEy是用来加密和执行PC与项目间通信加密的介质.从作用范围来讲不是传统意义上U盘作为存储介质来使用.其实熟悉网银驱动DR应该了解.在网银系统安全上一个最基本需求就是动态即时监控通信PC驱动以及设备列表通信变化.当然包括我们加密存储介质在PC上USB插拔.


思路一.在WinFrom中通过拦截Windows 消息机制来实现. 类似定义MEssageForm窗体. 假如用鼠标左击一下窗体, 系统会收到一条 WM_LBUTTONDOWN 消息;当鼠标抬起, 系统又会收到 WM_LBUTTONUP 消息.系统收到消息后, 会告诉窗体发生的事情, 然后窗体再做出反应; 当然窗体能否做出反应要看窗体是否有相应的响应代码. 同样也可以把USB设备插拔事件通过重写窗体

WndProc(Ref Message m)

方法拦截并处理.


首先引入命名空间:

   1:  using System.Management;
   2:  using System.Threading;
   3:  using System.Security.Permissions;


定义Device Management Event的枚举:

   1:    public enum DeviceEvent : int
   2:          {
   3:              DBT_CONFIGCHANGECANCELED = 0x0019,
   4:              DBT_CONFIGCHANGED=0x0018,
   5:              DBT_CUSTOMEVENT=0x8006,
   6:              DBT_DEVICEARRIVAL=0x8000,//USB Insert DEvice Statu
   7:              DBT_DEVICEQUERYREMOVE=0x8001,
   8:              DBT_DEVICEQUERYREMOVEFAILED=0x8002,
   9:              DBT_DEVICEREMOVEPENDING=0x8003,//USB Revoing.
  10:              DBT_DEVICEREMOVECOMPLETE=0x8004,//USB Remove Completed
  11:              DBT_DEVICETYPESPECIFIC=0x8005,
  12:              DBT_DEVNODES_CHANGED=0x0007,//Device List _Changed
  13:              DBT_QUERYCHANGECONFIG=0x0017,
  14:              DBT_USERDEFINED=0xFFFF
  15:          }


其中涉及到USB设备插拔的是DEVICEREMOVEPENDING/DEVICEREMOVECOMPLETE[删除]  DEVICEARRIVAL[插入设备]  重写WinFProc实现窗体上对Windows MEssage进行拦截并重新处理:

   1:        [PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
   2:          protected override void WndProc(ref Message m)
   3:          {
   4:              base.WndProc(ref m);
   5:              DeviceEvent lEvent;
   6:      
   7:              lEvent = (DeviceEvent)m.WParam.ToInt32();
   8:              switch (lEvent)
   9:              {
  10:                  case DeviceEvent.DBT_DEVICEARRIVAL://[Insert]
  11:                      this.CheckDeviceStatus_Lable.BackColor = Color.Green;
  12:                      this.CheckDeviceStatus_Lable.Text = "----Connection Device!----";
  13:                      MessageBox.Show("Just Insert At Moment !", "Insert");
  14:                      break;
  15:                  case DeviceEvent.DBT_DEVICEREMOVECOMPLETE://[REmove]
  16:                      this.CheckDeviceStatus_Lable.BackColor = Color.Red;
  17:                      this.CheckDeviceStatus_Lable.Text = "------No Connection------";
  18:                      MessageBox.Show("Remove Complete At Moment!", "Remove");
  19:                      break;
  20:                  case DeviceEvent.DBT_DEVNODES_CHANGED://[Device List Have Changed]
  21:                      MessageBox.Show("Device List have been Changed!");
  22:                      break;
  23:                  default:
  24:                      break;
  25:              }
  26:          }


首先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插拔时同样获得这个系统事件:

   1:    public void ControlUSBConnectionStatu()
   2:          {
   3:              ManagementEventWatcher getEventWatcher = null;
   4:              WqlEventQuery getEventQuery = null;
   5:   
   6:              ManagementOperationObserver getObserver = new ManagementOperationObserver();
   7:   
   8:              //Bind to Loacl Machine and Watch the PortConnection
   9:              ManagementScope getScope = new ManagementScope("root\\CIMV2");
  10:              getScope.Options.EnablePrivileges = true;//set requeired
  11:   
  12:              try
  13:              {
  14:                  getEventQuery = new WqlEventQuery();
  15:                  getEventQuery.EventClassName = "__InstanceOperationEvent";
  16:                  getEventQuery.WithinInterval = new TimeSpan(0, 0, 0, 1);
  17:                  getEventQuery.Condition = @"TargetInstance ISA 'Win32_DiskDrive' ";
                       //[Disk must have DiskDrive fuck ]
 
  20:                  //Event Watcher [Test Event and semd informatio to this message and create new informtion .]
  21:                  getEventWatcher = new ManagementEventWatcher(getEventQuery);
  22:                  getEventWatcher.EventArrived += new EventArrivedEventHandler(getEventWatcher_EventArrived);
  23:                  getEventWatcher.Start();//Start Watch Event
 
  25:              }
  26:              catch (Exception se)
  27:              { }
  28:              finally
  29:              {
  30:                  // getEventWatcher.Stop();
  31:              }
  32:          }


当发生USB插拔并成功监听到事件时处理方法:

   1:   void getEventWatcher_EventArrived(object sender, EventArrivedEventArgs e)
   2:          {
   3:              ManagementBaseObject getBaseObject = (ManagementBaseObject)e.NewEvent;
   4:              if ((getBaseObject.ClassPath.ClassName == "__InstanceCreationEvent"))
   5:              {
   6:                  //Usb Inserted
   7:                  MessageBox.Show("USB Disk Inserted!");
   8:              }
   9:              else
  10:              {
  11:                  //Usb Removed
  12:                  MessageBox.Show("USB Device Removed!");
  13:              }
  14:          }


如上在定义时设置一个Condition[条件]:存在Disk Driver 磁盘驱动.如果类似某些UKey不存在磁盘驱动同时也无存储介质 经过测试你会发现.加密的UKey插入 如上的WMI监听事件并不能扑捉到USB插拔. 但是针对这种方式我们还有一种更为彻底的方式就是USB插拔唯一可以确定在PC识别必然变化的因素是系统设备列表发生更新.


WMI处理监听:

   1:         /// <summary>
   2:          /// 监听USB Device设备插拔事件 完整操作.
   3:          /// WMI Handle Event Change Device List chenkai
   4:          /// </summary>
   5:          public void RegisterDeviceWMIEventStatu()
   6:          {
   7:              try 
   8:              {
   9:                  //Device List HAve Changed  And Send Message 
  10:                  WqlEventQuery query = new WqlEventQuery("SELECT * FROM Win32_DeviceChangeEvent");
  11:                  ManagementEventWatcher watcher = new ManagementEventWatcher(query);
  12:                  watcher.EventArrived += new EventArrivedEventHandler(watcher_EventArrived);
  13:                  watcher.Start();  // Start listening for events
  14:              }
  15:              catch (Exception se)
  16:              { }
  17:          }


WMI监听处理函数:

   1:   void watcher_EventArrived(object sender, EventArrivedEventArgs e)
   2:          {
   3:              string geteventtype = e.NewEvent.GetPropertyValue("EventType").ToString();
   4:              ManagementBaseObject getEventObject = (ManagementBaseObject)e.NewEvent;
   5:   
   6:              if (getEventObject != null)
   7:              {
   8:                  //close Operator 
   9:                  this.CloseDeviceEqument();
  10:              }
  11:          }


其实这依然还是一种折中办法.因为导致PC端设备列表发生变化的因素有很多.如何判定是USB口发生设备变化.WMI依然没有让我们失望:

   1:    //WMI Control The USB Device Change Statu And Send Message to When IT‘s Changed/
   2:          public void ControlUSBDeviceSTatu()
   3:          {
   4:              try
   5:              {
   6:                  WqlEventQuery query = new WqlEventQuery("select * from Win32_VolumeChangeEvent");
   7:                  ManagementEventWatcher getwatcher = new ManagementEventWatcher(query);
   8:                  getwatcher.EventArrived += new EventArrivedEventHandler(getwatcher_EventArrived);
   9:                  getwatcher.Start();
  10:              }
  11:              catch (Exception se)
  12:              { }
  13:          }


WMI在USB事情处理函数:

   2:          void getwatcher_EventArrived(object sender, EventArrivedEventArgs e)
   3:          {
   4:              MessageBox.Show(e.NewEvent.GetText(TextFormat.Mof).ToString());
   5:          }


这样来一来就可以清晰判定USB在插拔时所发生在系统PC端的变化通知给应用程序来进行处理.如何获得当前PC端 USB Driver列表.经过几番测试找到一种很好的方式获取全部的USB Driver信息:

   1:   //Get ALL USB DRiver And Driver Property Fuck this shit。chenkai
   2:          public static string[] AllInformation()
   3:          {
   4:              StringCollection propNames = new StringCollection();
   5:              ManagementClass driveClass = new ManagementClass("Win32_USBController");
   6:              PropertyDataCollection props = driveClass.Properties;
   7:              foreach (PropertyData driveProperty in props)
   8:                  propNames.Add(driveProperty.Name);
  12:              int idx = 0;
  13:              ManagementObjectCollection drives = driveClass.GetInstances();
  14:              string _s = string.Empty;
  15:              List<string> harddisk = new List<string>();
  16:   
  17:              foreach (ManagementObject drv in drives)
  18:              {
  19:                  idx++;
  20:                  _s = string.Format(" USB Driver({0}) Properties ", idx);
  21:                  harddisk.Add(_s);
  22:                  foreach (string strProp in propNames)
  23:                  {
  24:                      _s = string.Format("Property: {0}, Value: {1}", strProp, drv[strProp]);
  25:                      harddisk.Add(_s);
  26:                  }
  27:              }
  28:              string[] _ss = harddisk.ToArray();
  29:              return _ss;
  30:          }


WMI的更多体现是对Windows 交互中进一步封装和管理.


Can考资料:



Device ManageMent Events



System.Form.control.WinProc[]Method



System.Form.Control.Message[]Method