c++cwindowsdriverwdf

Calling WDF driver from c++


I've been trying to call a sample driver. I have written DriverEntry method, where I initialize both the driver name and symbolic ling pointing to the driver.

// UNICODE_STRING DriverName, SymbolName; // Driver registry paths
...
    // Driver Entrypoint
    NTSTATUS
    DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegistryPath) {
  Q_UNUSED(pRegistryPath);

  DbgPrintEx(0, 0, "Driver Loaded\n");

  // The PsSetLoadImageNotifyRoutine routine registers a driver-supplied
  // callback that is subsequently notified whenever
  // an image is loaded (or mapped into memory).
  PsSetLoadImageNotifyRoutine(ImageLoadCallback);

  // initialize driver name
  RtlInitUnicodeString(&DriverName, L"\\Device\\Explorer");
  // initialize symbolic link
  RtlInitUnicodeString(&SymbolName, L"\\DosDevices\\Explorer");

  IoCreateDevice(pDriverObject, 0, &SymbolName, FILE_DEVICE_UNKNOWN,
                 FILE_DEVICE_SECURE_OPEN, FALSE, &pDeviceObject);
  IoCreateSymbolicLink(&DriverName, &SymbolName);

  pDriverObject->MajorFunction[IRP_MJ_CREATE] = CreateCall;
  pDriverObject->MajorFunction[IRP_MJ_CLOSE] = CloseCall;
  pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IoControl;
  pDriverObject->DriverUnload = UnloadDriver;

  pDeviceObject->Flags |= DO_DIRECT_IO;
  pDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;

  return STATUS_SUCCESS;
}

When I load the driver up (using OSR Driver Loader, could be done using cmd also, by registering the driver as a new service), I get expected output in DebugView (sysinternals tool allowing to see kernel debug logs)

enter image description here

Now I needed to make sure that both the device and symlink are present in Windows Object Directories. To do that, I use WinObj (another tool from sysinternals), here is the output

What confuses me here, is that the symbolic link is in Device folder, instead of GLOBAL??. Symbolic link in Device enter image description here

Device in GLOBAL??

enter image description here

Now, finally, calling the driver itself. I use c++ for that purpose and this is my code,

class Test
{
public:
HANDLE hDriver; // Handle to driver

                // Initializer
Test::Test(LPCSTR RegistryPath)
{
    LPCSTR path = "\\\\.\\Explorer";
    hDriver = CreateFileA(path, GENERIC_READ | GENERIC_WRITE,
        FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);


    if (hDriver == INVALID_HANDLE_VALUE)
    {
        //  Handle the error.
        char result = GetLastError();
        bool zadek = false;
    }
}

The problem is that I can't get a valid handle for the driver. The value of hDriver is always either 0x00000000000000a0 or 0xffffffff, no matter the path I use. I'm using createFileA because I want to access system memory.

Is there some blatant mistake I made?


Solution

  • I should say it is over 8-9 year since last time I written a device driver, but what comes off the top of my head are:

    1. You say you get 0xa0 for hDriver which is a valid handle value.
    2. Right now, you can only use device IO control, because you only have callback for IRP_MJ_DEVICE_CONTROL.
    3. Try L"\\??\\Explorer" or L"\\GLOBAL??\\Explorer" for symbolic link.
    4. You need to use DriverName for IoCreateDevice.
    5. You are passing incorrect arguments to IoCreateSymbolicLink.

    So your code should become like this:

    ...
    // initialize driver name
    RtlInitUnicodeString(&DriverName, L"\\Device\\Explorer");
    // initialize symbolic link
    RtlInitUnicodeString(&SymbolName, L"\\??\\Explorer");
    
    IoCreateDevice(pDriverObject, 0, &DriverName, FILE_DEVICE_UNKNOWN,
                     FILE_DEVICE_SECURE_OPEN, FALSE, &pDeviceObject);
    IoCreateSymbolicLink(&SymbolName, &DriverName);
    ...