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