天天看點

【】編寫驅動攔截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);

    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)上測試通過!

繼續閱讀