Where is my read buffer?

I’ve been working with the Microsoft provided file system filter drivers from the IFS for quite some time now (a few weeks), but I’m still very new to driver development.

Like many others on this forum, I need to encrypt and decrypt file data. I’ve succeeded in encrypting file data for txt files. I’m just encrypting the Irp->UserBuffer in a IRP_MJ_WRITE operation by first making sure the file I’m writing to is a .TXT file and that it’s a UserMode operation.

Question on this: I noticed in-situ encryption is listed as a big “no no” here. I need to allocate my own buffer and use that. Heh? Actually, I originally did allocate my own buffer, but I don’t really know how to “use” it per se.

Create my own Irp? Can someone give me exact details on this process in a DispatchWrite() routine? Sure, I can make an Irp and fill it in with goodness and lovingkindness, but what *exactly* do I do with it then? Using my new Irp, do I?

IoCopyCurrentIrpStackLocationToNext( Irp );

IoSetCompletionRoutine( Irp,
DispatchReadCompletion,
NULL,
TRUE,
TRUE,
TRUE);

status = IoCallDriver( nextDrvThingy, Irp );

What do I do with the old Irp?

Okay. Enough of that.

How do I get the read buffer? My DispatchRead() routine will, of course, NOT have the read buffer. It might have information barely useful to what I need, but it doesn’t. I’ve created the DispatchReadCompletion() and successfully looked at ALL of the Irp->UserBuffer values returning, and they’re worthless.

Now, I’ve actually looked at this forum for this answer, and I’m all the more confused. People say to do the following:

IoAllocateMdl()
MmProbeAndLockPages()

And that’s about it. Wait, I also read I need to make the Irp pending for some reason.

As a big-time n00b, this stuff has confused me. Do I do this in my read dispatch routine?

Irp->MdlAddress = IoAllocateMdl()?

For all I’ve used Google until my eyes are bleeding, I can’t figure out what the heck I need to do to succesfully allocate an Mdl. Right now, I’m creating a buffer using ExAllocatePoolWithTag() and sending that buffer into the IoAllocateMdl() function

Wait, I found it, I also need to MmGetSystemAddressForMdlSafe() in my DispatchReadCompletion(), right?

None of this makes any sense to me.

First off, if I try to do this, it bombs most of the time:

Irp->MdlAddress = IoAllocateMdl(Irp->UserBuffer, strlen(Irp->UserBuffer), TRUE, FALSE, Irp);
if (Irp->MdlAddress != NULL)
{
try
{
MmProbeAndLockPages(Irp->MdlAddress, KernelMode, IoModifyAccess);
}
except (EXCEPTION_EXECUTE_HANDLER)
{
status = STATUS_ACCESS_VIOLATION;
}
}

…which is… I think… the gist of what I’ve read so far.

I would appreciate any help.

> Question on this: I noticed in-situ encryption is listed as a big “no no”
here.

Surely, since you will spoil the app’s data buffer. The app does not expect
that write() will make updates to its data buffer.

Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
xxxxx@storagecraft.com
http://www.storagecraft.com

why are you using “strlen(Irp->UserBuffer),” this is string function, will need a null terminated string and also will BSOD as DISPATCH_LEVEL

Well, here’s my actual code at this point:

DispatchRead()

if ( (Irp->RequestorMode == UserMode) && (Irp->UserBuffer != NULL) && (Irp->IoStatus.Information > 0) )
{
Irp->MdlAddress = IoAllocateMdl(Irp->UserBuffer, Irp->IoStatus.Information, TRUE, FALSE, Irp);
if (Irp->MdlAddress != NULL)
{
try
{
MmProbeAndLockPages(Irp->MdlAddress, UserMode, IoReadAccess);
}
except (EXCEPTION_EXECUTE_HANDLER)
{
status = STATUS_ACCESS_VIOLATION;
}
}

}

DispatchReadCompletion()

if (Irp->MdlAddress != NULL)
{
Irp->UserBuffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
}

I set my breakpoint as follows:

bp

"dc poi(esi+3c);dc;dc;g"

and see nothing of interest in the Irp->UserBuffer returned via that mmXXX call in the completion routine.

Maxim:
Actually, since I’m filtering for the fact I’m writing to a txt file, etc, it works really well for notepad.exe on a txt file.

Wordpad and Word would be different, because the apps write out more than pure text. however, i expect it would work the same.

Interestinly enough, right now, I’m using a simple XOR on the letter ‘R’ to “encrypt”. It’s symmetric, so if I open a text document in notepad, save out “hello daniel” it will encrypt. I can open it back up and it will be encrypted (sort of… XOR). Then, I save it again, close. When i open again, it’s decrypted.

While that’s fun, I still don’t have a clue what a *good* kernel mode driver filter system thingy guy would do if they were going to create an Irp and send it down the pipe still. Like, am "splitting’ the irp? Do I send down the first one that has the unencrypted data and a second Irp i birth using the IoGiveBirthToAnIrp() function and send my new baby down after it?

Not speaking about how hard is the encryption filter even for
FS filter veterans (so almost impossible to do for newbies),
there’s at least one problem in your code:

Irp->MdlAddress = IoAllocateMdl(Irp->UserBuffer,
Irp->IoStatus.Information, TRUE, FALSE, Irp);

Number of bytes *to read* is stored in the IO_STACK_LOCATION,
not in Irp->IoStatus.

L.

----- Original Message -----
From:
To: “Windows File Systems Devs Interest List”
Sent: Thursday, November 02, 2006 1:49 AM
Subject: RE:[ntfsd] Where is my read buffer?

> Well, here’s my actual code at this point:
>
> DispatchRead()
>
> if ( (Irp->RequestorMode == UserMode) && (Irp->UserBuffer != NULL) &&
> (Irp->IoStatus.Information > 0) )
> {
> Irp->MdlAddress = IoAllocateMdl(Irp->UserBuffer,
> Irp->IoStatus.Information, TRUE, FALSE, Irp);
> if (Irp->MdlAddress != NULL)
> {
> try
> {
> MmProbeAndLockPages(Irp->MdlAddress, UserMode, IoReadAccess);
> }
> except (EXCEPTION_EXECUTE_HANDLER)
> {
> status = STATUS_ACCESS_VIOLATION;
> }
> }
>
> }
>
> DispatchReadCompletion()
>
> if (Irp->MdlAddress != NULL)
> {
> Irp->UserBuffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress,
> NormalPagePriority);
> }
>
> I set my breakpoint as follows:
>
> bp “dc poi(esi+3c);dc;dc;g”
>
> and see nothing of interest in the Irp->UserBuffer returned via that mmXXX
> call in the completion routine.
>
>
> —
> Questions? First check the IFS FAQ at
> https://www.osronline.com/article.cfm?id=17
>
> You are currently subscribed to ntfsd as: xxxxx@volny.cz
> To unsubscribe send a blank email to xxxxx@lists.osr.com
>

Thanks. As you can see, I have no real feel for this. I’m guessing that using the Irp->UserBuffer is not correct either.

I can not find any documentation that tells me what I should be using for the IoAllocateMdl(virtual_address,…) piece. Do I pre-allocate a buffer and pass that in? Any Buffer of size irpSp->Parameters.Read.Length?

One note: There’s little to no documentation on writing a encryption filter (which could be related to Anti-Virus software, etc.). What I have seen are many of the same questions with very few answers.

I know this can be done – it *is* done.

However, it seems getting the details is nigh impossible. Why is that?

Your read buffer is here
__try{
if (Irp->Flags & DO_BUFFERED_IO){
pData = Irp->AssociatedIrp.SystemBuffer;
}else if (Irp->MdlAddress){pData = MmGetSystemAddressForMdlSafe(
Irp->MdlAddress, HighPagePriority);
}else if (Irp->UserBuffer ){
pData = Irp->UserBuffer;
}
}__except(EXCEPTION_EXECUTE_HANDLER){

}

The length is IrpSp->Parameters.Read.Length, offset in file
IrpSp->Parameters.Read.ByteOffset.

So you must do decryption on post-read operation. To do this you need:

NTSTATUS
ReadDispatcher (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
KEVENT event;

////…
///here is your code
////…

IoCopyCurrentIrpStackLocationToNext( Irp );
KeInitializeEvent( &event, NotificationEvent, FALSE );

IoSetCompletionRoutine(Irp,
WaitCompletion,
&event,
TRUE,
TRUE,
TRUE);

Status = IoCallDriver(TargetDevice, Irp );

if (STATUS_PENDING == Status) {
KeWaitForSingleObject( &event,
Executive,
KernelMode,
FALSE,
NULL );
Status = Irp->IoStatus.Status;
}
If (NT_SUCCES(status))
{
//here you can do the decryption of pData
}

IoCompleteRequest( Irp, IO_NO_INCREMENT );
return status;

}//ReadDispatcher

The code of WaitCompeltion:

NTSTATUS
WaitCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
PKEVENT pEvent = Context;
UNREFERENCED_PARAMETER(Irp);
UNREFERENCED_PARAMETER(DeviceObject);
KeSetEvent( pEvent, IO_NO_INCREMENT, FALSE );
return STATUS_MORE_PROCESSING_REQUIRED;
}

For write operation you need to copy the original buffer stored in pData,
before call IoCallDriver encrypt buffer and after on post-write copy
backuped buffer to pData.

It is that you need to do.

Andrey Gunko
soft Xpansion Ukraine Ltd.
Programmer
Powered by eKnow-how
Artjoma St. 118B … 83048 Donetsk … Tel/Fax: +38 062 3818874 …
Internet: [www.soft-xpansion.com]

|-----Original Message-----
|From: xxxxx@lists.osr.com [mailto:bounce-268663-
|xxxxx@lists.osr.com] On Behalf Of xxxxx@hotmail.com
|Sent: Thursday, November 02, 2006 5:02 PM
|To: Windows File Systems Devs Interest List
|Subject: RE:[ntfsd] Where is my read buffer?
|
|Thanks. As you can see, I have no real feel for this. I’m guessing that
|using the Irp->UserBuffer is not correct either.
|
|I can not find any documentation that tells me what I should be using for
|the IoAllocateMdl(virtual_address,…) piece. Do I pre-allocate a buffer
|and pass that in? Any Buffer of size irpSp->Parameters.Read.Length?
|
|
|—
|Questions? First check the IFS FAQ at
|https://www.osronline.com/article.cfm?id=17
|
|You are currently subscribed to ntfsd as: xxxxx@maus.donetsk.ua
|To unsubscribe send a blank email to xxxxx@lists.osr.com

Search throw this list and you find a lot of information but…
It is very hard to write encryption filter that will work in any cases. If
you start to filter read/write operations you’ll see that there would be
several operations with the same buffer(even the same buffer address),
length and the same offset in file and you will need to decide in what case
to decrypt (on read) or encrypt (on write) the buffer (if you don’t want to
encrypt/decrypt the buffer several times too). And this decision is very
hard. The only way is to write filter that acts like a file system and
stands above the original FS.

Andrey Gunko
soft Xpansion Ukraine Ltd.
Programmer
Powered by eKnow-how
Artjoma St. 118B … 83048 Donetsk … Tel/Fax: +38 062 3818874 …
Internet: [www.soft-xpansion.com]

|-----Original Message-----
|From: xxxxx@lists.osr.com [mailto:bounce-268668-
|xxxxx@lists.osr.com] On Behalf Of xxxxx@hotmail.com
|Sent: Thursday, November 02, 2006 5:18 PM
|To: Windows File Systems Devs Interest List
|Subject: RE:[ntfsd] Where is my read buffer?
|
|One note: There’s little to no documentation on writing a encryption
|filter (which could be related to Anti-Virus software, etc.). What I have
|seen are many of the same questions with very few answers.
|
|I know this can be done – it *is* done.
|
|However, it seems getting the details is nigh impossible. Why is that?
|
|—
|Questions? First check the IFS FAQ at
|https://www.osronline.com/article.cfm?id=17
|
|You are currently subscribed to ntfsd as: xxxxx@maus.donetsk.ua
|To unsubscribe send a blank email to xxxxx@lists.osr.com

> One note: There’s little to no documentation on writing a encryption

filter
(which could be related to Anti-Virus software, etc.). What I have seen
are many of the same questions with very few answers.

No one says there must be a documentation on this.
Companies who did such complicated task usually
keep that knowledge secret.

However, it seems getting the details is nigh impossible. Why is that?

I think, the reason is in too many vague rules in the FS world.
There’s too many maybe’s, buts or must-nots in the the rules for
file systems. Example: Several file systems do caching by one way
(local ones), another do it quite differently (network ones).

L.

I figured companies who’ve figured this out would want to keep it secret. It’s tough.

Okay, here’s my code right now (thank you VERY much Andrey!!!):

NTSTATUS
RRIFSDispatchRead (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
NTSTATUS status = STATUS_SUCCESS;
KEVENT waitEvent;
PVOID pData = NULL;

IoCopyCurrentIrpStackLocationToNext( Irp );
KeInitializeEvent( &waitEvent, NotificationEvent, FALSE );
IoSetCompletionRoutine( Irp,
RRIFSDispatchReadCompletion,
&waitEvent,
TRUE,
TRUE,
TRUE);
status = IoCallDriver( ((PRRIFSFILTER_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->NLExtHeader.AttachedToDeviceObject, Irp );

if (STATUS_PENDING == status)
{
KeWaitForSingleObject( &waitEvent, Executive, KernelMode, FALSE, NULL );
status = Irp->IoStatus.Status;
}

if (status == STATUS_SUCCESS)
{
RRIFS_LOG_PRINT(RRIFSDEBUG_TRACE_READFILE_OPS, (“READ:::: Do Decryption Here!!!\n”));
__try
{
if (Irp->Flags & DO_BUFFERED_IO)
{
pData = Irp->AssociatedIrp.SystemBuffer;
}
else if (Irp->MdlAddress)
{
pData = MmGetSystemAddressForMdlSafe( Irp->MdlAddress, HighPagePriority);
}else if (Irp->UserBuffer )
{
pData = Irp->UserBuffer;
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
status = STATUS_ACCESS_VIOLATION;
}
}

IoCompleteRequest( Irp, IO_NO_INCREMENT );

return status;

}

NTSTATUS
RRIFSDispatchReadCompletion (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
NTSTATUS status = STATUS_SUCCESS;
PKEVENT pEvent = Context;

UNREFERENCED_FORMAL_PARAMETER(DeviceObject);
UNREFERENCED_FORMAL_PARAMETER(Irp);

KeSetEvent( pEvent, IO_NO_INCREMENT, FALSE );
return STATUS_MORE_PROCESSING_REQUIRED;
}

Remember, it’s based off of the filter in the IFS. Anyway, the pData buffer returned via the if/else clause in the read dispatch function returns as EAX.

Setting a breakpoint at the IoCompleteRequest() function such that:

bp rrifsdriver!RRIFSDispatchRead+0x1fd “dc eax;dc;dc;g”

Opening a .txt file in NOTEPAD.EXE that contains the text:

Hello World!!!
xxxxxxxxxxxxx

I should see this string in one of the returned EAX buffers, eventually, right?

I don’t.

Why am I not seeing the exptected text?

Thanks!

One thing I’ve noted in the code above is I’m not locking any MDL’s or anything like that per MmProbeAndLockPages (). Do I still need to do that in some fashion.

At least this code doesn’t blue screen like my attempts to create a MDL buffer did earlier. Likewise, this code seems to make more sense. Thanks again.

> if (Irp->Flags & DO_BUFFERED_IO){

You’re interpreting Irp Flags with a device object constant. DO_BUFFERED_IO
= 0x4, which is IRP_SYNCHRONOUS_API in the Irp Flags field. IRP_BUFFERED_IO
is 0x10.

This is quite broken.

  • Dan.

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Gunko Andrey
Sent: Thursday, November 02, 2006 8:48 AM
To: Windows File Systems Devs Interest List
Subject: RE: [ntfsd] Where is my read buffer?

Your read buffer is here
__try{
if (Irp->Flags & DO_BUFFERED_IO){
pData = Irp->AssociatedIrp.SystemBuffer;
}else if (Irp->MdlAddress){pData = MmGetSystemAddressForMdlSafe(
Irp->MdlAddress, HighPagePriority);
}else if (Irp->UserBuffer ){
pData = Irp->UserBuffer;
}
}__except(EXCEPTION_EXECUTE_HANDLER){

}

The length is IrpSp->Parameters.Read.Length, offset in file
IrpSp->Parameters.Read.ByteOffset.

So you must do decryption on post-read operation. To do this you need:

NTSTATUS
ReadDispatcher (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
KEVENT event;

////…
///here is your code
////…

IoCopyCurrentIrpStackLocationToNext( Irp );
KeInitializeEvent( &event, NotificationEvent, FALSE );

IoSetCompletionRoutine(Irp,
WaitCompletion,
&event,
TRUE,
TRUE,
TRUE);

Status = IoCallDriver(TargetDevice, Irp );

if (STATUS_PENDING == Status) {
KeWaitForSingleObject( &event,
Executive,
KernelMode,
FALSE,
NULL );
Status = Irp->IoStatus.Status;
}
If (NT_SUCCES(status))
{
//here you can do the decryption of pData
}

IoCompleteRequest( Irp, IO_NO_INCREMENT );
return status;

}//ReadDispatcher

The code of WaitCompeltion:

NTSTATUS
WaitCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
PKEVENT pEvent = Context;
UNREFERENCED_PARAMETER(Irp);
UNREFERENCED_PARAMETER(DeviceObject);
KeSetEvent( pEvent, IO_NO_INCREMENT, FALSE );
return STATUS_MORE_PROCESSING_REQUIRED;
}

For write operation you need to copy the original buffer stored in pData,
before call IoCallDriver encrypt buffer and after on post-write copy
backuped buffer to pData.

It is that you need to do.

Andrey Gunko
soft Xpansion Ukraine Ltd.
Programmer
Powered by eKnow-how
Artjoma St. 118B … 83048 Donetsk … Tel/Fax: +38 062 3818874 …
Internet: [www.soft-xpansion.com]

|-----Original Message-----
|From: xxxxx@lists.osr.com [mailto:bounce-268663-
|xxxxx@lists.osr.com] On Behalf Of xxxxx@hotmail.com
|Sent: Thursday, November 02, 2006 5:02 PM
|To: Windows File Systems Devs Interest List
|Subject: RE:[ntfsd] Where is my read buffer?
|
|Thanks. As you can see, I have no real feel for this. I’m guessing
|that using the Irp->UserBuffer is not correct either.
|
|I can not find any documentation that tells me what I should be using
|for the IoAllocateMdl(virtual_address,…) piece. Do I pre-allocate a
|buffer and pass that in? Any Buffer of size
|irpSp->Parameters.Read.Length?
|
|
|—
|Questions? First check the IFS FAQ at
|https://www.osronline.com/article.cfm?id=17
|
|You are currently subscribed to ntfsd as: xxxxx@maus.donetsk.ua To
|unsubscribe send a blank email to xxxxx@lists.osr.com


Questions? First check the IFS FAQ at
https://www.osronline.com/article.cfm?id=17

You are currently subscribed to ntfsd as: xxxxx@privtek.com
To unsubscribe send a blank email to xxxxx@lists.osr.com

Yeah, Actually, I wondered about the DO_BUFFERED_IO business, but since I’m really a newb…

Anyway, it’s still not showing anything useful in the buffer returned.

Am I missing something?

Well by using Notepad you are facing a problem everybody who did a fs filter
faced once: mapped files. Notepad doesn’t do read/write to the files, it maps
them. To filter properly a file system you need to do several different things
besides ciphering during writing and deciphering whilst reading. It’s
unfortunately a bit more complex, mainly because of the tight relationship of
the cache manager with the VMM (and also because there is a worldwide
conspiracy to prevent people from writing drivers).

First of all you need to have a system that will be able to associate all
FILE_OBJECT related to a file. Otherwise you will miss the queries from
FILE_OBJECT created by the OS itself (to put it simple), because these
FILE_OBJECT are never caught in IRP_MJ_CREATE. This system can be a collection
being able to relate a given FCB (File Control Block) to a FILE_OBJECT. This
structure is found at FILE_OBJECT->FsContext. You maintain the collection by
monitoring most of the IRP_MJ. The more features you offer, the more complex
this “system” is. For cryptography you will also have to associate a
cryptographic context witch each file.

Then you will have to learn how your FS behaves. What is true for a file
system is not for another. For example, you want to filter data that goes to
the disk, not to the cache. If you cipher the cache you are in a world of
pain. This is why you need to know which combination of NO_CACHE, MAPPED,
IRP_OMGWTF, etc. has got the specific meaning you seek.

Thirdly, you need to create some sort of object or a set of functions that
will manage your IRP buffers. You can either forge your own Irps or
temporarily exchange the buffers of the one you receive. The advantage of the
latter is that you save the creation of one Irp. I cannot tell you however if
this has got a positive or negative impact on performances. I would suspect
reusing the Irp is better. Anyways, depending on the type of I/O, you will
have to treat the buffer differently, and don’t forget about Neither I/O.

By the way do you write a minifilter? If not, I would advise to switch to this
model.

EA

For the impossible we need a 48h delay.

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:bounce-268676-
xxxxx@lists.osr.com] On Behalf Of xxxxx@hotmail.com
Sent: Thursday, November 02, 2006 17:36
To: Windows File Systems Devs Interest List
Subject: RE:[ntfsd] Where is my read buffer?

I figured companies who’ve figured this out would want to keep it
secret. It’s tough.

Okay, here’s my code right now (thank you VERY much Andrey!!!):

NTSTATUS
RRIFSDispatchRead (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
NTSTATUS status
= STATUS_SUCCESS;
KEVENT waitEvent;
PVOID pData
= NULL;

IoCopyCurrentIrpStackLocationToNext( Irp );
KeInitializeEvent( &waitEvent, NotificationEvent, FALSE );
IoSetCompletionRoutine( Irp,
RRIFSDispatchReadCompletion,
&waitEvent,
TRUE,
TRUE,
TRUE);
status = IoCallDriver(
((PRRIFSFILTER_DEVICE_EXTENSION)DeviceObject->DeviceExtension)-
>NLExtHeader.AttachedToDeviceObject, Irp );

if (STATUS_PENDING == status)
{
KeWaitForSingleObject( &waitEvent, Executive,
KernelMode, FALSE, NULL );
status = Irp->IoStatus.Status;
}

if (status == STATUS_SUCCESS)
{
RRIFS_LOG_PRINT(RRIFSDEBUG_TRACE_READFILE_OPS,
(“READ:::: Do Decryption Here!!!\n”));
__try
{
if (Irp->Flags & DO_BUFFERED_IO)
{
pData = Irp-
>AssociatedIrp.SystemBuffer;
}
else if (Irp->MdlAddress)
{
pData =
MmGetSystemAddressForMdlSafe( Irp->MdlAddress, HighPagePriority);
}else if (Irp->UserBuffer )
{
pData = Irp->UserBuffer;
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
status = STATUS_ACCESS_VIOLATION;
}
}

IoCompleteRequest( Irp, IO_NO_INCREMENT );

return status;

}

NTSTATUS
RRIFSDispatchReadCompletion (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
NTSTATUS status =
STATUS_SUCCESS;
PKEVENT pEvent = Context;

UNREFERENCED_FORMAL_PARAMETER(DeviceObject);
UNREFERENCED_FORMAL_PARAMETER(Irp);

KeSetEvent( pEvent, IO_NO_INCREMENT, FALSE );
return STATUS_MORE_PROCESSING_REQUIRED; }

Remember, it’s based off of the filter in the IFS. Anyway, the pData
buffer returned via the if/else clause in the read dispatch function
returns as EAX.

Setting a breakpoint at the IoCompleteRequest() function such that:

bp rrifsdriver!RRIFSDispatchRead+0x1fd “dc eax;dc;dc;g”

Opening a .txt file in NOTEPAD.EXE that contains the text:

Hello World!!!
xxxxxxxxxxxxx

I should see this string in one of the returned EAX buffers,
eventually, right?

I don’t.

Why am I not seeing the exptected text?

Thanks!


Questions? First check the IFS FAQ at
https://www.osronline.com/article.cfm?id=17

You are currently subscribed to ntfsd as: xxxxx@fausse.info To
unsubscribe send a blank email to xxxxx@lists.osr.com

Thanks Eduardo.

Okay. I have a LOT to learn still.

Let’s say I stop using notepad as it’s a bad one. I had no idea, btw. Would WordPad be a better one to try?

What I REALLY need, and quickly because we have a “demo” to do in a few short days, is a way to open a doc of some sort in some app, encrypt it, decrypt it, etc.

I don’t need anything fancy NOW. I can do all the fancy stuff later. Yes, I will need a way to manage the encryption key, etc. Right now, I’m doing an XOR on a single character.

I will also need a way to ‘store’ the info that we’ve mucked with this file. I was thinking of the possibilty of using the FSContext2 pointer in the _FILE_OBJECT structure. Is that a good idea?

Thanks for all your help folks!

Ok. First off, I stopped using notepad. I had no idea it would hose me over by using it. Notepad is supposed to be SIMPLE.

I tested with WordPad and I can see the read buffer using Andrey’s technique and using the correct IRP flag test for buffering. I will still need to figure out WHEN to decrypt that IRP, but I think I can do that on my own.

Now, with the write, i want to do it the “right way” where i send down the encrypted buffer but send up the unencrypted. Isn’t that right?

For one, I noted my file system filter driver is already at the top of the irp stack, but still… we want to be correct, so I’ll do this…

In my write dispatch, I have the encrypted buffer and I will exchange the pointers such that Irp->UserBuffer points to the new buffer. I’ll save out the old Irp->UserBuffer pointer and… I’m thinking I’ll pass this into the WriteCompletion routine as the Context variable.

Is that correct?

If I do so, do I need to make a MDL out of it and set the MDL using MmProbeAndLockPages()? Seems I should be concerned that the buffer might go into lala land between the WriteDispatch and the WriteDispatchCompletion routine… or will it?

Thanks.

As I’m coding, I think the write operation is the exact same as the read except I switch the buffers before the IoCallDriver in the WriteDispatch() routine. The WriteDispatchCompletion() is just like the ReadDispatchCompletion(0 and I send the &waitEvent as the context. Right?

All righty-o. I got the buffer and I can decrypt it. I’m also doing the WriteDispatch correctly (as far as I, a n00b, can tell).

How do I pass the unencrypted buffer back up to my application? Wordpad.exe.

Here’re my Read Routines. Please ignore my stupid hacks like allocating and setting a buffer to all X’s. That’s because I was dumping out the filenames to the debugger and it was bombing out on me at times. If I allocated a separate buffer and copy over the memory, it seems to solve it.

I can deal with stuff like this AFTER the demo next week. I just need to show, with some slight robustness, that we’re opening up a file, typing in plain text, closing it, opening it up and it’s still plain text but it was stored encrypted.

Then, hopefully, I won’t get fired. Thanks again all.

NTSTATUS
RRIFSDispatchRead (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
NTSTATUS status = STATUS_SUCCESS;
KEVENT waitEvent;
PVOID pData = NULL;

PFILE_OBJECT oFileObj = NULL;
PNAME_CONTROL pNameControl = NULL;
PRRIFSFILTER_DEVICE_EXTENSION devExt = NULL;
PUNICODE_STRING puString = NULL;
UNICODE_STRING newString;
WCHAR myBigString[255];

BOOLEAN isCached = FALSE;
ULONG i = 0;
ULONG textLen = 0;
char * clearText = NULL;
BOOLEAN gotExt = FALSE;
wchar_t** fileExtension = NULL;

PUNICODE_STRING txtExtension = NULL;
PUNICODE_STRING fileExt = NULL;

fileExtension = ExAllocatePoolWithTag(NonPagedPool, 10, RRIFSFILTER_READ_TAG);
txtExtension = ExAllocatePoolWithTag(NonPagedPool, sizeof(UNICODE_STRING), RRIFSFILTER_READ_TAG);
fileExt = ExAllocatePoolWithTag(NonPagedPool, sizeof(UNICODE_STRING), RRIFSFILTER_READ_TAG);

RtlInitUnicodeString(txtExtension, L".doc");

IoCopyCurrentIrpStackLocationToNext( Irp );
KeInitializeEvent( &waitEvent, NotificationEvent, FALSE );
IoSetCompletionRoutine( Irp,
RRIFSDispatchReadCompletion,
&waitEvent,
TRUE,
TRUE,
TRUE);

status = IoCallDriver( ((PRRIFSFILTER_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->NLExtHeader.AttachedToDeviceObject, Irp );

if (status == STATUS_PENDING)
{
KeWaitForSingleObject( &waitEvent, Executive, KernelMode, FALSE, NULL );
status = Irp->IoStatus.Status;
}

if (status == STATUS_SUCCESS)
{
RRIFS_LOG_PRINT(RRIFSDEBUG_TRACE_READFILE_OPS, (“READ:::: Do Decryption Here!!!\n”));
__try
{
if (Irp->Flags & IRP_BUFFERED_IO)
{
pData = Irp->AssociatedIrp.SystemBuffer;
}
else if (Irp->MdlAddress)
{
pData = MmGetSystemAddressForMdlSafe( Irp->MdlAddress, HighPagePriority);
}
else if (Irp->UserBuffer )
{
pData = Irp->UserBuffer;
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
status = STATUS_ACCESS_VIOLATION;
}
if (Irp->RequestorMode == UserMode)
{
RRIFS_LOG_PRINT(RRIFSDEBUG_TRACE_READFILE_OPS, (“RRIFSDispatchRead – User Mode Processing.\n”));
oFileObj = Irp->Tail.Overlay.OriginalFileObject;
puString = &(oFileObj->FileName);
newString.MaximumLength = 256;
newString.Length = 255;
for ( i = 0; i < 255; i++)
{
myBigString[i] = ‘X’;
}
newString.Buffer = myBigString;
RtlInitUnicodeString(&newString, puString->Buffer);

RRIFS_LOG_PRINT(RRIFSDEBUG_TRACE_READFILE_OPS, (" Read File Name is : %ls\n", newString.Buffer));

gotExt = RetrieveFileExtension(newString.Buffer, fileExtension);

if (gotExt == TRUE)
{
RRIFS_LOG_PRINT(RRIFSDEBUG_TRACE_READFILE_OPS, (" The File Extension for this file is %ls\n", *fileExtension));
RtlInitUnicodeString(fileExt, (PCWSTR)(*fileExtension));
}

if (RtlCompareUnicodeString(fileExt, txtExtension, TRUE) == 0)
{
i = 0;
textLen = strlen(pData);
if (textLen > 1)
{
clearText = ExAllocatePoolWithTag(NonPagedPool, textLen + sizeof(char), RRIFSFILTER_READ_TAG);
for (i = 0 ; i < textLen; i++)
{
*(clearText + i) = *(((char*)(pData) + i)) ^ ‘R’;
}
RRIFS_LOG_PRINT(RRIFSDEBUG_TRACE_READFILE_OPS, (“Cypher Text is %s\n”, (char*)pData));
RRIFS_LOG_PRINT(RRIFSDEBUG_TRACE_READFILE_OPS, (“Original Text is %s\n”, clearText));

}
}

}
Irp->UserBuffer = clearText;

if (clearText != NULL)
ExFreePoolWithTag(clearText, RRIFSFILTER_READ_TAG);

if (fileExtension != NULL)
ExFreePoolWithTag(fileExtension, RRIFSFILTER_READ_TAG);

if (txtExtension != NULL)
ExFreePoolWithTag(txtExtension, RRIFSFILTER_READ_TAG);

if (fileExt != NULL)
ExFreePoolWithTag(fileExt, RRIFSFILTER_READ_TAG);
}

IoCompleteRequest( Irp, IO_NO_INCREMENT );

return status;

}

NTSTATUS
RRIFSDispatchReadCompletion (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
NTSTATUS status = STATUS_SUCCESS;
PKEVENT pEvent = Context;

UNREFERENCED_FORMAL_PARAMETER(DeviceObject);
UNREFERENCED_FORMAL_PARAMETER(Irp);

KeSetEvent( pEvent, IO_NO_INCREMENT, FALSE );
return STATUS_MORE_PROCESSING_REQUIRED;
}