1.背景
    在windows平台下,应用程序通常使用API函数来进行文件访问,创建,打开,读写文件。从kernel32的CreateFile/ReadFile/WriteFile函数,到本地系统服务,再到FileSystem及其FilterDriver,经历了很多层次。在每个层次上,都存在着安全防护软件,病毒或者后门作监视或者过滤的机会。作为安全产品开发者,我们需要比别人走得更远,因此我们需要一个底层的“windows平台内核级文件访问”的方法来确保我们能够看到正确的干净的文件系统。

2.用途
    直接的内核级别文件访问,在信息安全领域内有广泛的用途。用于***者的方面,可以让他绕过杀毒软件,IDS等安全保护系统的监视。用于检测者的方面,可以看到一个干净的系统,以此来查杀隐藏的后门或者rootkit。用于监控者的方面,则可以了解最新的绕过监控的技术,可以根据来设计更新的监控方案。

3.直接访问FSD的内核级别文件访问
    FSD(FileSystemDriver)层是文件API函数经过本地系统服务层(native API)最后到达的驱动层次。如果我们可以模仿操作系统,在我们自己的驱动程序里直接向FSD发送IRP,就可以绕过那些native API 和win32 API了,也就可以绕过设置在这些层次上面的API钩子等监控措施。

3.1文件的Create和Open
    文件的Create和Open可以通过发送IRP_MJ_CREATE给FSD,或者调用IoCreateFile函数来完成。Create和Open的区别实际上在于IoCreateFile/IRP_MJ_CREATE的一个参数Disposition的取值。使用IoCreateFile函数的样例代码:

HANDLE openfile(WCHAR* name,ACCESS_MASK access,ULONG share)
{
    //return 0 for error.
    HANDLE hfile;
    IO_STATUS_BLOCK iosb;
    int stat;
    OBJECT_ATTRIBUTES oba;
    UNICODE_STRING nameus;
    ///
    if(KeGetCurrentIrql()>PASSIVE_LEVEL){return 0;}
    RtlInitUnicodeString(&nameus,name);
    InitializeObjectAttributes(&oba,&nameus,OBJ_KERNEL_HANDLE|OBJ_CASE_INSENSITIVE,0,0);
    stat=IoCreateFile(&hfile,access,&oba,&iosb,0,FILE_ATTRIBUTE_NORMAL,share,FILE_OPEN,0,0,0,0,0,0);
    if(!NT_SUCCESS(stat)){return 0;}
    return hfile;
}

HANDLE createnewfile(WCHAR* name,ACCESS_MASK access,ULONG share)
{
    //return 0 for error.
    HANDLE hfile;
    IO_STATUS_BLOCK iosb;
    int stat;
    OBJECT_ATTRIBUTES oba;
    UNICODE_STRING nameus;
    ///
    if(KeGetCurrentIrql()>PASSIVE_LEVEL){return 0;}
    RtlInitUnicodeString(&nameus,name);
    InitializeObjectAttributes(&oba,&nameus,OBJ_KERNEL_HANDLE|OBJ_CASE_INSENSITIVE,0,0);
    stat=IoCreateFile(&hfile,access,&oba,&iosb,0,//AllocationSize this set to 0 that when file opened it was zeroed.
        FILE_ATTRIBUTE_NORMAL,share,FILE_OVERWRITE_IF,0,0,0,0,0,0);
    if(!NT_SUCCESS(stat)){return 0;}
    return hfile;
}

通过发送IRP_MJ_CREATE给FSD的方法与此类似,可以参考IFSDDK document的IRP_MJ_CREATE说明。不同于上面方法的是需要自己创建一个FILE_OBJECT,好于上面方法的是这种方法不需要一个HANDLE,HANDLE是线程依赖的,FileObject则是线程无关。

3.2文件的Read和Write
    我们通过给FSD发送IRP_MJ_READ来读取文件,给FSD发送IRP_MJ_WRITE来改写文件。
    如果我们是通过一个HANDLE来执行(如使用IoCreateFile打开的文件),就要先用ObReferenceObjectByHandle函数来获得这个Handle对应的FileObject。我们只能给FileObject发送IRP。

stat=ObReferenceObjectByHandle(handle,GENERIC_READ,*IoFileObjectType,KernelMode,(PVOID*)&fileob,0);

之后我们使用IoAllocateIrp分配一个IRP。根据FileObject->DeviceObject->Flags的值,我们判断目标文件系统使用什么样的IO方式。

if(fileob->DeviceObject->Flags & DO_BUFFERED_IO)
    {
        irp->AssociatedIrp.SystemBuffer=buffer;//buffered io
    }
    else if(fileob->DeviceObject->Flags & DO_DIRECT_IO)
    {
        mdl=IoAllocateMdl(buffer,count,0,0,0);
        MmBuildMdlForNonPagedPool(mdl);
        irp->MdlAddress=mdl;//direct io
    }
    else
    {
        irp->UserBuffer=buffer;//neither i/o, use kernel buffer
    }

对每种不同的IO方式使用不同的地址传递方式。随后我们填充IRP内的各个参数域,就可以发送IRP了。以Read为例:

irpsp->FileObject=fileob;
    irpsp->MajorFunction=IRP_MJ_READ;
    irpsp->MinorFunction=IRP_MN_NORMAL;//0
    irpsp->Parameters.Read.ByteOffset=offsetused;
    irpsp->Parameters.Read.Key=0;
    irpsp->Parameters.Read.Length=count;

接着要考虑如果IRP不能及时完成,会异步的返回的情况,我们安装一个CompletionRoutine,在CompletionRoutine里面设置一个事件为已激活,通知我们的主线程读取或者写入操作已经完成。

IoSetCompletionRoutine(irp,IoCompletion,&event,1,1,1);

NTSTATUS
  IoCompletion(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp,
    IN PVOID  Context
    )
{
    KeSetEvent((PRKEVENT)Context, IO_DISK_INCREMENT, 0);
    return STATUS_MORE_PROCESSING_REQUIRED;
}

现在可以发送IRP了。如果不采取特殊的措施的话,IRP发送目标是FileObject对应的DeviceObject。发送后,等待IRP的完成并且释放资源,返回。

stat=IoCallDriver(fileob->DeviceObject,irp);
    if(stat==STATUS_PENDING){
        KeWaitForSingleObject(&event, Executive,KernelMode,0,0);
        stat=irp->IoStatus.Status;
    }
    if(!NT_SUCCESS(stat))
    {
        IoFreeIrp(irp);
        if(mdl){IoFreeMdl(mdl);}//if DO_DIRECT_IO
        return -1;
    }
    stat=irp->IoStatus.Information;//bytes read
    IoFreeIrp(irp);
    if(mdl){IoFreeMdl(mdl);}//if DO_DIRECT_IO
    return stat;

3.3文件的Delete
    Delete实际上是通过向FSD发送IRP_MJ_SET_INFORMATION的IRP,并把IrpSp->Parameters.SetFile.FileInformationClass设置为FileDispositionInformation,用一个FILE_DISPOSITION_INFORMATION结构填充buffer来执行的。

fdi.DeleteFile=TRUE;

irpsp->MajorFunction=IRP_MJ_SET_INFORMATION;
    irpsp->Parameters.SetFile.Length = sizeof(FILE_DISPOSITION_INFORMATION);
    irpsp->Parameters.SetFile.FileInformationClass = FileDispositionInformation;
    irpsp->Parameters.SetFile.DeleteHandle = (HANDLE)handle;

3.4文件的Rename
    类似于Delete,Rename是向FSD发送IRP_MJ_SET_INFORMATION的IRP,把IrpSp->Parameters.SetFile.FileInformationClass设置为FileRenameInformation,填充buffer为FILE_RENAME_INFORMATION结构。

fri.ReplaceIfExists=TRUE;
    fri.RootDirectory=0;//Set fri.FileName to full path name.
    fri.FileNameLength=wcslen(filename)*2;
    wcscpy(fri.FileName,filename);//If the RootDirectory member is NULL, and the file is being moved to a different directory, this member specifies the full pathname to be assigned to the file.

irpsp->MajorFunction=IRP_MJ_SET_INFORMATION;
    irpsp->Parameters.SetFile.Length = sizeof(FILE_FILE_RENAME_INFORMATION);
    irpsp->Parameters.SetFile.FileInformationClass = FileRenameInformation;

综上,于是我们可以在驱动里面通过发送IRP来直接访问文件系统了,绕过了native API 和win32 API层次。

4.绕过文件系统过滤驱动和钩子

有了第三部分的内容,我们目前可以直接给FSD发送请求操作文件。但是这还不够,因为有很多的杀毒软件或者监视工具使用FSD Filter Driver或者FSD Hook的办法来监控文件操作。在今天这篇文章里我讲一些原理性的东西,提供绕过FSD Filter Driver / FSD Hook的思路。

4.1对付文件系统过滤驱动

文件系统过滤驱动Attach在正常的文件系统之上,监视和过滤我们的文件访问。文件系统驱动栈就是由这一连串的Attach起来的过滤驱动组成。我们可以用IoGetRelatedDeviceObject这个函数来获得一个FileObject对应的最底层的那个功能驱动对象(FDO)。但是这样虽然绕过了那些过滤驱动,却同时也绕过了正常的FSD如Ntfs/Fastfat,因为正常的FSD也是作为一个过滤驱动存在的。磁盘文件对象的对应的最底层的FDO是Ftdisk.sys,它已经因为过于底层而不能处理我们投递的IRP请求。
    其实正常的FSD信息存储在一个Vpb结构中,我们可以使用IoGetBaseFileSystemDeviceObject这个未公开的内核函数来得到它。它就是我们发送IRP的目标了。

4.2对付替换DispatchRoutine的FSD Hook

这是一种常用的FSD Hook方式。我们需要得到原本的DispatchRoutine,向原本的DispatchRoutine发送我们的IRP。这里提供一个思路:我们可以读取原本FSD驱动的.INIT段或者.TEXT段,查找其DriverEntry函数,在它的DriverEntry函数中肯定设置了自己的DriverObject的各个DispatchRoutine。在这个函数中我们就能找到我们想要的DispatchRoutine的地址。只需要使用特征码搜索的方法就可以搜索到这个值。

4.3对付Inline Hook DispatchRoutine函数本身的FSD Hook

这种Hook方法比较狠毒,但不是非常常见于安全产品中,一般应用在***和rootkit上,比如我自己写的rootkit。它没有更改DriverObject里面的DispatchRoutine的函数指针,而是向函数开头写入汇编指令的JMP来跳转函数。对付它的基本思路就是读取存在磁盘上的FSD的文件,加载到内存一份干净的备份,察看我们要调用的DispatchRoutine开头的几个字节和这个干净备份是否一致。如果不一致,尤其是存在JMP,RET,INT3一类的汇编指令的时候,很可能就是存在了Inline Hook。(但要充分考虑重定位的情况。)如果存在Inline Hook,我们就把干净的函数开头拷贝过来覆盖掉被感染的函数头。然后在发送IRP,就不会被Inline Hook监视或篡改了。

转载于:https://blog.51cto.com/xiong/18092

Windows平台内核级文件访问相关推荐

  1. Recuva 是一个免费的 Windows 平台下的文件恢复工具

    是不是有时会遇到文件误删除,大家的第一反应肯定是在回收站里还原文件.但如果文件在U盘或硬盘里被不小心格式化后那又如何找回呢? 今天给大家带来了一款数据恢复软件Recuva,Recuva 是一个免费的 ...

  2. Java在Windows下导出xml文件到Linux服务器上

    最近由于公司项目需要,学习了在Windows平台导出xml文件到Linux服务器上的指定目录下的方法,(注:这里的我的Linux是在本机上装的虚拟机)现在写下来记录一下! 1.首先是项目截图: 2.主 ...

  3. SDL_gfx-2.0.23在windows平台下的编译及例子

    SDL_gfx是SDL的一个扩展库,包括了许多图形相关的操作函数,本文介绍该库在Windows平台使用VS2003编译过程,并给出一个简单的例子. SDL_gfx主页地址:http://www.fer ...

  4. linux 生成dll文件,Linux和Windows平台 动态库.so和.dll文件的生成

    Linux动态库的生成 1. 纯cpp文件打包动态库 将所有cpp文件和所需要的头文件放在同一文件夹,然后执行下面命令 gcc -shared - fpic *.c -o xxx.so: g++ -s ...

  5. windows平台 python生成 pyd文件

    Python的文件类型介绍: .py       python的源代码文件 .pyc     Python源代码import后,编译生成的字节码 .pyo     Python源代码编译优化生成的字节 ...

  6. Linux和Windows平台 动态库.so和.dll文件的生成

    Linux动态库的生成 1. 纯cpp文件打包动态库 将所有cpp文件和所需要的头文件放在同一文件夹,然后执行下面命令 gcc -shared - fpic *.c -o xxx.so: g++ -s ...

  7. Windows平台真实时毫秒级4K H264/H265直播技术方案探讨

    背景 在刚提出4K视频的时候,大多数人都觉得没有必要,4K的出现,意味着更高的硬件规格和传输要求,1080P看的很爽.很清晰,完全满足了日常的需求.随着电视的尺寸越来越大,原本1080P成像已经无法满 ...

  8. 计算机中文件访问时间是什么情况,【反计算机取证必看】Windows系统中文件时间属性的变化及影响因素.pdf...

    [反计算机取证必看]Windows系统中文件时间属性的变化及影响因素.pdf ·技术交流· Windows系统中文件时间属性的变化及影响因素 滕冲1,方靖然2,张国臣3(1.中国人民公安大学,北京 3 ...

  9. 成功解决无法写入输出文件,此实现不是Windows平台FIPS验证加密算法的一部分

    成功解决无法写入输出文件,此实现不是Windows平台FIPS验证加密算法的一部分 目录 解决问题 解决方法 解决问题 无法写入输出文件,此实现不是Windows平台FIPS验证加密算法的一部分 解决 ...

最新文章

  1. 使用GitHub Pages搭建博客
  2. Android动态权限管理模型(4.3-6.0)
  3. 蓝宝石 470 原版 bios_想怎么玩就怎么玩!改造双BIOS显卡,不再为噪音和性能选择而烦恼...
  4. hdu2102(bfs)
  5. 催人泪下!一个程序员的悲惨故事
  6. 恐怖之城(深圳)系列1---K113大巴洗劫一空
  7. Day31 python基础--网络编程基础-socketserver
  8. Fastformer:史上最强最快Transformer!清华、MSRA出品!
  9. 一文快速掌握IPv6基础知识及使用指南
  10. 安卓(Android)+苹果(Ios)仿微信、陌陌 移动社交APP系统源码,手机IM聊天软件源码,企业即时通讯APP程序源码...
  11. 基于springboot+vue的商城/体育用品商城/衣服商城系统(前后端分离)
  12. [译] 在 Android 使用协程(part III) - 在实际工作中使用
  13. C语言程序设计(第五版)-谭浩强著-课后习题
  14. 超星尔雅移动图书馆账号密码
  15. linux qt编译器设置,Qt使用教程:添加编译器(一)
  16. 【转】框架(蔡学镛)
  17. Android开发中的图片压缩
  18. oracle解一元二次方程,第 6 章 浮点运算
  19. H3C无线ap基本配置套路
  20. 神经网络建模的建模步骤,人工神经网络建模过程

热门文章

  1. java语言采用16位颜色标准_华为Java笔试题一
  2. 苹果三星业绩比惨:iPhone营收降17%,三星手机运营利润降40%
  3. AI向程序员老司机学习:从眼神的变化中寻找bug
  4. 从RedHat到MongoDB,开源商业软件是如何占领世界的
  5. 马斯克又有新麻烦上身!前员工将他告到美国证监会,曝出一大堆惊天八卦
  6. 一头盔一电极,MIT机器人读心完毕
  7. 谷歌非洲AI中心成立,有坑,速来
  8. 毕啸南专栏 | 对话姚星:腾讯有后来居上的传统,我们的战略是全民AI
  9. 腾讯首发汽车解决方案 助力广汽打造新智能网联云平台
  10. 如何滚动更新 Service?- 每天5分钟玩转 Docker 容器技术(102)