`
dato0123
  • 浏览: 936231 次
文章分类
社区版块
存档分类
最新评论

【转】Windows平台内核级文件访问

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

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

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

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

HANDLEopenfile(WCHAR*name,ACCESS_MASKaccess,ULONGshare)
{
//return0forerror.
HANDLEhfile;
IO_STATUS_BLOCKiosb;
intstat;
OBJECT_ATTRIBUTESoba;
UNICODE_STRINGnameus;
/**////
if(KeGetCurrentIrql()>PASSIVE_LEVEL){return0;}
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)){return0;}
returnhfile;
}


HANDLEcreatenewfile(WCHAR
*name,ACCESS_MASKaccess,ULONGshare)
{
//return0forerror.
HANDLEhfile;
IO_STATUS_BLOCKiosb;
intstat;
OBJECT_ATTRIBUTESoba;
UNICODE_STRINGnameus;
/**////
if(KeGetCurrentIrql()>PASSIVE_LEVEL){return0;}
RtlInitUnicodeString(
&nameus,name);
InitializeObjectAttributes(
&oba,&nameus,OBJ_KERNEL_HANDLE|OBJ_CASE_INSENSITIVE,0,0);
stat
=IoCreateFile(&hfile,access,&oba,&iosb,0,//AllocationSizethissetto0thatwhenfileopeneditwaszeroed.
FILE_ATTRIBUTE_NORMAL,share,FILE_OVERWRITE_IF,0,0,0,0,0,0);
if(!NT_SUCCESS(stat)){return0;}
returnhfile;
}

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

3.2
文件的ReadWrite
我们通过给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;//bufferedio
}

elseif(fileob->DeviceObject->Flags&DO_DIRECT_IO)
{
mdl
=IoAllocateMdl(buffer,count,0,0,0);
MmBuildMdlForNonPagedPool(mdl);
irp
->MdlAddress=mdl;//directio
}

else
{
irp
->UserBuffer=buffer;//neitheri/o,usekernelbuffer
}

对每种不同的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(
INPDEVICE_OBJECTDeviceObject,
INPIRPIrp,
INPVOIDContext
)
{
KeSetEvent((PRKEVENT)Context,IO_DISK_INCREMENT,
0);
returnSTATUS_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);}//ifDO_DIRECT_IO
return-1;
}

stat
=irp->IoStatus.Information;//bytesread
IoFreeIrp(irp);
if(mdl){IoFreeMdl(mdl);}//ifDO_DIRECT_IO
returnstat;
3.3文件的Delete
Delete
实际上是通过向FSD发送IRP_MJ_SET_INFORMATIONIRP,并把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
类似于DeleteRename是向FSD发送IRP_MJ_SET_INFORMATIONIRP,把IrpSp->Parameters.SetFile.FileInformationClass设置为FileRenameInformation,填充bufferFILE_RENAME_INFORMATION结构。

fri.ReplaceIfExists=TRUE;
fri.RootDirectory
=0;//Setfri.FileNametofullpathname.
fri.FileNameLength=wcslen(filename)*2;
wcscpy(fri.FileName,filename);
//IftheRootDirectorymemberisNULL,andthefileisbeingmovedtoadifferentdirectory,thismemberspecifiesthefullpathnametobeassignedtothefile.

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)。但是这样虽然绕过了那些过滤驱动,却同时也绕过了正常的FSDNtfs/Fastfat,因为正常的FSD也是作为一个过滤驱动存在的。磁盘文件对象的对应的最底层的FDOFtdisk.sys,它已经因为过于底层而不能处理我们投递的IRP请求。
其实正常的FSD信息存储在一个Vpb结构中,我们可以使用IoGetBaseFileSystemDeviceObject这个未公开的内核函数来得到它。它就是我们发送IRP的目标了。

4.2
对付替换DispatchRoutineFSD 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监视或篡改了。<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

分享到:
评论

相关推荐

    Windows内核 Windows内核

    HAL是Windows内核与硬件交互的关键,它隐藏了不同硬件平台的差异,使得操作系统能在多种硬件上运行。HAL负责初始化硬件、管理中断、设备驱动交互等工作。 5. **设备驱动程序** 设备驱动程序是Windows内核与硬件...

    windows XP系统内核文件分析(全)

    《Windows XP系统内核文件分析全解析》 Windows XP系统内核文件是操作系统的核心组成部分,它们负责管理系统的硬件资源、进程调度、内存分配以及驱动程序的加载等关键任务。深入理解系统内核文件有助于优化系统性能...

    windows内核 自创建IRP访问文件加非递归遍历文件

    在Windows操作系统中,内核是系统的核心部分,负责管理和调度系统资源,包括处理硬件中断、管理内存、调度进程以及...通过深入理解IRP机制和非递归遍历,开发者可以在Windows内核级别实现更高效、更安全的文件操作。

    ring0驱动内核级的ROOTKIT实现隐藏文件,隐藏注册表项,隐藏端口.zip

    在Windows系统中,Rootkit可以修改文件系统驱动,使恶意文件在文件管理器中不可见,同时避开文件系统的遍历和扫描。对于注册表项,Rootkit可以利用内核级别的钩子,改变注册表查询的返回结果,使得恶意注册表键不被...

    寒江独钓《Windows内核安全编程》

    编写Windows内核程序,就意味着这个程序可以执行任意指令,可以访问计算机所有的软件、硬件资源。因此,稍有不慎就有可能将系统变得不稳定。Windows的设计者设计了各种驱动模型或者框架,如NT式内核驱动模型、WDM...

    WindowsNT内核下文件系统过滤驱动程序开发

    开发文件系统过滤驱动程序时,开发者需要具备扎实的Windows内核和驱动开发知识,因为不正确的操作可能会导致系统崩溃(蓝屏)或安全漏洞。开发者还需要了解硬件平台、中断处理、同步机制以及调试技术等高级主题。 ...

    Windows内核设计思想 光盘源代码

    10. **文件系统**:Windows内核支持多种文件系统,如NTFS、FAT等,它们管理着文件的创建、读写和删除操作,并维护文件元数据。 11. **网络堆栈**:Windows内核包含了TCP/IP协议栈,负责网络数据包的封装、解封装和...

    Windows内核设计思想 完整版 .pdf

    - **文件缓存机制**:利用文件缓存机制来提高文件访问速度,减少磁盘I/O操作。 - **文件权限管理**:通过文件权限设置和用户组管理等功能,确保数据的安全性和完整性。 ### 结论 通过对Windows内核设计思想的深入...

    Windows 内核设计思想

    Windows内核提供了丰富的调试组件和接口,以协助开发者进行系统级的调试工作。这些调试组件包括但不限于内存转储、异常处理、性能分析等功能。 4. 结构化异常处理(SEH) 结构化异常处理(SEH)是Windows内核用于...

    windows xp内核重载

    `KernelDebug.cpp` 和 `KernelDebug.h` 是两个常见的源代码文件,它们很可能包含了用于内核级调试的代码和相关头文件。在Windows XP中,内核调试是一个强大的工具,它允许开发者直接查看和控制操作系统内核的行为,...

    Windows内核原理与实现.PDF

    ### Windows内核原理与实现 #### 一、书籍概述 《Windows内核原理与实现》是潘爱民大师的一部力作,该书深入浅出地解析了Windows操作系统的核心技术,帮助读者理解Windows内核的工作机制。作者通过结合实际的...

    Windows内核的分析

    7. **文件系统**:Windows内核支持多种文件系统,如NTFS、FAT32等。文件系统负责数据的持久化存储,提供文件的创建、读写、删除等操作。 8. **网络堆栈**:Windows内核包含网络协议栈,实现了TCP/IP协议,支持网络...

    windows kernel 内核的一些英文版本

    Windows内核采用了基于访问控制列表(ACL)的安全模型,为每个对象(如文件、进程、线程)设置权限。它还实现了强制完整性控制(Mandatory Integrity Control, MIC),以防止恶意代码篡改关键系统组件。 通过对以上...

    Windows内核安全与驱动开发光盘源码

    总之,Windows内核安全与驱动开发是一门深奥且实践性强的技术,结合源码学习,可以加深对操作系统底层原理的理解,提高系统级编程技能。通过深入研究,你将能够创建更高效、更安全的驱动程序,为Windows平台的稳定性...

    内核级后门Rootkit技术

    接着,让我们探讨Windows内核级后门Rootkit的常见技术。其中一种是驱动级Rootkit,它们通过编写恶意驱动程序,将自身注入到内核模式,从而能够控制系统的所有资源。这些驱动程序可能会替换系统关键函数,使安全软件...

    windows内核研究(部分微软内部资料)

    7. **文件系统**:Windows内核支持多种文件系统,如NTFS、FAT等。资料可能讲解文件系统的结构、元数据管理、文件操作流程等。 8. **系统调用**:系统调用是用户程序与内核通信的主要途径,包括创建进程、读写文件、...

    WindowsNT.rar_Windows内核_windows 内核_windows内核代码

    5. **安全性**:Windows NT内核引入了访问控制列表(ACL)和安全标识符(SID),以实现细粒度的权限管理和身份验证,保障系统安全。 6. **文件系统**:内核支持多种文件系统,如NTFS、FAT等,提供文件的创建、读写...

    Windows内核安全编程

    - Windows内核采用微内核架构,将一些服务如网络和文件系统移到用户空间,提高了系统的稳定性和安全性。 2. **内核模式与用户模式** - Windows操作系统分为内核模式和用户模式。内核模式拥有最高的权限,可以直接...

    windows内核实验教程

    7. **安全与权限**:Windows内核提供了访问控制机制,确保系统的安全性和稳定性。实验可能涵盖权限验证、令牌管理、权限提升等相关内容。 8. **并发与同步**:理解Windows内核中的同步原语,如事件对象、信号量、...

    Windows内核安全与驱动开发 随书源码.rar

    随书源码rar文件提供了书中所讲解的各种实例代码,是学习和理解Windows内核安全以及驱动编程的重要辅助资源。这里我们将围绕这些关键概念进行详细阐述。 Windows内核是操作系统的核心部分,它负责管理系统的硬件...

Global site tag (gtag.js) - Google Analytics