大家都知道,WMI(Windows Management Instrumentation,Windows 管理规范)是一项核心的 Windows 管理技术;用户可以使用 WMI 管理本地和远程计算机,在这里只讨论它的硬件信息管理功能。
所有硬件设备的信息要能被WMI收集,其编写的驱动程序必须符合WMI规范,即WMI相当于这些硬件信息的管理员。通过IRPTrace这个工具可以很方便看到,当ring3有读取硬件序列号的动作,传到ring0层是这样:WMIDataDevice内核设备会收到一个名叫IRP_MJ_SYSTEM_CONTROL的通知,当然该通知还会附加着一个类似于IRP_MN_QUERY_ALL_DATA的通知。只要有一定驱动编程基础的人都知道,该通知会层层传递下去,得到结果后返回上来。
所以,我的拦截思路很简单,编写一个过滤驱动设备,附载在WMIDataDevice内核设备上,我的过滤驱动只对IRP_MJ_SYSTEM_CONTROL进行过滤:
NTSTATUS DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
{
.................
for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) {
DriverObject->MajorFunction[i] = LS2capDispatchGeneral;
}
//
// Our read function is where we do our real work.
//
DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = LS2DispatchSystemControl;
return LS2capInit( DriverObject );
}
然后再设置完成例程,目的是等该通知取到序列号后可以拦截并任意修改序列号。
主要就是编写NTSTATUS LS2DispatchSystemControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
....
}例程。
代码如下:
NTSTATUS LS2DispatchSystemControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
//PAGED_CODE();
PIO_STACK_LOCATION currentIrpStack;
PIO_STACK_LOCATION nextIrpStack;
NTSTATUS status ;
PDEVICE_EXTENSION devExt;
UCHAR minorFunc;
PIO_STACK_LOCATION IrpSp;
char teststr2[34]="IRP_MN_QUERY_ALL_DATA";
char teststr3[34]="IRP_MN_QUERY_SINGLE_INSTANCE";
char teststr0[34]="NOTHING";
IrpSp = IoGetCurrentIrpStackLocation( Irp );
devExt = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
status = STATUS_SUCCESS ;
minorFunc = IrpSp->MinorFunction;
switch(minorFunc)
{
case IRP_MN_QUERY_ALL_DATA:
devExt->controlcode=2;
currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
nextIrpStack = IoGetNextIrpStackLocation(Irp);
*nextIrpStack = *currentIrpStack;
IoSetCompletionRoutine( Irp, Ctrl2capWMIComplete,
DeviceObject, TRUE, TRUE, TRUE );
WriteFileTest(teststr2,34);
break;
case IRP_MN_QUERY_SINGLE_INSTANCE:
devExt->controlcode=3;
currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
nextIrpStack = IoGetNextIrpStackLocation(Irp);
*nextIrpStack = *currentIrpStack;
IoSetCompletionRoutine( Irp, Ctrl2capWMIComplete,
DeviceObject, TRUE, TRUE, TRUE );
WriteFileTest(teststr3,34);
break;
case IRP_MN_REGINFO:
case IRP_MN_REGINFO_EX:
case IRP_MN_CHANGE_SINGLE_INSTANCE:
case IRP_MN_CHANGE_SINGLE_ITEM:
case IRP_MN_EXECUTE_METHOD:
case IRP_MN_DISABLE_EVENTS:
case IRP_MN_ENABLE_COLLECTION:
case IRP_MN_DISABLE_COLLECTION:
case IRP_MN_ENABLE_EVENTS:
default:
#if WIN2K
IoSkipCurrentIrpStackLocation(Irp);
#else // WIN2K
//
// This is the equivalent of the IoSkipCurrentIrpStackLocation macro,
// which doesn't exist in the NT 4 DDK.
//
Irp->CurrentLocation++;
Irp->Tail.Overlay.CurrentStackLocation++;
#endif // WIN2K
WriteFileTest(teststr0,34);
return IoCallDriver(((PDEVICE_EXTENSION) DeviceObject->DeviceExtension)->TopOfStack, Irp);
break;
}
// 完成IRP
/*
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = 0; // bytes xfered
IoCompleteRequest( Irp, IO_NO_INCREMENT ); //结束IRP请求,即不再往下传递
return status;
*/
return IoCallDriver( devExt->TopOfStack, Irp );
}
为了方便检测是否过滤成功,可以创建一个文本文件,并往里写入标记。本人已实现对硬盘,主板,MAC地址等读取拦截。主要思路和代码就是这些,请各位多多指教。
- 标 题:关于拦截“通过WMI读取硬件序列号”的一些心得
- 作 者:夜鹰fly
- 时 间:2010-12-27 14:17:08
- 链 接:http://bbs.pediy.com/showthread.php?t=127176