Silhouette/Filter_Main.cpp (226 lines of code) (raw):
#include "Silhouette.h"
PFLT_FILTER gpFilter = NULL;
// pagefile.sys
FILE_ID_INFORMATION gProtectedFiles[1] = { 0, };
CONST FLT_OPERATION_REGISTRATION Callbacks[] = {
{ IRP_MJ_CREATE,
0,
PreCreateCallback,
PostCreateCallback },
{ IRP_MJ_READ,
0,
PreReadCallback,
PostReadCallback },
{ IRP_MJ_OPERATION_END }
};
CONST FLT_REGISTRATION FilterRegistration = {
sizeof(FLT_REGISTRATION), // Size
FLT_REGISTRATION_VERSION, // Version
FLTFL_REGISTRATION_DO_NOT_SUPPORT_SERVICE_STOP, // Flags
NULL, // Context
Callbacks, // Operation callbacks
FilterUnload, // FilterUnload
InstanceSetupCallback, // InstanceSetup
QueryTeardown, // InstanceQueryTeardown
NULL, // InstanceTeardownStart
NULL, // InstanceTeardownComplete
NULL, // GenerateFileName
NULL, // GenerateDestinationFileName
NULL // NormalizeNameComponent
};
NTSTATUS GetFileIdByPath(PUNICODE_STRING pFilePath, PFILE_ID_INFORMATION pFileIdInfo)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
OBJECT_ATTRIBUTES objAttr = { 0, };
IO_STATUS_BLOCK iosb = { 0, };
HANDLE hFile = NULL;
InitializeObjectAttributes(&objAttr, pFilePath, OBJ_KERNEL_HANDLE, 0, NULL);
// This fails with a sharing violation pagefile.sys, even with IO_IGNORE_SHARE_ACCESS_CHECK
ntStatus = FltCreateFile(
gpFilter, NULL, &hFile, 0, &objAttr, &iosb, NULL, 0,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
FILE_OPEN, FILE_NON_DIRECTORY_FILE, NULL, 0, IO_IGNORE_SHARE_ACCESS_CHECK);
if (!NT_SUCCESS(ntStatus))
{
goto Cleanup;
}
ntStatus = ZwQueryInformationFile(hFile, &iosb, pFileIdInfo, sizeof(*pFileIdInfo), FileIdInformation);
Cleanup:
HandleDelete(hFile);
return ntStatus;
}
NTSTATUS FindPagefile()
{
const ULONG systemProcessId = HandleToULong(PsGetProcessId(PsInitialSystemProcess)); // Always 4, but you never know?
DECLARE_CONST_UNICODE_STRING(pagefile_sys, L"\\pagefile.sys");
NTSTATUS ntStatus = STATUS_SUCCESS;
PSYSTEM_HANDLE_INFORMATION pHandleInfo = NULL;
ULONG handleInfoMem = 0;
ULONG returnLength = 0;
PFILE_OBJECT pFile = NULL;
PFILE_NAME_INFORMATION pNameInfo = NULL;
for (ULONG tries = 0; tries < 5; tries++)
{
ntStatus = ZwQuerySystemInformation(SystemHandleInformation, pHandleInfo, handleInfoMem, &returnLength);
if (STATUS_INFO_LENGTH_MISMATCH != ntStatus)
{
break;
}
HandleDelete(pHandleInfo);
handleInfoMem = returnLength * 2;
pHandleInfo = (PSYSTEM_HANDLE_INFORMATION)ExAllocatePoolWithTag(PagedPool, handleInfoMem, POOL_TAG);
if (!pHandleInfo)
{
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
RtlZeroMemory(pHandleInfo, handleInfoMem);
}
if (!NT_SUCCESS(ntStatus))
{
goto Cleanup;
}
for (ULONG i = 0; i < pHandleInfo->NumberOfHandles; i++)
{
UNICODE_STRING nameInfoUni = { 0, };
if (systemProcessId != pHandleInfo->Handles[i].UniqueProcessId)
{
continue;
}
ReferenceDelete(pFile);
PoolDeleteWithTag(pNameInfo, POOL_TAG);
// I'm not fond of temporarily referencing other handles in the System process, but the point here is to prove the concept
ntStatus = ObReferenceObjectByHandle(
MAKE_KERNEL_HANDLE(ULongToHandle(pHandleInfo->Handles[i].HandleValue)), FILE_READ_DATA|FILE_WRITE_DATA, *IoFileObjectType, KernelMode, (PVOID*)&pFile, NULL);
if (!NT_SUCCESS(ntStatus))
{
continue;
}
// pagefile.sys is opened without buffering
if (!FlagOn(pFile->Flags, FO_NO_INTERMEDIATE_BUFFERING))
{
continue;
}
// pagefile.sys is opened for RW- with -W- sharing
if (!pFile->ReadAccess || !pFile->WriteAccess || pFile->DeleteAccess || pFile->SharedRead || pFile->SharedDelete)
{
continue;
}
pNameInfo = (PFILE_NAME_INFORMATION)ExAllocatePoolWithTag(PagedPool, 4096, POOL_TAG);
if (!pNameInfo)
{
continue;
}
RtlZeroMemory(pNameInfo, 4096);
pNameInfo->FileNameLength = 4096 - sizeof(*pNameInfo); // Leave room for a NULL
ntStatus = FsRtlQueryInformationFile(pFile, pNameInfo, 4096, FileNameInformation, &returnLength);
if (!NT_SUCCESS(ntStatus) || (pNameInfo->FileNameLength > MAXUSHORT))
{
continue;
}
nameInfoUni.Buffer = pNameInfo->FileName;
nameInfoUni.Length = (USHORT)pNameInfo->FileNameLength;
nameInfoUni.MaximumLength = nameInfoUni.Length;
if (!RtlEqualUnicodeString(&nameInfoUni, &pagefile_sys, FALSE))
{
continue;
}
ntStatus = FsRtlQueryInformationFile(pFile, &gProtectedFiles[0], sizeof(gProtectedFiles[0]), FileIdInformation, &returnLength);
if (NT_SUCCESS(ntStatus) && (sizeof(gProtectedFiles[0]) == returnLength))
{
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL,
"Silhouette: Pagefile: %wZ\n",
&nameInfoUni);
goto Cleanup;
}
}
ntStatus = STATUS_PAGEFILE_NOT_SUPPORTED;
Cleanup:
PoolDeleteWithTag(pHandleInfo, POOL_TAG);
PoolDeleteWithTag(pNameInfo, POOL_TAG);
ReferenceDelete(pFile);
return ntStatus;
}
NTSTATUS
RegisterFilter(_In_ PDRIVER_OBJECT pDriverObject)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
ntStatus = FltRegisterFilter(pDriverObject, &FilterRegistration, &gpFilter);
if (!NT_SUCCESS(ntStatus))
{
goto Cleanup;
}
ntStatus = FindPagefile();
if (!NT_SUCCESS(ntStatus))
{
goto Cleanup;
}
ntStatus = FltStartFiltering(gpFilter);
if (!NT_SUCCESS(ntStatus))
{
FltUnregisterFilter(gpFilter);
gpFilter = NULL;
goto Cleanup;
}
Cleanup:
return ntStatus;
}
VOID
UnregisterFilter()
{
if (gpFilter)
{
FltUnregisterFilter(gpFilter);
gpFilter = NULL;
}
}
NTSTATUS
FilterUnload(_In_ FLT_FILTER_UNLOAD_FLAGS Flags
)
{
UNREFERENCED_PARAMETER(Flags);
FltUnregisterFilter(gpFilter);
return STATUS_SUCCESS;
}
NTSTATUS InstanceSetupCallback(
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);
NTSTATUS ntStatus = STATUS_SUCCESS;
UNICODE_STRING volumeName = { 0, };
PWCHAR pBuffer = NULL;
ULONG volumeNameLength = 0;
ntStatus = FltGetVolumeName(FltObjects->Volume, NULL, &volumeNameLength);
pBuffer = (PWCHAR)ExAllocatePoolWithTag(PagedPool, volumeNameLength, POOL_TAG);
if (!pBuffer)
{
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
RtlInitEmptyUnicodeString(&volumeName, pBuffer, (USHORT)volumeNameLength);
ntStatus = FltGetVolumeName(FltObjects->Volume, &volumeName, &volumeNameLength);
if (!NT_SUCCESS(ntStatus))
{
goto Cleanup;
}
// Volume Reads
// Flags == FLTFL_INSTANCE_SETUP_AUTOMATIC_ATTACHMENT
// VolumeDeviceType == FILE_DEVICE_DISK_FILE_SYSTEM
// VolumeFilesystemType == FLT_FSTYPE_NTFS
// TODO: Raw disk reads
#if 0
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL,
"Silhouette: InstanceSetupCallback for Flags: 0x%x DevType: %u FS: %u for %wZ\n",
Flags, VolumeDeviceType, VolumeFilesystemType, &volumeName);
#endif
Cleanup:
PoolDeleteWithTag(pBuffer, POOL_TAG);
return STATUS_SUCCESS;
}
NTSTATUS
QueryTeardown(
_In_ PCFLT_RELATED_OBJECTS FltObjects,
_In_ FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags
)
{
UNREFERENCED_PARAMETER(FltObjects);
UNREFERENCED_PARAMETER(Flags);
return STATUS_ACCESS_DENIED;
}