驱动中DriverObject指定的MajorFunction调用形式及IRP_MJ_WRITE调用方法问询
Alright, let's break this down clearly for you. First, let's clarify how those MajorFunction handlers get invoked, then we'll cover exactly how to trigger your IRP_MJ_WRITE handler, and throw in some concrete examples to make it tangible.
一、How MajorFunction Handlers Are Invoked
The functions you assigned to DriverObject->MajorFunction aren't meant to be called directly by your code. They're callback functions triggered by the Windows I/O Manager. Here's the flow:
- When an I/O request (like a write operation) is initiated (from user mode or kernel mode), the I/O Manager constructs an IRP (I/O Request Packet) that describes the request.
- The I/O Manager looks up the
MajorFunctioncode in the IRP (e.g.,IRP_MJ_WRITE), then fetches the corresponding function pointer from your driver'sDriverObject. - It then invokes your handler (in this case,
ctlDevicePut) to process the IRP.
So you don't "call" these handlers directly—you trigger them by sending valid I/O requests to your driver's device.
二、Triggering IRP_MJ_WRITE (Your ctlDevicePut Handler)
There are two main ways to trigger a write request to your driver: from user mode, or from kernel mode. Here are examples for both:
1. User-Mode Trigger (Most Common)
Use standard Win32 APIs like CreateFile to open your driver's device, then WriteFile to send a write request. This will automatically trigger the IRP_MJ_WRITE handler in your driver.
#include <windows.h> #include <iostream> int main() { // Replace with your driver's device name (matches what you set in IoCreateDevice) LPCWSTR devicePath = L"\\\\.\\YourDeviceSymbolicLink"; // Open the driver device HANDLE hDevice = CreateFile( devicePath, GENERIC_WRITE, // Request write access 0, // No shared access NULL, // Default security attributes OPEN_EXISTING, // Open existing device FILE_ATTRIBUTE_NORMAL, // Standard attributes NULL // No template file ); if (hDevice == INVALID_HANDLE_VALUE) { std::cout << "Failed to open device. Error code: " << GetLastError() << std::endl; return 1; } // Data to write to the driver const char* writeData = "Hello from user mode to driver!"; DWORD bytesWritten = 0; // Send write request BOOL writeSuccess = WriteFile( hDevice, writeData, strlen(writeData), // Length of data to write &bytesWritten, // Output: bytes actually written NULL // No overlapped I/O ); if (writeSuccess) { std::cout << "Successfully wrote " << bytesWritten << " bytes to driver." << std::endl; } else { std::cout << "WriteFile failed. Error code: " << GetLastError() << std::endl; } // Cleanup CloseHandle(hDevice); return 0; }
2. Kernel-Mode Trigger
If you need to send a write request from another kernel-mode driver, you can use ZwWriteFile (simpler) or manually construct and send an IRP (more low-level).
Example with ZwWriteFile:
NTSTATUS TriggerDriverWrite(PDEVICE_OBJECT targetDevice) { NTSTATUS status; HANDLE deviceHandle; OBJECT_ATTRIBUTES objAttr; IO_STATUS_BLOCK ioStatus; // Initialize object attributes for the target device InitializeObjectAttributes( &objAttr, &targetDevice->DeviceName, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL ); // Open the target device status = ZwCreateFile( &deviceHandle, GENERIC_WRITE, &objAttr, &ioStatus, NULL, FILE_ATTRIBUTE_NORMAL, 0, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0 ); if (!NT_SUCCESS(status)) { return status; } // Data to write CHAR writeBuffer[] = "Hello from kernel mode to driver!"; ULONG bufferSize = sizeof(writeBuffer); // Send write request status = ZwWriteFile( deviceHandle, NULL, // No event NULL, // No APC routine NULL, // No context &ioStatus, writeBuffer, bufferSize, NULL, // No byte offset (adjust if your driver uses it) NULL // No key ); // Cleanup ZwClose(deviceHandle); return status; }
三、Debugging Tip: Why You Can't Find the "Call Location"
Your debugger won't show a direct function call to ctlDevicePut because the I/O Manager invokes it via a function pointer stored in DriverObject->MajorFunction[IRP_MJ_WRITE]. Instead of looking for a caller:
- Set a breakpoint directly on
ctlDevicePut(in WinDbg, usebp ctlDevicePut). - When you trigger a write request (using the examples above), the debugger will break into your handler.
- Check the call stack—you'll see I/O Manager functions (like
IofCallDriverorNtWriteFile) at the top, which are responsible for invoking your handler.
内容的提问来源于stack exchange,提问作者szefitoo

