WriteFile and receiving IRP_MJ_WRITE with buffer on Irp->UserBuffer

209 Views Asked by At

I am coding a kernel mode driver and pretending to send buffers from userland, I am doing it with DirectIO creating a file and symbolik link on service, and listening for IRP_MJ_WRITE and then sending data from userland with WriteFile.

I am receving everything well so far but I am getting it through MDL from address at Irp->UserBuffer as I am receiving Irp->AssociatedIrp.SystemBuffer and Irp->MdlAddress both NULL. No matter if I set the IO_BUFFERED flag or not.

I am wondering why this behavior as I am looking through the documentation and nothing is explaning this at the minute, and in theory Irp->UserBuffer should be an output buffer.

Could someone explain what's happening here?

The code example is the following:

Initialising driver

...
    // routine for handling write requests
    DriverObject->MajorFunction[IRP_MJ_WRITE] = DriverWrite;

    // Create device
    status = IoCreateDevice(DriverObject, 0, &DEVICE_NAME, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &DriverObject->DeviceObject);
    if (NT_SUCCESS(status))
    {
        DbgPrint("Device %wZ created", DEVICE_NAME);
    }
    else
    {
        DbgPrint("Could not create device %wZ", DEVICE_NAME);
    }

    // Create symbolic link, which is user-visible
    status = IoCreateSymbolicLink(&DEVICE_SYMBOLIC_NAME, &DEVICE_NAME);
    if (NT_SUCCESS(status))
    {
        DbgPrint("Symbolic link %wZ created", DEVICE_SYMBOLIC_NAME);
    }
    else
    {
        DbgPrint("Error creating symbolic link %wZ", DEVICE_SYMBOLIC_NAME);
    }

    DbgPrint("Driver loaded");
    return STATUS_SUCCESS;
...

WriteFile routine from other app in userland

[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr CreateFile(
    string lpFileName,
    uint dwDesiredAccess,
    uint dwShareMode,
    IntPtr lpSecurityAttributes,
    uint dwCreationDisposition,
    uint dwFlagsAndAttributes,
    IntPtr hTemplateFile);

[DllImport("kernel32.dll", SetLastError = true)]
static extern bool WriteFile(
    IntPtr hFile,
    byte[] lpBuffer,
    uint nNumberOfBytesToWrite,
    out uint lpNumberOfBytesWritten,
    IntPtr lpOverlapped);

[DllImport("kernel32.dll", SetLastError = true)]
static extern bool CloseHandle(IntPtr hObject);



IntPtr handle = CreateFile("\\\\.\\SampleDeviceLink", 0x40000000, 0, IntPtr.Zero, 3, 0, IntPtr.Zero);
if (handle.ToInt32() == -1)
{
    Console.WriteLine("Error opening the file");
    return;
}

string frase = "testing stuff";
byte[] data = Encoding.ASCII.GetBytes(frase);

uint bytesWritten;
bool success = WriteFile(handle, data, (uint)data.Length, out bytesWritten, IntPtr.Zero);
if (!success)
{
    Console.WriteLine("Error written the file");
}
else
{
    Console.WriteLine($"Written {bytesWritten}");
}
CloseHandle(handle);

Console.WriteLine("Press any key to close this..");
Console.ReadLine();

Then when executing this I am receiving on DriverWrite function an Irp that has:

Irp->AssociatedIrp.SystemBuffer -> NULL
Irp->MdlAddress -> NULL

But the size of the buffer is ok, obtained in this way:

PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
ULONG bufferSize = irpStack->Parameters.Write.Length;

And if I use the address located at Irp->UserBuffer to get the MDL then I can access the buffer through that; like this:

MDL* mdl = IoAllocateMdl(Irp->UserBuffer, bufferSize, FALSE, FALSE, NULL);
MmProbeAndLockPages(mdl, KernelMode, IoWriteAccess);
PVOID v_buffer = MmGetSystemAddressForMdlSafe(mdl, NormalPagePriority);
// Here v_buffer has what I sent from WriteFile
0

There are 0 best solutions below