主页 > 原创 | 学习笔记 > 用硬盘物理编号(序列号)、mac地址、文件版本、当前时间来生成机器序列号

用硬盘物理编号(序列号)、mac地址、文件版本、当前时间来生成机器序列号

在制作程序注册机的时候需要获取到机器的唯一编号,本文从硬盘、网卡硬件地址及文件版本生成一个4*7的序列号,形如 3CEA-82E6-1396-9C78-45C4-06C9-9564

1.获取硬盘物理地址(非逻辑分区序列号)
逻辑分区序列号获取很简单,但是这个编号不唯一,且可以轻易修改。如果ghost系统的话恐怕id也一样,所以获取硬盘的物理地址更合理一些。
需要的结构体及头文件

#include <winioctl.h>

#include <pshpack1.h>
#pragma pack(1)

typedef struct _IDENTIFY_DATA {
  USHORT GeneralConfiguration;            // 00 00
  USHORT NumberOfCylinders;               // 02  1
  USHORT Reserved1;                       // 04  2
  USHORT NumberOfHeads;                   // 06  3
  USHORT UnformattedBytesPerTrack;        // 08  4
  USHORT UnformattedBytesPerSector;       // 0A  5
  USHORT SectorsPerTrack;                 // 0C  6
  USHORT VendorUnique1[3];                // 0E  7-9
  USHORT SerialNumber[10];                // 14  10-19
  USHORT BufferType;                      // 28  20
 USHORT BufferSectorSize;                // 2A  21
 USHORT NumberOfEccBytes;                // 2C  22
 USHORT FirmwareRevision[4];             // 2E  23-26
  USHORT ModelNumber[20];                 // 36  27-46
  UCHAR  MaximumBlockTransfer;            // 5E  47
 UCHAR  VendorUnique2;                   // 5F
 USHORT DoubleWordIo;                    // 60  48
 USHORT Capabilities;                    // 62  49
 USHORT Reserved2;                       // 64  50
 UCHAR  VendorUnique3;                   // 66  51
 UCHAR  PioCycleTimingMode;              // 67
 UCHAR  VendorUnique4;                   // 68  52
 UCHAR  DmaCycleTimingMode;              // 69
 USHORT TranslationFieldsValid:1;        // 6A  53
 USHORT Reserved3:15;
  USHORT NumberOfCurrentCylinders;        // 6C  54
 USHORT NumberOfCurrentHeads;            // 6E  55
 USHORT CurrentSectorsPerTrack;          // 70  56
 ULONG  CurrentSectorCapacity;           // 72  57-58
  USHORT CurrentMultiSectorSetting;       //     59
 ULONG  UserAddressableSectors;          //     60-61
  USHORT SingleWordDMASupport : 8;        //     62
 USHORT SingleWordDMAActive : 8;
 USHORT MultiWordDMASupport : 8;         //     63
 USHORT MultiWordDMAActive : 8;
  USHORT AdvancedPIOModes : 8;            //     64
 USHORT Reserved4 : 8;
 USHORT MinimumMWXferCycleTime;          //     65
 USHORT RecommendedMWXferCycleTime;      //     66
 USHORT MinimumPIOCycleTime;             //     67
 USHORT MinimumPIOCycleTimeIORDY;        //     68
 USHORT Reserved5[2];                    //     69-70
  USHORT ReleaseTimeOverlapped;           //     71
 USHORT ReleaseTimeServiceCommand;       //     72
 USHORT MajorRevision;                   //     73
 USHORT MinorRevision;                   //     74
 USHORT Reserved6[50];                   //     75-126
 USHORT SpecialFunctionsEnabled;         //     127
  USHORT Reserved7[128];                  //     128-255
} IDENTIFY_DATA, *PIDENTIFY_DATA;

#pragma pack()

实现函数

CString GetHardDiskSerialNumber()
{
 CString strHardDiskSerialNumber ;

 HANDLE hDrive = 0;

  CString szDriveName = _T("\\\\.\\PhysicalDrive0");

  hDrive = CreateFile (szDriveName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
  if (hDrive != INVALID_HANDLE_VALUE)
 {
   DWORD cbBytesReturned = 0 ;

   GETVERSIONINPARAMS objVersionParams ;
   memset (&objVersionParams, 0, sizeof(objVersionParams)) ;
   if (  DeviceIoControl (hDrive, SMART_GET_VERSION, NULL, 0, &objVersionParams, sizeof (GETVERSIONINPARAMS), &cbBytesReturned, NULL) )
    {        
      ULONG nCommandSize = sizeof(SENDCMDINPARAMS) + IDENTIFY_BUFFER_SIZE;
      PSENDCMDINPARAMS pSendCommands = (PSENDCMDINPARAMS) malloc (nCommandSize) ;

     pSendCommands->irDriveRegs.bCommandReg = ID_CMD ;
     DWORD BytesReturned = 0 ;
     if (DeviceIoControl (hDrive, SMART_RCV_DRIVE_DATA, pSendCommands, sizeof(SENDCMDINPARAMS), pSendCommands, nCommandSize, &BytesReturned, NULL) )
     {
       WORD* pIdSector = (WORD *) (PIDENTIFY_DATA) ((PSENDCMDOUTPARAMS) pSendCommands)->bBuffer ;

        char szSerialNumber[100] = "" ;
       for (int index = 10, position=0; index <= 19; index++)
        {
         szSerialNumber[position] = (char) (pIdSector[index] / 256) ;
          position++ ;

          szSerialNumber[position] = (char) (pIdSector[index] % 256) ;
          position++ ;
        }

       strHardDiskSerialNumber = szSerialNumber ;
        strHardDiskSerialNumber.TrimLeft() ;
        strHardDiskSerialNumber.TrimRight() ;
     }

     CloseHandle (hDrive) ;
      free (pSendCommands) ;
      pSendCommands = NULL ;
    }
 }

 return strHardDiskSerialNumber ;
}

最后获取到的字串类似为 WD-WMAYUS743480 ,只需要取后八位就可以了。

CString GetHardDiskSerialID()
{
  CString serialId = GetHardDiskSerialNumber();
 serialId.Remove('-');
 return serialId.Right(8);
}

2.获取以太网网卡地址

CString GetMacAddress(bool format/*=false*/)
{
 CString csMacAddress;
 ULONG BufferLength = 0;
 BYTE* pBuffer = 0;
  if( ERROR_BUFFER_OVERFLOW == GetAdaptersInfo( 0, &BufferLength ))
 {
   pBuffer = new BYTE[ BufferLength ];
 }

 PIP_ADAPTER_INFO pAdapterInfo =
   reinterpret_cast<PIP_ADAPTER_INFO>(pBuffer);
  GetAdaptersInfo( pAdapterInfo, &BufferLength );

 while( pAdapterInfo )
 {
   if (pAdapterInfo->Type==MIB_IF_TYPE_ETHERNET)
   {
     CString szFormat;
     if (format)
     {
       szFormat = _T("%02x:%02x:%02x:%02x:%02x:%02x");
     }
     else
      {
       szFormat = _T("%02x%02x%02x%02x%02x%02x");
      }
     csMacAddress.Format(szFormat,
       pAdapterInfo->Address[0],
       pAdapterInfo->Address[1],
       pAdapterInfo->Address[2],
       pAdapterInfo->Address[3],
       pAdapterInfo->Address[4],
       pAdapterInfo->Address[5]);
    }
   pAdapterInfo = pAdapterInfo->Next;
  }
 delete[] pBuffer;

 return csMacAddress;
}

3.获取程序版本号
需要在项目属性连接里引入Version.lib

bool GetProductAndVersion(CString &strProductName, CString &strProductVersion)
{
 TCHAR szFilename[MAX_PATH + 1] = {0};
 if (GetModuleFileName(NULL, szFilename, MAX_PATH) == 0)
 {
   return false;
 }

 DWORD dummy;
  DWORD dwSize = GetFileVersionInfoSize(szFilename, &dummy);
  if (dwSize == 0)
  {
   return false;
 }
 std::vector<BYTE> data(dwSize);

 if (!GetFileVersionInfo(szFilename, NULL, dwSize, &data[0]))
  {
   return false;
 }

 LPVOID pvProductName = NULL;
  unsigned int iProductNameLen = 0;
 LPVOID pvProductVersion = NULL;
 unsigned int iProductVersionLen = 0;

  if (!VerQueryValue(&data[0], _T("\\StringFileInfo\\080404b0\\ProductName"), &pvProductName, &iProductNameLen) ||
    !VerQueryValue(&data[0], _T("\\StringFileInfo\\080404b0\\ProductVersion"), &pvProductVersion, &iProductVersionLen))
 {
   return false;
 }

 strProductName.SetString((LPCTSTR)pvProductName, iProductNameLen);
  strProductVersion.SetString((LPCTSTR)pvProductVersion, iProductVersionLen);

 return true;
}

CString GetFileVersion()
{
  CString strProductName, strProductVersion;
  GetProductAndVersion(strProductName, strProductVersion);

  return strProductVersion.Left(strProductVersion.ReverseFind('.'));
}

4.生成序列号

CString CKeyController::GenerateMachineID()
{
 CString serialID = GetHardDiskSerialID();
 CString timeID;
 timeID.Format(_T("%lx"), time(NULL));
 timeID.Delete(6,3);
 return serialID+timeID+GetMacAddress();
}

CString CKeyController::GenerateSerialNumber()
{
 CString serialNumber = GenerateMachineID();
 for (int i=0; i<6; i++)
 {
   serialNumber.Insert(i*5+4, _T("-"));
  }
 CString version = GetFileVersion();
 version.Delete(1,1);
  version.Delete(2,1);
  version.Format(_T("%2x"), _ttoi(version));
  serialNumber.Append(version);
 serialNumber.MakeUpper();
 return serialNumber;
}

最后调用GenerateSerialNumber()即可生成序列号。

Tags: mac地址 MFC 序列号 文件版本号 注册机 注册机制 硬盘物理地址

发表评论

电子邮件地址不会被公开。 必填项已用*标注