澳门新葡亰网址下载Windows 文件过滤驱动经验总结

by admin on 2020年1月27日

Windows 文件过滤驱动资历总计
作者:ai3000

1.背景      在windows平台下,应用程序经常接纳API函数来扩充文件访问,创制,打开,读写文件。从kernel32的CreateFile/ReadFile/WriteFile函数,到本地系统服务,再到FileSystem及其FilterDriver,经验了重重档案的次序。在每种档次上,都存在着安全防护软件,病毒照旧后门作监视可能过滤的时机。作为安全付加物开荒者,大家要求比人家走得更远,因而大家要求四个底层的“windows平台内核级文件访谈”的方法来确认保证大家能够见到科学的到底的文件系统。 

正文转发自驱动开采网

2.用途      直接的基本品级文件访谈,在音讯安全领域内有大面积的用场。用于侵犯者的上面,能够让她绕过杀毒软件,IDS等安全保安种类的监视。用于检验者的上边,能够看出三个完完全全的体系,以此来查杀隐藏的后门大概rootkit。用于监察和控制者的方面,则足以领悟最新的绕过监察和控制的技能,能够依据来统筹更新的监督检查方案。 

看了 ChuKuangRen
的第二版《文件过滤驱动开采教程》后,颇负令人感动。笔者想,沟通都以创立在相近的底蕴上,在抱怨氛围和意况不佳的同期应该先想生机勃勃想本身到底付出了多少?只知索取不愿付出的人也就无须抱怨了,要怪也必须要怪本身。发本身经验的人仅仅是两种目的,一是抓住部分谈谈,好改进自个儿错误的认知,以便从当中得到越来越多的文化使和谐发展的越来越快。二是做风流倜傥份备忘,当本人忘记的时候能够立时找到相关材料。小编那边也总计了近几年做文件过滤驱动时所积存下去的有个别微小经历,那分笔记也是看了
ChuKuangRen
的课程后,有的时候想到的一小部分而已,是想到哪写到哪,不是很全,要是以往再纪念起怎么着也会不停补充。因其工作原因,近段时间在
SOLA奇骏IS 驱动与 Linux 内核方面投入的生气比很多,Windows
下的文件过滤驱动平素也并未有怎么去碰,所以最后依旧那句老话 FIXME。

3.一贯访谈FSD的根基品级文件访谈      FSD(FileSystemDriver卡塔尔国层是文本API函数经过本地系统服务层(native API卡塔尔(قطر‎最终达到的驱动等级次序。假设大家得以效仿操作系统,在大家相濡以沫的驱动程序里一向向FSD发送IRP,就足以绕过那个native API 和win32 API了,也就能够绕过设置在此些等级次序方面包车型地铁API钩子等监督措施。 

 1、获得文件全路径以致剖断时机

3.1文件的Create和Open      文件的Create和Open能够经过发送IRP_MJ_CREATE给FSD,也许调用IoCreateFile函数来成功。Create和Open的分别其实在于IoCreateFile/IRP_MJ_CREATE的一个参数Disposition的取值。使用IoCreateFile函数的样例代码: 

除在具备 IRP_MJ_XXX 在此之前自身起先创立 IRP
发送到下层设备查询全路线外,不要品味在 IRP_MJ_CREATE
以外的地点获得全路径,因为唯有在 IRP_MJ_CREATE
中才会动用 ObCreateObject(State of Qatar 来建设构造二个管用的 FILE_OBJECT。而在
IRP_READ IRP_W奔驰G级ITE 中它们是直接操作 FCB (File Control Block卡塔尔(قطر‎的。

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; 

 2、从头建设布局 IRP 发送关怀点

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,是 IRP_MJ_CREATE 也好依旧IRP_MJ_DIRECTORY_CONTROL也罢,最要升迁的就是后生可畏对表明。差异的标识会代来分歧的结果,有个别结果是直接重返战败。这里指的注明不光是
IRP->Flags,还要思考IO_STACK_LOCATION->Flags还恐怕有别的等等。特别是您要高达一些十分目标,那个时候更须求注意,如
IRP_MN_QUERY_DIRECTO途乐Y,不一致的标记结果有超级大的不等。

    通过发送IRP_MJ_CREATE给FSD的法子与此相像,能够参见IFSDDK document的IRP_MJ_CREATE表达。分裂于上面方法的是亟需和煦创办叁个FILE_OBJECT,好于地点方法的是这种措施无需二个HANDLE,HANDLE是线程信任的,FileObject则是线程非亲非故。

 3、从头构建 IRP 获取全路径注意点

3.2文件的Read和Write      我们经过给FSD发送IRP_MJ_READ来读取文件,给FSD发送IRP_MJ_W奥迪Q7ITE来改写文件。 
    要是大家是透过二个HANDLE来执行(如利用IoCreateFile打开的文书卡塔尔国,将在先用ObReferenceObjectByHandle函数来获取这一个Handle对应的FileObject。大家不能不给FileObject发送IRP。 

协调开班创建三个 IRP_MJ_QUERY_INFORMATION 的 IRP
获取全路径时要求小心,不仅仅在 IRP_MJ_CREATE 要做分裂管理,在
IRP_MJ_CLOSE 也要做相仿的管理,不然生龙活虎旦指标是 NTFS
文件系统的话大概产生 deadlock。借使是 NTFS 那么在 IRP_MJ_CLEANUP
的时候也急需对 FO_STREAM_FILE 类型的文件做相似管理。

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

 4、得到地点/远程访谈客商名(域名/SID)

    之后我们选用IoAllocateIrp分配叁个IRP。依据FileObject->DeviceObject->Flags的值,我们看清目的文件系统使用什么的IO形式。 

主意独有在 IRP_MJ_CREATE 中才可用,那是因为 IO_SECURITY_CONTEXT
只有在 IO_STACK_LOCATION->Parameters.Create.SecurityContext
才会立见功能。那样你才有异常的大希望从
IO_SECURITY_CONTEXT->SecurityContext->AccessState->SubjectSecurityContext.XXXToken
中得到访谈 TOKEN,进而进一层获取客商名或 SID。记得 IFS 中有贰个库,它的
LIB 导出二个函数可以令你在获得上述消息后拿到顾客名与域名。但假诺您想宽容NT4 的话,只可以和睦深入分析来得出本地和长间距的 SID。

    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 
    } 

 5、文件与目录的推断

    对每一种分歧的IO方式选拔差异的地点传递方式。随后大家填充IRP内的次第参数域,就足以发送IRP了。以Read为例: 

准确的格局在楚狂人的文档里早已说过了,再补充一句。借让你的文书过滤驱动要合作全部文件系统,那么毫不特别相信从
FileObject->FsContext 里获得的数量。正确的主意照旧在你传递下去
IRP_MJ_CREATE 后从最下层文件系统延设备栈再次回到到你这边后再得到。

    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; 

 6、加/解密中决断点

    接着要思索假设IRP不可能及时完毕,会异步的回来的意况,大家设置三个CompletionRoutine,在CompletionRoutine里面安装多少个平地风波为已激活,通告大家的主线程读取也许写入操作已经产生。 

只判断 IRP_PAGING_IO,IRP_SYNCHRONOUS_PAGING_IO,IRP_NOCACHE
是没错的。假使有毛病,相信是温馨的标题。关于有人涉嫌在
FILE_OBJECT->Flags中的 FO_NO_INTERMEDIATE_BUFFEENVISIONING
是还是不是须要看清,对此主题素材的对答是风流洒脱旦你认清了 IRP_NOCACHE 就不用再判别FILE_OBJECT 中的,因为它最后会安装 IRP->Flags 为
IRP_NOCACHE。关于您看到的比如 IRP_DEFER_IO_COMPLETION 等 IRP
不要去管它,因为它只是四个进程。最后读写依旧如上所介绍。至于以上那么些 IRP
哪个是由 CC MGTucson 发送的,哪些是由 I/O MGRAV4发送和在哪一天发送的,这一个已经有数不胜数探究了,相信能够找到。

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

 7、例如表达关于 IRP 传递与成就注意事项

NTSTATUS 
  IoCompletion( 
    IN PDEVICE_OBJECT  DeviceObject, 
    IN PIRP  Irp, 
    IN PVOID  Context 
    ) 

    KeSetEvent((PRKEVENT)Context, IO_DISK_INCREMENT, 0); 
    return STATUS_MORE_PROCESSING_REQUIRED; 

只看 Walter Oney 的那本 《Programming the Microsoft Windows driver
model》里介绍的流水生产线,自身不曾实际的咀嚼依然相当不够的,这里只介绍了底工概念,让和睦有了文化。知道怎么着用,在哪些状态下用,用哪一类方法,能够用的休保养息那叫有了本事。大家从另叁个角度出发,把标题分为两段来看,那样方便总括。一个IRP 在过滤驱动中,把它分成要求设置 CompleteRoutine 的与不供给安装
CompleteRoutine 的。那么在无需设置 CompleteRoutine
的有以下几类情状。

    今后得以发送IRP了。假若不应用特殊的点子以来,IRP发送对象是FileObject对应的DeviceObject。发送后,等待IRP的成就並且释放财富,重返。 

(1卡塔尔 得到这几个 IRP 后怎么都不做,直接调用 IoCompleteRequest(State of Qatar 来回到。
(2卡塔尔国 得到这些 IRP
后怎么样都不做,直接传送到底层设备,使用IoSkipCurrentIrpStackLocation(卡塔尔后调用 IoCallDriver(卡塔尔国 传递。
(3) 使用 IoBuildSynchronousFsdRequest() 或
IoBuildDeviceIoControlRequest()来建立 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;

如上两种依照须要一向动用就可以,除了有的参数与标记须要注意外,未有啥系统编写制定相关的事物须求小心了。那么再来看须求设置
CompleteRoutine 的意况。大家把这种情景再细分为三种,一是在
CompleteRoutine 中回到标记为STATUS_MORE_PROCESSING_REQUIRED
的意况。二是回随地那么些外的标识,必要动用函数IoMarkIrpPending(State of Qatar的意况。在 CompleteRoutine
中山大学部就疑似此三种景况,你供给使用此中的生龙活虎种状态。那么为啥要求安装
CompleteRoutine 呢?那是因为我们对其 IRP
从上层驱动,经过我们驱动,在通过底层设备栈再次来到到大家那意气风发层驱动时供给得到在那之中内容作为参谋依赖的,还应该有对中间内容要求展开改善的。再有少年老成种情状是从未经过上层驱动,而
IRP
的发生是在大家驱动直接下发到底层驱动,而透过设备栈后再次回到到大家那生龙活虎层,且大家不在希望它三回九转提升重临的,因为这一个IRP 本身就不是从上层来的。综上说述,先来看下 IoMarkIrpPending(State of Qatar的动静。

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

(1卡塔尔国 在 CompleteRoutine 中推断 Irp->PendingReturned 并利用
IoMarkIrpPending(卡塔尔(قطر‎然后回到。这种格局在未有选拔 KeSet伊芙nt(卡塔尔(قطر‎的情形下,且不是自行建造 IRP
发送到底层驱动再次来到时选择。也正是说有相当的大希望自个儿所做的工作都是在
CompleteRoutine
中开展的。举个例子加/解密时,笔者在这里对下层驱动重返数据的论断并订正。改过后因为未有利用
STATUS_MORE_PROCESSING_REQUIRED
标记,它会延设备堆从来向上重回并到客户取得数码截至。这里肯定要注意,在这里种情况下
CompleteRoutine重临后,不要在碰这么些 IRP。相当于说如果此时你选用了
IoCompleteRequest(卡塔尔国的话会并发五个 MULTIPLE_IRP_COMPLIETE_REQUEST 的
BSOD 错误。

    fdi.DeleteFile=TRUE; 

(2卡塔尔国 在 CompleteRoutine 中一贯回到 STATUS_MORE_PROCESSING_REQUIRED
标记。这种场地在行使了 KeSet伊夫nt(卡塔尔(قطر‎的函数下现身。这里又有八个小小的的比例。

    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;  

1卡塔尔(قطر‎ 现身于上层发送到作者那边,当自家那边运用 IoCallDriver(State of Qatar后,底层再次来到数据经过作者那后生可畏层时,作者想让它临时告朝气蓬勃段落继续发展传递,让那几个 IRP
微微暂息一会,等自己对这一个 IRP 重返的数量操作实现后(平日是绝非在
CompleteRoutine中对回到数据实行操作景况下,约等于说等到成功例程再次回到后再张开操作),由自个儿来调用
IoCompleteRequest(卡塔尔国让它延着设备栈继续回来。这里要专一,我们是想让它回到的,所以调用了
IoCompleteRequest(卡塔尔(قطر‎。那么些可不一样于下边所讲的友好在此以前分配 IRP 时在
CompleteRoutine 中早就调用 IoFreeIrp(卡塔尔(قطر‎ 释放了当前IRP
的动静。比方笔者在做一个转移文件大小,向文件头写入加密标识的驱动时,在上层发来了
IRP_MJ_QUERY_INFORMATION
查询文件,作者想在这里个时候拿到文件音讯进行判定,然后根据本身的论断结果再移动文件指针。注意:上边是两步,第一步是先获得文件大小,那么在此个时候自身就须要选用上述措施,先让这些IRP传递下去,得到本身想要的事物后在张开对照。等待合适合时宜机完毕这么些IRP,让多少继续传递,直到顾客选拔结束。第二步我会结合下边小节来说。

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

2卡塔尔 现身于本人开端创设 IRP,当使用 IoAllocate(卡塔尔 或
IoBuildAsynchronousFsdRequest(卡塔尔国创立 IRP 调用 IoCallDriver(卡塔尔国后,底层再次来到数据到小编那生龙活虎层时,作者不想让那一个 IRP
继续提升延设备栈传递。因为这一个 IRP
便是在自己那档期的顺序创立的,上层本就不知情有这么三个 IRP。那么到这里本身就要在
CompleteRoutine 中运用 IoFreeIrp(卡塔尔国来刑满释放解除劳教掉这么些IRP,并不让它继续传递。这里料定要注意,在
CompleteRoutine函数再次回到后,这些 IRP
已经释放了,假使那时在有别的有关那几个 IRP
的操作那么结果是惨无人理的,必定引致 BSOD 错误。后面 1)小节交由的例证只完毕了第一步这里继续讲第二步,第一步笔者援引这一个 IRP
获得了文件大小,那么此时就算知情大小,但小编照旧无法明白这几个文件是不是被小编加过密。这时候,作者就须求在此边和煦开班建设构造四个IRP_MJ_READ 的 IRP
来读取文件来判别是不是自己加密过了的文书,若是是,则要减少相应的抑扬顿挫,然后继续回到。注意:这里的回到是指让第一步的IRP
重返。实际不是我们相濡相呴创立的。我们创造的都早就在CompleteRoutine
中销毁了。

    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.  

 8、关于达成 IRP 的动作简要介绍

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

当二个尾部驱动调用了 IoCompleteRequest(State of Qatar 函数时,基本上全体设施栈相关
IRP 处监护人业都是在它这里达成的。包含 IRP->Flags 的风流倜傥对标注的剖断,对
APC 的管理,抛出MULTIPLE_IRP_COMPLETE_REQUESTS
错误等。当它延设备栈一贯调用驱动所设置的 CompleteRoutine时,假若开掘STATUS_MORE_PROCESSING_REQUIRED
那一个标记,则会甘休前行继续回滚。那也是为何在 CompleteRoutine
中利用这些标识就能够暂停 IRP 的由来。

    综上,于是大家得以在驱动里面通过发送IRP来直接待上访谈文件系统了,绕过了native API 和win32 API等级次序。 

 9、关于 ObQueryNameString 的使用

4.绕过文件系统过滤驱动和钩子 
    有了第三某些的剧情,大家当前能够直接给FSD发送央求操作文件。可是那还非常不够,因为有无数的杀毒软件或许监视工具使用FSD Filter Driver恐怕FSD Hook的主意来监督文件操作。在明天那篇小说里自身讲一些原理性的东西,提供绕过FSD Filter Driver / FSD Hook的思绪。 

其黄金时代函数的运用,在有个别条件下会有标题。它的上层函数是
ZwQueryObject(卡塔尔(قطر‎。在有些情形下会招致系统挂起,或许直接 BSOD。它是从
对象微型机中的 ObpRootDirectoryObject起首遍历,通过
OBJECT_HEADER_TO_NAME_INFO 拿到对象名称。今楚辞了下
PolyMeta好象是在管理 PIPE 时会挂启,这些难题出未来 二〇〇三 系统。在 XP
上好象补丁了。

4.1应付文件系统过滤驱动 
    文件系统过滤驱动Attach在平常的文件系统之上,监视和过滤大家的文件访谈。文件系统驱动栈正是由那生机勃勃类别的Attach起来的过滤驱动组成。我们可以用IoGetRelatedDeviceObject那一个函数来收获一个FileObject对应的最尾部的充足功用驱动对象(FDO卡塔尔国。但是这么即使绕过了这几个过滤驱动,却还要也绕过了正规的FSD如Ntfs/法斯特fat,因为健康的FSD也是作为一个过滤驱动存在的。磁盘文件对象的照管的最底部的FDO是Ftdisk.sys,它已经因为过分底层而不能够管理大家投递的IRP央浼。 
    其实平常的FSD音讯存款和储蓄在四个Vpb构造中,大家能够动用IoGetBaseFileSystemDeviceObject这一个未公开的内核函数来获得它。它正是大家发送IRP的靶子了。 

 10、关于重入难点

4.2应付替换DispatchRoutine的FSD Hook 
    那是大器晚成种常用的FSD Hook格局。大家要求获得原来的DispatchRoutine,向原来的DispatchRoutine发送大家的IRP。这里提供叁个思路:我们能够读取原来FSD驱动的.INIT段或许.TEXT段,查找其DriverEntry函数,在它的DriverEntry函数中必然设置了友好的DriverObject的次第DispatchRoutine。在这里个函数中大家就能够找到大家想要的DispatchRoutine之处。只必要运用特征码搜索的不二诀窍就能够找出到这么些值。 

实际上那些标题在比较久前的 IFS FAQ
里曾经介绍的很掌握,富含管理措施以致每个格局可能带给的主题素材。IFS FAQ 里的
Q34 生龙活虎共介绍了多种办法,富含自个儿开班创建 IRP发送,使用
ShadowDevice,使用特征字符串,依据线程 ID,在 XP
下选取IoCreateFileSpecifyDeviceObjectHint(卡塔尔(قطر‎函数。何况把以上三种在区别条件下利用要管理的主题材料也做了简约的介绍。且在
Q33 里介绍了在 CIFS 遇到的 FILE_COMPLETE_IF_OPLOCKED 难题的消除方法。

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地图