加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

FileDisk源码分析(以前的笔记了~)

(2011-04-27 13:19:50)
标签:

it

这差不多是去年写的学习笔记了...当时后面部分好像偷懒了...没写全的样子...呵呵~当时本来还打算A掉Virtual CD ROM的VcdRom.sys,不过debugman上已经有人放出src了...所以也就学习了一下...下面凑合着看.

 

filedisk是一个网上流传比较广泛的开源程序,它能够 mount / unmount CD/DVD images.通俗点说就是实现虚拟光驱的功能,也是一个学习磁盘过滤驱动非常好的例子.

 你可以从Windows driver examples下载最新的filedisk源代码,下面的代码是基于最新的filedisk-17.

[1.0] FileDisk的使用

  打开install.txt文件.里面讲述的很清楚.

  首先,将filedisk.sys驱动程序复制到%systemroot%\system32\drivers\.目录下.

  然后,双击filedisk.reg文件.添加到注册表中.

  最后,重启即可.

  上面这些其实就是实现对 filedisk.sys的驱动安装而已,在启动的时候将filedisk.sys加载到内核中.

  重启之后,就可以在控制台中运行filedisk.exe程序,可以使用 mount 和 unmount 命令了.

 

[2.0] FileDisk驱动分析.

FileDisk驱动程序,通过增加一个设备,实现磁盘过滤.

对磁盘的过滤,重点要关注的是对磁盘的读,写,以及关于磁盘信息的获取.

[2.1] filedisk.h

1.定义了设备名和符号链接名

2.定义三个IOCTL_CODE,分别与Read,Write,Query三个操作相关

3.定义了 OPEN_FILE_INFORMATION结构,该结构保存和传递关于被mount的文件的相关信息.

typedef struct _OPEN_FILE_INFORMATION {
    LARGE_INTEGER   FileSize;// 文件大小
    BOOLEAN         ReadOnly;// 是否可读写
    UCHAR           DriveLetter;// 盘符
    USHORT          FileNameLength;// 文件名的长度
    UCHAR           FileName[1];// 文件名
} OPEN_FILE_INFORMATION, *POPEN_FILE_INFORMATION;

 

[2.2]filedisk.c

再分析函数之前先来熟悉下几个结构

1.DEVICE_EXTENSION结构.

  其实关于DEVICE_EXTENSION,它是由I/O管理器自动分配这个内存,并把设备对象中的DeviceExtension指针指向这块内存.

typedef struct _DEVICE_EXTENSION {
    BOOLEAN                     media_in_device;//是否指定了一个文件作为存储媒介
    HANDLE                      file_handle; // 文件句柄
    ANSI_STRING                 file_name;// 文件名
    LARGE_INTEGER               file_size;// 文件大小
    BOOLEAN                     read_only;// 是否只读
    BOOLEAN                     is_cd_or_dvd;// 是否为cd/dvd
    PSECURITY_CLIENT_CONTEXT    security_client_context;// 线程客户安全context
    LIST_ENTRY                  list_head;// 链表头
    KSPIN_LOCK                  list_lock;// 自旋锁
    KEVENT                      request_event;// 请求事件
    PVOID                       thread_pointer;// 线程函数指针
    BOOLEAN                     terminate_thread;// 线程结束标志
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;

 media_in_device是指这个设备是否已经指定了一个文件作为存储媒质。这是一个用文件来虚拟磁盘的驱动。那么一个磁盘应该对应一个实际存在的文件。读写这个磁盘的请求最终转变为对文件的读写。如果一个磁盘设备对象还没有指定文件,那么这个内容是FALSE.
    file_handle是文件句柄。也就是这个虚拟磁盘所对应的文件。
    file_information是这个文件的一些信息。
    read_only是否只读。
    security_client_context 访问文件的时候需要使用的一个线程客户安全性上下文。
    list_head是一个链表头。一部分irp(windows发来的请求包)被放入这个链表中。我们为每个磁盘对象开启一个系统线程(处理线程),专门用来处理这些请求。
    list_lock是为了保证链表读写同步的锁。
    request_event是一个事件。当链表中没有请求的时候,处理请求的系统线程并不做任何事情,而只等待这个事件。当有请求到来,我们把请求放入链表,然后设置这个事件。处理线程就会开始处理这些请求。
    thread_pointer是线程的指针,用来最后等待这个线程的结束。
    terminate_thread是一个标志。如果设置为TRUE,处理线程执行的时候检测到这个,就会把自己终止掉。

 

在DriverEntry中.

1.首先通过RtlQueryRegistryValues()函数,获得注册表相关信息.

主要是为了获得n_devices的值.n_devices决定生成多少个磁盘设备对象,默认的数值为4.

2.然后通过FileDiskCreateDevice()创建磁盘设备对象.

3.设置好IRP分发函数.

NTSTATUS
DriverEntry (
    IN PDRIVER_OBJECT   DriverObject,
    IN PUNICODE_STRING  RegistryPath
    )
{

.....

//查询注册表信息,获取n_devices

    status = RtlQueryRegistryValues(
        RTL_REGISTRY_ABSOLUTE,
        parameter_path.Buffer,
        &query_table[0],
        NULL,
        NULL
        );

// 如果失败,将n_devices设为默认值4

    if (!NT_SUCCESS(status))
    {
        KdPrint(("FileDisk: Query registry failed, using default values.\n"));
        n_devices = DEFAULT_NUMBEROFDEVICES;
    }

....

// 创建n_devices个磁盘设备对象,FILE_DEVICE_DISK类型的

    for (n = 0, n_created_devices = 0; n < n_devices; n++)
    {
        status = FileDiskCreateDevice(DriverObject, n, FILE_DEVICE_DISK);

        if (NT_SUCCESS(status))
        {
            n_created_devices++;
        }
    }

// 创建n_devices个磁盘设备对象,FILE_DEVICE_CD_ROM类型的.

    for (n = 0; n < n_devices; n++)
    {
        status = FileDiskCreateDevice(DriverObject, n, FILE_DEVICE_CD_ROM);

        if (NT_SUCCESS(status))
        {
            n_created_devices++;
        }
    }

.....

// 设置分发函数

    DriverObject->MajorFunction[IRP_MJ_CREATE]         = FileDiskCreateClose;
    DriverObject->MajorFunction[IRP_MJ_CLOSE]          = FileDiskCreateClose;
    DriverObject->MajorFunction[IRP_MJ_READ]           = FileDiskReadWrite;
    DriverObject->MajorFunction[IRP_MJ_WRITE]          = FileDiskReadWrite;
    DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = FileDiskDeviceControl;

    DriverObject->DriverUnload = FileDiskUnload;

    return STATUS_SUCCESS;
}

 FileDiskCreateDevice()函数.

1.首先判断DeviceType,然后根据类型的不同,添加的Devicename的前缀也不一样.CD类型的前缀带"Cd"

2.调用IoCreateSecureDevice(),创建设备.初始化链表头,初始化SpinLock(自旋锁),初始化Event(事件),这些都用于后面的线程同步.

3.调用PsCreateSystemThread(),创建系统线程函数.FileDiskThread(). thread_handle保存线程处理函数的句柄.

4.调用ObReferenceObjectByHandle(),保存线程函数的指针.

 

FileDiskThread()函数

1.调用KeSetPriorityThread(),设置当前线程的优先级为LOW_REALTIME_PRIORITY.

2.for(;;)死循环中调用KeWaitForSingleObject(),等待reques_event事件.如果等到事件,则判断事件类型,分别处理.

IRP_MJ_READ:调用ZwReadFile读取文件,从内核到用户缓冲区;
IRP_MJ_WRITE:调用ZwWriteFile写入文件,从用户到内核缓冲区;
IRP_MJ_DEVICE_CONTROL:在FileDiskDeviceControl设置事件才会触发,主要有如下两种操作码:
 IOCTL_FILE_DISK_OPEN_FILE:调用FileDiskOpenFile。
 IOCTL_FILE_DISK_CLOSE_FILE:调用FileDiskCloseFile。

FileDiskOpenFile:根据用户程序传入的映像文件全路径,调用ZwCreateFile在内核中打开它,如果文件不存在则再创建它,返回文件句柄。
FileDiskCloseFile:调用ZwClose关闭文件。

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有