-1

So I am trying to write a minifilter driver which only attaches to specific USB devices, to differentiate said devices I have use the combination of Product ID + Vendor ID + Serial Number.

I can successfully send IOCTL_STORAGE_QUERY_PROPERTY to the device which returns the Product ID,Vendor ID, Serial number.

The issue I have is the serial number which is returned to my minifilter is correct for some USB s but not all.

eg: when i call

C:\Windows\system32>wmic diskdrive get pnpdeviceid PNPDeviceID USBSTOR\DISK&VEN_SONY&PROD_STORAGE_MEDIA&REV_PMAP\5C3000637C2070A595&0 USBSTOR\DISK&VEN_BM&PROD_&REV_1.10\070007AA1F02CF40063F&0

And these are the serial numbers returned from my minifilter :

Serial Number found 57C03A050905. Serial Number found 070007AA1F02CF400630.

As it can be seen that the second device's serial number is successfully returned but not for the first one. So what is the serial number that my minifilter is receiving? Is this stored somewhere which can be queried?

I can attach the code if required but since I get some Serial Numbers correctly i doubt that my code is wrong.

Edit: Code

STORAGE_PROPERTY_QUERY query;
pQuery.PropertyId = StorageDeviceProperty;
pQuery.QueryType = PropertyStandardQuery

KeInitializeEvent(&event, NotificationEvent, FALSE);
Irp = IoBuildDeviceIoControlRequest(IOCTL_STORAGE_QUERY_PROPERTY, pDeviceObject, (PVOID)&query, sizeof(query), infoBuffer,
                                        sizeof(infoBuffer), FALSE, &event, &ioStatusBlock);
if (Irp) {
    if(!NT_SUCCESS(IoCallDriver(pDeviceObject, Irp)))
        return STATUS_FLT_DO_NOT_ATTACH;
}
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
pDescriptor = (PSTORAGE_DEVICE_DESCRIPTOR)infoBuffer;

ULONG offset = pDescriptor->SerialNumberOfffset;
size_t size;
if (offset == 0) 
    return;

PCHAR c = offset + &buffer[0];
size = strlen(c);
*dest = ExAllocatePoolWithTag(PagedPool, size + 1, 'DIcI');
RtlZeroMemory(*dest, size + 1);
RtlCopyMemory(*dest, c, size + 1);

DbgPrint("Serial Number Found %s \n", *dest);
// String comparison of serial number and more processing

tested on my external harddisk and this is what i get from device manager

575834314137363534565656 

and from my minifilter:

WX41A7654VVV 

it seems that the serial number in the device manager is hex representation of the serial number which i got from my minifilter

57 58 34 31 41 37 36 35 34 56 56 56 

W  X  4  1  A  7  6  5  4  V  V  V 

so for some devices it is represented in Hex format while others is Char format?

So is there anyway to get serial number from kernel level or it would just be easier calling a user application?

qwn
  • 347
  • 3
  • 15
  • 1
    `... since I get some Serial Numbers correctly i doubt that my code is wrong` That is a completely wrong way of thinking... Post your code and ask if someone can spot the bug – Support Ukraine Sep 01 '17 at 11:58
  • Edited the orignal post to add code – qwn Sep 01 '17 at 12:15
  • 1
    `infoBuffer, sizeof(infoBuffer)` - this say that you use hard-coded array for `infoBuffer` - this is already error. it size unknown and you need query it in runtime. the correct code - https://stackoverflow.com/a/44656144/6401656 – RbMm Sep 01 '17 at 12:28
  • really code containing many errors. you not check status returned from `IoCallDriver`. however it can be `STATUS_BUFFER_OVERFLOW`. even on `STATUS_SUCCESS` you need check `Size` member of `STORAGE_DEVICE_DESCRIPTOR` and if it greater than your `sizeof(infoBuffer)` you need resend request with tthis `Size` buffer size. call `KeWaitForSingleObject` exist sense only in case `STATUS_PENDING` – RbMm Sep 01 '17 at 12:34
  • And what makes you think the device id contains the exact serial number? The exact format of this string is undocumented AFAIK. – Anders Sep 01 '17 at 12:44

1 Answers1

0

the STORAGE_DEVICE_DESCRIPTOR is variable length structure. after success call IOCTL_STORAGE_QUERY_PROPERTY need

check its Size member to determine the number of bytes the structure actually requires.

but in your code i view infoBuffer, sizeof(infoBuffer) - this mean that you use hard-coded size for STORAGE_DEVICE_DESCRIPTOR.

really need send IOCTL_STORAGE_QUERY_PROPERTY and compare Size member with your OutputBufferLength and if it greater - send IOCTL_STORAGE_QUERY_PROPERTY again with larger OutputBufferLength .

void PrintSerial(PDEVICE_OBJECT DeviceObject)
{
    STORAGE_PROPERTY_QUERY spq = { StorageDeviceProperty, PropertyStandardQuery }; 

    union {
        PVOID buf;
        PSTR psz;
        PSTORAGE_DEVICE_DESCRIPTOR psdd;
    };

    ULONG size = sizeof(STORAGE_DEVICE_DESCRIPTOR) + 0x100;

    NTSTATUS status;

    do 
    {
        status = STATUS_INSUFFICIENT_RESOURCES;

        if (buf = ExAllocatePool(PagedPool, size))
        {
            switch (status = IoControlDevice(DeviceObject, IOCTL_STORAGE_QUERY_PROPERTY, &spq, sizeof(spq), buf, size))
            {
            case STATUS_SUCCESS:
            case STATUS_BUFFER_OVERFLOW:

                if (psdd->Version == sizeof(STORAGE_DEVICE_DESCRIPTOR))
                {
                    if (psdd->Size > size)
                    {
                        size = psdd->Size;
                        status = STATUS_BUFFER_OVERFLOW;
                    }
                    else
                    {
                        if (psdd->SerialNumberOffset)
                        {
                            DbgPrint("SerialNumber = %s\n", psz + psdd->SerialNumberOffset);
                        }
                        else
                        {
                            DbgPrint("SerialNumberOffset==0\n");
                        }
                    }
                }
                else
                {
                    status = STATUS_INVALID_PARAMETER;
                }
                break;
            }

            ExFreePool(buf);
        }
    } while (status == STATUS_BUFFER_OVERFLOW);
}

NTSTATUS IoControlDevice(
                       PDEVICE_OBJECT DeviceObject,
                       ULONG IoControlCode,
                       PVOID InputBuffer,
                       ULONG InputBufferLength,
                       PVOID OutputBuffer,
                       ULONG OutputBufferLength,
                       BOOLEAN InternalDeviceIoControl = FALSE
                       )
{
    KEVENT Event;
    KeInitializeEvent(&Event, NotificationEvent, FALSE);

    IO_STATUS_BLOCK  IoStatusBlock;

    if (PIRP Irp = IoBuildDeviceIoControlRequest(IoControlCode, DeviceObject, InputBuffer, InputBufferLength,
        OutputBuffer, OutputBufferLength, InternalDeviceIoControl, &Event, &IoStatusBlock))
    {
        NTSTATUS status = IofCallDriver(DeviceObject, Irp);

        if (status == STATUS_PENDING)
        {
            KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, 0);

            status = IoStatusBlock.Status;
        }

        return status;
    }

    return STATUS_INSUFFICIENT_RESOURCES;
}
RbMm
  • 31,280
  • 3
  • 35
  • 56
  • Accepted the answer because it taught me some things. Although this does not solve my problem. Slava Imameev on OSR forums says : The request is propagated down the device stack. The first driver/filter that completes it reports some ID. This might not be a valid hardware ID in all cases. Also, some devices do not have a unique hardware ID. If a unique ID is requested the driver provides a software generated ID. In case of USB devices this ID has the '&' symbol. I will most likely create a port for calling user level application from which i can retrieve the information. Thanks for the help. – qwn Sep 02 '17 at 04:53
  • @qwn - of course not all hardware have `SerialNumber`. this is how correct query `STORAGE_DEVICE_DESCRIPTOR`. if in some case `SerialNumber` not returned - not because code invalid, but because this info not exist. and of course no different - query it from user or kernel space – RbMm Sep 02 '17 at 07:53
  • in all case - this is reply to your question - `Getting Serial Number using IOCTL_STORAGE_QUERY_PROPERTY`. if you want really another- you need ask another question. if you want some another info - say get device interfaces - you need call [`IoGetDeviceInterfaces`](https://msdn.microsoft.com/en-us/library/windows/hardware/ff549186(v=vs.85).aspx) – RbMm Sep 02 '17 at 07:59