mirror of
https://github.com/JKornev/hidden
synced 2024-06-16 12:08:05 +00:00
958 lines
26 KiB
C
958 lines
26 KiB
C
// =========================================================================================
|
|
// Filesystem Minifilter
|
|
// =========================================================================================
|
|
|
|
#include <fltKernel.h>
|
|
#include "ExcludeList.h"
|
|
#include "FsFilter.h"
|
|
#include "Helper.h"
|
|
#include "PsMonitor.h"
|
|
#include "Driver.h"
|
|
#include "Configs.h"
|
|
|
|
#define FSFILTER_ALLOC_TAG 'DHlF'
|
|
|
|
NTSTATUS FilterSetup(PCFLT_RELATED_OBJECTS FltObjects, FLT_INSTANCE_SETUP_FLAGS Flags, DEVICE_TYPE VolumeDeviceType, FLT_FILESYSTEM_TYPE VolumeFilesystemType);
|
|
|
|
FLT_PREOP_CALLBACK_STATUS FltCreatePreOperation(PFLT_CALLBACK_DATA Data, PCFLT_RELATED_OBJECTS FltObjects, PVOID *CompletionContext);
|
|
//FLT_POSTOP_CALLBACK_STATUS FltCreatePostOperation(PFLT_CALLBACK_DATA Data, PCFLT_RELATED_OBJECTS FltObjects, PVOID CompletionContext, FLT_POST_OPERATION_FLAGS Flags);
|
|
FLT_PREOP_CALLBACK_STATUS FltDirCtrlPreOperation(PFLT_CALLBACK_DATA Data, PCFLT_RELATED_OBJECTS FltObjects, PVOID *CompletionContext);
|
|
FLT_POSTOP_CALLBACK_STATUS FltDirCtrlPostOperation(PFLT_CALLBACK_DATA Data, PCFLT_RELATED_OBJECTS FltObjects, PVOID CompletionContext, FLT_POST_OPERATION_FLAGS Flags);
|
|
|
|
NTSTATUS CleanFileFullDirectoryInformation(PFILE_FULL_DIR_INFORMATION info, PFLT_FILE_NAME_INFORMATION fltName);
|
|
NTSTATUS CleanFileBothDirectoryInformation(PFILE_BOTH_DIR_INFORMATION info, PFLT_FILE_NAME_INFORMATION fltName);
|
|
NTSTATUS CleanFileDirectoryInformation(PFILE_DIRECTORY_INFORMATION info, PFLT_FILE_NAME_INFORMATION fltName);
|
|
NTSTATUS CleanFileIdFullDirectoryInformation(PFILE_ID_FULL_DIR_INFORMATION info, PFLT_FILE_NAME_INFORMATION fltName);
|
|
NTSTATUS CleanFileIdBothDirectoryInformation(PFILE_ID_BOTH_DIR_INFORMATION info, PFLT_FILE_NAME_INFORMATION fltName);
|
|
NTSTATUS CleanFileNamesInformation(PFILE_NAMES_INFORMATION info, PFLT_FILE_NAME_INFORMATION fltName);
|
|
|
|
|
|
const FLT_CONTEXT_REGISTRATION Contexts[] = {
|
|
{ FLT_CONTEXT_END }
|
|
};
|
|
|
|
CONST FLT_OPERATION_REGISTRATION Callbacks[] = {
|
|
{ IRP_MJ_CREATE, 0, FltCreatePreOperation, /*FltCreatePostOperation*/ NULL },
|
|
{ IRP_MJ_DIRECTORY_CONTROL, 0, FltDirCtrlPreOperation, FltDirCtrlPostOperation },
|
|
{ IRP_MJ_OPERATION_END }
|
|
};
|
|
|
|
CONST FLT_REGISTRATION FilterRegistration = {
|
|
sizeof(FLT_REGISTRATION), // Size
|
|
FLT_REGISTRATION_VERSION, // Version
|
|
FLTFL_REGISTRATION_DO_NOT_SUPPORT_SERVICE_STOP, // Flags
|
|
Contexts, // Context
|
|
Callbacks, // Operation callbacks
|
|
/*FilterUnload*/NULL, // MiniFilterUnload
|
|
FilterSetup, // InstanceSetup
|
|
NULL, // InstanceQueryTeardown
|
|
NULL, // InstanceTeardownStart
|
|
NULL, // InstanceTeardownComplete
|
|
NULL, // GenerateFileName
|
|
NULL, // GenerateDestinationFileName
|
|
NULL // NormalizeNameComponent
|
|
};
|
|
|
|
BOOLEAN g_fsMonitorInited = FALSE;
|
|
PFLT_FILTER gFilterHandle = NULL;
|
|
|
|
ExcludeContext g_excludeFileContext;
|
|
ExcludeContext g_excludeDirectoryContext;
|
|
|
|
// Use this variable for hard code full file paths that you would like to hide
|
|
// For instance: L"\\Device\\HarddiskVolume1\\Windows\\System32\\calc.exe"
|
|
// Notice: this array should be NULL terminated
|
|
CONST PWCHAR g_excludeFiles[] = {
|
|
NULL
|
|
};
|
|
|
|
// Use this variable for hard code full directory paths that you would like to hide
|
|
// For instance: L"\\Device\\HarddiskVolume1\\Windows\\System32\\mysecretdir"
|
|
// Notice: this array should be NULL terminated
|
|
CONST PWCHAR g_excludeDirs[] = {
|
|
NULL
|
|
};
|
|
|
|
NTSTATUS FilterSetup(PCFLT_RELATED_OBJECTS FltObjects, FLT_INSTANCE_SETUP_FLAGS Flags, DEVICE_TYPE VolumeDeviceType, FLT_FILESYSTEM_TYPE VolumeFilesystemType)
|
|
{
|
|
UNREFERENCED_PARAMETER(FltObjects);
|
|
UNREFERENCED_PARAMETER(Flags);
|
|
UNREFERENCED_PARAMETER(VolumeDeviceType);
|
|
UNREFERENCED_PARAMETER(VolumeFilesystemType);
|
|
|
|
LogTrace("Attach to a new device (flags:%x, device:%d, fs:%d)", (ULONG)Flags, (ULONG)VolumeDeviceType, (ULONG)VolumeFilesystemType);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
enum {
|
|
FoundExcludeFile = 1,
|
|
FoundExcludeDir = 2,
|
|
};
|
|
|
|
FLT_PREOP_CALLBACK_STATUS FltCreatePreOperation(
|
|
_Inout_ PFLT_CALLBACK_DATA Data,
|
|
_In_ PCFLT_RELATED_OBJECTS FltObjects,
|
|
_Flt_CompletionContext_Outptr_ PVOID *CompletionContext)
|
|
{
|
|
UINT32 disposition, options;
|
|
PFLT_FILE_NAME_INFORMATION fltName;
|
|
NTSTATUS status;
|
|
BOOLEAN neededPrevent = FALSE;
|
|
|
|
UNREFERENCED_PARAMETER(FltObjects);
|
|
UNREFERENCED_PARAMETER(CompletionContext);
|
|
|
|
if (!IsDriverEnabled())
|
|
return FLT_PREOP_SUCCESS_NO_CALLBACK;
|
|
|
|
LogInfo("%wZ (options:%x)", &Data->Iopb->TargetFileObject->FileName, Data->Iopb->Parameters.Create.Options);
|
|
|
|
if (IsProcessExcluded(PsGetCurrentProcessId()))
|
|
return FLT_PREOP_SUCCESS_NO_CALLBACK;
|
|
|
|
options = Data->Iopb->Parameters.Create.Options & 0x00FFFFFF;
|
|
disposition = (Data->Iopb->Parameters.Create.Options & 0xFF000000) >> 24;
|
|
|
|
status = FltGetFileNameInformation(Data, FLT_FILE_NAME_NORMALIZED, &fltName);
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
if (status != STATUS_OBJECT_PATH_NOT_FOUND)
|
|
LogWarning("FltGetFileNameInformation() failed with code:%08x", status);
|
|
|
|
return FLT_PREOP_SUCCESS_NO_CALLBACK;
|
|
}
|
|
|
|
if (!(options & FILE_DIRECTORY_FILE))
|
|
{
|
|
// If it is create file event
|
|
if (CheckExcludeListDirectory(g_excludeFileContext, &fltName->Name))
|
|
neededPrevent = TRUE;
|
|
}
|
|
|
|
// If it is create directory/file event
|
|
if (!neededPrevent && CheckExcludeListDirectory(g_excludeDirectoryContext, &fltName->Name))
|
|
neededPrevent = TRUE;
|
|
|
|
FltReleaseFileNameInformation(fltName);
|
|
|
|
if (neededPrevent)
|
|
{
|
|
LogTrace("Operation has been cancelled for: %wZ", &Data->Iopb->TargetFileObject->FileName);
|
|
Data->IoStatus.Status = STATUS_NO_SUCH_FILE;
|
|
return FLT_PREOP_COMPLETE;
|
|
}
|
|
|
|
return FLT_PREOP_SUCCESS_NO_CALLBACK;
|
|
}
|
|
|
|
FLT_PREOP_CALLBACK_STATUS FltDirCtrlPreOperation(PFLT_CALLBACK_DATA Data, PCFLT_RELATED_OBJECTS FltObjects, PVOID *CompletionContext)
|
|
{
|
|
UNREFERENCED_PARAMETER(FltObjects);
|
|
UNREFERENCED_PARAMETER(CompletionContext);
|
|
|
|
if (!IsDriverEnabled())
|
|
return FLT_PREOP_SUCCESS_NO_CALLBACK;
|
|
|
|
LogInfo("%wZ", &Data->Iopb->TargetFileObject->FileName);
|
|
|
|
if (Data->Iopb->MinorFunction != IRP_MN_QUERY_DIRECTORY)
|
|
return FLT_PREOP_SUCCESS_NO_CALLBACK;
|
|
|
|
switch (Data->Iopb->Parameters.DirectoryControl.QueryDirectory.FileInformationClass)
|
|
{
|
|
case FileIdFullDirectoryInformation:
|
|
case FileIdBothDirectoryInformation:
|
|
case FileBothDirectoryInformation:
|
|
case FileDirectoryInformation:
|
|
case FileFullDirectoryInformation:
|
|
case FileNamesInformation:
|
|
break;
|
|
default:
|
|
return FLT_PREOP_SUCCESS_NO_CALLBACK;
|
|
}
|
|
|
|
return FLT_PREOP_SUCCESS_WITH_CALLBACK;
|
|
}
|
|
|
|
FLT_POSTOP_CALLBACK_STATUS FltDirCtrlPostOperation(PFLT_CALLBACK_DATA Data, PCFLT_RELATED_OBJECTS FltObjects, PVOID CompletionContext, FLT_POST_OPERATION_FLAGS Flags)
|
|
{
|
|
PFLT_PARAMETERS params = &Data->Iopb->Parameters;
|
|
PFLT_FILE_NAME_INFORMATION fltName;
|
|
NTSTATUS status;
|
|
|
|
UNREFERENCED_PARAMETER(FltObjects);
|
|
UNREFERENCED_PARAMETER(CompletionContext);
|
|
UNREFERENCED_PARAMETER(Flags);
|
|
|
|
if (!IsDriverEnabled())
|
|
return FLT_POSTOP_FINISHED_PROCESSING;
|
|
|
|
if (!NT_SUCCESS(Data->IoStatus.Status))
|
|
return FLT_POSTOP_FINISHED_PROCESSING;
|
|
|
|
LogInfo("%wZ", &Data->Iopb->TargetFileObject->FileName);
|
|
|
|
if (IsProcessExcluded(PsGetCurrentProcessId()))
|
|
{
|
|
LogTrace("Operation is skipped for excluded process");
|
|
return FLT_POSTOP_FINISHED_PROCESSING;
|
|
}
|
|
|
|
status = FltGetFileNameInformation(Data, FLT_FILE_NAME_NORMALIZED, &fltName);
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
LogWarning("FltGetFileNameInformation() failed with code:%08x", status);
|
|
return FLT_POSTOP_FINISHED_PROCESSING;
|
|
}
|
|
|
|
__try
|
|
{
|
|
status = STATUS_SUCCESS;
|
|
|
|
switch (params->DirectoryControl.QueryDirectory.FileInformationClass)
|
|
{
|
|
case FileFullDirectoryInformation:
|
|
status = CleanFileFullDirectoryInformation((PFILE_FULL_DIR_INFORMATION)params->DirectoryControl.QueryDirectory.DirectoryBuffer, fltName);
|
|
break;
|
|
case FileBothDirectoryInformation:
|
|
status = CleanFileBothDirectoryInformation((PFILE_BOTH_DIR_INFORMATION)params->DirectoryControl.QueryDirectory.DirectoryBuffer, fltName);
|
|
break;
|
|
case FileDirectoryInformation:
|
|
status = CleanFileDirectoryInformation((PFILE_DIRECTORY_INFORMATION)params->DirectoryControl.QueryDirectory.DirectoryBuffer, fltName);
|
|
break;
|
|
case FileIdFullDirectoryInformation:
|
|
status = CleanFileIdFullDirectoryInformation((PFILE_ID_FULL_DIR_INFORMATION)params->DirectoryControl.QueryDirectory.DirectoryBuffer, fltName);
|
|
break;
|
|
case FileIdBothDirectoryInformation:
|
|
status = CleanFileIdBothDirectoryInformation((PFILE_ID_BOTH_DIR_INFORMATION)params->DirectoryControl.QueryDirectory.DirectoryBuffer, fltName);
|
|
break;
|
|
case FileNamesInformation:
|
|
status = CleanFileNamesInformation((PFILE_NAMES_INFORMATION)params->DirectoryControl.QueryDirectory.DirectoryBuffer, fltName);
|
|
break;
|
|
}
|
|
|
|
Data->IoStatus.Status = status;
|
|
}
|
|
__finally
|
|
{
|
|
FltReleaseFileNameInformation(fltName);
|
|
}
|
|
|
|
return FLT_POSTOP_FINISHED_PROCESSING;
|
|
}
|
|
|
|
NTSTATUS CleanFileFullDirectoryInformation(PFILE_FULL_DIR_INFORMATION info, PFLT_FILE_NAME_INFORMATION fltName)
|
|
{
|
|
PFILE_FULL_DIR_INFORMATION nextInfo, prevInfo = NULL;
|
|
UNICODE_STRING fileName;
|
|
UINT32 offset, moveLength;
|
|
BOOLEAN matched, search;
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
|
|
offset = 0;
|
|
search = TRUE;
|
|
|
|
do
|
|
{
|
|
fileName.Buffer = info->FileName;
|
|
fileName.Length = (USHORT)info->FileNameLength;
|
|
fileName.MaximumLength = (USHORT)info->FileNameLength;
|
|
|
|
if (info->FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
|
matched = CheckExcludeListDirFile(g_excludeDirectoryContext, &fltName->Name, &fileName);
|
|
else
|
|
matched = CheckExcludeListDirFile(g_excludeFileContext, &fltName->Name, &fileName);
|
|
|
|
if (matched)
|
|
{
|
|
BOOLEAN retn = FALSE;
|
|
|
|
if (prevInfo != NULL)
|
|
{
|
|
if (info->NextEntryOffset != 0)
|
|
{
|
|
prevInfo->NextEntryOffset += info->NextEntryOffset;
|
|
offset = info->NextEntryOffset;
|
|
}
|
|
else
|
|
{
|
|
prevInfo->NextEntryOffset = 0;
|
|
status = STATUS_SUCCESS;
|
|
retn = TRUE;
|
|
}
|
|
|
|
RtlFillMemory(info, sizeof(FILE_FULL_DIR_INFORMATION), 0);
|
|
}
|
|
else
|
|
{
|
|
if (info->NextEntryOffset != 0)
|
|
{
|
|
nextInfo = (PFILE_FULL_DIR_INFORMATION)((PUCHAR)info + info->NextEntryOffset);
|
|
moveLength = 0;
|
|
while (nextInfo->NextEntryOffset != 0)
|
|
{
|
|
moveLength += nextInfo->NextEntryOffset;
|
|
nextInfo = (PFILE_FULL_DIR_INFORMATION)((PUCHAR)nextInfo + nextInfo->NextEntryOffset);
|
|
}
|
|
|
|
moveLength += FIELD_OFFSET(FILE_FULL_DIR_INFORMATION, FileName) + nextInfo->FileNameLength;
|
|
RtlMoveMemory(info, (PUCHAR)info + info->NextEntryOffset, moveLength);//continue
|
|
}
|
|
else
|
|
{
|
|
status = STATUS_NO_MORE_ENTRIES;
|
|
retn = TRUE;
|
|
}
|
|
}
|
|
|
|
LogTrace("Removed from query: %wZ\\%wZ", &fltName->Name, &fileName);
|
|
|
|
if (retn)
|
|
return status;
|
|
|
|
info = (PFILE_FULL_DIR_INFORMATION)((PCHAR)info + offset);
|
|
continue;
|
|
}
|
|
|
|
offset = info->NextEntryOffset;
|
|
prevInfo = info;
|
|
info = (PFILE_FULL_DIR_INFORMATION)((PCHAR)info + offset);
|
|
|
|
if (offset == 0)
|
|
search = FALSE;
|
|
} while (search);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS CleanFileBothDirectoryInformation(PFILE_BOTH_DIR_INFORMATION info, PFLT_FILE_NAME_INFORMATION fltName)
|
|
{
|
|
PFILE_BOTH_DIR_INFORMATION nextInfo, prevInfo = NULL;
|
|
UNICODE_STRING fileName;
|
|
UINT32 offset, moveLength;
|
|
BOOLEAN matched, search;
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
|
|
offset = 0;
|
|
search = TRUE;
|
|
|
|
do
|
|
{
|
|
fileName.Buffer = info->FileName;
|
|
fileName.Length = (USHORT)info->FileNameLength;
|
|
fileName.MaximumLength = (USHORT)info->FileNameLength;
|
|
|
|
if (info->FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
|
matched = CheckExcludeListDirFile(g_excludeDirectoryContext, &fltName->Name, &fileName);
|
|
else
|
|
matched = CheckExcludeListDirFile(g_excludeFileContext, &fltName->Name, &fileName);
|
|
|
|
if (matched)
|
|
{
|
|
BOOLEAN retn = FALSE;
|
|
|
|
if (prevInfo != NULL)
|
|
{
|
|
if (info->NextEntryOffset != 0)
|
|
{
|
|
prevInfo->NextEntryOffset += info->NextEntryOffset;
|
|
offset = info->NextEntryOffset;
|
|
}
|
|
else
|
|
{
|
|
prevInfo->NextEntryOffset = 0;
|
|
status = STATUS_SUCCESS;
|
|
retn = TRUE;
|
|
}
|
|
|
|
RtlFillMemory(info, sizeof(FILE_BOTH_DIR_INFORMATION), 0);
|
|
}
|
|
else
|
|
{
|
|
if (info->NextEntryOffset != 0)
|
|
{
|
|
nextInfo = (PFILE_BOTH_DIR_INFORMATION)((PUCHAR)info + info->NextEntryOffset);
|
|
moveLength = 0;
|
|
while (nextInfo->NextEntryOffset != 0)
|
|
{
|
|
moveLength += nextInfo->NextEntryOffset;
|
|
nextInfo = (PFILE_BOTH_DIR_INFORMATION)((PUCHAR)nextInfo + nextInfo->NextEntryOffset);
|
|
}
|
|
|
|
moveLength += FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION, FileName) + nextInfo->FileNameLength;
|
|
RtlMoveMemory(info, (PUCHAR)info + info->NextEntryOffset, moveLength);//continue
|
|
}
|
|
else
|
|
{
|
|
status = STATUS_NO_MORE_ENTRIES;
|
|
retn = TRUE;
|
|
}
|
|
}
|
|
|
|
LogTrace("Removed from query: %wZ\\%wZ", &fltName->Name, &fileName);
|
|
|
|
if (retn)
|
|
return status;
|
|
|
|
info = (PFILE_BOTH_DIR_INFORMATION)((PCHAR)info + offset);
|
|
continue;
|
|
}
|
|
|
|
offset = info->NextEntryOffset;
|
|
prevInfo = info;
|
|
info = (PFILE_BOTH_DIR_INFORMATION)((PCHAR)info + offset);
|
|
|
|
if (offset == 0)
|
|
search = FALSE;
|
|
} while (search);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS CleanFileDirectoryInformation(PFILE_DIRECTORY_INFORMATION info, PFLT_FILE_NAME_INFORMATION fltName)
|
|
{
|
|
PFILE_DIRECTORY_INFORMATION nextInfo, prevInfo = NULL;
|
|
UNICODE_STRING fileName;
|
|
UINT32 offset, moveLength;
|
|
BOOLEAN matched, search;
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
|
|
offset = 0;
|
|
search = TRUE;
|
|
|
|
do
|
|
{
|
|
fileName.Buffer = info->FileName;
|
|
fileName.Length = (USHORT)info->FileNameLength;
|
|
fileName.MaximumLength = (USHORT)info->FileNameLength;
|
|
|
|
if (info->FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
|
matched = CheckExcludeListDirFile(g_excludeDirectoryContext, &fltName->Name, &fileName);
|
|
else
|
|
matched = CheckExcludeListDirFile(g_excludeFileContext, &fltName->Name, &fileName);
|
|
|
|
if (matched)
|
|
{
|
|
BOOLEAN retn = FALSE;
|
|
|
|
if (prevInfo != NULL)
|
|
{
|
|
if (info->NextEntryOffset != 0)
|
|
{
|
|
prevInfo->NextEntryOffset += info->NextEntryOffset;
|
|
offset = info->NextEntryOffset;
|
|
}
|
|
else
|
|
{
|
|
prevInfo->NextEntryOffset = 0;
|
|
status = STATUS_SUCCESS;
|
|
retn = TRUE;
|
|
}
|
|
|
|
RtlFillMemory(info, sizeof(FILE_DIRECTORY_INFORMATION), 0);
|
|
}
|
|
else
|
|
{
|
|
if (info->NextEntryOffset != 0)
|
|
{
|
|
nextInfo = (PFILE_DIRECTORY_INFORMATION)((PUCHAR)info + info->NextEntryOffset);
|
|
moveLength = 0;
|
|
while (nextInfo->NextEntryOffset != 0)
|
|
{
|
|
moveLength += nextInfo->NextEntryOffset;
|
|
nextInfo = (PFILE_DIRECTORY_INFORMATION)((PUCHAR)nextInfo + nextInfo->NextEntryOffset);
|
|
}
|
|
|
|
moveLength += FIELD_OFFSET(FILE_DIRECTORY_INFORMATION, FileName) + nextInfo->FileNameLength;
|
|
RtlMoveMemory(info, (PUCHAR)info + info->NextEntryOffset, moveLength);//continue
|
|
}
|
|
else
|
|
{
|
|
status = STATUS_NO_MORE_ENTRIES;
|
|
retn = TRUE;
|
|
}
|
|
}
|
|
|
|
LogTrace("Removed from query: %wZ\\%wZ", &fltName->Name, &fileName);
|
|
|
|
if (retn)
|
|
return status;
|
|
|
|
info = (PFILE_DIRECTORY_INFORMATION)((PCHAR)info + offset);
|
|
continue;
|
|
}
|
|
|
|
offset = info->NextEntryOffset;
|
|
prevInfo = info;
|
|
info = (PFILE_DIRECTORY_INFORMATION)((PCHAR)info + offset);
|
|
|
|
if (offset == 0)
|
|
search = FALSE;
|
|
} while (search);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS CleanFileIdFullDirectoryInformation(PFILE_ID_FULL_DIR_INFORMATION info, PFLT_FILE_NAME_INFORMATION fltName)
|
|
{
|
|
PFILE_ID_FULL_DIR_INFORMATION nextInfo, prevInfo = NULL;
|
|
UNICODE_STRING fileName;
|
|
UINT32 offset, moveLength;
|
|
BOOLEAN matched, search;
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
|
|
offset = 0;
|
|
search = TRUE;
|
|
|
|
do
|
|
{
|
|
fileName.Buffer = info->FileName;
|
|
fileName.Length = (USHORT)info->FileNameLength;
|
|
fileName.MaximumLength = (USHORT)info->FileNameLength;
|
|
|
|
if (info->FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
|
matched = CheckExcludeListDirFile(g_excludeDirectoryContext, &fltName->Name, &fileName);
|
|
else
|
|
matched = CheckExcludeListDirFile(g_excludeFileContext, &fltName->Name, &fileName);
|
|
|
|
if (matched)
|
|
{
|
|
BOOLEAN retn = FALSE;
|
|
|
|
if (prevInfo != NULL)
|
|
{
|
|
if (info->NextEntryOffset != 0)
|
|
{
|
|
prevInfo->NextEntryOffset += info->NextEntryOffset;
|
|
offset = info->NextEntryOffset;
|
|
}
|
|
else
|
|
{
|
|
prevInfo->NextEntryOffset = 0;
|
|
status = STATUS_SUCCESS;
|
|
retn = TRUE;
|
|
}
|
|
|
|
RtlFillMemory(info, sizeof(FILE_ID_FULL_DIR_INFORMATION), 0);
|
|
}
|
|
else
|
|
{
|
|
if (info->NextEntryOffset != 0)
|
|
{
|
|
nextInfo = (PFILE_ID_FULL_DIR_INFORMATION)((PUCHAR)info + info->NextEntryOffset);
|
|
moveLength = 0;
|
|
while (nextInfo->NextEntryOffset != 0)
|
|
{
|
|
moveLength += nextInfo->NextEntryOffset;
|
|
nextInfo = (PFILE_ID_FULL_DIR_INFORMATION)((PUCHAR)nextInfo + nextInfo->NextEntryOffset);
|
|
}
|
|
|
|
moveLength += FIELD_OFFSET(FILE_ID_FULL_DIR_INFORMATION, FileName) + nextInfo->FileNameLength;
|
|
RtlMoveMemory(info, (PUCHAR)info + info->NextEntryOffset, moveLength);//continue
|
|
}
|
|
else
|
|
{
|
|
status = STATUS_NO_MORE_ENTRIES;
|
|
retn = TRUE;
|
|
}
|
|
}
|
|
|
|
LogTrace("Removed from query: %wZ\\%wZ", &fltName->Name, &fileName);
|
|
|
|
if (retn)
|
|
return status;
|
|
|
|
info = (PFILE_ID_FULL_DIR_INFORMATION)((PCHAR)info + offset);
|
|
continue;
|
|
}
|
|
|
|
offset = info->NextEntryOffset;
|
|
prevInfo = info;
|
|
info = (PFILE_ID_FULL_DIR_INFORMATION)((PCHAR)info + offset);
|
|
|
|
if (offset == 0)
|
|
search = FALSE;
|
|
} while (search);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS CleanFileIdBothDirectoryInformation(PFILE_ID_BOTH_DIR_INFORMATION info, PFLT_FILE_NAME_INFORMATION fltName)
|
|
{
|
|
PFILE_ID_BOTH_DIR_INFORMATION nextInfo, prevInfo = NULL;
|
|
UNICODE_STRING fileName;
|
|
UINT32 offset, moveLength;
|
|
BOOLEAN matched, search;
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
|
|
offset = 0;
|
|
search = TRUE;
|
|
|
|
do
|
|
{
|
|
fileName.Buffer = info->FileName;
|
|
fileName.Length = (USHORT)info->FileNameLength;
|
|
fileName.MaximumLength = (USHORT)info->FileNameLength;
|
|
|
|
if (info->FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
|
matched = CheckExcludeListDirFile(g_excludeDirectoryContext, &fltName->Name, &fileName);
|
|
else
|
|
matched = CheckExcludeListDirFile(g_excludeFileContext, &fltName->Name, &fileName);
|
|
|
|
if (matched)
|
|
{
|
|
BOOLEAN retn = FALSE;
|
|
|
|
if (prevInfo != NULL)
|
|
{
|
|
if (info->NextEntryOffset != 0)
|
|
{
|
|
prevInfo->NextEntryOffset += info->NextEntryOffset;
|
|
offset = info->NextEntryOffset;
|
|
}
|
|
else
|
|
{
|
|
prevInfo->NextEntryOffset = 0;
|
|
status = STATUS_SUCCESS;
|
|
retn = TRUE;
|
|
}
|
|
|
|
RtlFillMemory(info, sizeof(FILE_ID_BOTH_DIR_INFORMATION), 0);
|
|
}
|
|
else
|
|
{
|
|
if (info->NextEntryOffset != 0)
|
|
{
|
|
nextInfo = (PFILE_ID_BOTH_DIR_INFORMATION)((PUCHAR)info + info->NextEntryOffset);
|
|
moveLength = 0;
|
|
while (nextInfo->NextEntryOffset != 0)
|
|
{
|
|
moveLength += nextInfo->NextEntryOffset;
|
|
nextInfo = (PFILE_ID_BOTH_DIR_INFORMATION)((PUCHAR)nextInfo + nextInfo->NextEntryOffset);
|
|
}
|
|
|
|
moveLength += FIELD_OFFSET(FILE_ID_BOTH_DIR_INFORMATION, FileName) + nextInfo->FileNameLength;
|
|
RtlMoveMemory(info, (PUCHAR)info + info->NextEntryOffset, moveLength);//continue
|
|
}
|
|
else
|
|
{
|
|
status = STATUS_NO_MORE_ENTRIES;
|
|
retn = TRUE;
|
|
}
|
|
}
|
|
|
|
LogTrace("Removed from query: %wZ\\%wZ", &fltName->Name, &fileName);
|
|
|
|
if (retn)
|
|
return status;
|
|
|
|
info = (PFILE_ID_BOTH_DIR_INFORMATION)((PCHAR)info + offset);
|
|
continue;
|
|
}
|
|
|
|
offset = info->NextEntryOffset;
|
|
prevInfo = info;
|
|
info = (PFILE_ID_BOTH_DIR_INFORMATION)((PCHAR)info + offset);
|
|
|
|
if (offset == 0)
|
|
search = FALSE;
|
|
} while (search);
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS CleanFileNamesInformation(PFILE_NAMES_INFORMATION info, PFLT_FILE_NAME_INFORMATION fltName)
|
|
{
|
|
PFILE_NAMES_INFORMATION nextInfo, prevInfo = NULL;
|
|
UNICODE_STRING fileName;
|
|
UINT32 offset, moveLength;
|
|
BOOLEAN search;
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
|
|
offset = 0;
|
|
search = TRUE;
|
|
|
|
do
|
|
{
|
|
fileName.Buffer = info->FileName;
|
|
fileName.Length = (USHORT)info->FileNameLength;
|
|
fileName.MaximumLength = (USHORT)info->FileNameLength;
|
|
|
|
//TODO: check, can there be directories?
|
|
if (CheckExcludeListDirFile(g_excludeFileContext, &fltName->Name, &fileName))
|
|
{
|
|
BOOLEAN retn = FALSE;
|
|
|
|
if (prevInfo != NULL)
|
|
{
|
|
if (info->NextEntryOffset != 0)
|
|
{
|
|
prevInfo->NextEntryOffset += info->NextEntryOffset;
|
|
offset = info->NextEntryOffset;
|
|
}
|
|
else
|
|
{
|
|
prevInfo->NextEntryOffset = 0;
|
|
status = STATUS_SUCCESS;
|
|
retn = TRUE;
|
|
}
|
|
|
|
RtlFillMemory(info, sizeof(FILE_NAMES_INFORMATION), 0);
|
|
}
|
|
else
|
|
{
|
|
if (info->NextEntryOffset != 0)
|
|
{
|
|
nextInfo = (PFILE_NAMES_INFORMATION)((PUCHAR)info + info->NextEntryOffset);
|
|
moveLength = 0;
|
|
while (nextInfo->NextEntryOffset != 0)
|
|
{
|
|
moveLength += nextInfo->NextEntryOffset;
|
|
nextInfo = (PFILE_NAMES_INFORMATION)((PUCHAR)nextInfo + nextInfo->NextEntryOffset);
|
|
}
|
|
|
|
moveLength += FIELD_OFFSET(FILE_NAMES_INFORMATION, FileName) + nextInfo->FileNameLength;
|
|
RtlMoveMemory(info, (PUCHAR)info + info->NextEntryOffset, moveLength);//continue
|
|
}
|
|
else
|
|
{
|
|
status = STATUS_NO_MORE_ENTRIES;
|
|
retn = TRUE;
|
|
}
|
|
}
|
|
|
|
LogTrace("Removed from query: %wZ\\%wZ", &fltName->Name, &fileName);
|
|
|
|
if (retn)
|
|
return status;
|
|
|
|
info = (PFILE_NAMES_INFORMATION)((PCHAR)info + offset);
|
|
continue;
|
|
}
|
|
|
|
offset = info->NextEntryOffset;
|
|
prevInfo = info;
|
|
info = (PFILE_NAMES_INFORMATION)((PCHAR)info + offset);
|
|
|
|
if (offset == 0)
|
|
search = FALSE;
|
|
} while (search);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
VOID LoadConfigFilesCallback(PUNICODE_STRING Str, PVOID Params)
|
|
{
|
|
ULONGLONG id;
|
|
UNREFERENCED_PARAMETER(Params);
|
|
AddHiddenFile(Str, &id);
|
|
}
|
|
|
|
VOID LoadConfigDirsCallback(PUNICODE_STRING Str, PVOID Params)
|
|
{
|
|
ULONGLONG id;
|
|
UNREFERENCED_PARAMETER(Params);
|
|
AddHiddenDir(Str, &id);
|
|
}
|
|
|
|
NTSTATUS InitializeFSMiniFilter(PDRIVER_OBJECT DriverObject)
|
|
{
|
|
NTSTATUS status;
|
|
UNICODE_STRING str;
|
|
UINT32 i;
|
|
ExcludeEntryId id;
|
|
|
|
// Initialize and fill exclude file\dir lists
|
|
|
|
status = InitializeExcludeListContext(&g_excludeFileContext, ExcludeFile);
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
LogError("Exclude file list initialization failed with code:%08x", status);
|
|
return status;
|
|
}
|
|
|
|
for (i = 0; g_excludeFiles[i]; i++)
|
|
{
|
|
RtlInitUnicodeString(&str, g_excludeFiles[i]);
|
|
AddExcludeListFile(g_excludeFileContext, &str, &id, 0);
|
|
}
|
|
|
|
CfgEnumConfigsTable(HideFilesTable, &LoadConfigFilesCallback, NULL);
|
|
|
|
status = InitializeExcludeListContext(&g_excludeDirectoryContext, ExcludeDirectory);
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
LogError("Exclude file list initialization failed with code:%08x", status);
|
|
DestroyExcludeListContext(g_excludeFileContext);
|
|
return status;
|
|
}
|
|
|
|
for (i = 0; g_excludeDirs[i]; i++)
|
|
{
|
|
RtlInitUnicodeString(&str, g_excludeDirs[i]);
|
|
AddExcludeListDirectory(g_excludeDirectoryContext, &str, &id, 0);
|
|
}
|
|
|
|
CfgEnumConfigsTable(HideDirsTable, &LoadConfigDirsCallback, NULL);
|
|
|
|
// Filesystem mini-filter initialization
|
|
|
|
status = FltRegisterFilter(DriverObject, &FilterRegistration, &gFilterHandle);
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
status = FltStartFiltering(gFilterHandle);
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
LogError("Error, can't start filtering, code:%08x", status);
|
|
FltUnregisterFilter(gFilterHandle);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LogError("Error, can't register filter, code:%08x", status);
|
|
}
|
|
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
DestroyExcludeListContext(g_excludeFileContext);
|
|
DestroyExcludeListContext(g_excludeDirectoryContext);
|
|
return status;
|
|
}
|
|
|
|
g_fsMonitorInited = TRUE;
|
|
|
|
LogTrace("Initialization is completed");
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS DestroyFSMiniFilter()
|
|
{
|
|
if (!g_fsMonitorInited)
|
|
return STATUS_NOT_FOUND;
|
|
|
|
FltUnregisterFilter(gFilterHandle);
|
|
gFilterHandle = NULL;
|
|
|
|
DestroyExcludeListContext(g_excludeFileContext);
|
|
DestroyExcludeListContext(g_excludeDirectoryContext);
|
|
g_fsMonitorInited = FALSE;
|
|
|
|
LogTrace("Deitialization is completed");
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS AddHiddenFile(PUNICODE_STRING FilePath, PULONGLONG ObjId)
|
|
{
|
|
const USHORT maxBufSize = FilePath->Length + NORMALIZE_INCREAMENT;
|
|
UNICODE_STRING normalized;
|
|
NTSTATUS status;
|
|
|
|
normalized.Buffer = (PWCH)ExAllocatePoolWithTag(PagedPool, maxBufSize, FSFILTER_ALLOC_TAG);
|
|
normalized.Length = 0;
|
|
normalized.MaximumLength = maxBufSize;
|
|
|
|
if (!normalized.Buffer)
|
|
{
|
|
LogWarning("Error, can't allocate buffer");
|
|
return STATUS_MEMORY_NOT_ALLOCATED;
|
|
}
|
|
|
|
status = NormalizeDevicePath(FilePath, &normalized);
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
LogWarning("Path normalization failed with code:%08x, path:%wZ", status, FilePath);
|
|
ExFreePoolWithTag(normalized.Buffer, FSFILTER_ALLOC_TAG);
|
|
return status;
|
|
}
|
|
|
|
status = AddExcludeListFile(g_excludeFileContext, &normalized, ObjId, 0);
|
|
if (NT_SUCCESS(status))
|
|
LogTrace("Added hidden file:%wZ", &normalized);
|
|
else
|
|
LogTrace("Adding hidden file failed with code:%08x, path:%wZ", status, &normalized);
|
|
|
|
ExFreePoolWithTag(normalized.Buffer, FSFILTER_ALLOC_TAG);
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS RemoveHiddenFile(ULONGLONG ObjId)
|
|
{
|
|
NTSTATUS status = RemoveExcludeListEntry(g_excludeFileContext, ObjId);
|
|
if (NT_SUCCESS(status))
|
|
LogTrace("Hidden file is removed, id:%lld", ObjId);
|
|
else
|
|
LogTrace("Can't remove hidden file, code:%08x, id:%lld", status, ObjId);
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS RemoveAllHiddenFiles()
|
|
{
|
|
NTSTATUS status = RemoveAllExcludeListEntries(g_excludeFileContext);
|
|
if (NT_SUCCESS(status))
|
|
LogTrace("All hidden files are removed");
|
|
else
|
|
LogTrace("Can't remove all hidden files, code:%08x", status);
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS AddHiddenDir(PUNICODE_STRING DirPath, PULONGLONG ObjId)
|
|
{
|
|
const USHORT maxBufSize = DirPath->Length + NORMALIZE_INCREAMENT;
|
|
UNICODE_STRING normalized;
|
|
NTSTATUS status;
|
|
|
|
normalized.Buffer = (PWCH)ExAllocatePoolWithTag(PagedPool, maxBufSize, FSFILTER_ALLOC_TAG);
|
|
normalized.Length = 0;
|
|
normalized.MaximumLength = maxBufSize;
|
|
|
|
if (!normalized.Buffer)
|
|
{
|
|
LogWarning("Error, can't allocate buffer");
|
|
return STATUS_MEMORY_NOT_ALLOCATED;
|
|
}
|
|
|
|
status = NormalizeDevicePath(DirPath, &normalized);
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
LogWarning("Path normalization failed with code:%08x, path:%wZ\n", status, DirPath);
|
|
ExFreePoolWithTag(normalized.Buffer, FSFILTER_ALLOC_TAG);
|
|
return status;
|
|
}
|
|
|
|
status = AddExcludeListDirectory(g_excludeDirectoryContext, &normalized, ObjId, 0);
|
|
if (NT_SUCCESS(status))
|
|
LogTrace("Added hidden dir:%wZ", &normalized);
|
|
else
|
|
LogTrace("Adding hidden dir failed with code:%08x, path:%wZ", status, &normalized);
|
|
|
|
ExFreePoolWithTag(normalized.Buffer, FSFILTER_ALLOC_TAG);
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS RemoveHiddenDir(ULONGLONG ObjId)
|
|
{
|
|
NTSTATUS status = RemoveExcludeListEntry(g_excludeDirectoryContext, ObjId);
|
|
if (NT_SUCCESS(status))
|
|
LogTrace("Hidden dir is removed, id:%lld", ObjId);
|
|
else
|
|
LogTrace("Can't remove hidden dir, code:%08x, id:%lld", status, ObjId);
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS RemoveAllHiddenDirs()
|
|
{
|
|
NTSTATUS status = RemoveAllExcludeListEntries(g_excludeDirectoryContext);
|
|
if (NT_SUCCESS(status))
|
|
LogTrace("All hidden dirs are removed");
|
|
else
|
|
LogTrace("Can't remove all hidden dirs, code:%08x", status);
|
|
|
|
return status;
|
|
}
|