zhjie374
驱动小牛
驱动小牛
  • 注册日期2004-10-27
  • 最后登录2012-01-17
  • 粉丝2
  • 关注1
  • 积分17分
  • 威望144点
  • 贡献值1点
  • 好评度21点
  • 原创分0分
  • 专家分0分
阅读:31744回复:78

共享我写的一个USB过滤驱动,实现U盘只读控制

楼主#
更多 发布于:2005-04-05 17:29
看到很多人都把自己的东西拿出来共享,我也来写一点。

功能:
 这是一个简单的USB过滤驱动,采用标准的WDM过滤,以DDK中的filter为原形。实现了U盘的只读控制。

说明:
1 在整个编写过程中,受到tiamo等众多高手的帮助,感激不尽。还要向他们多多学习。
2 这是我写的具有具体功能的第一个驱动,高兴。
3 本人是一位就读于排名在300名以外的大学的大四学生,水平有限,有错误的地方请各位指出。见笑了。

开发中使用的工具和环境:
vc 6.0+2000ddk 用DbgViewer查看信息。 用DeviceTree查看驱动加载情况

正文:

我从开始看驱动就认为,一个完整的驱动是改出来的。
     因此我修改了ddk中toaster/filter程序。这个程序写的思路很清晰,把一个标准的过滤驱动程序应该有的各个模块都写了出来。特
别是很完整的做了PNP的相关操作。
     作为一个标准过滤驱动,应该在AddDevice中将创建的设备IoAttachDeviceToDeviceStack到欲过滤的设备上。而这个设备就是
AddDevice的第二个参数。这里要说明的是,我过滤的设备对象是usbstor.sys,是一个FlowerFilters。 在注册表中加入相应的项(这个
过程应该是INF做的,我不会做,因此直接加的),系统在加载usbstor.sys这个驱动的时候,根据注册表中FlowerFilters对应的值就会
自动去加载你的驱动,非常的方便。
     系统加载你的设备以后就进入了AddDevice,此时你可以IoAttachDeviceToDeviceStack,填写你的PDEVICE_EXTENSION等等。
这样完成以后,你的设备就可以在DeviceTree中看到,位置在USBSTOR打开以后,展开可以看到。
     剩下的不用我说,大家也知道。就是拦截相应的IRP了。对应不同的过滤功能,需要拦截的IRP也不同,以我这为例子,我想拦截
所有的写操作,就是使U盘成为只读的。开始我去拦截IRP_MJ_WRITE,跟踪发现,写U盘的时候根本不走这个地方。询问后知道要
拦截相应的scsi命令,关于SCSI命令有相关的规范去看。对SCSI命令的取得和操作大致如下:
1 得到当前的SCSI命令:
  DbgPrint(\"IRP_MJ_SCSI\");
  irpStack = IoGetCurrentIrpStackLocation(irp);
  CurSrb=irpStack->Parameters.Scsi.Srb;
  cdb=CurSrb->Cdb;
  opCode=cdb->CDB6GENERIC.OperationCode;
   现在opCode中就是当前的SCSI命令。

2 分析SCSI命令(由于SCSI命令很多,找到真正要拦截的SCSI命令,还需要参看实例)
  if(opCode==SCSIOP_MODE_SENSE)//一个mode sense结构
  { }
  if(opCode==SCSIOP_WRITE||opCode==SCSIOP_WRITE6)//写操作
  {           }
  其他的参看SCSI规范

  当我拦截到SCSI命令以后,认为一切边的顺利起来。但是实际上,我在只拦截SCSIOP_WRITE的时候,虽然系统不会真正的写东西到
U盘上,但却要过很久才会提示延时写错误。这样的程序显然是不能给用户的。这个时候tiamo告诉我一个方法,这个方法来源于市场
上的一种“带写保护功能”的U盘,他可以象软盘一样的写保护。当然他是硬件上实现的。软件实现更加的简单,如下:
  irpStack = IoGetCurrentIrpStackLocation(Irp);
CurSrb=irpStack->Parameters.Scsi.Srb;//Get Current Scsi SRB, Analysis SCSI Command here!
cdb=CurSrb->Cdb;
opCode=cdb->CDB6GENERIC.OperationCode;
if(opCode==SCSIOP_MODE_SENSE && CurSrb->DataBuffer && CurSrb->DataTransferLength >= sizeof(MODE_PARAMETER_HEADER)
{
modeData = (PMODE_PARAMETER_HEADER)CurSrb->DataBuffer;
modeData->DeviceSpecificParameter|=MODE_DSP_WRITE_PROTECT;
}
具体就是modeData->DeviceSpecificParameter|=MODE_DSP_WRITE_PROTECT;这句话了。
    
    写到这里,U盘的只读功能就完成了。效果很好。

    写这个文章的时候我正在完善这个程序,希望用一个应用层的程序和他配合。可以控制U盘只读、读写、全锁定等等。遇到一些大问题。
当我完成那个功能的时候,再把这些详细的东西加上。


献丑了。。
zhjie374
驱动小牛
驱动小牛
  • 注册日期2004-10-27
  • 最后登录2012-01-17
  • 粉丝2
  • 关注1
  • 积分17分
  • 威望144点
  • 贡献值1点
  • 好评度21点
  • 原创分0分
  • 专家分0分
沙发#
发布于:2005-04-06 13:27
首先要保证你的过滤驱动已经是在SERVICES中有这个项.
然后在相应的ENUM下加上FLOWERFILTERS 是一个MUTI_SZ,值就是你对应的那个服务名字.
zhjie374
驱动小牛
驱动小牛
  • 注册日期2004-10-27
  • 最后登录2012-01-17
  • 粉丝2
  • 关注1
  • 积分17分
  • 威望144点
  • 贡献值1点
  • 好评度21点
  • 原创分0分
  • 专家分0分
板凳#
发布于:2005-04-06 15:59
名牌确实机会多.
没有办法.
深有体会
游客

返回顶部