Hello OSR-list,
I have a pre-existing file of test data. This file is 0x800 bytes long.
I want to skip 0x200 bytes from the start of the file during read so that userspace sees an apparent/virtual file that begins at offset 0x200 and has a length of 0x600.
My sole requirement is to handle userspace reading the file sequentially using CreateFile ReadFile CloseHandle with FILE_ATTRIBUTE_NORMAL or FILE_FLAG_NO_BUFFERING.
I have no other requirements at this stage.
In an attempt to satisfy this requirement I add 0x200 to ‘Data->Iopb->Parameters.Read.ByteOffset.QuadPart’ during uncached reads.
Then the apparent file begins at offset 0x200 (good news) but still has a length of 0x800 and has 0x200 zeros on the end (bad news).
The read that populates the cache transfers 0x600 bytes.
The read that eventually populates the user buffer from the cache transfers 0x800 bytes.
Where did the extra 0x200 bytes come from?
It seems that something is directly acquiring the actual file length from FSRTL_COMMON_FCB_HEADER.FileSize. I think it should use IRP_MJ_QUERY_INFORMATION but that never occurs in the trace below so it would not help to intercept it. (indeed in would not help to intercept any IRP that does not occur in the trace of my sole requirement)
I have confirmed that this happens because because I can hack it to “work” by subtracting 0x200 from FSRTL_COMMON_FCB_HEADER.FileSize in post-create then add it back on pre-read and subtract it again on post-read such that, when this field is accessed directly the accessor receives the apparent/virtual length of 0x600 but the read itself still sees the actual length of 0x800. This hack would not multithread though (if two threads are between pre and post read).
Anyway, I’d expect not to need any hacks and to just intercept IRP_MJ_QUERY_INFORMATION but, like I said, it is never called in the trace below. As far as I can see nothing is called that could discover the length in a way that I could intercept.
If something is going around the minfilter abstraction and just accessing FileObject fields directly then, as a minifilter author, what can I do?
Thanks in advance for any assistance.
David
Pre IRP_MJ_READ (start populating userspace buffer)
…Data = 84574068
…Buffer = 0012DD08
…FltObjects->FileObject = 84569968
…FltObjects->FileObject->FsContext = A1181C58
…FLT_IS_IRP_OPERATION(Data) = 1
…FltObjects->FileObject->Flags = 40002
…Data->Iopb->IrpFlags = 60900
…Data->Iopb->OperationFlags = 0
…Data->Iopb->Parameters.Read.Length = 2000
…Data->Iopb->Parameters.Read.ByteOffset.QuadPart = 0
Pre IRP_MJ_READ (start populating the cache)
…Data = 859642F0
…Buffer = 805C1000
…FltObjects->FileObject = 84569968
…FltObjects->FileObject->FsContext = A1181C58
…FLT_IS_IRP_OPERATION(Data) = 1
…FltObjects->FileObject->Flags = 40002
…Data->Iopb->IrpFlags = 60403
…Data->Iopb->OperationFlags = 0
…Data->Iopb->Parameters.Read.Length = 1000
…Data->Iopb->Parameters.Read.ByteOffset.QuadPart = 0
…Doing Data->Iopb->Parameters.Read.ByteOffset.QuadPart += 0x200
…Data->Iopb->Parameters.Read.ByteOffset.QuadPart = 200
…Doing FltSetCallbackDataDirty(Data)
Post IRP_MJ_READ (done populating the cache)
…Data = 859642F0
…Buffer = 805C1000
…FltObjects->FileObject = 84569968
…FltObjects->FileObject->FsContext = A1181C58
…FLT_IS_IRP_OPERATION(Data) = 1
…FltObjects->FileObject->Flags = 40002
…Data->Iopb->IrpFlags = 60403
…Data->Iopb->OperationFlags = 0
…Data->Iopb->Parameters.Read.Length = 1000
…Data->Iopb->Parameters.Read.ByteOffset.QuadPart = 0
…Data->IoStatus.Status = 0
…Data->IoStatus.Information = 600
…Contents of Buffer = 02000202020402060208020a020c020e02100212021402160218021a021c021e…then 5e0 bytes more…
Post IRP_MJ_READ (done populating userspace buffer)
…Data = 84574068
…Buffer = 0012DD08
…FltObjects->FileObject = 84569968
…FltObjects->FileObject->FsContext = A1181C58
…FLT_IS_IRP_OPERATION(Data) = 1
…FltObjects->FileObject->Flags = c0002
…Data->Iopb->IrpFlags = 60900
…Data->Iopb->OperationFlags = 0
…Data->Iopb->Parameters.Read.Length = 2000
…Data->Iopb->Parameters.Read.ByteOffset.QuadPart = 0
…Data->IoStatus.Status = 0
…Data->IoStatus.Information = 800
…Contents of Buffer = 02000202020402060208020a020c020e02100212021402160218021a021c021e…then 7e0 bytes more…
Pre IRP_MJ_READ
…Data = 84574068
…Buffer = 0012DD08
…FltObjects->FileObject = 84569968
…FltObjects->FileObject->FsContext = A1181C58
…FLT_IS_IRP_OPERATION(Data) = 0
…FltObjects->FileObject->Flags = c0002
…Data->Iopb->IrpFlags = 0
…Data->Iopb->OperationFlags = 0
…Data->Iopb->Parameters.Read.Length = 2000
…Data->Iopb->Parameters.Read.ByteOffset.QuadPart = 800
Pre IRP_MJ_FAST_IO_CHECK_IF_POSSIBLE
Post IRP_MJ_FAST_IO_CHECK_IF_POSSIBLE
Post IRP_MJ_READ
…Data = 84574068
…Buffer = 0012DD08
…FltObjects->FileObject = 84569968
…FltObjects->FileObject->FsContext = A1181C58
…FLT_IS_IRP_OPERATION(Data) = 0
…FltObjects->FileObject->Flags = c0002
…Data->Iopb->IrpFlags = 0
…Data->Iopb->OperationFlags = 0
…Data->Iopb->Parameters.Read.Length = 2000
…Data->Iopb->Parameters.Read.ByteOffset.QuadPart = 800
…Data->IoStatus.Status = c0000011
…Data->IoStatus.Information = 0
…Contents of Buffer =
Pre IRP_MJ_CLEANUP
Post IRP_MJ_CLEANUP