编写驱动拦截NT的API实现隐藏文件目录

目前NT下有很多种隐藏文件和目录的方法,其中最简单的一种是给文件和文件夹加上系统属性和隐藏属性,操作系统就会不在显示了,而且查找也找不到了,但是这种方法一点都不彻底,没有可用性!下面我们来介绍用NT驱动程序来拦截NTAPI来实现彻底隐藏文件和目录的目的。NT下有一个文件NTDLL.DLL,大部分NTAPI都是在这个库中封装的。其中实现查找文件和目录的API接口是ZwQueryDirectoryFile,所以我们只要拦截这个API的话,文件和目录就可以完全隐藏了!下面来一步不实现(准备工作:到NTDDK中找一个WDM驱动程序模型,也就是最简单的驱动程序了):  
   
            1.定义FILE_INFORMATION_CLASS的第3号结构:_FILE_BOTH_DIR_INFORMATION,这个结构是ZwQueryDirectoryFile必须参数。  
   
  typedef   struct   _FILE_BOTH_DIR_INFORMATION   {  
          ULONG                       NextEntryOffset;  
          ULONG                       FileIndex;  
          LARGE_INTEGER       CreationTime;  
          LARGE_INTEGER       LastAccessTime;  
          LARGE_INTEGER       LastWriteTime;  
          LARGE_INTEGER       ChangeTime;  
          LARGE_INTEGER       EndOfFile;  
          LARGE_INTEGER       AllocationSize;  
          ULONG                       FileAttributes;  
          ULONG                       FileNameLength;  
          ULONG                       EaSize;  
          CCHAR                       ShortNameLength;  
          WCHAR                       ShortName[12];  
          WCHAR                       FileName[1];  
  }   FILE_BOTH_DIR_INFORMATION,   *PFILE_BOTH_DIR_INFORMATION;  
   
     
   
  2.先申明ZwQueryDirectoryFile,然后定义ZwQueryDirectoryFile的原型:  
   
  extern   NTSYSAPI   NTSTATUS   NTAPI   ZwQueryDirectoryFile(  
                            IN   HANDLE   hFile,  
                            IN   HANDLE   hEvent   OPTIONAL,  
                            IN   PIO_APC_ROUTINE   IoApcRoutine   OPTIONAL,  
                            IN   PVOID   IoApcContext   OPTIONAL,  
                            OUT   PIO_STATUS_BLOCK   pIoStatusBlock,  
                            OUT   PVOID   FileInformationBuffer,  
                            IN   ULONG   FileInformationBufferLength,  
                            IN   FILE_INFORMATION_CLASS   FileInfoClass,  
                            IN   BOOLEAN   bReturnOnlyOneEntry,  
                            IN   PUNICODE_STRING   PathMask   OPTIONAL,  
                            IN   BOOLEAN   bRestartQuery);  
   
  //定义ZwQueryDirectoryFile的原型  
   
  typedef   NTSTATUS   (*REALZWQUERYDIRECTORYFILE)(IN   HANDLE   hFile,  
                          IN   HANDLE   hEvent   OPTIONAL,  
                          IN   PIO_APC_ROUTINE   IoApcRoutine   OPTIONAL,  
                          IN   PVOID   IoApcContext   OPTIONAL,  
                          OUT   PIO_STATUS_BLOCK   pIoStatusBlock,  
                          OUT   PVOID   FileInformationBuffer,  
                          IN   ULONG   FileInformationBufferLength,  
                          IN   FILE_INFORMATION_CLASS   FileInfoClass,  
                          IN   BOOLEAN   bReturnOnlyOneEntry,  
                          IN   PUNICODE_STRING   PathMask   OPTIONAL,  
                          IN   BOOLEAN   bRestartQuery);  
   
  //定义一个原函数指针  
  REALZWQUERYSYSTEMINFORMATION   RealZwQuerySystemInformation;  
   
  3.定义替换API函数的原型:  
   
  NTSTATUS   HookZwQueryDirectoryFile(    
                      IN   HANDLE   hFile,  
                      IN   HANDLE   hEvent   OPTIONAL,  
                      IN   PIO_APC_ROUTINE   IoApcRoutine   OPTIONAL,  
                      IN   PVOID   IoApcContext   OPTIONAL,  
                      OUT   PIO_STATUS_BLOCK   pIoStatusBlock,  
                      OUT   PVOID   FileInformationBuffer,  
                      IN   ULONG   FileInformationBufferLength,  
                      IN   FILE_INFORMATION_CLASS   FileInfoClass,  
                      IN   BOOLEAN   bReturnOnlyOneEntry,  
                      IN   PUNICODE_STRING   PathMask   OPTIONAL,  
                      IN   BOOLEAN   bRestartQuery);  
   
  4.在DriverEntry(驱动入口)函数中加入如下申明:  
   
  //保存真正的ZwQueryDirectoryFile函数地址  
   
  RealZwQueryDirectoryFile=(REALZWQUERYDIRECTORYFILE)(SYSTEMSERVICE(ZwQueryDirectoryFile));  
   
  //把自定义的替换函数指针指向真正的ZwQueryDirectoryFile函数  
   
  (REALZWQUERYDIRECTORYFILE)(SYSTEMSERVICE(ZwQueryDirectoryFile))=HookZwQueryDirectoryFile;  
   
  5.在DriverUnload(驱动卸载函数)函数中加入恢复代码:  
   
  //恢复原来的函数指针  
   
  (REALZWQUERYDIRECTORYFILE)(SYSTEMSERVICE(ZwQueryDirectoryFile))=RealZwQueryDirectoryFile;  
   
  6.现在准备工作做好了,函数指针都已经设置转向了,剩下的是实现这个我们自定义的替换函数HookZwQueryDirectoryFile,代码如下:  
   
  NTSTATUS   HookZwQueryDirectoryFile(  
          IN   HANDLE   hFile,  
          IN   HANDLE   hEvent   OPTIONAL,  
          IN   PIO_APC_ROUTINE   IoApcRoutine   OPTIONAL,  
          IN   PVOID   IoApcContext   OPTIONAL,  
          OUT   PIO_STATUS_BLOCK   pIoStatusBlock,  
          OUT   PVOID   FileInformationBuffer,  
          IN   ULONG   FileInformationBufferLength,  
          IN   FILE_INFORMATION_CLASS   FileInfoClass,  
          IN   BOOLEAN   bReturnOnlyOneEntry,  
          IN   PUNICODE_STRING   PathMask   OPTIONAL,  
          IN   BOOLEAN   bRestartQuery)  
  {  
    NTSTATUS   rc;  
    ULONG   CR0VALUE;  
     
    ANSI_STRING   ansiFileName,ansiDirName,HideDirFile;  
    UNICODE_STRING   uniFileName;  
     
    //初始化要过虑的文件名这里是debug.exe  
    RtlInitAnsiString(&HideDirFile,"DBGVIEW.EXE");    
     
    //   执行真正的ZwQueryDirectoryFile函数  
    rc   =   ((REALZWQUERYDIRECTORYFILE)(RealZwQueryDirectoryFile))(  
      hFile,    
      hEvent,  
      IoApcRoutine,  
      IoApcContext,  
      pIoStatusBlock,  
      FileInformationBuffer,  
      FileInformationBufferLength,  
      FileInfoClass,  
      bReturnOnlyOneEntry,  
      PathMask,  
      bRestartQuery);  
        /*如果执行成功(而且FILE_INFORMATION_CLASS的值为FileBothDirectoryInformation,我们就进行处理,过滤*/  
          if(NT_SUCCESS(rc)&&   (FileInfoClass   ==   FileBothDirectoryInformation))  
    {  
      PFILE_BOTH_DIR_INFORMATION   pFileInfo;  
      PFILE_BOTH_DIR_INFORMATION   pLastFileInfo;  
      BOOL   bLastOne;  
      //把执行结果赋给pFileInfo    
      pFileInfo   =   (PFILE_BOTH_DIR_INFORMATION)FileInformationBuffer;    
      pLastFileInfo   =   NULL;  
      //循环检查  
      do  
      {  
        bLastOne   =   !(   pFileInfo->NextEntryOffset   );  
        RtlInitUnicodeString(&uniFileName,pFileInfo->FileName);  
        RtlUnicodeStringToAnsiString(&ansiFileName,&uniFileName,TRUE);  
        RtlUnicodeStringToAnsiString(&ansiDirName,&uniFileName,TRUE);  
        RtlUpperString(&ansiFileName,&ansiDirName);  
        //打印结果,用debugview可以查看打印结果  
        DbgPrint("ansiFileName   :%s/n",ansiFileName.Buffer);  
        DbgPrint("HideDirFile   :%s/n",HideDirFile.Buffer);  
         
        //   开始进行比较,如果找到了就隐藏这个文件或者目录  
        if(   RtlCompareMemory(ansiFileName.Buffer,HideDirFile.Buffer,HideDirFile.Length   )   ==   HideDirFile.Length)  
        {  
          DbgPrint("This   is   HideDirFile!/n");  
          if(bLastOne)    
          {  
            if(pFileInfo   ==   (PFILE_BOTH_DIR_INFORMATION)FileInformationBuffer   )  
            {  
              rc   =   0x80000006;   //隐藏文件或者目录;  
            }  
            else  
            {  
              pLastFileInfo->NextEntryOffset   =   0;  
            }  
            break;  
          }    
          else   //指针往后移动  
          {  
            int   iPos   =   ((ULONG)pFileInfo)   -   (ULONG)FileInformationBuffer;  
            int   iLeft   =   (DWORD)FileInformationBufferLength   -   iPos   -   pFileInfo->NextEntryOffset;  
            RtlCopyMemory(   (PVOID)pFileInfo,   (PVOID)(   (char   *)pFileInfo   +   pFileInfo->NextEntryOffset   ),   (DWORD)iLeft   );  
            continue;  
          }  
        }  
        pLastFileInfo   =   pFileInfo;  
        pFileInfo   =   (PFILE_BOTH_DIR_INFORMATION)((char   *)pFileInfo   +   pFileInfo->NextEntryOffset);  
         
      }while(!bLastOne);  
      RtlFreeAnsiString(&ansiDirName);    
      RtlFreeAnsiString(&ansiFileName);  
    }  
    return(rc);  
  }  
   
  本代码在开发机器(WINXP+SP1+XPDDK)上测试通过!  

 

从楼主提到的这点可以分析出来,那个程序确实采用了HOOK   API的方法,挂接了ZwQueryDirectoryFile  
  之类的列举文件目录的API,如我上面提到的方法,对特定的目录进行保护,如果目录名是你需要保护的目录名,则直接return   true;如果不是,则正常调用。  
  这种方法的缺点,就是对CMD模式下的dir命令无效,因为dir命令没有调用该API,所以能看到,但是在桌面环境下看不见受保护的文件目录。

 

问题解决了!  
  在注册表键HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows/CurrentVersion/Explorer/Advanced/Folder/Hidden下有两个子键:HIDDEN、SHOWALL,分别代表文件夹选项——查看对话框中的“不显示隐藏的文件和文件夹”和“显示所有的文件和文件夹”。你也可以自己创建类似的子键,也会在对话框中添加子定义的Radio按钮(不过就没有相对应的功能哦)。每个键下有键值名CheckedValue,正常情况下对应键值  
  1(显示所有的文件和文件夹)、2(不显示隐藏的文件和文件夹)。也就是说当你选中了相应的Radio后,会将控制值1或2送到相关的处理程序。例如:  
  somefunc()  
  {  
  swtich(type)  
  {  
  case   1:  
          ShowAll();  
          break  
  case   2:  
  default:  
          Hide();  
  }  
  }  
  “文件夹保密专家”一类的程序将SHOWALL的CheckedValue改为0或其他数值,这样,当控制值被送到处理程序时,没有相应的处理程序,则系统不会将隐藏的文件显示出来,所以下一次打开该对话框时,系统获得的数据仍然是文件的隐藏状态,使Radio总是指向“不显示隐藏文件和文件夹”了。:)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值