驱动级彻底隐藏文件或文件夹的方法网上有很多,方法大致一样,不过网上贴出来的代码都忽略了一些东西,我先把我的通过验证的代码贴出来,再一一说明
ssdt hook那块的实现就不贴了,主要是对hook到ZwQueryDirectoryFile之后的实现
我做的是要隐藏指定目录下的指定后缀名的文件
NTSTATUS __stdcall NtQueryDirectoryFile_HOOK(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, ULONG Length, FILE_INFORMATION_CLASS FileInformationClass, BOOLEAN ReturnSingleEntry, PUNICODE_STRING FileName, BOOLEAN RestartScan) { NTSTATUS ntStatus = STATUS_SUCCESS; PFILE_BOTH_DIR_INFORMATION pFileInfo = NULL; PFILE_BOTH_DIR_INFORMATION pLastFileInfo = NULL; UNICODE_STRING usFilePathProfix = {0}; UNICODE_STRING usFileName = {0}; UNICODE_STRING usDirName = {0}; char szFileName[MAX_PATH] = {0}; ntStatus = ((NtQueryDirectoryFile_T)(g_fNtQueryDirectoryFile.trampoline)) (FileHandle, Event, ApcRoutine, ApcContext, IoStatusBlock, FileInformation, Length, FileInformationClass, ReturnSingleEntry, FileName, RestartScan); pFileInfo = (PFILE_BOTH_DIR_INFORMATION)FileInformation; if (pFileInfo == NULL) return ntStatus; if (NT_SUCCESS(ntStatus) && (FileInformationClass == FileBothDirectoryInformation)) { BOOLEAN bLastOne = FALSE; PFILE_OBJECT FileObj = NULL; status = ObReferenceObjectByHandle(FileHandle, FILE_READ_DATA, *IoFileObjectType, KernelMode, &FileObj, NULL); if(NT_SUCCESS(status)) { ObDereferenceObject(FileObj); RtlVolumeDeviceToDosName(FileObj->DeviceObject, &usDirName); if (..) // 这里是判断是否是指定目录 { KStr_SetValue_WChar(&usFilePathProfix, L".txt"); pLastFileInfo = pFileInfo; do { if (pFileInfo == NULL) break; bLastOne = !(pFileInfo->NextEntryOffset); if (..) // 这里判断是否是以指定后缀名结尾 { if (bLastOne) { if (pFileInfo == (PFILE_BOTH_DIR_INFORMATION)FileInformation) { ntStatus = ((NtQueryDirectoryFile_T)(g_fNtQueryDirectoryFile.trampoline)) (FileHandle, Event, ApcRoutine, ApcContext, IoStatusBlock, FileInformation, Length, FileInformationClass, ReturnSingleEntry, FileName, FALSE); if (!NT_SUCCESS(ntStatus)) return ntStatus; pFileInfo = (PFILE_BOTH_DIR_INFORMATION)FileInformation; bLastOne = FALSE; continue;
}
else pLastFileInfo->NextEntryOffset = 0; break; } else { int iPos = (ULONG)pFileInfo - (ULONG)FileInformation; int iLeft = (DWORD)Length - 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); } } } return ntStatus; }
蓝色部分是很多地方都遗漏的,如果查找到第一个文件需要隐藏的话,实际应该是上面调用了FindFirstFile,返回 0x80000006,导致的后果是,该目录下的所有文件都无法显示。所以出现这种情况应该继续查找。