Hello all, Can anybody tell me how can we get hard disk serial number (NOT THE VOLUME SERIAL NUMBER), which is UNIQUE for each physical hard disk, using Win32 APIs? Thanks in advance.
Code: int ReadPhysicalDriveInNT (void) { int done = FALSE; int drive = 0; for (drive = 0; drive < MAX_IDE_DRIVES; drive++) { HANDLE hPhysicalDriveIOCTL = 0; // Try to get a handle to PhysicalDrive IOCTL, report failure // and exit if can't. char driveName [256]; sprintf (driveName, "\\\\.\\PhysicalDrive%d", drive); // Windows NT, Windows 2000, must have admin rights hPhysicalDriveIOCTL = CreateFile (driveName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); // if (hPhysicalDriveIOCTL == INVALID_HANDLE_VALUE) // printf ("Unable to open physical drive %d, error code: 0x%lX\n", // drive, GetLastError ()); if (hPhysicalDriveIOCTL != INVALID_HANDLE_VALUE) { GETVERSIONOUTPARAMS VersionParams; DWORD cbBytesReturned = 0; // Get the version, etc of PhysicalDrive IOCTL memset ((void*) &VersionParams, 0, sizeof(VersionParams)); if ( ! DeviceIoControl (hPhysicalDriveIOCTL, DFP_GET_VERSION, NULL, 0, &VersionParams, sizeof(VersionParams), &cbBytesReturned, NULL) ) { // printf ("DFP_GET_VERSION failed for drive %d\n", i); // continue; } // If there is a IDE device at number "i" issue commands // to the device if (VersionParams.bIDEDeviceMap > 0) { BYTE bIDCmd = 0; // IDE or ATAPI IDENTIFY cmd SENDCMDINPARAMS scip; //SENDCMDOUTPARAMS OutCmd; // Now, get the ID sector for all IDE devices in the system. // If the device is ATAPI use the IDE_ATAPI_IDENTIFY command, // otherwise use the IDE_ATA_IDENTIFY command bIDCmd = (VersionParams.bIDEDeviceMap >> drive & 0x10) ? \ IDE_ATAPI_IDENTIFY : IDE_ATA_IDENTIFY; memset (&scip, 0, sizeof(scip)); memset (IdOutCmd, 0, sizeof(IdOutCmd)); if ( DoIDENTIFY (hPhysicalDriveIOCTL, &scip, (PSENDCMDOUTPARAMS)&IdOutCmd, (BYTE) bIDCmd, (BYTE) drive, &cbBytesReturned)) { DWORD diskdata [256]; int ijk = 0; USHORT *pIdSector = (USHORT *) ((PSENDCMDOUTPARAMS) IdOutCmd) -> bBuffer; for (ijk = 0; ijk < 256; ijk++) diskdata [ijk] = pIdSector [ijk]; PrintIdeInfo (drive, diskdata); done = TRUE; } } CloseHandle (hPhysicalDriveIOCTL); } } return done; } int ReadIdeDriveAsScsiDriveInNT (void) { int done = FALSE; int controller = 0; for (controller = 0; controller < 2; controller++) { HANDLE hScsiDriveIOCTL = 0; char driveName [256]; // Try to get a handle to PhysicalDrive IOCTL, report failure // and exit if can't. sprintf (driveName, "\\\\.\\Scsi%d:", controller); // Windows NT, Windows 2000, any rights should do hScsiDriveIOCTL = CreateFile (driveName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); // if (hScsiDriveIOCTL == INVALID_HANDLE_VALUE) // printf ("Unable to open SCSI controller %d, error code: 0x%lX\n", // controller, GetLastError ()); if (hScsiDriveIOCTL != INVALID_HANDLE_VALUE) { int drive = 0; for (drive = 0; drive < 2; drive++) { char buffer [sizeof (SRB_IO_CONTROL) + SENDIDLENGTH]; SRB_IO_CONTROL *p = (SRB_IO_CONTROL *) buffer; SENDCMDINPARAMS *pin = (SENDCMDINPARAMS *) (buffer + sizeof (SRB_IO_CONTROL)); DWORD dummy; memset (buffer, 0, sizeof (buffer)); p -> HeaderLength = sizeof (SRB_IO_CONTROL); p -> Timeout = 10000; p -> Length = SENDIDLENGTH; p -> ControlCode = IOCTL_SCSI_MINIPORT_IDENTIFY; strncpy ((char *) p -> Signature, "SCSIDISK", 8); pin -> irDriveRegs.bCommandReg = IDE_ATA_IDENTIFY; pin -> bDriveNumber = drive; if (DeviceIoControl (hScsiDriveIOCTL, IOCTL_SCSI_MINIPORT, buffer, sizeof (SRB_IO_CONTROL) + sizeof (SENDCMDINPARAMS) - 1, buffer, sizeof (SRB_IO_CONTROL) + SENDIDLENGTH, &dummy, NULL)) { SENDCMDOUTPARAMS *pOut = (SENDCMDOUTPARAMS *) (buffer + sizeof (SRB_IO_CONTROL)); IDSECTOR *pId = (IDSECTOR *) (pOut -> bBuffer); if (pId -> sModelNumber [0]) { DWORD diskdata [256]; int ijk = 0; USHORT *pIdSector = (USHORT *) pId; for (ijk = 0; ijk < 256; ijk++) diskdata [ijk] = pIdSector [ijk]; PrintIdeInfo (controller * 2 + drive, diskdata); done = TRUE; } } } CloseHandle (hScsiDriveIOCTL); } } return done; } int ReadDrivePortsInWin9X (void) { int done = FALSE; int drive = 0; InitializeWinIo (); // Get IDE Drive info from the hardware ports // loop thru all possible drives for (drive = 0; drive < 8; drive++) { DWORD diskdata [256]; WORD baseAddress = 0; // Base address of drive controller DWORD portValue = 0; int waitLoop = 0; int index = 0; switch (drive / 2) { case 0: baseAddress = 0x1f0; break; case 1: baseAddress = 0x170; break; case 2: baseAddress = 0x1e8; break; case 3: baseAddress = 0x168; break; } // Wait for controller not busy waitLoop = 100000; while (--waitLoop > 0) { GetPortVal ((WORD) (baseAddress + 7), &portValue, (BYTE) 1); // drive is ready if ((portValue & 0x40) == 0x40) break; // previous drive command ended in error if ((portValue & 0x01) == 0x01) break; } if (waitLoop < 1) continue; // Set Master or Slave drive if ((drive % 2) == 0) SetPortVal ((WORD) (baseAddress + 6), 0xA0, 1); else SetPortVal ((WORD) (baseAddress + 6), 0xB0, 1); // Get drive info data SetPortVal ((WORD) (baseAddress + 7), 0xEC, 1); // Wait for data ready waitLoop = 100000; while (--waitLoop > 0) { GetPortVal ((WORD) (baseAddress + 7), &portValue, 1); // see if the drive is ready and has it's info ready for us if ((portValue & 0x48) == 0x48) break; // see if there is a drive error if ((portValue & 0x01) == 0x01) break; } // check for time out or other error if (waitLoop < 1 || portValue & 0x01) continue; // read drive id information for (index = 0; index < 256; index++) { diskdata [index] = 0; // init the space GetPortVal (baseAddress, &(diskdata [index]), 2); } PrintIdeInfo (drive, diskdata); done = TRUE; } ShutdownWinIo (); return done; }
i saw a method that used deviceiocontrolfile to spoof this value, from a program that requiered that serial number. here is the spoofing part Code: #define ATA_IDENTIFY_DEVICE 0xec #pragma pack(1) struct ata_identify_device { unsigned short words000_009[10]; unsigned char serial_no[20]; unsigned short words020_022[3]; unsigned char fw_rev[8]; unsigned char model[40]; unsigned short words047_079[33]; unsigned short major_rev_num; unsigned short minor_rev_num; unsigned short command_set_1; unsigned short command_set_2; unsigned short command_set_extension; unsigned short cfs_enable_1; unsigned short word086; unsigned short csf_default; unsigned short words088_255[168]; }; #pragma pack() NTSTATUS (*pNtDeviceIoControlFile)( IN HANDLE FileHandle, IN HANDLE Event OPTIONAL, IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, IN PVOID ApcContext OPTIONAL, OUT PIO_STATUS_BLOCK IoStatusBlock, IN ULONG IoControlCode, IN PVOID InputBuffer OPTIONAL, IN ULONG InputBufferLength, OUT PVOID OutputBuffer OPTIONAL, IN ULONG OutputBufferLength ); NTSTATUS MyNtDeviceIoControlFile( IN HANDLE FileHandle, IN HANDLE Event OPTIONAL, IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, IN PVOID ApcContext OPTIONAL, OUT PIO_STATUS_BLOCK IoStatusBlock, IN ULONG IoControlCode, IN PVOID InputBuffer OPTIONAL, IN ULONG InputBufferLength, OUT PVOID OutputBuffer OPTIONAL, IN ULONG OutputBufferLength ) { NTSTATUS ret = pNtDeviceIoControlFile( FileHandle, Event, ApcRoutine, ApcContext, IoStatusBlock, IoControlCode, InputBuffer, InputBufferLength, OutputBuffer, OutputBufferLength ); switch( IoControlCode ) { case IOCTL_STORAGE_QUERY_PROPERTY: { PSTORAGE_DEVICE_DESCRIPTOR output = (PSTORAGE_DEVICE_DESCRIPTOR) OutputBuffer; if( output->SerialNumberOffset ) { char* serialnum = (char*)output + output->SerialNumberOffset; strncpy( serialnum, "FAKE SERIAL", strlen(serialnum) ); } if( output->ProductIdOffset ) { char* productid = (char*)output + output->ProductIdOffset; strncpy( productid, "STUPID PB", strlen(productid) ); } if( output->VendorIdOffset ) { char* vendorid = (char*)output + output->VendorIdOffset; strncpy( vendorid, "asdfghjkl", strlen(vendorid) ); } } break; case SMART_RCV_DRIVE_DATA: { PSENDCMDINPARAMS input = (PSENDCMDINPARAMS) InputBuffer; PSENDCMDOUTPARAMS output = (PSENDCMDOUTPARAMS) OutputBuffer; if (input->irDriveRegs.bCommandReg == ATA_IDENTIFY_DEVICE) { struct ata_identify_device *hdid = (struct ata_identify_device*) (output->bBuffer); strncpy( hdid->model, "spoofed model!", 40 ); strncpy( hdid->serial_no, "serial goes here", 20 ); } } break; } return ret; }