How to get a serial number of a Windows disk?

☆樱花仙子☆ 提交于 2020-01-06 06:02:15

问题


I'm trying to get a serial number of a disk, using IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER:

HANDLE h = CreateFile ("\\\\.\\PhysicalDrive0", GENERIC_READ,
                        FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
                        OPEN_EXISTING,
                        FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING, 0);
if (h != INVALID_HANDLE_VALUE) {
  struct {
    USHORT Reserved;
    USHORT SerialNumberLength;
    UCHAR SerialNumber[252];
  } dsn;
  DWORD nr;   
  memset(&dsn, '\0', sizeof dsn);
  if ((DeviceIoControl(h, IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER,
                       NULL, 0, &dsn, sizeof(dsn), &nr, 0))) {
    printf("Serial number: %s\n", dsn.SerialNumber);
  } else {
    printf("No serial number, error %d.\n", (int)GetLastError());
  }
}

However, GetLastError() returns ERROR_INVALID_FUNCTION.

The disk does exist, and it has a serial number, see this registry entry:

How can I retrieve the serial number from C code without using the registry?


回答1:


we can use IOCTL_STORAGE_QUERY_PROPERTY with StorageDeviceProperty (Indicates that the caller is querying for the device descriptor, STORAGE_DEVICE_DESCRIPTOR)

and use SerialNumberOffset member of STORAGE_DEVICE_DESCRIPTOR

Specifies the byte offset from the beginning of the structure to a NULL-terminated ASCII string that contains the device's serial number. If the device has no serial number, this member is zero.

code can look like this:

ULONG GetSerial(HANDLE hFile)
{
    static STORAGE_PROPERTY_QUERY spq = { StorageDeviceProperty, PropertyStandardQuery }; 

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

    ULONG size = sizeof(STORAGE_DEVICE_DESCRIPTOR) + 0x100;

    ULONG dwError;

    do 
    {
        dwError = ERROR_NO_SYSTEM_RESOURCES;

        if (buf = LocalAlloc(0, size))
        {
            ULONG BytesReturned;

            if (DeviceIoControl(hFile, IOCTL_STORAGE_QUERY_PROPERTY, &spq, sizeof(spq), buf, size, &BytesReturned, 0))
            {
                if (psdd->Version >= sizeof(STORAGE_DEVICE_DESCRIPTOR))
                {
                    if (psdd->Size > size)
                    {
                        size = psdd->Size;
                        dwError = ERROR_MORE_DATA;
                    }
                    else
                    {
                        if (psdd->SerialNumberOffset)
                        {
                            DbgPrint("SerialNumber = %s\n", psz + psdd->SerialNumberOffset);
                            dwError = NOERROR;
                        }
                        else
                        {
                            dwError = ERROR_NO_DATA;
                        }
                    }
                }
                else
                {
                    dwError = ERROR_GEN_FAILURE;
                }
            }
            else
            {
                dwError = GetLastError();
            }

            LocalFree(buf);
        }
    } while (dwError == ERROR_MORE_DATA);

    return dwError;
}

also for open device we can use CreateFileW (L"\\\\.\\PhysicalDrive0", 0, 0, 0, OPEN_EXISTING, 0, 0); - in place dwDesiredAccess we can use 0 because IOCTL_STORAGE_QUERY_PROPERTY defined as CTL_CODE(IOCTL_STORAGE_BASE, 0x0500, METHOD_BUFFERED, FILE_ANY_ACCESS) - so FILE_ANY_ACCESS - accept any file access and FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING have sense only for file system devices (more general which use cache) - for disk devices - this is irrelevant



来源:https://stackoverflow.com/questions/48250004/how-to-get-a-serial-number-of-a-windows-disk

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!