获取硬盘的序列号、型号和固件版本号,此类功能通常用于做硬盘绑定或硬件验证操作,通过使用Windows API
的DeviceIoControl
函数与物理硬盘驱动程序进行通信,发送ATA
命令来获取硬盘的信息。
以下是该程序的主要功能和流程:
定义常量 IDE_ATAPI_IDENTIFY
和 IDE_ATA_IDENTIFY
分别表示读取 ATAPI
设备和 ATA
设备信息的命令。
- 实现
Trim
函数,用于去除字符串首尾的空格。 - 实现
ConvertToString
函数,用于将DWORD
数组转换为字符串,并通过Trim
函数去除首尾空格。 - 实现
DoIdentify
函数,该函数通过DeviceIoControl
发送SMART
命令,获取硬盘的详细信息。 - 实现
GetDiskInfo
函数,该函数打开物理硬盘设备,并调用DoIdentify
获取硬盘序列号、型号和固件版本号。
在 main
函数中,通过调用 GetDiskInfo
获取硬盘信息,并输出到控制台。
#define _CRT_SECURE_NO_WARNINGS
#include <windows.h>
#include <iostream>
#include <winioctl.h>
#include <string>const WORD IDE_ATAPI_IDENTIFY = 0xA1; // 读取ATAPI设备的命令
const WORD IDE_ATA_IDENTIFY = 0xEC; // 读取ATA设备的命令// 去除字符串首尾的空格
BOOL Trim(char* szStr)
{int i = 0, j = 0, iFirst = -1, iLast = -1;int iLen = strlen(szStr);char szTemp[256] = { 0 };// 从前往后遍历,获取第一个不为 空格 的下标for (i = 0; i < iLen; i++){if (' ' != szStr[i]){iFirst = i;break;}}// 从后往前遍历,获取第一个不为 空格 的下标for (i = (iLen - 1); 0 <= i; i--){if (' ' != szStr[i]){iLast = i;break;}}// 字符串全为 空格if (-1 == iFirst || -1 == iLast){return FALSE;}// 获取去除 空格 部分for (i = iFirst; i <= iLast; i++){szTemp[j] = szStr[i];j++;}szTemp[j] = '\0';strcpy(szStr, szTemp);return TRUE;
}// 数据转换
char* __fastcall ConvertToString(DWORD dwDiskData[256],int iFirstIndex,int iLastIndex)
{static char szResBuf[256];int iIndex = 0;int iPosition = 0;for (iIndex = iFirstIndex; iIndex <= iLastIndex; iIndex++){szResBuf[iPosition] = (char)(dwDiskData[iIndex] / 256);iPosition++;// Get low BYTE for 2nd characterszResBuf[iPosition] = (char)(dwDiskData[iIndex] % 256);iPosition++;}szResBuf[iPosition] = '\0';// 删除首尾的空格Trim(szResBuf);return szResBuf;
}BOOL __fastcall DoIdentify(HANDLE hPhysicalDriveIOCTL,PSENDCMDINPARAMS pSCIP,PSENDCMDOUTPARAMS pSCOP,BYTE btIDCmd,BYTE btDriveNum,PDWORD pdwBytesReturned)
{pSCIP->cBufferSize = IDENTIFY_BUFFER_SIZE;pSCIP->irDriveRegs.bFeaturesReg = 0;pSCIP->irDriveRegs.bSectorCountReg = 1;pSCIP->irDriveRegs.bSectorNumberReg = 1;pSCIP->irDriveRegs.bCylLowReg = 0;pSCIP->irDriveRegs.bCylHighReg = 0;pSCIP->irDriveRegs.bDriveHeadReg = (btDriveNum & 1) ? 0xB0 : 0xA0;pSCIP->irDriveRegs.bCommandReg = btIDCmd;pSCIP->bDriveNumber = btDriveNum;return DeviceIoControl(hPhysicalDriveIOCTL,SMART_RCV_DRIVE_DATA,(LPVOID)pSCIP,sizeof(SENDCMDINPARAMS) - 1,(LPVOID)pSCOP,sizeof(SENDCMDOUTPARAMS) + IDENTIFY_BUFFER_SIZE - 1,pdwBytesReturned,NULL);return FALSE;
}int GetDiskInfo(int iDriver, char* szSerialNumber, char* szModelNumber, char* szFirmwareNumber)
{char szFilePath[64] = { 0 };sprintf(szFilePath, "\\\\.\\PHYSICALDRIVE%d", iDriver);// 打开设备HANDLE hFile = CreateFileA(szFilePath,GENERIC_READ | GENERIC_WRITE,FILE_SHARE_READ | FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,NULL);if (INVALID_HANDLE_VALUE == hFile){return -1;}// 发送控制代码到指定设备驱动程序DWORD dwBytesReturned = 0;GETVERSIONINPARAMS gvopVersionParam;DeviceIoControl(hFile,SMART_GET_VERSION,NULL,0,&gvopVersionParam,sizeof(gvopVersionParam),&dwBytesReturned,NULL);if (0 >= gvopVersionParam.bIDEDeviceMap){return -2;}// IDE or ATAPI IDENTIFY cmdunsigned int uiIDCmd = 0;SENDCMDINPARAMS InParams;unsigned int uiDrive = 0;uiIDCmd = (gvopVersionParam.bIDEDeviceMap >> uiDrive & 0x10) ? IDE_ATAPI_IDENTIFY : IDE_ATA_IDENTIFY;// 输出参数BYTE btOutCmd[sizeof(SENDCMDOUTPARAMS) + IDENTIFY_BUFFER_SIZE - 1];if (FALSE == DoIdentify(hFile,&InParams,(SENDCMDOUTPARAMS*)btOutCmd,(BYTE)uiIDCmd,(BYTE)uiDrive,&dwBytesReturned)){return -3;}// 关闭设备CloseHandle(hFile);DWORD dwDiskData[256];USHORT* pIDSector = NULL;// 对应结构IDSECTOR 见头文件pIDSector = (USHORT*)((SENDCMDOUTPARAMS*)btOutCmd)->bBuffer;for (int i = 0; i < 256; i++){dwDiskData[i] = pIDSector[i];}// 获取序列号strcpy(szSerialNumber, ConvertToString(dwDiskData, 10, 19));// 获取型号strcpy(szModelNumber, ConvertToString(dwDiskData, 27, 46));// 获取固件版本号strcpy(szFirmwareNumber, ConvertToString(dwDiskData, 23, 26));return 0;
}int main(int argc,char *argv[])
{char SerialNumber[64]; // 硬盘序列号char ModelNumber[64]; // 硬盘型号char FirmwareNumber[64]; // 硬盘固件版本号if (0 == GetDiskInfo(0, SerialNumber, ModelNumber, FirmwareNumber)){std::cout << "序列号: " << SerialNumber << std::endl;std::cout << "硬盘型号: " << ModelNumber << std::endl;std::cout << "固件版本:" << FirmwareNumber << std::endl;}system("pause");return 0;
}
输出效果;