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