使用IOCTL_STORAGE_QUERY_PROPERTY获取序列号

时间:2017-09-01 11:44:35

标签: c windows wmi drivers

所以我正在尝试编写一个仅连接到特定USB设备的微过滤器驱动程序,以区分所述设备,我使用了产品ID +供应商ID +序列号的组合。

我可以成功将IOCTL_STORAGE_QUERY_PROPERTY发送到返回产品ID,供应商ID,序列号的设备。

我遇到的问题是返回到我的minifilter的序列号对于某些USB是正确的,但不是全部。

例如:当我打电话时

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

这些是我的minifilter返回的序列号:

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

可以看出第二个设备的序列号已成功返回,但第一个没有。那么我的minifilter接收的序列号是多少?这是存储在可以查询的地方吗?

如果需要,我可以附加代码,但由于我正确获得了一些序列号,我怀疑我的代码是错误的。

编辑:代码

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

在我的外部硬盘上测试,这是我从设备管理器获得的

575834314137363534565656 

来自我的minifilter:

WX41A7654VVV 

设备管理器中的序列号似乎是我从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 

所以对于某些设备,它以十六进制格式表示,而其他设备是Char格式?

那么无论如何从内核级别获取序列号,或者只是更容易调用用户应用程序?

1 个答案:

答案 0 :(得分:0)

STORAGE_DEVICE_DESCRIPTOR是可变长度结构。成功通话后IOCTL_STORAGE_QUERY_PROPERTY需要

  

检查其大小成员以确定其字节数   结构实际上需要。

但在我的代码中我查看infoBuffer, sizeof(infoBuffer) - 这意味着您使用STORAGE_DEVICE_DESCRIPTOR的硬编码大小。

确实需要发送IOCTL_STORAGE_QUERY_PROPERTY并将大小成员与 OutputBufferLength 进行比较,如果更大 - 再次使用较大的 OutputBufferLength发送IOCTL_STORAGE_QUERY_PROPERTY

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;
}