最近做了UKey加密中設計到USB裝置. 因UKEy是用來加密和執行PC與項目間通信加密的媒體.從作用範圍來講不是傳統意義上U盤作為存儲媒體來使用.其實熟悉網銀驅動DR應該了解.在網銀系統安全上一個最基本需求就是動态即時監控通信PC驅動以及裝置清單通信變化.當然包括我們加密存儲媒體在PC上USB插拔.
首先引入命名空間:
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");
case DeviceEvent.DBT_DEVNODES_CHANGED://[Device List Have Changed]
MessageBox.Show("Device List have been Changed!");
default:
}
}
首先USB在進行插拔即時如果沒有存儲媒體即Disk或是無驅動的方式可能不能觸發DeviceEvent.DBT_DEVICEREMOVECOMPLETE 和 DeviceEvent.DBT_DEVICEARRIVAL插把事件. 但是一點是可以确認的是.PC端隻要接受USB裝置.PC識别之後裝置清單肯定會發生變化. 如果不是加密Key. u盤的 盤符方式存在Disk存儲媒體.則沒有問題.
當然需要移植這種基于From窗體系統Message攔截方法時發現這種可重用性就不高.換一種思路采用Windows底層方式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();
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考資料:
<a target="_blank" href="http://msdn.microsoft.com/en-us/library/aa363232(v=vs.85).aspx">Device ManageMent Events</a>
<a target="_blank" href="http://msdn.microsoft.com/zh-cn/library/system.windows.forms.control.wndproc(v=VS.100).aspx">System.Form.control.WinProc[]Method</a>
<a target="_blank" href="http://msdn.microsoft.com/zh-cn/library/system.windows.forms.message.aspx">System.Form.Control.Message[]Method</a>
本文轉自chenkaiunion 51CTO部落格,原文連結:http://blog.51cto.com/chenkai/763645