zhjie374
驱动小牛
驱动小牛
  • 注册日期2004-10-27
  • 最后登录2012-01-17
  • 粉丝2
  • 关注1
  • 积分17分
  • 威望144点
  • 贡献值1点
  • 好评度21点
  • 原创分0分
  • 专家分0分
阅读:31709回复: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盘只读、读写、全锁定等等。遇到一些大问题。
当我完成那个功能的时候,再把这些详细的东西加上。


献丑了。。
snmqd
禁止发言
禁止发言
  • 注册日期2018-08-24
  • 最后登录2018-09-04
  • 粉丝0
  • 关注0
  • 积分-133分
  • 威望80点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
沙发#
发布于:2018-09-04 18:57
用户被禁言,该主题自动屏蔽!
znsoft
管理员
管理员
  • 注册日期2001-03-23
  • 最后登录2023-10-25
  • 粉丝300
  • 关注6
  • 积分910分
  • 威望14796点
  • 贡献值7点
  • 好评度2410点
  • 原创分5分
  • 专家分100分
  • 社区居民
  • 最爱沙发
  • 社区明星
板凳#
发布于:2015-07-17 18:47
注意,以上代码是用户态的,但是核心思想就是发送irp下去
http://www.zndev.com 免费源码交换网 ----------------------------- 软件创造价值,驱动提供力量! 淡泊以明志,宁静以致远。 ---------------------------------- 勤用搜索,多查资料,先搜再问。
znsoft
管理员
管理员
  • 注册日期2001-03-23
  • 最后登录2023-10-25
  • 粉丝300
  • 关注6
  • 积分910分
  • 威望14796点
  • 贡献值7点
  • 好评度2410点
  • 原创分5分
  • 专家分100分
  • 社区居民
  • 最爱沙发
  • 社区明星
地板#
发布于:2015-07-17 18:47
#pragma once
#include <tchar.h>
#include <winioctl.h>
/*
* USB 输助函数
* Author: M.Y
* Version: 1.0
* Revision: 1
*/


typedef enum _Sg_disk_type
{
    NONE_TYPE=0,
    IDE_DISK,
    USB_DISK,
    F1394_DISK, // 1394总线盘
}
SG_DISK_TYPE;

// SetupDiGetInterfaceDeviceDetail所需要的输出长度
#define INTERFACE_DETAIL_SIZE    (1024)

// IOCTL_STORAGE_GET_MEDIA_TYPES_EX可能返回不止一条DEVICE_MEDIA_INFO,故定义足够的空间
#define MEDIA_INFO_SIZE        (sizeof(GET_MEDIA_TYPES) + sizeof(DEVICE_MEDIA_INFO) * 15)

#define IOCTL_STORAGE_QUERY_PROPERTY   CTL_CODE(IOCTL_STORAGE_BASE, 0x0500, METHOD_BUFFERED, FILE_ANY_ACCESS)


// 查询存储设备属性的类型
typedef enum _STORAGE_QUERY_TYPE {
    PropertyStandardQuery = 0,          // 读取描述
    PropertyExistsQuery,                // 测试是否支持
    PropertyMaskQuery,                  // 读取指定的描述
    PropertyQueryMaxDefined                // 验证数据
} STORAGE_QUERY_TYPE, *PSTORAGE_QUERY_TYPE;

// 查询存储设备还是适配器属性
typedef enum _STORAGE_PROPERTY_ID {
    StorageDeviceProperty = 0,            // 查询设备属性
    StorageAdapterProperty                // 查询适配器属性
} STORAGE_PROPERTY_ID, *PSTORAGE_PROPERTY_ID;

// 查询属性输入的数据结构
typedef struct _STORAGE_PROPERTY_QUERY {
    STORAGE_PROPERTY_ID PropertyId;        // 设备/适配器
    STORAGE_QUERY_TYPE QueryType;        // 查询类型 
    UCHAR AdditionalParameters[1];        // 额外的数据(仅定义了象征性的1个字节)
} STORAGE_PROPERTY_QUERY, *PSTORAGE_PROPERTY_QUERY;


// 查询属性输出的数据结构
typedef struct _STORAGE_DEVICE_DESCRIPTOR {
    ULONG Version;        // 版本
    ULONG Size;            // 结构大小
    UCHAR DeviceType;    // 设备类型
    UCHAR DeviceTypeModifier;    // SCSI-2额外的设备类型
    BOOLEAN RemovableMedia;        // 是否可移动
    BOOLEAN CommandQueueing;    // 是否支持命令队列
    ULONG VendorIdOffset;        // 厂家设定值的偏移
    ULONG ProductIdOffset;        // 产品ID的偏移
    ULONG ProductRevisionOffset;    // 产品版本的偏移
    ULONG SerialNumberOffset;        // 序列号的偏移
    STORAGE_BUS_TYPE BusType;        // 总线类型
    ULONG RawPropertiesLength;        // 额外的属性数据长度
    UCHAR RawDeviceProperties[1];    // 额外的属性数据(仅定义了象征性的1个字节)
} STORAGE_DEVICE_DESCRIPTOR, *PSTORAGE_DEVICE_DESCRIPTOR;



class SgUSB
{

public:

    static SG_DISK_TYPE GetDriveType(TCHAR chDrv)
    {
        TCHAR szDeviceName[7]=_T("\\\\?\\x:");

        SG_DISK_TYPE   disktype;

        PSTORAGE_DEVICE_DESCRIPTOR pDevDesc;
        pDevDesc = (PSTORAGE_DEVICE_DESCRIPTOR)new BYTE[sizeof(STORAGE_DEVICE_DESCRIPTOR) + 512 - 1];
        pDevDesc->Size = sizeof(STORAGE_DEVICE_DESCRIPTOR) + 512 - 1;
        szDeviceName[4]=chDrv;

        HANDLE hHandle=OpenDevice(szDeviceName);
        if( hHandle == INVALID_HANDLE_VALUE )
            return NONE_TYPE;

        if(GetDriveProperty(hHandle,pDevDesc) )
        {
            
            switch(pDevDesc->BusType )
            {
            case BusType1394:
                disktype =  F1394_DISK;
            break;
            case BusTypeUsb:
                disktype =USB_DISK;
            break;
            
            default:

                disktype= NONE_TYPE;
            }

        }
        else
            disktype= NONE_TYPE;

        delete []pDevDesc;
        CloseHandle(hHandle);


        return disktype;


    }


    static HANDLE OpenDevice(LPCTSTR pszDevicePath)
    {
        HANDLE hDevice;

    // 打开设备
        hDevice= ::CreateFile(pszDevicePath,            // 设备路径
                GENERIC_READ | GENERIC_WRITE,            // 读写方式
                FILE_SHARE_READ | FILE_SHARE_WRITE,        // 共享方式
                NULL,                                    // 默认的安全描述符
                OPEN_EXISTING,                            // 创建方式
                0,                                        // 不需设置文件属性
                NULL);                                    // 不需参照模板文件

        return hDevice;
    }
    static BOOL GetDriveGeometry(HANDLE hDevice, PDISK_GEOMETRY pGeometry)
    {
            
        PGET_MEDIA_TYPES pMediaTypes;    // 内部用的输出缓冲区
        DWORD dwOutBytes;                // 输出数据长度
        BOOL bResult;                    // DeviceIoControl的返回结果

        // 申请内部用的输出缓冲区
        pMediaTypes = (PGET_MEDIA_TYPES)::GlobalAlloc(LMEM_ZEROINIT, MEDIA_INFO_SIZE);

        // 用IOCTL_STORAGE_GET_MEDIA_TYPES_EX取介质类型参数
        bResult = ::DeviceIoControl(hDevice,            // 设备句柄
                IOCTL_STORAGE_GET_MEDIA_TYPES_EX,        // 取介质类型参数
                NULL, 0,                                // 不需要输入数据
                pMediaTypes, MEDIA_INFO_SIZE,            // 输出数据缓冲区
                &dwOutBytes,                            // 输出数据长度
                (LPOVERLAPPED)NULL);                    // 用同步I/O    

        if(bResult)
        {
            // 注意到结构DEVICE_MEDIA_INFO是在结构DISK_GEOMETRY的基础上扩充的
            // 为简化程序,用memcpy代替如下多条赋值语句:
            // pGeometry->MediaType = (MEDIA_TYPE)pMediaTypes->MediaInfo[0].DeviceSpecific.DiskInfo.MediaType;
            // pGeometry->Cylinders = pMediaTypes->MediaInfo[0].DeviceSpecific.DiskInfo.Cylinders;
            // pGeometry->TracksPerCylinder = pMediaTypes->MediaInfo[0].DeviceSpecific.DiskInfo.TracksPerCylinder;
            // ... ...
            ::memcpy(pGeometry, pMediaTypes->MediaInfo, sizeof(DISK_GEOMETRY));
        }

        // 释放内部缓冲区
        ::GlobalFree(pMediaTypes);

        return bResult;

    }
    static BOOL GetDriveProperty(HANDLE hDevice, PSTORAGE_DEVICE_DESCRIPTOR pDevDesc)
    {
        STORAGE_PROPERTY_QUERY    Query;    // 查询输入参数
        DWORD dwOutBytes;                // IOCTL输出数据长度
        BOOL bResult;                    // IOCTL返回值

        // 指定查询方式
        Query.PropertyId = StorageDeviceProperty;
        Query.QueryType = PropertyStandardQuery;

        // 用IOCTL_STORAGE_QUERY_PROPERTY取设备属性信息
        bResult = ::DeviceIoControl(hDevice,            // 设备句柄
                IOCTL_STORAGE_QUERY_PROPERTY,            // 取设备属性信息
                &Query, sizeof(STORAGE_PROPERTY_QUERY),    // 输入数据缓冲区
                pDevDesc, pDevDesc->Size,                // 输出数据缓冲区
                &dwOutBytes,                            // 输出数据长度
                (LPOVERLAPPED)NULL);                    // 用同步I/O    

        return bResult;
    }




};

 
 
http://www.zndev.com 免费源码交换网 ----------------------------- 软件创造价值,驱动提供力量! 淡泊以明志,宁静以致远。 ---------------------------------- 勤用搜索,多查资料,先搜再问。
znsoft
管理员
管理员
  • 注册日期2001-03-23
  • 最后登录2023-10-25
  • 粉丝300
  • 关注6
  • 积分910分
  • 威望14796点
  • 贡献值7点
  • 好评度2410点
  • 原创分5分
  • 专家分100分
  • 社区居民
  • 最爱沙发
  • 社区明星
地下室#
发布于:2015-07-17 18:40
对于u盘只读控制,还有一个办法,就是在文件系统中文件打开或写的时候检查一下卷下面的总线类型,如果是usb或1394等可热插拨的,就进行禁止操作。

关于检查总线类型,可以向下面发送irp解决:
http://www.zndev.com 免费源码交换网 ----------------------------- 软件创造价值,驱动提供力量! 淡泊以明志,宁静以致远。 ---------------------------------- 勤用搜索,多查资料,先搜再问。
whisper_lc
驱动牛犊
驱动牛犊
  • 注册日期2015-07-07
  • 最后登录2015-07-10
  • 粉丝0
  • 关注0
  • 积分1分
  • 威望11点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
5楼#
发布于:2015-07-07 16:02
我觉得这个帖子基本解决不了问题,关键问题根本跳过部描述
hyb951
驱动牛犊
驱动牛犊
  • 注册日期2015-04-12
  • 最后登录2015-07-08
  • 粉丝0
  • 关注1
  • 积分2分
  • 威望21点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
6楼#
发布于:2015-05-01 18:37
谢谢分享
hyb951
驱动牛犊
驱动牛犊
  • 注册日期2015-04-12
  • 最后登录2015-07-08
  • 粉丝0
  • 关注1
  • 积分2分
  • 威望21点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
7楼#
发布于:2015-04-13 13:27
USB监控难么?
liwen930723
驱动牛犊
驱动牛犊
  • 注册日期2013-10-13
  • 最后登录2014-12-10
  • 粉丝0
  • 关注0
  • 积分8分
  • 威望81点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
8楼#
发布于:2014-01-15 12:29
我大二时做了一个U盘过滤,在总线驱动上的。。。不知道扔哪去了
o7781693
驱动牛犊
驱动牛犊
  • 注册日期2013-01-08
  • 最后登录2013-01-11
  • 粉丝0
  • 关注0
  • 积分3分
  • 威望31点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
9楼#
发布于:2013-01-08 21:17
新人报道,求大神指点
o7781693
驱动牛犊
驱动牛犊
  • 注册日期2013-01-08
  • 最后登录2013-01-11
  • 粉丝0
  • 关注0
  • 积分3分
  • 威望31点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
10楼#
发布于:2013-01-08 21:15
新人冒泡。各位大神求指教
yukun840101
驱动牛犊
驱动牛犊
  • 注册日期2009-07-29
  • 最后登录2016-05-23
  • 粉丝2
  • 关注2
  • 积分23分
  • 威望251点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
11楼#
发布于:2012-04-16 16:34
英雄不问出处,谢谢了。
bajiao
驱动牛犊
驱动牛犊
  • 注册日期2010-07-29
  • 最后登录2011-01-02
  • 粉丝0
  • 关注0
  • 积分5分
  • 威望41点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
12楼#
发布于:2010-08-17 22:29
特地赶来, 学习下!
cyyhtzx
驱动牛犊
驱动牛犊
  • 注册日期2009-03-31
  • 最后登录2012-08-01
  • 粉丝0
  • 关注0
  • 积分6分
  • 威望61点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
13楼#
发布于:2010-07-14 17:09
好人啊,好人,支持这样的共享精神。
yixql
驱动牛犊
驱动牛犊
  • 注册日期2010-05-12
  • 最后登录2010-12-06
  • 粉丝0
  • 关注0
  • 积分6分
  • 威望61点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
14楼#
发布于:2010-05-31 09:04
up~~~
crazy4stef
驱动牛犊
驱动牛犊
  • 注册日期2008-08-24
  • 最后登录2016-01-09
  • 粉丝2
  • 关注0
  • 积分42分
  • 威望425点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
15楼#
发布于:2010-04-13 12:52
代码被删掉了?
hnsyz
驱动牛犊
驱动牛犊
  • 注册日期2001-12-31
  • 最后登录2010-04-20
  • 粉丝1
  • 关注0
  • 积分108分
  • 威望259点
  • 贡献值0点
  • 好评度8点
  • 原创分0分
  • 专家分0分
16楼#
发布于:2010-03-12 09:21
我晕. 这两天我也在看这个. 我怎摸拦不住读写U盘的请求. 看网上有文章说拦截IRP_MJ_SCSI, 我拦截也没拦截住.
谁告诉你拦截身摸的?
学习,交流
Sanicle
驱动牛犊
驱动牛犊
  • 注册日期2004-08-11
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分32分
  • 威望54点
  • 贡献值0点
  • 好评度2点
  • 原创分0分
  • 专家分0分
17楼#
发布于:2010-03-11 15:07
最近在做这个,特地赶来看看,不错~ 多谢楼主分享
guenli
驱动牛犊
驱动牛犊
  • 注册日期2009-12-18
  • 最后登录2010-02-19
  • 粉丝0
  • 关注0
  • 积分61分
  • 威望611点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
18楼#
发布于:2010-02-13 10:54
学习了!
zyfnhct
驱动牛犊
驱动牛犊
  • 注册日期2008-06-24
  • 最后登录2013-07-07
  • 粉丝0
  • 关注0
  • 积分11分
  • 威望110点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
19楼#
发布于:2010-02-01 15:36
回 楼主(zhjie374) 的帖子
学习,好人
上一页
游客

返回顶部