Intro
I have this solution.
MNWE - (Minimum Non-Working Example)
ChatGPT gave me the following test app:
#include <windows.h>
#include <stdio.h>
#define DEVICE_PATH "\\\\.\\MemoryGraveyard"
#define BUFF_SIZE 1024
__declspec(align(512)) BYTE readBuffer[BUFF_SIZE];
void readWithOverlapped(HANDLE device, DWORD offset, DWORD length) {
OVERLAPPED overlapped = { 0 };
overlapped.Offset = offset;
overlapped.OffsetHigh = 0;
DWORD bytesRead = 0;
printf("[INFO] Reading with OVERLAPPED (offset: %u, length: %u)\n", offset, length);
BOOL success = ReadFile(
device,
readBuffer,
length,
&bytesRead,
&overlapped);
if (!success) {
DWORD err = GetLastError();
if (err == ERROR_IO_PENDING) {
// Wait for the async I/O to complete
if (GetOverlappedResult(device, &overlapped, &bytesRead, TRUE)) {
printf("[OK] Read %lu bytes: '%.*s'\n", bytesRead, bytesRead, readBuffer);
}
else {
printf("[ERROR] GetOverlappedResult failed: %lu\n", GetLastError());
}
}
else {
printf("[ERROR] ReadFile (OVERLAPPED) failed: %lu\n", err);
}
}
else {
printf("[OK] Read %lu bytes: '%.*s'\n", bytesRead, bytesRead, readBuffer);
}
}
void readWithSetFilePointer(HANDLE device, DWORD offset, DWORD length) {
LARGE_INTEGER li;
li.QuadPart = offset;
DWORD bytesRead = 0;
printf("[INFO] Reading with SetFilePointerEx (offset: %u, length: %u)\n", offset, length);
if (!SetFilePointerEx(device, li, NULL, FILE_BEGIN)) {
printf("[ERROR] SetFilePointerEx failed: %lu\n", GetLastError());
return;
}
BOOL success = ReadFile(
device,
readBuffer,
length,
&bytesRead,
NULL);
if (!success) {
printf("[ERROR] ReadFile failed: %lu\n", GetLastError());
return;
}
printf("[OK] Read %lu bytes: '%.*s'\n", bytesRead, bytesRead, readBuffer);
}
int main() {
HANDLE device = CreateFileA(
DEVICE_PATH,
GENERIC_READ,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, // needed for OVERLAPPED I/O
NULL);
if (device == INVALID_HANDLE_VALUE) {
printf("[ERROR] Failed to open device: %lu\n", GetLastError());
return 1;
}
printf("[INFO] Device opened successfully.\n");
// Example usage
readWithOverlapped(device, 0, 16);
readWithSetFilePointer(device, 32, 16);
CloseHandle(device);
return 0;
}
Needless to say, I get:
[INFO] Device opened successfully.
[INFO] Reading with OVERLAPPED (offset: 0, length: 16)
[ERROR] ReadFile (OVERLAPPED) failed: 87
[INFO] Reading with SetFilePointerEx (offset: 32, length: 16)
[ERROR] SetFilePointerEx failed: 1
My driver code is:
#include <ntddk.h>
/*
This device driver is not supposed to synchronize access to the graveyard buffer.
Also, it is not supposed to initialize the graveyard.
*/
#define BUFF_SIZE 1024
static char graveyard[BUFF_SIZE];
// Marks the Irp as completed and returns an error status for bad parameters:
static NTSTATUS badParamsReturn(PIRP Irp) {
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_INVALID_PARAMETER;
}
// Marks the Irp as completed and returns a normal status with transferred bytes:
static NTSTATUS normalReturn(PIRP Irp,
ULONG transferred = 0) {
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = transferred;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
// Checks if the parameters are valid:
static bool badParams(PVOID userBuffer,
ULONGLONG offsetBytes,
ULONG lengthBytes) {
if (userBuffer == nullptr || lengthBytes == 0) return true;
// The size of the graveyard buffer:
ULONGLONG graveyardSize = sizeof(graveyard);
if (offsetBytes >= graveyardSize) {
return true;
}
return lengthBytes > graveyardSize - offsetBytes;
}
// Read handler:
static void serveReadRequest(PVOID userBuffer,
ULONGLONG offset,
ULONG length) {
RtlCopyMemory(userBuffer,
&graveyard[(size_t) offset],
length);
}
// Write handler:
static void serveWriteRequest(PVOID userBuffer,
ULONGLONG offset,
ULONG length) {
RtlCopyMemory(&graveyard[(size_t) offset],
userBuffer,
length);
}
// The read handler for the driver:
NTSTATUS MyRead(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp) {
UNREFERENCED_PARAMETER(DeviceObject);
auto stack = IoGetCurrentIrpStackLocation(Irp);
auto length = stack->Parameters.Read.Length;
auto offset = stack->Parameters.Read.ByteOffset.QuadPart;
DbgPrint("MyRead: offset %llu, length %lu\n",
offset,
length);
PVOID userBuffer = Irp->AssociatedIrp.SystemBuffer;
if (badParams(userBuffer, offset, length)) {
return badParamsReturn(Irp);
}
serveReadRequest(userBuffer,
offset,
length);
return normalReturn(Irp,
length);
}
// The write handler for the driver:
NTSTATUS MyWrite(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp) {
UNREFERENCED_PARAMETER(DeviceObject);
auto stack = IoGetCurrentIrpStackLocation(Irp);
auto length = stack->Parameters.Write.Length;
auto offset = stack->Parameters.Write.ByteOffset.QuadPart;
DbgPrint("MyWrite: offset %llu, length %lu\n",
offset,
length);
PVOID userBuffer = Irp->AssociatedIrp.SystemBuffer;
if (badParams(userBuffer, offset, length)) {
return badParamsReturn(Irp);
}
serveWriteRequest(userBuffer,
offset,
length);
return normalReturn(Irp,
length);
}
NTSTATUS MyCreateClose(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp) {
UNREFERENCED_PARAMETER(DeviceObject);
return normalReturn(Irp);
}
VOID DriverUnload(IN PDRIVER_OBJECT DriverObject) {
UNICODE_STRING symbolicLink = RTL_CONSTANT_STRING(L"\\??\\MemoryGraveyard");
IoDeleteSymbolicLink(&symbolicLink);
IoDeleteDevice(DriverObject->DeviceObject);
DbgPrint("MemoryGraveyard driver unloaded.\n");
}
extern "C" NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) {
UNREFERENCED_PARAMETER(RegistryPath);
UNICODE_STRING deviceName = RTL_CONSTANT_STRING(L"\\Device\\MemoryGraveyard");
UNICODE_STRING symbolicLink = RTL_CONSTANT_STRING(L"\\??\\MemoryGraveyard");
PDEVICE_OBJECT DeviceObject = nullptr;
NTSTATUS status = IoCreateDevice(
DriverObject,
0,
&deviceName,
FILE_DEVICE_UNKNOWN,
0,
FALSE,
&DeviceObject);
if (!NT_SUCCESS(status)) return status;
//DriverObject->Flags |= DO_BUFFERED_IO;
status = IoCreateSymbolicLink(&symbolicLink, &deviceName);
if (!NT_SUCCESS(status)) {
IoDeleteDevice(DeviceObject);
return status;
}
DriverObject->MajorFunction[IRP_MJ_CREATE] = MyCreateClose;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = MyCreateClose;
DriverObject->MajorFunction[IRP_MJ_READ] = MyRead;
DriverObject->MajorFunction[IRP_MJ_WRITE] = MyWrite;
DriverObject->DriverUnload = DriverUnload;
DbgPrint("MemoryGraveyard driver loaded.\n");
return STATUS_SUCCESS;
}
In DriverEntry, I set DriverObject->Flags |= DO_BUFFERED_IO;.
So, I suppose that the fault is in the length/offset parameters, yet I have no idea how to resolve this issue. Any help?
-
4Recommendation: Provide compile-able code. Helping you out effectively may require experimentation, and the more people have to change to run your program the more likely things will go wrong and you'll get answer covering bugs added when filling in the blanks. At the very least you need to add the missing headers.user4581301– user45813012025年06月25日 05:11:52 +00:00Commented Jun 25, 2025 at 5:11
-
@user4581301 Thanks for your attention! Do you suggest to include the full code?coderodde– coderodde2025年06月25日 05:17:09 +00:00Commented Jun 25, 2025 at 5:17
-
4No, provide the minimum possible code to demonstrate the problem. Often the process of creating this leads you to the solution.user207421– user2074212025年06月25日 05:43:39 +00:00Commented Jun 25, 2025 at 5:43
-
1does your request get to your driver? if so, what do you actually want? your driver and returned this error code. you returned an error to yourself. and the driver code, the part of it that processes your request, is incompleteRbMm– RbMm2025年06月25日 07:24:15 +00:00Commented Jun 25, 2025 at 7:24
-
1Side note: Remove the mention of ChatGPT. For a bunch of reasons, a lot of them good, LLM generated stuff, questions and answers, is forbidden here. And what isn't outright banned generally receives a negative response.user4581301– user45813012025年06月25日 16:50:59 +00:00Commented Jun 25, 2025 at 16:50
1 Answer 1
for set Buffered I/O on device need use DeviceObject->Flags |= DO_BUFFERED_IO - set DO_BUFFERED_IO in DeviceObject (not DriverObject ) Flags. but code not do this, as result
Irp->AssociatedIrp.SystemBuffer is always 0. so badParams always return true and you by self return
STATUS_INVALID_PARAMETER . really you need use Irp->UserBuffer instead Irp->AssociatedIrp.SystemBuffer
about why SetFilePointerEx fail. at first this is senseless api, simply direct set read/write offset in
OVERLAPPED
at second in case asynchronous I/O this is double senseless - result ot file offset in FILE_OBJECT not used and we always must direct specify file offset in read/write operation (if this not pipe or mailslot). then, in case asynchronous I/O always need provide direct offset and pointer to
OVERLAPPED
but you not do this. so readWithSetFilePointer is complete wrong. and why exact this error code is returned ? because SetFilePointerEx internal first call FileValidDataLengthInformation - so IRP_MJ_SET_INFORMATION is sent to your driver. but you not implement this. as result STATUS_INVALID_DEVICE_REQUEST is returned, and win32 subsystem mup it to ERROR_INVALID_FUNCTION
Comments
Explore related questions
See similar questions with these tags.