首页
社区
课程
招聘
[原创]两种获取硬盘序列号的方法.
发表于: 2019-7-22 21:23 15419

[原创]两种获取硬盘序列号的方法.

2019-7-22 21:23
15419

方法一,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;
}

如果只是要序列号跟名称,还是方法二好用一点,名称获取完整.
调用过程已经运行结果:


还有什么奇葩读取硬盘ID的方法,发出来学习呗!



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

如果只是要序列号跟名称,还是方法二好用一点,名称获取完整.
调用过程已经运行结果:


还有什么奇葩读取硬盘ID的方法,发出来学习呗!


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

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());

}

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());

}

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

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2019-7-23 02:04 被游乐娃子编辑 ,原因:
收藏
免费 6
支持
分享
最新回复 (14)
雪    币: 9698
活跃值: (2506)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
mark 两种获取硬盘序列号的方法
2019-7-22 23:29
0
雪    币: 7553
活跃值: (5392)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
3
HARDDISKINFO2->get_name1()有个小问题.有兴趣的自己调试一下看看.
2019-7-23 01:18
0
雪    币: 248
活跃值: (3789)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
io控制码获取
2019-7-23 01:29
0
雪    币: 136
活跃值: (342)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
标记
2019-7-23 15:18
0
雪    币: 19
活跃值: (205)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
make a
2019-7-23 19:06
0
雪    币: 10
活跃值: (894)
能力值: ( LV3,RANK:27 )
在线值:
发帖
回帖
粉丝
7
thank you,make~!
2019-7-23 20:17
0
雪    币: 5451
活跃值: (3537)
能力值: ( LV5,RANK:75 )
在线值:
发帖
回帖
粉丝
8
需要管理员权限么?
2019-7-24 23:30
0
雪    币: 27
活跃值: (127)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
DiskGenius 用的其实就是这个方法,烂大街的方法,还要破解?
STORAGE_PROPERTY_QUERY spq = { StorageDeviceProperty };
spq.QueryType = PropertyStandardQuery;

union {
	BYTE Data[offsetof(STORAGE_DEVICE_DESCRIPTOR, RawDeviceProperties) + 1024];
	BYTE &operator[](size_t n)
	{
		return Data[n];
	}
	STORAGE_DEVICE_DESCRIPTOR sdd;
	STORAGE_DEVICE_DESCRIPTOR *operator->()
	{
		return &sdd;
	}
} sdd = { 0 };

bResult = DeviceIoControl(hFile, IOCTL_STORAGE_QUERY_PROPERTY, &spq, sizeof(spq), &sdd, sizeof(sdd), nullptr, nullptr);

wprintf(L"============================ StorageDeviceProperty =============================\n");
wprintf(L"  BusType [%s]\n", aBusTypes[sdd->BusType]);
wprintf(L" VendorId [%hs]\n", sdd->VendorIdOffset ? &sdd[sdd->VendorIdOffset] : nullptr);
wprintf(L"ProductId [%hs]\n", sdd->ProductIdOffset ? &sdd[sdd->ProductIdOffset] : nullptr);
wprintf(L" Revision [%hs]\n", sdd->ProductRevisionOffset ? &sdd[sdd->ProductRevisionOffset] : nullptr);
wprintf(L"   Serial [%hs]\n", sdd->SerialNumberOffset ? &sdd[sdd->SerialNumberOffset] : nullptr);

最后于 2019-7-26 11:04 被Xenophon编辑 ,原因:
2019-7-26 11:02
0
雪    币: 7553
活跃值: (5392)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
10
賈可 DiskGenius 用的其实就是这个方法,烂大街的方法,还要破解? STORAGE_PROPERTY_QUERY&nbsp;spq&nbsp;=&nbsp;{& ...
通过搜索你提供的 STORAGE_DEVICE_DESCRIPTOR,找到这个,https://bbs.pediy.com/thread-221514.htm,比较详细的结构体.

但是还是想跟您说,滚.
2019-7-27 01:54
0
雪    币: 7092
活跃值: (2988)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
通过wmi获取过
2019-7-29 18:50
0
雪    币: 27
活跃值: (127)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12

您厉害,您无敌!但我该说的还是要说,方法二的确烂大街,这是事实。不知道为什么贴个代码都能刺痛您的某根神经?

如果您认为我在嘲讽您,那是您想多了。我没有您厉害,但十几年前我在网上搜索获取硬盘序列号,看到的的确都是方法二的代码。

如果您认为我是在扯淡,我只能告诉您,我回帖不是随随便便贴点代码就完事:

  1. IOCTL_STORAGE_QUERY_PROPERTY 数值完全匹配
    wprintf(L"0x%08X\n", IOCTL_STORAGE_QUERY_PROPERTY ); // 0x002D1400
  2. STORAGE_PROPERTY_QUERY 结构体 12 个字节,前两个字节刚好都是 0,第三个字节无用数据。
    typedef struct _STORAGE_PROPERTY_QUERY {
    	STORAGE_PROPERTY_ID PropertyId;
    	STORAGE_QUERY_TYPE QueryType;
    	BYTE AdditionalParameters[1]; // 对齐到 4 字节
    } STORAGE_PROPERTY_QUERY;
    
    STORAGE_PROPERTY_QUERY spq;
    spq.PropertyId = StorageDeviceProperty; // StorageDeviceProperty == 0
    spq.QueryType = PropertyStandardQuery;  // PropertyStandardQuery == 0
    
  3. STORAGE_DEVICE_DESCRIPTOR 的几个重要偏移量都没问题,您备注错的刚好也没用上:
    typedef struct _STORAGE_DEVICE_DESCRIPTOR {       // 这边是您给出的数据结构
    	DWORD            Version;                 // ULONG of_name1; //名称1偏移
    	DWORD            Size;                    // ULONG unknown1[3]; //未知数据
    	BYTE             DeviceType;
    	BYTE             DeviceTypeModifier;
    	BOOLEAN          RemovableMedia;
    	BOOLEAN          CommandQueueing;
    	DWORD            VendorIdOffset;        
    	DWORD            ProductIdOffset;         // ULONG of_name2; //名称2偏移
    	DWORD            ProductRevisionOffset;   // ULONG of_FirmwareRev; // 固件版本偏移
    	DWORD            SerialNumberOffset;      // ULONG of_SerialNumber; // 序列号偏移
    	STORAGE_BUS_TYPE BusType;                 // ULONG unknown2; //未知数据
    	DWORD            RawPropertiesLength;
    	BYTE             RawDeviceProperties[1];
    } STORAGE_DEVICE_DESCRIPTOR;

我的说完了。咱承认咱讲话不太中听,水平不如您,但首先咱不讲脏话。
但您这态度,还是贴吧比较适合您,别在这里拉低程序员的整体素质。

最后于 2019-9-26 22:30 被Xenophon编辑 ,原因:
2019-9-26 22:27
0
雪    币: 1821
活跃值: (4035)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
賈可 您厉害,您无敌!但我该说的还是要说,方法二的确烂大街,这是事实。不知道为什么贴个代码都能刺痛您的某根神经? 如果您认为我在嘲讽您,那是您想多了。我没有您厉害,但十几年前我在网上搜索获取硬 ...
不尊重别人发帖内容
最后于 2019-10-5 13:39 被小希希编辑 ,原因:
2019-10-5 13:38
0
雪    币: 4720
活跃值: (3229)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
我测试第一种方法,在WIn11取不到硬盘序列号了
2022-8-16 23:26
0
雪    币: 261
活跃值: (547)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
15
现在都是获取所有盘的特征码吧 就是直接打开C: D: E:  很少看到用PhysicalDrive
2023-9-26 17:26
0
游客
登录 | 注册 方可回帖
返回
//