Hi, I am currently writing a minifilter. As part of the minifilter I monitor for file writes (to test file data before and after a write).
When looking on a mapped file, I first monitor IRP_MJ_ACQUIRE_FOR_SECTION_SYNCHRONIZATION and check the data in the file, then I monitor IRP_MJ_CLEANUP and check for a change in the file data.
This is not good enough since it is possible to close the handles before the file is written to.
I wrote two POCs, one using passthrough from Windows-driver-samples. In this POC I monitor all IRPs and log them. The second POC is for mapping a file, closing its handles and only then writing to the mapped view.
Minifilter POC:
CONST FLT_OPERATION_REGISTRATION Callbacks[] = {
{ IRP_MJ_CREATE,
0,
PtPreOperationPassThrough,
PtPostOperationPassThrough },
{ IRP_MJ_CREATE_NAMED_PIPE,
0,
PtPreOperationPassThrough,
PtPostOperationPassThrough },
{ IRP_MJ_CLOSE,
0,
PtPreOperationPassThrough,
PtPostOperationPassThrough },
{ IRP_MJ_READ,
0,
PtPreOperationPassThrough,
PtPostOperationPassThrough },
{ IRP_MJ_WRITE,
0,
PtPreOperationPassThrough,
PtPostOperationPassThrough },
{ IRP_MJ_QUERY_INFORMATION,
0,
PtPreOperationPassThrough,
PtPostOperationPassThrough },
{ IRP_MJ_SET_INFORMATION,
0,
PtPreOperationPassThrough,
PtPostOperationPassThrough },
{ IRP_MJ_QUERY_EA,
0,
PtPreOperationPassThrough,
PtPostOperationPassThrough },
{ IRP_MJ_SET_EA,
0,
PtPreOperationPassThrough,
PtPostOperationPassThrough },
{ IRP_MJ_FLUSH_BUFFERS,
0,
PtPreOperationPassThrough,
PtPostOperationPassThrough },
{ IRP_MJ_QUERY_VOLUME_INFORMATION,
0,
PtPreOperationPassThrough,
PtPostOperationPassThrough },
{ IRP_MJ_SET_VOLUME_INFORMATION,
0,
PtPreOperationPassThrough,
PtPostOperationPassThrough },
{ IRP_MJ_DIRECTORY_CONTROL,
0,
PtPreOperationPassThrough,
PtPostOperationPassThrough },
{ IRP_MJ_FILE_SYSTEM_CONTROL,
0,
PtPreOperationPassThrough,
PtPostOperationPassThrough },
{ IRP_MJ_DEVICE_CONTROL,
0,
PtPreOperationPassThrough,
PtPostOperationPassThrough },
{ IRP_MJ_INTERNAL_DEVICE_CONTROL,
0,
PtPreOperationPassThrough,
PtPostOperationPassThrough },
{ IRP_MJ_SHUTDOWN,
0,
PtPreOperationNoPostOperationPassThrough,
NULL }, //post operations not supported
{ IRP_MJ_LOCK_CONTROL,
0,
PtPreOperationPassThrough,
PtPostOperationPassThrough },
{ IRP_MJ_CLEANUP,
0,
PtPreOperationPassThrough,
PtPostOperationPassThrough },
{ IRP_MJ_CREATE_MAILSLOT,
0,
PtPreOperationPassThrough,
PtPostOperationPassThrough },
{ IRP_MJ_QUERY_SECURITY,
0,
PtPreOperationPassThrough,
PtPostOperationPassThrough },
{ IRP_MJ_SET_SECURITY,
0,
PtPreOperationPassThrough,
PtPostOperationPassThrough },
{ IRP_MJ_QUERY_QUOTA,
0,
PtPreOperationPassThrough,
PtPostOperationPassThrough },
{ IRP_MJ_SET_QUOTA,
0,
PtPreOperationPassThrough,
PtPostOperationPassThrough },
{ IRP_MJ_PNP,
0,
PtPreOperationPassThrough,
PtPostOperationPassThrough },
{ IRP_MJ_ACQUIRE_FOR_SECTION_SYNCHRONIZATION,
0,
PtPreOperationPassThrough,
PtPostOperationPassThrough },
{ IRP_MJ_RELEASE_FOR_SECTION_SYNCHRONIZATION,
0,
PtPreOperationPassThrough,
PtPostOperationPassThrough },
{ IRP_MJ_ACQUIRE_FOR_MOD_WRITE,
0,
PtPreOperationPassThrough,
PtPostOperationPassThrough },
{ IRP_MJ_RELEASE_FOR_MOD_WRITE,
0,
PtPreOperationPassThrough,
PtPostOperationPassThrough },
{ IRP_MJ_ACQUIRE_FOR_CC_FLUSH,
0,
PtPreOperationPassThrough,
PtPostOperationPassThrough },
{ IRP_MJ_RELEASE_FOR_CC_FLUSH,
0,
PtPreOperationPassThrough,
PtPostOperationPassThrough },
{ IRP_MJ_FAST_IO_CHECK_IF_POSSIBLE,
0,
PtPreOperationPassThrough,
PtPostOperationPassThrough },
{ IRP_MJ_NETWORK_QUERY_OPEN,
0,
PtPreOperationPassThrough,
PtPostOperationPassThrough },
{ IRP_MJ_MDL_READ,
0,
PtPreOperationPassThrough,
PtPostOperationPassThrough },
{ IRP_MJ_MDL_READ_COMPLETE,
0,
PtPreOperationPassThrough,
PtPostOperationPassThrough },
{ IRP_MJ_PREPARE_MDL_WRITE,
0,
PtPreOperationPassThrough,
PtPostOperationPassThrough },
{ IRP_MJ_MDL_WRITE_COMPLETE,
0,
PtPreOperationPassThrough,
PtPostOperationPassThrough },
{ IRP_MJ_VOLUME_MOUNT,
0,
PtPreOperationPassThrough,
PtPostOperationPassThrough },
{ IRP_MJ_VOLUME_DISMOUNT,
0,
PtPreOperationPassThrough,
PtPostOperationPassThrough },
{ IRP_MJ_OPERATION_END }
};
File mapper POC (calling writeFile which calls mapFile):
char* mapFile(std::string filePath, BOOL isRead, HANDLE* hFile, HANDLE* hFileMapping)
{
DWORD filesize = 0;
if (isRead)
{
*hFile = CreateFileA(filePath.c_str(), GENERIC_WRITE | GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (*hFile == INVALID_HANDLE_VALUE) return NULL;
DWORD highSize;
filesize = GetFileSize(*hFile, &highSize);
}
else
{
*hFile = CreateFileA(filePath.c_str(), GENERIC_WRITE | GENERIC_READ, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (*hFile == INVALID_HANDLE_VALUE) return NULL;
filesize = sizeof(dataToWrite);
}
*hFileMapping = CreateFileMapping(*hFile, NULL, PAGE_READWRITE, 0, filesize, NULL);
if (*hFileMapping == NULL)
{
CloseHandle(*hFile);
return NULL;
}
char* viewData = (char*)MapViewOfFile(*hFileMapping, FILE_MAP_ALL_ACCESS, 0, 0, filesize);
if (viewData == NULL)
{
}
CloseHandle(*hFileMapping);
CloseHandle(*hFile);
return viewData;
}
**BOOL writeFile(std::string filePath)**
{
HANDLE hFile;
HANDLE hFileMapping;
char* viewData = mapFile(filePath, FALSE, &hFile, &hFileMapping);
if (viewData == NULL)
{
return FALSE;
}
CopyMemory(viewData, dataToWrite, sizeof(dataToWrite));
unmapFile(viewData, hFile, hFileMapping);
return TRUE;
}
When running the POC I looked at the logs and couldn’t find any writes to the file after an IRP_MJ_CLEANUP is issued, only IRP_MJ_READ.
Logs:
Process name: \Device\HarddiskVolume4\Users\user\Desktop\FileMappingRW64.exe PID: 6332 IRP: IRP_MJ_CREATE
Process name: \Device\HarddiskVolume4\Users\user\Desktop\FileMappingRW64.exe PID: 6332 IRP: IRP_MJ_ACQUIRE_FOR_SECTION_SYNCHRONIZATION
Process name: \Device\HarddiskVolume4\Users\user\Desktop\FileMappingRW64.exe PID: 6332 IRP: IRP_MJ_QUERY_INFORMATION
Process name: \Device\HarddiskVolume4\Users\user\Desktop\FileMappingRW64.exe PID: 6332 IRP: IRP_MJ_RELEASE_FOR_SECTION_SYNCHRONIZATION
Process name: \Device\HarddiskVolume4\Users\user\Desktop\FileMappingRW64.exe PID: 6332 IRP: IRP_MJ_QUERY_INFORMATION
Process name: \Device\HarddiskVolume4\Users\user\Desktop\FileMappingRW64.exe PID: 6332 IRP: IRP_MJ_SET_INFORMATION
Process name: \Device\HarddiskVolume4\Users\user\Desktop\FileMappingRW64.exe PID: 6332 IRP: IRP_MJ_ACQUIRE_FOR_SECTION_SYNCHRONIZATION
Process name: \Device\HarddiskVolume4\Users\user\Desktop\FileMappingRW64.exe PID: 6332 IRP: IRP_MJ_RELEASE_FOR_SECTION_SYNCHRONIZATION
Process name: \Device\HarddiskVolume4\Users\user\Desktop\FileMappingRW64.exe PID: 6332 IRP: IRP_MJ_CLEANUP
Process name: \Device\HarddiskVolume4\Users\user\Desktop\FileMappingRW64.exe PID: 6332 IRP: IRP_MJ_CLOSE
Process name: \Device\HarddiskVolume4\Users\user\Desktop\FileMappingRW64.exe PID: 6332 IRP: IRP_MJ_READ
Am I doing something wrong? is there a way to monitor a write to the mapped view?
After a while I do see the write from the system process but it is too late.
Let me know if additional data is required.
Thanks!