hook NtQueryDirectoryFile实现文件隐藏
一、NtQueryDirectoryFile函数功能(NT系列函数)
NtQueryDirectoryFile函数:在一个给定的文件句柄,该函数返回该文件句柄指定目录下的不同文件的各种信息。
根据传入的文件句柄参数fileHandle,返回句柄所表示的目录中的不同文件的信息。
NTSTATUS ZwQueryDirectoryFile( _In_ HANDLE FileHandle, _In_opt_ HANDLE Event, _In_opt_ PIO_APC_ROUTINE ApcRoutine, _In_opt_ PVOID ApcContext, _Out_ PIO_STATUS_BLOCK IoStatusBlock, _Out_ PVOID FileInformation, _In_ ULONG Length, _In_ FILE_INFORMATION_CLASS FileInformationClass, _In_ BOOLEAN ReturnSingleEntry, _In_opt_ PUNICODE_STRING FileName, _In_ BOOLEAN RestartScan );
下面就简单说几个重要的参数:
1.FileHandle [in]文件句柄
ZwCreateFile或者ZwOpenFile返回的句柄。
A handle returned by ZwCreateFile or ZwOpenFile for the file object that represents the directory for which information is being requested. The file object must have been opened for asynchronous I/O if the caller specifies a non-NULL value for Event or ApcRoutine.
7.FileInformation [out]
FileInformation是一个指向一个缓冲区的指针。该缓冲区存储关于文件的信息。信息的结构由FileInformationClassparameter定义。就由最后一个参数FileInformationClass决定。所以要先判断这个参数的值是什么呀。
A pointer to a buffer that receives the desired information about the file. The structure of the information returned in the buffer is defined by the FileInformationClassparameter.
8.Length [in] 长度,代表缓冲区的size,以字节大小记录。
The size, in bytes, of the buffer pointed to by FileInformation. The caller should set this parameter according to the given FileInformationClass.
9.FileInformationClass [in]文件信息类
返回的关于在一个目录中的文件的信息类型。它的取值是下表中的一个。
The type of information to be returned about files in the directory. One of the following.
Value | Meaning |
---|---|
FileBothDirectoryInformation |
Return a FILE_BOTH_DIR_INFORMATION structure for each file. |
FileDirectoryInformation |
Return a FILE_DIRECTORY_INFORMATION structure for each file. |
FileFullDirectoryInformation |
Return a FILE_FULL_DIR_INFORMATION structure for each file. |
FileIdBothDirectoryInformation |
Return a FILE_ID_BOTH_DIR_INFORMATION structure for each file. |
FileIdFullDirectoryInformation |
Return a FILE_ID_FULL_DIR_INFORMATION structure for each file. |
FileNamesInformation |
Return a FILE_NAMES_INFORMATION structure for each file. |
FileObjectIdInformation |
Return a FILE_OBJECTID_INFORMATION structure for each file. This information class is valid only for NTFS volumes on Windows 2000 and later versions of Windows. |
FileReparsePointInformation |
Return a single FILE_REPARSE_POINT_INFORMATION structure for the directory. |
ReturnSingleEntry [in]
Set to TRUE if only a single entry should be returned, FALSE otherwise. If this parameter is TRUE, ZwQueryDirectoryFile returns only the first entry that is found.
FileName [in, optional]
An optional pointer to a caller-allocated Unicode string containing the name of a file (or multiple files, if wildcards are used) within the directory specified by FileHandle. This parameter is optional and can be NULL.
If FileName is not NULL, only files whose names match the FileName string are included in the directory scan. If FileName is NULL, all files are included.
The FileName is used as a search expression and is captured on the very first call to ZwQueryDirectoryFile for a given handle. Subsequent calls toZwQueryDirectoryFile will use the search expression set in the first call. The FileName parameter passed to subsequent calls will be ignored.
RestartScan [in]
Set to TRUE if the scan is to start at the first entry in the directory. Set to FALSE if resuming the scan from a previous call.
When the ZwQueryDirectoryFile routine is called for a particular handle, the RestartScan parameter is treated as if it were set to TRUE, regardless of its value. On subsequent ZwQueryDirectoryFile calls, the value of the RestartScan parameter is honored.
2.hook NtQueryDirectoryFile()实现对文件的隐藏
1 #include "ntddk.h" 2 3 4 #pragma pack(1) 5 typedef struct ServiceDescriptorEntry { 6 unsigned int *ServiceTableBase; 7 unsigned int *ServiceCounterTableBase; 8 unsigned int NumberOfServices; 9 unsigned char *ParamTableBase; 10 } ServiceDescriptorTableEntry_t, *PServiceDescriptorTableEntry_t; 11 12 typedef struct _FILE_BOTH_DIR_INFORMATION { 13 ULONG NextEntryOffset; 14 ULONG FileIndex; 15 LARGE_INTEGER CreationTime; 16 LARGE_INTEGER LastAccessTime; 17 LARGE_INTEGER LastWriteTime; 18 LARGE_INTEGER ChangeTime; 19 LARGE_INTEGER EndOfFile; 20 LARGE_INTEGER AllocationSize; 21 ULONG FileAttributes; 22 ULONG FileNameLength; 23 ULONG EaSize; 24 CCHAR ShortNameLength; 25 WCHAR ShortName[12]; 26 WCHAR FileName[1]; 27 } FILE_BOTH_DIR_INFORMATION, *PFILE_BOTH_DIR_INFORMATION; 28 29 30 // Our System Call Table 31 PVOID* NewSystemCallTable; 32 33 // Our Memory Descriptor List 34 PMDL pMyMDL; 35 36 #define HOOK_INDEX(function2hook) *(PULONG)((PUCHAR)function2hook+1) 37 38 #define HOOK(functionName, newPointer2Function, oldPointer2Function ) \ 39 oldPointer2Function = (PVOID) InterlockedExchange( (PLONG) &NewSystemCallTable[HOOK_INDEX(functionName)], (LONG) newPointer2Function) 40 41 #define UNHOOK(functionName, oldPointer2Function) \ 42 InterlockedExchange( (PLONG) &NewSystemCallTable[HOOK_INDEX(functionName)], (LONG) oldPointer2Function) 43 44 NTSYSAPI 45 NTSTATUS 46 NTAPI ZwQueryDirectoryFile( 47 IN HANDLE FileHandle, 48 IN HANDLE Event OPTIONAL, 49 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, 50 IN PVOID ApcContext OPTIONAL, 51 OUT PIO_STATUS_BLOCK IoStatusBlock, 52 OUT PVOID FileInformation, 53 IN ULONG Length, 54 IN FILE_INFORMATION_CLASS FileInformationClass, 55 IN BOOLEAN ReturnSingleEntry, 56 IN PUNICODE_STRING FileName OPTIONAL, 57 IN BOOLEAN RestartScan 58 ); 59 60 61 typedef NTSTATUS (__stdcall* ZWQUERYDIRECTORYFILE)( 62 __in HANDLE FileHandle, 63 __in_opt HANDLE Event OPTIONAL, 64 __in_opt PIO_APC_ROUTINE ApcRoutine OPTIONAL, 65 __in_opt PVOID ApcContext OPTIONAL, 66 __out PIO_STATUS_BLOCK IoStatusBlock, 67 __out PVOID FileInformation, 68 __in ULONG Length, 69 __in FILE_INFORMATION_CLASS FileInformationClass, 70 __in BOOLEAN ReturnSingleEntry, 71 __in PUNICODE_STRING FileName OPTIONAL, 72 __in BOOLEAN RestartScan 73 ); 74 75 int ZwQueryDirectoryFileIndex;//作为ZwQueryDirectoryFileIndex在ssdt索引地址中的相对路径。 76 77 78 NTSTATUS __stdcall NewNtQueryDirectoryFile( 79 __in HANDLE FileHandle, 80 __in_opt HANDLE Event , 81 __in_opt PIO_APC_ROUTINE ApcRoutine, 82 __in_opt PVOID ApcContext OPTIONAL, 83 __out PIO_STATUS_BLOCK IoStatusBlock, 84 __out PVOID FileInformation, 85 __in ULONG Length, 86 __in FILE_INFORMATION_CLASS FileInformationClass, 87 __in BOOLEAN ReturnSingleEntry, 88 __in PUNICODE_STRING FileName, 89 __in BOOLEAN RestartScan 90 ) 91 { 92 NTSTATUS status; 93 ANSI_STRING ansiFileName,ansiDirName,HideDirFile; 94 UNICODE_STRING uniFileName; 95 ZWQUERYDIRECTORYFILE OldZwQueryDirectoryFile; 96 int 1; 97 //测试C盘中的123.txt是否可以被隐藏。 98 RtlInitAnsiString(&HideDirFile,"123.txt"); 99 KdPrint(("hide: NewZwQueryDirectoryFile called.")); 100 101 if(MmIsAddressValidEx(OriginalServiceDescriptorTable->ServiceTable[ZwQueryDirectoryFileIndex]))//判断函数的地址是否有效 102 { 103 OldZwQueryDirectoryFile=OriginalServiceDescriptorTable->ServiceTable[ZwQueryDirectoryFileIndex]; 104 } 105 else 106 OldZwQueryDirectoryFile=KeServiceDescriptorTable->ServiceTable[ZwQueryDirectoryFileIndex]; 107 108 status = OldZwQueryDirectoryFile ( 109 FileHandle, 110 Event, 111 ApcRoutine, 112 ApcContext, 113 IoStatusBlock, 114 FileInformation, 115 Length, 116 FileInformationClass, 117 ReturnSingleEntry, 118 FileName, 119 RestartScan); 120 if() 121 //这部分是隐藏文件的核心部分 122 if(NT_SUCCESS(status)&&FileInformationClass==FileBothDirectoryInformation) 123 { 124 PFILE_BOTH_DIR_INFORMATION pFileInfo; 125 PFILE_BOTH_DIR_INFORMATION pLastFileInfo; 126 BOOLEAN bLastOne=FALSE; 127 pFileInfo = (PFILE_BOTH_DIR_INFORMATION)FileInformation; 128 pLastFileInfo = NULL; 129 do 130 { 131 bLastOne = !( pFileInfo->NextEntryOffset ); 132 RtlInitUnicodeString(&uniFileName,pFileInfo->FileName); RtlUnicodeStringToAnsiString(&ansiFileName,&uniFileName,TRUE); 133 RtlUnicodeStringToAnsiString(&ansiDirName,&uniFileName,TRUE); 134 135 if( RtlCompareMemory(ansiFileName.Buffer,HideDirFile.Buffer,HideDirFile.Length ) == HideDirFile.Length) 136 { 137 if(bLastOne) 138 { 139 pLastFileInfo->NextEntryOffset = 0; 140 break; 141 } 142 else //指针往后移动 143 { 144 int iPos = ((ULONG)pFileInfo) - (ULONG)FileInformation; 145 int iLeft = (DWORD)Length - iPos - pFileInfo->NextEntryOffset; 146 RtlCopyMemory( (PVOID)pFileInfo, (PVOID)( (char *)pFileInfo + pFileInfo->NextEntryOffset ), (DWORD)iLeft ); 147 continue; 148 } 149 } 150 pLastFileInfo = pFileInfo; 151 pFileInfo = (PFILE_BOTH_DIR_INFORMATION)((char *)pFileInfo + pFileInfo->NextEntryOffset); 152 }while(!bLastOne); 153 RtlFreeAnsiString(&ansiDirName); 154 RtlFreeAnsiString(&ansiFileName); 155 } 156 goto _FunctionRet; 157 158 _FunctionRet: 159 160 return status; 161 162 } 163
其中,指针类型变量强化转换为ULONG型变量。
(ULONG)pFileInfo ;//即把地址转化为ULONG型变量。
(ULONG) FileInformation;
那么int iPos=((ULONG)pFileInfo)- (ULONG) FileInformation;
得到的就是地址偏移值。
int iLeft=(DWORD)Length-iPos-pFileInfo->NextEntryOffset;
3.上述代码,采用WDK编译。然后再整合到MFC开发的用户界面程序中。
4.在Vmware虚拟机中,操作系统是Windows XP,做测试。
5.发现在点击XX.exe之后,C盘中的123.txt就消失不见。说明对123.txt的文件隐藏成功。