Windows平台内核级文件访问

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监视或篡改了。

http://www.cnblogs.com/lzjsky/archive/2010/11/19/1881599.html

时间: 2024-12-28 08:44:24

Windows平台内核级文件访问的相关文章

cocos3.9 windows平台 AssetsManager创建文件失败问题

在做热更新功能时用到了AssetsManager,发现在windows平台总是报CREATE_FILE错误,errorStr "Can't renamefile from: xxx.tmp to: C:/Users/Administrator/AppData/Local/xxx",最后发现创建下载任务时第二个参数传错了,传的是_storagePath,应该是_downloader->createDownloadFileTask(_packageUrl, outFileName);

windows平台mysql -zip文件包安装方法

Android基础--文件访问权限

1.Android 底层是Linux内核,因此文件访问权限与Linux中文件访问权限类似 d   rwx   rwx   rwx 文件类型 owner group other 文件类型   d 代表文件夹,-代表文件,l 代表链接 owner文件创建的用户 group 与文件创建者在同一组的其他用户 other 与文件创建者不在同一组的其他用户 Android中每一个应用都对应独立的用户,不同应用所在组是不同的,可以通过设置是两个应用在同一个组中   2.以下是在当前应用的私有空间内创建文件时指

转移終止支援Windows 平台的经验分享

MicrosoftWindows Server 2003将于今年7月终止支持,很多企业为避免遭受漏洞攻击,正努力转移到新的平台工作.然而对于许多企业来说,基于人力.财力及其他因素,要在时限之内完成转移是一项特别艰巨的挑战. 在趋势科技协助客户转移的过程当中,我们也看到客户对于近期终止支持一事的独到见解,因此特别和大家分享(当然,若客户在7月14日之前尚未准备好转移,我们也能协助他们保护Windows Server 2003,而且还能保护Windows Server2012与 Azure等新的 W

windows平台是上的sublime编辑远程linux平台上的文件

sublime是个跨平台的强大的代码编辑工具,不多说. 想使用sublime完成linux平台下django站点的代码编辑工作以提高效率(原来使用linux下的vim效率较低,适合编辑一些小脚本). 下载linux平台下的Sublime_Text_2.0.2_x64.tar.bz2(http://www.sublimetext.com/) 解压使用: tar -xjvf Sublime_Text_2.0.2_x64.tar.bz2 cd Sublime\ Text\ 2/ 执行 ./sublim

linux内核编程入门--系统调用监控文件访问

参考的资料: hello world   https://www.cnblogs.com/bitor/p/9608725.html linux内核监控模块——系统调用的截获  https://www.cnblogs.com/lxw315/p/4773566.html 实现: 实验目的: 内核模块的编写:完成一个Linux/Windows内核/驱动模块的编写, 能够实现对文件访问的监控.或者对键盘设备.USB设备.网络设备. 蓝牙设备等的监控. 实验内容: 通过linux内核模块编程,写一个模块使

Windows平台快速的创建一个指定大小的文件

有时,我们需要快速创建一个指定大小的文件,做系统测试使用,我们指定在Linux平台中可以使用如下命令: 创建一个100M的空文件 dd if=/dev/zero of=hello.txt bs=100M count=1 在windows平台同样可以使用下列命令快速创建一个指定大小的文件: fsutil file createnew <filename> <length> C:\>fsutil file createnew用法 : fsutil file createnew &

Cocos2d-x--iOS平台lua加密成luac资源方法和Jsc文件&lt;MAC平台开发试用--windows平台暂未研究&gt;

    首先要说,最近真的是太忙了,好久没写博客了,今天正好有空,就写一下最近在写游戏中的一些发现: 话说,基于Cocos2dx 引擎 + 脚本写游戏,至今的感触就是可以进行增量更新和即时编译等,节省了很多时间:好了废话不多说了,进入正题: 这里我是以Cocos2d-x-2.2.2 为例<其实,写着文章时候Cocos2d-x-3.2 都封版了>: 今天我就说一下怎么用Cocos2d-x3.2中的cocos-console 去 批量 加密lua脚本-变成luac文件 ,js文件变成jsc加密文

Windows平台上安装LaTex工具以及LaTex常见的文件类型汇总

LaTex广泛用于学术报告.paper.学术PPT的撰写和制作,熟练掌握LaTex是在学术界生存的必备基本技能之一.本文简要介绍了在Windows平台上安装LaTex工具的基本方法和流程以及LaTeX常见的文件类型. 1.下载MiKTeX,下载地址为:http://miktex.org/download.MiKTeX的正确读音为/'mik'tek/. 2.安装MikTeX.安装完毕后,在开始菜单会出现"Previewer"和"TeXworks"程序图标.Previe