MENU

两种获取硬盘序列号的方法

July 16, 2021 • Read: 498 • C/C++

方法一 0x7c088

网上搜素出来一堆,自己进行修改优化,如下:

typedef struct _IDSECTOR
{
    USHORT  wGenConfig;
    USHORT  wNumCyls;
    USHORT  wReserved;
    USHORT  wNumHeads;
    USHORT  wBytesPerTrack;
    USHORT  wBytesPerSector;
    USHORT  wSectorsPerTrack;
    USHORT  wVendorUnique[3];
    CHAR    sSerialNumber[20];
    USHORT  wBufferType;
    USHORT  wBufferSize;
    USHORT  wECCSize;
    CHAR    sFirmwareRev[8];
    CHAR    sModelNumber[40];
    USHORT  wMoreVendorUnique;
    USHORT  wDoubleWordIO;
    USHORT  wCapabilities;
    USHORT  wReserved1;
    USHORT  wPIOTiming;
    USHORT  wDMATiming;
    USHORT  wBS;
    USHORT  wNumCurrentCyls;
    USHORT  wNumCurrentHeads;
    USHORT  wNumCurrentSectorsPerTrack;
    ULONG   ulCurrentSectorCapacity;
    USHORT  wMultSectorStuff;
    ULONG   ulTotalAddressableSectors;
    USHORT  wSingleWordDMA;
    USHORT  wMultiWordDMA;
//  BYTE    bReserved[128];
    BYTE    bReserved2[512];
} IDSECTOR, * PIDSECTOR;
 
 //这里我把SENDCMDOUTPARAMS跟IDSECTOR直接合并来了,这样的操作方便传入输参
typedef struct _HARDDISKINFO
{
    //SENDCMDOUTPARAMS
    DWORD                   cBufferSize;            // Size of bBuffer in bytes
    DRIVERSTATUS            DriverStatus;           // Driver status structure.
    IDSECTOR    info;
}HARDDISKINFO ,*PHARDDISKINFO;
 
string get_HardDiskSerialNumber_1(int harddiskindex)//硬盘序列号索引,第一个硬盘=0,第二个硬盘=1
{
 
    char objName[50] = {0};
    wsprintfA(objName, "\\\\.\\PhysicalDrive%d", harddiskindex);
    HANDLE hDevice = ::CreateFileA(objName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);
    if (hDevice == INVALID_HANDLE_VALUE)return "-1";
     
    SENDCMDINPARAMS scip;//输入
 
    ZeroMemory(&scip, sizeof(SENDCMDINPARAMS));
    scip.cBufferSize = IDENTIFY_BUFFER_SIZE;
    scip.irDriveRegs.bSectorCountReg = 1;
    scip.irDriveRegs.bSectorNumberReg = 1;
    scip.irDriveRegs.bDriveHeadReg = 0xA0;
    scip.irDriveRegs.bCommandReg = 0xEC;
 
 
    HARDDISKINFO hdinfo = {0};//输出,把SENDCMDOUTPARAMS ,IDSECTOR直接合并成一个结构了
       DWORD dwBytesReturned = 0;
    if (!DeviceIoControl(hDevice, SMART_RCV_DRIVE_DATA, &scip, sizeof(SENDCMDINPARAMS),&hdinfo, sizeof(HARDDISKINFO), &dwBytesReturned, NULL))
    {
     
        ::CloseHandle(hDevice);
        return "-2";
    }
    ConvertSerialString(hdinfo.info.sSerialNumber, sizeof(hdinfo.info.sSerialNumber));//转换格式
    ::CloseHandle(hDevice);
    return string(hdinfo.info.sSerialNumber);
     
}

方法二 0x2D1400

网上找到不资料,根据硬盘分区工具DiskGenius.exe逆出来的,其中的结构体我也不懂是啥,随便构造了一个
代码如下:

typedef struct _HARDDISKINFO2
{
    ULONG  of_name1;//名称1偏移
    ULONG  unknown1[3];//未知数据
    ULONG  of_name2;//名称2偏移
    ULONG  of_FirmwareRev;  //  固件版本偏移
    ULONG  of_SerialNumber; // 序列号偏移
    ULONG  unknown2;//未知数据
    char   outdata[520];//硬盘数据
    PCHAR  get_FirmwareRev()
    {
        if (of_FirmwareRev <sizeof(_HARDDISKINFO2))
        {
            return (PCHAR)this + of_FirmwareRev;
        }
        return "";
    }
    PCHAR  get_name1()
    {
        if (((PCHAR)this)[of_name1] == 0)
                return (PCHAR)this + of_name1+8;
            else
                return (PCHAR)this + of_name1;
        return NULL;
    }
    PCHAR  get_name2()
    {
        if (of_name2 < sizeof(_HARDDISKINFO2))
        {
            return (PCHAR)this + of_name2;
        }
        return "";
    }
    PCHAR  get_SerialNumber()
    {
        if (of_SerialNumber < sizeof(_HARDDISKINFO2))
        {
            return (PCHAR)this + of_SerialNumber;
        }
        return "";
    }
}HARDDISKINFO2, * PHARDDISKINFO2;
 
string get_HardDiskSerialNumber_2(int harddiskindex)
{
 
    char objName[50] = { 0 };
    wsprintfA(objName, "\\\\.\\PhysicalDrive%d", harddiskindex);
    HANDLE hDevice = ::CreateFileA(objName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);
    if (hDevice == INVALID_HANDLE_VALUE)return "-1";
 
    char inputdata[] = { 0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x80,  0x03,  0x00,  0x00 };//不知道这个是什么结构,格式就这样
 
    HARDDISKINFO2 hdinfo = {0};
       DWORD dwBytesReturned = 0;
    if (!DeviceIoControl(hDevice, 0x2D1400, inputdata, sizeof(inputdata), &hdinfo, sizeof(HARDDISKINFO2), &dwBytesReturned , NULL))
    {
        ::CloseHandle(hDevice);
        return "-2";
    }
    ::CloseHandle(hDevice);
    return string(hdinfo.get_SerialNumber());
 
}

方法一获取的硬盘数据多一些,但是硬盘型号名称获取有时候不太对,而且序列号,名字这些字符要转换,转换方式我这么写:

VOID DiskSerialConvert(PCHAR DiskSerial, PCHAR newDiskSerial)
{
    int len = strlen(DiskSerial);
    int i = 0;
 
    if (len > 20)
    {
        len = 20;
    }
    if (len % 2 == 1)
    {
        len = len + 1;
    }
    for (i = 0; i < len; i++)
    {
        if (i % 2 == 0)
        {
            newDiskSerial[i] = DiskSerial[i + 1];
        }
        else
        {
            newDiskSerial[i] = DiskSerial[i - 1];
        }
    }
}
void ConvertSerialString(PCHAR str,int len)
{
    char* strTemp = new char[len];
    DiskSerialConvert(str, strTemp);
    RtlCopyMemory(str, strTemp, len);
    delete[] strTemp;
}

如果只是要序列号跟名称,还是方法二好用一点,名称获取完整.

回到上个页面 QR Code
QR Code for this page
Tipping QR Code