zzbwang
驱动牛犊
驱动牛犊
  • 注册日期2009-03-18
  • 最后登录2016-01-09
  • 粉丝1
  • 关注0
  • 积分62分
  • 威望611点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分1分
阅读:1934回复:7

初学驱动,关于文件过滤驱动程序的几个问题

楼主#
更多 发布于:2009-03-20 16:40
我刚学windows驱动程序开发,想尝试在sfilter基础上设计一个实现文件加密解密的驱动程序,有几个问题:

1)sfilter没有处理IRP_MJ_READ和IRP_MJ_WRITE,而是使用了fastio回调函数,我应该在IRP_MJ_READ和IRP_MJ_WRITE的处理函数中完成数据的加密解密还是在FastIORead和FastIOWrite函数中完成加密、解密?

2)在FastIORead、FastIOWrite函数中我需要判断读写文件的进程是否是指定进程(比如WINWORD.exe),如果是就进行加密解密,否则不做处理。如何获得读写文件的进程名字?

3)我想用3DES或者AES之类的加密算法,是以8字节或者16字节分组完成加密解密的,对于长度不是16整数倍的文件,需要补齐到整数倍字节,不知道我的设想是否正确。

4)对于读文件的操作,如果应用程序要求读文件的offset不是16的整数倍,我可以要求底层文件系统驱动多读几个字节,解密后从正确的偏移量开始给应用程序正确长度的数据;但是对于写文件加密,如果应用程序写的内容是文件中间的几个字节,是不是我还得把数据从文件中读出来,把相应内容的数据修改,再加密,再写回文件?

5)问题4)中描述的写加密的实现方式,对于以前是明文保存,用受控软件打开后再保存的文件,可能会存在部分内容加密了,部分内容未加密的情况,这样就麻烦了。不知道这时应该怎么处理?

初学驱动程序,不懂的问题很多,希望大拿们不吝赐教!先谢谢啦!
sichuanwww
驱动牛犊
驱动牛犊
  • 注册日期2009-02-21
  • 最后登录2012-05-06
  • 粉丝0
  • 关注0
  • 积分4分
  • 威望41点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
沙发#
发布于:2009-03-22 14:20
zzbwang
驱动牛犊
驱动牛犊
  • 注册日期2009-03-18
  • 最后登录2016-01-09
  • 粉丝1
  • 关注0
  • 积分62分
  • 威望611点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分1分
板凳#
发布于:2009-03-22 17:40
楚狂人的回复(他只回答了4个问题):

(1)中的“不是”“而是”是错误的。sfilter没有处理irp_mj_read和irp_mj_write,是因为所有的read和write都被默认的分发函数处理了。默认分发函数的功能就是直接下发。
 fast io read write也是直接下发。只是因为每个fast io函数原型不同,无法写出一个通用的处理函数,所以你才以为每个fast io都“处理了”。要加密解密必须自己增加对read,write的分发函数,取代默认的分发函数。
(2)获取进程的名字不是一件简单的事情,我拷贝代码给你。但是切记:请勿向我索要任何代码或者发送代码让我帮你找bug。这是业内的大忌。(楼主注:俺没有向他要代码,也没有让他帮忙找bug,不知楚狂人何出此言)

// 这个函数必须在DriverEntry中调用,否则cfCurProcName将不起作用。
static size_t s_cf_proc_name_offset = 0;
void cfCurProcNameInit()
{
    ULONG i;
    PEPROCESS  curproc;
    curproc = PsGetCurrentProcess();
    // 搜索KPEB结构,在其中找到字符串
    for(i=0;i<3*4*1024;i++)
    {
        if(!strncmp("System",(PCHAR)curproc+i,strlen("System")))
        {
            s_cf_proc_name_offset = i;
            break;
        }
    }
}

// 以下函数可以获得进程名。返回获得的长度。
ULONG cfCurProcName(PUNICODE_STRING name)
{
    PEPROCESS  curproc;
    ULONG    i,need_len;
    ANSI_STRING ansi_name;
    if(s_cf_proc_name_offset == 0)
        return 0;

    // 获得当前进程PEB,然后移动一个偏移得到进程名所在位置。
    curproc = PsGetCurrentProcess();

    // 这个名字是ansi字符串,现在转化为unicode字符串。
    RtlInitAnsiString(&ansi_name,((PCHAR)curproc + s_cf_proc_name_offset));
    need_len = RtlAnsiStringToUnicodeSize(&ansi_name);
    if(need_len > name->MaximumLength)
    {
        return RtlAnsiStringToUnicodeSize(&ansi_name);
    }
    RtlAnsiStringToUnicodeString(name,&ansi_name,FALSE);
    return need_len;
}
(3)你的想法是对的。
(4)所以需要加密标识。加密标识可以保存在文件头也可以保存在文件尾,必须对应用程序隐藏。保存在文件尾比较容易实现。
zzbwang
驱动牛犊
驱动牛犊
  • 注册日期2009-03-18
  • 最后登录2016-01-09
  • 粉丝1
  • 关注0
  • 积分62分
  • 威望611点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分1分
地板#
发布于:2009-03-22 19:31
关于第五个问题的答案:

我看了tooflat的sfilter程序,是这样处理的:

对于任何一个新打开的文件,根据规则判断这个文件以前是否加密了,现在是否需要加密,然后根据要求更新整个文件:以前没加密现在需要加密的,全部读出来,加密后再写回去(在sfWrite完成),以前加密了的,现在需要不加密的,全部读出来,解密(在sfRead()中完成),再写回去。

这样,就可以保证文件在打开之后处于正确的加密状态。
rong1028
驱动牛犊
驱动牛犊
  • 注册日期2008-04-29
  • 最后登录2018-04-30
  • 粉丝0
  • 关注0
  • 积分8分
  • 威望62点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
  • 社区居民
地下室#
发布于:2009-04-12 19:37
引用楼主zzbwang于2009-03-20 16:40发表的 初学驱动,关于文件过滤驱动程序的几个问题 :
我刚学windows驱动程序开发,想尝试在sfilter基础上设计一个实现文件加密解密的驱动程序,有几个问题:
对于读文件的操作,如果应用程序要求读文件的offset不是16的整数倍,我可以要求底层文件系统驱动多读几个字节
.......

想请问如何要求多读几个字节?
zzbwang
驱动牛犊
驱动牛犊
  • 注册日期2009-03-18
  • 最后登录2016-01-09
  • 粉丝1
  • 关注0
  • 积分62分
  • 威望611点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分1分
5楼#
发布于:2009-04-12 22:07
把readLen = iopb->Parameters.Read.Length以及ByteOffset设置成你想读的值,然后向底层驱动发送IRP读就行了。

如果用minifilter,在preread中设置参数后调用FltSetCallbackDataDirty()就行了。

注意Offet和length的长度需要满足底层驱动的要求。
rong1028
驱动牛犊
驱动牛犊
  • 注册日期2008-04-29
  • 最后登录2018-04-30
  • 粉丝0
  • 关注0
  • 积分8分
  • 威望62点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
  • 社区居民
6楼#
发布于:2009-04-15 15:21
回 5楼(zzbwang) 的帖子
Read的部份我瞭解了! 谢谢!但是现在疑问是在 pre-write时,每次进来的iopb->Parameters.Write.Length都不一样
不知道如何让它进来就是固定的size. 如:4096
zzbwang
驱动牛犊
驱动牛犊
  • 注册日期2009-03-18
  • 最后登录2016-01-09
  • 粉丝1
  • 关注0
  • 积分62分
  • 威望611点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分1分
7楼#
发布于:2009-04-15 19:43
如果你的驱动只过滤Paging io,那么长度都是4096,这是一个簇的大小。如果还要处理cached io,进来的数据长度可以是任意值,你只能先把数据读出来,用新数据部分覆盖后再写回去。
游客

返回顶部