【问题标题】:Getting Serial Number using IOCTL_STORAGE_QUERY_PROPERTY使用 IOCTL_STORAGE_QUERY_PROPERTY 获取序列号
【发布时间】:2017-09-01 11:44:34
【问题描述】:

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

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

我遇到的问题是返回到我的微过滤器的序列号对于某些 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

这些是我的微过滤器返回的序列号:

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

可以看出,第二个设备的序列号成功返回,但第一个没有。那么我的微过滤器收到的序列号是什么?这是存储在可以查询的地方吗?

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

编辑:代码

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 

来自我的微过滤器:

WX41A7654VVV 

似乎设备管理器中的序列号是我从微过滤器获得的序列号的十六进制表示

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

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

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

那么有没有办法从内核级别获取序列号,或者调用用户应用程序会更容易?

【问题讨论】:

  • ... since I get some Serial Numbers correctly i doubt that my code is wrong 这是一种完全错误的思维方式...发布您的代码并询问是否有人可以发现错误
  • 编辑原帖添加代码
  • infoBuffer, sizeof(infoBuffer) - 这表示您对infoBuffer 使用硬编码数组 - 这已经是错误的。它的大小未知,您需要在运行时查询它。正确的代码 - stackoverflow.com/a/44656144/6401656
  • 真正的代码包含很多错误。您没有检查从IoCallDriver 返回的状态。但是它可以是STATUS_BUFFER_OVERFLOW。即使在STATUS_SUCCESS 上,您也需要检查SizeSTORAGE_DEVICE_DESCRIPTOR 成员,如果它大于您的sizeof(infoBuffer),您需要使用此Size 缓冲区大小重新发送请求。仅在 STATUS_PENDING 的情况下调用 KeWaitForSingleObject 存在意义
  • 是什么让您认为设备 ID 包含确切的序列号?此字符串的确切格式未记录在 AFAIK 中。

标签: c windows wmi drivers


【解决方案1】:

STORAGE_DEVICE_DESCRIPTOR 是可变长度结构。成功后调用IOCTL_STORAGE_QUERY_PROPERTY需要

检查它的 Size 成员以确定字节数 结构实际上需要。

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

真的需要发送 IOCTL_STORAGE_QUERY_PROPERTY 并将 Size 成员与您的 OutputBufferLength 进行比较,如果它更大 - 再次发送 IOCTL_STORAGE_QUERY_PROPERTY 并使用更大的 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;
}

【讨论】:

  • 接受了答案,因为它教会了我一些东西。虽然这并不能解决我的问题。 OSR 论坛上的 Slava Imameev 说:请求沿设备堆栈向下传播。完成它的第一个驱动程序/过滤器会报告一些 ID。在所有情况下,这可能不是有效的硬件 ID。此外,某些设备没有唯一的硬件 ID。如果请求一个唯一的 ID,驱动程序会提供一个软件生成的 ID。对于 USB 设备,此 ID 带有“&”符号。我很可能会创建一个用于调用用户级应用程序的端口,我可以从中检索信息。感谢您的帮助。
  • @qwn - 当然不是所有硬件都有SerialNumber。这就是查询STORAGE_DEVICE_DESCRIPTOR 的正确方法。如果在某些情况下SerialNumber 未返回 - 不是因为代码无效,而是因为此信息不存在。当然没有什么不同 - 从用户或内核空间查询它
  • 无论如何-这是对您问题的答复-Getting Serial Number using IOCTL_STORAGE_QUERY_PROPERTY。如果你真的想要另一个 - 你需要问另一个问题。如果你想要一些其他信息——比如获取设备接口——你需要打电话给IoGetDeviceInterfaces
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-06-10
  • 2012-02-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-04
  • 1970-01-01
相关资源
最近更新 更多