windowswinapikerneldrivermsdn

Convert PVOID to ULONG or use PVOID as HANDLE in windows kernel driver


I am trying to convert PVOID to ULONG but it always fails and gives me wrong data and it is also adviced that not to type cast pointer variables to int, ulong or such other data types in msdn like ULONG client = (ULONG) pvoidVar but i tried different techniques and pre defined functions like:

ULONG client = PtrToUlong(pvoidVar);
ULONG client = (ULONG) PtrToUlong(pvoidVar);

What is happening is that i am trying to send client id from a usermode app to kernel driver but the recieving part in kernel driver makes it as PVOID Irp->UserBuffer also it sends process id which i want to use as a HANDLE now now handles are same as PVOID and i thought of using it directly but it still doesn't work like:

HANDLE processID = (HANDLE) Irp->UserBuffer;
HANDLE processID = Irp->UserBUffer;

I have read everywhere and all have adviced to use PtrToUlong and HANDLE is same as PVOID am i wrong? please advice me how to convert PVOID to ULONG or how can i use PVOID as a HANDLE

EDIT---

here is the code for my main driver it doesn't crash but gives me wrong output

#include <ntddk.h>
#include <wdm.h>

#define DEVICE L"\\Device\\TEST"
#define DOSDEVICE L"\\DosDevices\\TEST"

VOID Unload(PDRIVER_OBJECT  DriverObject) {
    UNICODE_STRING DosDeviceName;

    DbgPrint("Driver Unloaded");

    RtlInitUnicodeString(&DosDeviceName, DOSDEVICE);
    IoDeleteSymbolicLink(&DosDeviceName);

    IoDeleteDevice(DriverObject->DeviceObject);
}

NTSTATUS IODispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
    Irp->IoStatus.Status = STATUS_SUCCESS;
    IoCompleteRequest(Irp, IO_NO_INCREMENT);
    return STATUS_SUCCESS;
}

NTSTATUS IOManager(PDEVICE_OBJECT DeviceObject, PIRP Irp) {

    PIO_STACK_LOCATION StackLocation = IoGetCurrentIrpStackLocation(Irp);
    ULONG IRPcode = StackLocation->Parameters.DeviceIoControl.IoControlCode;

            // Here i cannot convert pvoid as ULONG if i try to do that it gives me some other value
    DbgPrint("%lu", (ULONG)Irp->AssociatedIrp.SystemBuffer);


    NTSTATUS ntStatus = STATUS_SUCCESS;
    HANDLE hProcess;
    OBJECT_ATTRIBUTES ObjectAttributes;
    CLIENT_ID ClientId;

            // Here i cannot use pvoid directly as a handle nor cast it as a handle as it fails
    ClientId.UniqueProcess = (HANDLE)Irp->AssociatedIrp.SystemBuffer;
    ClientId.UniqueThread = NULL;

    InitializeObjectAttributes(&ObjectAttributes, NULL, OBJ_INHERIT, NULL, NULL);

    ntStatus = ZwOpenProcess(&hProcess, PROCESS_ALL_ACCESS, &ObjectAttributes, &ClientId);
    if(NT_SUCCESS(ntStatus)) {
        ZwClose(hProcess);
    }

    Irp->IoStatus.Status = STATUS_SUCCESS;
    IoCompleteRequest(Irp, IO_NO_INCREMENT);

    return STATUS_SUCCESS;
}

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegistryPath) {
    NTSTATUS status = STATUS_SUCCESS;
    int uiIndex = 0;
    PDEVICE_OBJECT pDeviceObject = NULL;
    UNICODE_STRING DriverName, DosDeviceName;

    DbgPrint("Driver Loaded");

    RtlInitUnicodeString(&DriverName, DEVICE);
    RtlInitUnicodeString(&DosDeviceName, DOSDEVICE);

    pDriverObject->DriverUnload =  Unload;

    status = IoCreateDevice(pDriverObject, 0, &DriverName, FILE_DEVICE_UNKNOWN, 0, FALSE, &pDeviceObject);

    if (!NT_SUCCESS(status)) {
        DbgPrint("IoCreateDevice failed: %x", status);
        return status;
    }

    status = IoCreateSymbolicLink(&DosDeviceName, &DriverName);

    if (!NT_SUCCESS(status)) {
        IoDeleteDevice(pDeviceObject);
        DbgPrint("IoCreateSymbolicLink failed");
        return status;
    }

    pDriverObject->MajorFunction[IRP_MJ_CREATE] = IODispatch;
    pDriverObject->MajorFunction[IRP_MJ_CLOSE]  = IODispatch;
    pDriverObject->MajorFunction[IRP_MJ_READ]   = IODispatch;
    pDriverObject->MajorFunction[IRP_MJ_WRITE]  = IODispatch;
    pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IOManager;

    return status;

}

here is my user mode app

#define SYSFILE L"C:\\TEST.sys"
#define SERVICENAME L"TEST"

BOOL GetProcessList();
VOID startServ(DWORD processID);

int _cdecl main(void) {
    GetProcessList();
    return 0;
}

BOOL GetProcessList() {
    HANDLE hProcessSnap;
    PROCESSENTRY32 pe32;

    hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hProcessSnap == INVALID_HANDLE_VALUE) {
        printf("CreateTool");
        getchar();
        return(FALSE);
    }

    pe32.dwSize = sizeof(PROCESSENTRY32);

    if(!Process32First(hProcessSnap, &pe32)) {
        CloseHandle(hProcessSnap);
        printf("Process32");
        getchar();
        return(FALSE);
    }

    do {
        if (wcscmp(L"test.exe", pe32.szExeFile) == 0) {
            startServ(pe32.th32ProcessID);
        }

    } while(Process32Next(hProcessSnap, &pe32));

    CloseHandle(hProcessSnap);
    return(TRUE);
}

VOID startServ(DWORD processID) {

    SC_HANDLE hSCManager;
    SC_HANDLE hService;
    SERVICE_STATUS ss;

    hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);

    printf("Load Driver\n");

    if(hSCManager)
    {
        printf("Create Service\n");

        hService = CreateService(hSCManager, SERVICENAME, 
            SERVICENAME, 
            SERVICE_ALL_ACCESS, 
            SERVICE_KERNEL_DRIVER,
            SERVICE_DEMAND_START, 
            SERVICE_ERROR_IGNORE, 
            SYS_FILE, 
            NULL, NULL, NULL, NULL, NULL);

        printf("CreateService: %d\r\n", GetLastError());

        if(!hService) {
            hService = OpenService(hSCManager, SERVICENAME, SERVICE_ALL_ACCESS);
        }

        printf("OpenService: %d\r\n", GetLastError());

        if(hService) {
            printf("Start Service\n");

            StartService(hService, 0, NULL);

            printf("StartService: %d\r\n", GetLastError());

            HANDLE hFile;

            hFile = CreateFile(L"\\\\.\\Global\\TEST\0", GENERIC_READ|GENERIC_WRITE, 0, NULL,
                OPEN_EXISTING, 0, NULL);

            printf("CreateFile: %d\r\n", GetLastError());

            wchar_t pid[1024];

            wsprintf(pid, L"%d", processID);

            if(hFile) {
                char ret[1024];
                DWORD bytes;

                DeviceIoControl(hFile, 4092, pid, (wcslen(pid)+1)*2, &ret, sizeof(ret), &bytes, NULL); 
                CloseHandle(hFile);
            }

            printf("Press Enter to close service\r\n");
            getchar();
            ControlService(hService, SERVICE_CONTROL_STOP, &ss);

            DeleteService(hService);

            CloseServiceHandle(hService);

        }

        CloseServiceHandle(hSCManager);
    }

}

Now all this doesn't crash or break or give me blue screen but it gives me the wrong output in the driver how ever if i do not cast it and use it as PVOID only then it gives me the correct output


Solution

  • You have missed a pointer dereference:

    HANDLE processID = *(HANDLE*)Irp->UserBuffer;
    

    Also pay attention that sizeof(HANDLE) depends on a process bitness, so it is better to use fixed size types. For PID/TID values 32-bit is enough.

    Update:

    Also you are passing a string representation of the PID. Use a binary form:

    DeviceIoControl(hFile, 4092, &processID, sizeof(processID)