Created
January 15, 2020 17:20
-
-
Save namazso/9ad3bbb17328ee91ebf65dcac1d3e2c1 to your computer and use it in GitHub Desktop.
DiskId32 updated, fixed, modernized
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// diskid32.cpp - display the details of hard drives in a command window | |
// | |
// Modernized version that compiles under VS2019 by namazso at 2020-01-15 | |
// Additional fixes and changes: | |
// - Rewrote MAC address part to not crash on 0 NICs and support 16+ NICs | |
// - Removed "ComputerId" and the relevant primitive hash method and parts | |
// | |
// 06/11/00 Lynn McGuire written with many contributions from others, | |
// IDE drives only under Windows NT/2K and 9X, | |
// maybe SCSI drives later | |
// 11/20/03 Lynn McGuire added ReadPhysicalDriveInNTWithZeroRights | |
// 10/26/05 Lynn McGuire fix the flipAndCodeBytes function | |
// 01/22/08 Lynn McGuire incorporate changes from Gonzalo Diethelm, | |
// remove media serial number code since does | |
// not work on USB hard drives or thumb drives | |
// 01/29/08 Lynn McGuire add ReadPhysicalDriveInNTUsingSmart | |
// 10/01/13 Lynn Mcguire fixed reference of buffer address per Torsten Eschner email | |
#define PRINTING_TO_CONSOLE_ALLOWED | |
#define _CRT_SECURE_NO_WARNINGS | |
#include <windows.h> | |
#include <Iphlpapi.h> | |
#include <cstdlib> | |
#include <cstdio> | |
#include <cstring> | |
#pragma comment(lib, "iphlpapi.lib") | |
#define TITLE "DiskId32" | |
char HardDriveSerialNumber[1024]; | |
char HardDriveModelNumber[1024]; | |
int PRINT_DEBUG = false; | |
static void dump_buffer( | |
const char* title, | |
const unsigned char* buffer, | |
int len | |
); | |
void WriteConstantString(const char* entry, const char* string) {} | |
// Required to ensure correct PhysicalDrive IOCTL structure setup | |
#pragma pack(1) | |
#define IDENTIFY_BUFFER_SIZE 512 | |
// IOCTL commands | |
#define DFP_GET_VERSION 0x00074080 | |
#define DFP_SEND_DRIVE_COMMAND 0x0007c084 | |
#define DFP_RECEIVE_DRIVE_DATA 0x0007c088 | |
#define FILE_DEVICE_SCSI 0x0000001b | |
#define IOCTL_SCSI_MINIPORT_IDENTIFY ((FILE_DEVICE_SCSI << 16) + 0x0501) | |
#define IOCTL_SCSI_MINIPORT 0x0004D008 // see NTDDSCSI.H for definition | |
#define SMART_GET_VERSION CTL_CODE(IOCTL_DISK_BASE, 0x0020, METHOD_BUFFERED, FILE_READ_ACCESS) | |
#define SMART_SEND_DRIVE_COMMAND CTL_CODE(IOCTL_DISK_BASE, 0x0021, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) | |
#define SMART_RCV_DRIVE_DATA CTL_CODE(IOCTL_DISK_BASE, 0x0022, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) | |
// GETVERSIONOUTPARAMS contains the data returned from the | |
// Get Driver Version function. | |
typedef struct _GETVERSIONOUTPARAMS | |
{ | |
BYTE bVersion; // Binary driver version. | |
BYTE bRevision; // Binary driver revision. | |
BYTE bReserved; // Not used. | |
BYTE bIDEDeviceMap; // Bit map of IDE devices. | |
DWORD fCapabilities; // Bit mask of driver capabilities. | |
DWORD dwReserved[4]; // For future use. | |
} GETVERSIONOUTPARAMS, *PGETVERSIONOUTPARAMS, *LPGETVERSIONOUTPARAMS; | |
// Bits returned in the fCapabilities member of GETVERSIONOUTPARAMS | |
#define CAP_IDE_ID_FUNCTION 1 // ATA ID command supported | |
#define CAP_IDE_ATAPI_ID 2 // ATAPI ID command supported | |
#define CAP_IDE_EXECUTE_SMART_FUNCTION 4 // SMART commannds supported | |
// Valid values for the bCommandReg member of IDEREGS. | |
#define IDE_ATAPI_IDENTIFY 0xA1 // Returns ID sector for ATAPI. | |
#define IDE_ATA_IDENTIFY 0xEC // Returns ID sector for ATA. | |
// The following struct defines the interesting part of the IDENTIFY | |
// buffer: | |
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]; | |
} IDSECTOR, *PIDSECTOR; | |
typedef struct _SRB_IO_CONTROL | |
{ | |
ULONG HeaderLength; | |
UCHAR Signature[8]; | |
ULONG Timeout; | |
ULONG ControlCode; | |
ULONG ReturnCode; | |
ULONG Length; | |
} SRB_IO_CONTROL, *PSRB_IO_CONTROL; | |
// Define global buffers. | |
BYTE IdOutCmd [sizeof(SENDCMDOUTPARAMS) + IDENTIFY_BUFFER_SIZE - 1]; | |
char* ConvertToString( | |
const DWORD diskdata [256], | |
int firstIndex, | |
int lastIndex, | |
char* buf | |
); | |
void PrintIdeInfo(int drive, DWORD diskdata [256]); | |
BOOL DoIDENTIFY( | |
HANDLE hPhysicalDriveIOCTL, | |
PSENDCMDINPARAMS pSCIP, | |
PSENDCMDOUTPARAMS pSCOP, | |
BYTE bIDCmd, | |
BYTE bDriveNum, | |
PDWORD lpcbBytesReturned | |
); | |
// Max number of drives assuming primary/secondary, master/slave topology | |
#define MAX_IDE_DRIVES 16 | |
int ReadPhysicalDriveInNTWithAdminRights() | |
{ | |
auto done = FALSE; | |
for (auto drive = 0; drive < MAX_IDE_DRIVES; drive++) | |
{ | |
// 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 | |
const auto hPhysicalDriveIOCTL = CreateFile( | |
driveName, | |
GENERIC_READ | GENERIC_WRITE, | |
FILE_SHARE_READ | FILE_SHARE_WRITE, | |
nullptr, | |
OPEN_EXISTING, | |
0, | |
nullptr | |
); | |
// if (hPhysicalDriveIOCTL == INVALID_HANDLE_VALUE) | |
// printf ("Unable to open physical drive %d, error code: 0x%lX\n", | |
// drive, GetLastError ()); | |
if (hPhysicalDriveIOCTL == INVALID_HANDLE_VALUE) | |
{ | |
#ifdef PRINTING_TO_CONSOLE_ALLOWED | |
if (PRINT_DEBUG) | |
printf( | |
"\n%d ReadPhysicalDriveInNTWithAdminRights ERROR" | |
"\nCreateFile(%s) returned INVALID_HANDLE_VALUE\n", | |
__LINE__, | |
driveName | |
); | |
#endif | |
} | |
else | |
{ | |
GETVERSIONOUTPARAMS VersionParams; | |
DWORD cbBytesReturned = 0; | |
// Get the version, etc of PhysicalDrive IOCTL | |
memset((void*)&VersionParams, 0, sizeof(VersionParams)); | |
if (! DeviceIoControl( | |
hPhysicalDriveIOCTL, | |
DFP_GET_VERSION, | |
nullptr, | |
0, | |
&VersionParams, | |
sizeof(VersionParams), | |
&cbBytesReturned, | |
nullptr | |
)) | |
{ | |
#ifdef PRINTING_TO_CONSOLE_ALLOWED | |
if (PRINT_DEBUG) | |
{ | |
const auto err = GetLastError(); | |
printf( | |
"\n%d ReadPhysicalDriveInNTWithAdminRights ERROR" | |
"\nDeviceIoControl(%p, DFP_GET_VERSION) returned 0, error is %d\n", | |
__LINE__, | |
hPhysicalDriveIOCTL, | |
(int)err | |
); | |
} | |
#endif | |
} | |
// If there is a IDE device at number "i" issue commands | |
// to the device | |
if (VersionParams.bIDEDeviceMap <= 0) | |
{ | |
#ifdef PRINTING_TO_CONSOLE_ALLOWED | |
if (PRINT_DEBUG) | |
printf( | |
"\n%d ReadPhysicalDriveInNTWithAdminRights ERROR" | |
"\nNo device found at position %d (%d)\n", | |
__LINE__, | |
(int)drive, | |
(int)VersionParams.bIDEDeviceMap | |
); | |
#endif | |
} | |
else | |
{ | |
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 | |
const BYTE 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]; | |
const auto pIdSector = (USHORT *) | |
((PSENDCMDOUTPARAMS)IdOutCmd)->bBuffer; | |
for (auto ijk = 0; ijk < 256; ijk++) | |
diskdata[ijk] = pIdSector[ijk]; | |
PrintIdeInfo(drive, diskdata); | |
done = TRUE; | |
} | |
} | |
CloseHandle(hPhysicalDriveIOCTL); | |
} | |
} | |
return done; | |
} | |
// | |
// IDENTIFY data (from ATAPI driver source) | |
// | |
#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() | |
int ReadPhysicalDriveInNTUsingSmart() | |
{ | |
auto done = FALSE; | |
for (auto drive = 0; drive < MAX_IDE_DRIVES; drive++) | |
{ | |
// 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, Windows Server 2003, Vista | |
const auto hPhysicalDriveIOCTL = CreateFile( | |
driveName, | |
GENERIC_READ | GENERIC_WRITE, | |
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, | |
nullptr, | |
OPEN_EXISTING, | |
0, | |
nullptr | |
); | |
// if (hPhysicalDriveIOCTL == INVALID_HANDLE_VALUE) | |
// printf ("Unable to open physical drive %d, error code: 0x%lX\n", | |
// drive, GetLastError ()); | |
if (hPhysicalDriveIOCTL == INVALID_HANDLE_VALUE) | |
{ | |
#ifdef PRINTING_TO_CONSOLE_ALLOWED | |
if (PRINT_DEBUG) | |
printf( | |
"\n%d ReadPhysicalDriveInNTUsingSmart ERROR" | |
"\nCreateFile(%s) returned INVALID_HANDLE_VALUE\n" | |
"Error Code %lu\n", | |
__LINE__, | |
driveName, | |
GetLastError() | |
); | |
#endif | |
} | |
else | |
{ | |
GETVERSIONINPARAMS GetVersionParams; | |
DWORD cbBytesReturned = 0; | |
// Get the version, etc of PhysicalDrive IOCTL | |
memset((void*)&GetVersionParams, 0, sizeof(GetVersionParams)); | |
if (! DeviceIoControl( | |
hPhysicalDriveIOCTL, | |
SMART_GET_VERSION, | |
nullptr, | |
0, | |
&GetVersionParams, | |
sizeof(GETVERSIONINPARAMS), | |
&cbBytesReturned, | |
nullptr | |
)) | |
{ | |
#ifdef PRINTING_TO_CONSOLE_ALLOWED | |
if (PRINT_DEBUG) | |
{ | |
const auto err = GetLastError(); | |
printf( | |
"\n%d ReadPhysicalDriveInNTUsingSmart ERROR" | |
"\nDeviceIoControl(%p, SMART_GET_VERSION) returned 0, error is %d\n", | |
__LINE__, | |
hPhysicalDriveIOCTL, | |
(int)err | |
); | |
} | |
#endif | |
} | |
else | |
{ | |
// Print the SMART version | |
// PrintVersion (& GetVersionParams); | |
// Allocate the command buffer | |
const ULONG CommandSize = sizeof(SENDCMDINPARAMS) + IDENTIFY_BUFFER_SIZE; | |
const auto Command = (PSENDCMDINPARAMS)malloc(CommandSize); | |
// Retrieve the IDENTIFY data | |
// Prepare the command | |
#define ID_CMD 0xEC // Returns ID sector for ATA | |
Command->irDriveRegs.bCommandReg = ID_CMD; | |
DWORD BytesReturned = 0; | |
if (! DeviceIoControl( | |
hPhysicalDriveIOCTL, | |
SMART_RCV_DRIVE_DATA, | |
Command, | |
sizeof(SENDCMDINPARAMS), | |
Command, | |
CommandSize, | |
&BytesReturned, | |
nullptr | |
)) | |
{ | |
// Print the error | |
//PrintError ("SMART_RCV_DRIVE_DATA IOCTL", GetLastError()); | |
} | |
else | |
{ | |
// Print the IDENTIFY data | |
DWORD diskdata [256]; | |
const auto pIdSector = (USHORT *) | |
(PIDENTIFY_DATA)((PSENDCMDOUTPARAMS)Command)->bBuffer; | |
for (auto ijk = 0; ijk < 256; ijk++) | |
diskdata[ijk] = pIdSector[ijk]; | |
PrintIdeInfo(drive, diskdata); | |
done = TRUE; | |
} | |
// Done | |
CloseHandle(hPhysicalDriveIOCTL); | |
free(Command); | |
} | |
} | |
} | |
return done; | |
} | |
#pragma pack(4) | |
// function to decode the serial numbers of IDE hard drives | |
// using the IOCTL_STORAGE_QUERY_PROPERTY command | |
char* flipAndCodeBytes( | |
const char* str, | |
int pos, | |
int flip, | |
char* buf | |
) | |
{ | |
int i; | |
auto j = 0; | |
auto k = 0; | |
buf[0] = '\0'; | |
if (pos <= 0) | |
return buf; | |
if (! j) | |
{ | |
char p = 0; | |
// First try to gather all characters representing hex digits only. | |
j = 1; | |
k = 0; | |
buf[k] = 0; | |
for (i = pos; j && str[i] != '\0'; ++i) | |
{ | |
char c = tolower(str[i]); | |
if (isspace(c)) | |
c = '0'; | |
++p; | |
buf[k] <<= 4; | |
if (c >= '0' && c <= '9') | |
buf[k] |= (unsigned char)(c - '0'); | |
else if (c >= 'a' && c <= 'f') | |
buf[k] |= (unsigned char)(c - 'a' + 10); | |
else | |
{ | |
j = 0; | |
break; | |
} | |
if (p == 2) | |
{ | |
if (buf[k] != '\0' && ! isprint(buf[k])) | |
{ | |
j = 0; | |
break; | |
} | |
++k; | |
p = 0; | |
buf[k] = 0; | |
} | |
} | |
} | |
if (! j) | |
{ | |
// There are non-digit characters, gather them as is. | |
j = 1; | |
k = 0; | |
for (i = pos; j && str[i] != '\0'; ++i) | |
{ | |
const auto c = str[i]; | |
if (! isprint(c)) | |
{ | |
j = 0; | |
break; | |
} | |
buf[k++] = c; | |
} | |
} | |
if (! j) | |
{ | |
// The characters are not there or are not printable. | |
k = 0; | |
} | |
buf[k] = '\0'; | |
if (flip) | |
// Flip adjacent characters | |
for (j = 0; j < k; j += 2) | |
{ | |
const auto t = buf[j]; | |
buf[j] = buf[j + 1]; | |
buf[j + 1] = t; | |
} | |
// Trim any beginning and end space | |
i = j = -1; | |
for (k = 0; buf[k] != '\0'; ++k) | |
{ | |
if (! isspace(buf[k])) | |
{ | |
if (i < 0) | |
i = k; | |
j = k; | |
} | |
} | |
if ((i >= 0) && (j >= 0)) | |
{ | |
for (k = i; (k <= j) && (buf[k] != '\0'); ++k) | |
buf[k - i] = buf[k]; | |
buf[k - i] = '\0'; | |
} | |
return buf; | |
} | |
#define IOCTL_DISK_GET_DRIVE_GEOMETRY_EX CTL_CODE(IOCTL_DISK_BASE, 0x0028, METHOD_BUFFERED, FILE_ANY_ACCESS) | |
int ReadPhysicalDriveInNTWithZeroRights() | |
{ | |
auto done = FALSE; | |
for (auto drive = 0; drive < MAX_IDE_DRIVES; drive++) | |
{ | |
HANDLE hPhysicalDriveIOCTL = nullptr; | |
// 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, Windows XP - admin rights not required | |
hPhysicalDriveIOCTL = CreateFile( | |
driveName, | |
0, | |
FILE_SHARE_READ | FILE_SHARE_WRITE, | |
nullptr, | |
OPEN_EXISTING, | |
0, | |
nullptr | |
); | |
if (hPhysicalDriveIOCTL == INVALID_HANDLE_VALUE) | |
{ | |
#ifdef PRINTING_TO_CONSOLE_ALLOWED | |
if (PRINT_DEBUG) | |
printf( | |
"\n%d ReadPhysicalDriveInNTWithZeroRights ERROR" | |
"\nCreateFile(%s) returned INVALID_HANDLE_VALUE\n", | |
__LINE__, | |
driveName | |
); | |
#endif | |
} | |
else | |
{ | |
STORAGE_PROPERTY_QUERY query; | |
DWORD cbBytesReturned = 0; | |
char local_buffer [10000]; | |
memset((void *)&query, 0, sizeof (query)); | |
query.PropertyId = StorageDeviceProperty; | |
query.QueryType = PropertyStandardQuery; | |
memset(local_buffer, 0, sizeof (local_buffer)); | |
if (DeviceIoControl( | |
hPhysicalDriveIOCTL, | |
IOCTL_STORAGE_QUERY_PROPERTY, | |
&query, | |
sizeof (query), | |
&local_buffer[0], | |
sizeof (local_buffer), | |
&cbBytesReturned, | |
nullptr | |
)) | |
{ | |
const auto descrip = (STORAGE_DEVICE_DESCRIPTOR *)&local_buffer; | |
char serialNumber [1000]; | |
char modelNumber [1000]; | |
char vendorId [1000]; | |
char productRevision [1000]; | |
#ifdef PRINTING_TO_CONSOLE_ALLOWED | |
if (PRINT_DEBUG) | |
{ | |
printf( | |
"\n%d STORAGE_DEVICE_DESCRIPTOR contents for drive %d\n" | |
" Version: %ld\n" | |
" Size: %ld\n" | |
" DeviceType: %02x\n" | |
" DeviceTypeModifier: %02x\n" | |
" RemovableMedia: %d\n" | |
" CommandQueueing: %d\n" | |
" VendorIdOffset: %4ld (0x%02lx)\n" | |
" ProductIdOffset: %4ld (0x%02lx)\n" | |
" ProductRevisionOffset: %4ld (0x%02lx)\n" | |
" SerialNumberOffset: %4ld (0x%02lx)\n" | |
" BusType: %d\n" | |
" RawPropertiesLength: %ld\n", | |
__LINE__, | |
drive, | |
(unsigned long)descrip->Version, | |
(unsigned long)descrip->Size, | |
(int)descrip->DeviceType, | |
(int)descrip->DeviceTypeModifier, | |
(int)descrip->RemovableMedia, | |
(int)descrip->CommandQueueing, | |
(unsigned long)descrip->VendorIdOffset, | |
(unsigned long)descrip->VendorIdOffset, | |
(unsigned long)descrip->ProductIdOffset, | |
(unsigned long)descrip->ProductIdOffset, | |
(unsigned long)descrip->ProductRevisionOffset, | |
(unsigned long)descrip->ProductRevisionOffset, | |
(unsigned long)descrip->SerialNumberOffset, | |
(unsigned long)descrip->SerialNumberOffset, | |
(int)descrip->BusType, | |
(unsigned long)descrip->RawPropertiesLength | |
); | |
dump_buffer( | |
"Contents of RawDeviceProperties", | |
(unsigned char*)descrip->RawDeviceProperties, | |
descrip->RawPropertiesLength | |
); | |
dump_buffer( | |
"Contents of first 256 bytes in buffer", | |
(unsigned char*)local_buffer, | |
256 | |
); | |
} | |
#endif | |
flipAndCodeBytes( | |
local_buffer, | |
descrip->VendorIdOffset, | |
0, | |
vendorId | |
); | |
flipAndCodeBytes( | |
local_buffer, | |
descrip->ProductIdOffset, | |
0, | |
modelNumber | |
); | |
flipAndCodeBytes( | |
local_buffer, | |
descrip->ProductRevisionOffset, | |
0, | |
productRevision | |
); | |
flipAndCodeBytes( | |
local_buffer, | |
descrip->SerialNumberOffset, | |
1, | |
serialNumber | |
); | |
if (0 == HardDriveSerialNumber[0] && | |
// serial number must be alphanumeric | |
// (but there can be leading spaces on IBM drives) | |
(isalnum(serialNumber[0]) || isalnum(serialNumber[19]))) | |
{ | |
strcpy(HardDriveSerialNumber, serialNumber); | |
strcpy(HardDriveModelNumber, modelNumber); | |
done = TRUE; | |
} | |
#ifdef PRINTING_TO_CONSOLE_ALLOWED | |
printf( | |
"\n**** STORAGE_DEVICE_DESCRIPTOR for drive %d ****\n" | |
"Vendor Id = [%s]\n" | |
"Product Id = [%s]\n" | |
"Product Revision = [%s]\n" | |
"Serial Number = [%s]\n", | |
drive, | |
vendorId, | |
modelNumber, | |
productRevision, | |
serialNumber | |
); | |
#endif | |
// Get the disk drive geometry. | |
memset(local_buffer, 0, sizeof(local_buffer)); | |
if (! DeviceIoControl( | |
hPhysicalDriveIOCTL, | |
IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, | |
nullptr, | |
0, | |
&local_buffer[0], | |
sizeof (local_buffer), | |
&cbBytesReturned, | |
nullptr | |
)) | |
{ | |
#ifdef PRINTING_TO_CONSOLE_ALLOWED | |
if (PRINT_DEBUG) | |
printf( | |
"\n%d ReadPhysicalDriveInNTWithZeroRights ERROR" | |
"|nDeviceIoControl(%s, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX) returned 0", | |
__LINE__, | |
driveName | |
); | |
#endif | |
} | |
else | |
{ | |
const auto geom = (DISK_GEOMETRY_EX *)&local_buffer[0]; | |
const int fixed = (geom->Geometry.MediaType == FixedMedia); | |
const auto size = geom->DiskSize.QuadPart; | |
#ifdef PRINTING_TO_CONSOLE_ALLOWED | |
printf( | |
"\n**** DISK_GEOMETRY_EX for drive %d ****\n" | |
"Disk is%s fixed\n" | |
"DiskSize = %I64d\n", | |
drive, | |
fixed ? "" : " NOT", | |
size | |
); | |
#endif | |
} | |
} | |
else | |
{ | |
const auto err = GetLastError(); | |
#ifdef PRINTING_TO_CONSOLE_ALLOWED | |
printf("\nDeviceIOControl IOCTL_STORAGE_QUERY_PROPERTY error = %lu\n", err); | |
#endif | |
} | |
CloseHandle(hPhysicalDriveIOCTL); | |
} | |
} | |
return done; | |
} | |
// DoIDENTIFY | |
// FUNCTION: Send an IDENTIFY command to the drive | |
// bDriveNum = 0-3 | |
// bIDCmd = IDE_ATA_IDENTIFY or IDE_ATAPI_IDENTIFY | |
BOOL DoIDENTIFY( | |
HANDLE hPhysicalDriveIOCTL, | |
PSENDCMDINPARAMS pSCIP, | |
PSENDCMDOUTPARAMS pSCOP, | |
BYTE bIDCmd, | |
BYTE bDriveNum, | |
PDWORD lpcbBytesReturned | |
) | |
{ | |
// Set up data structures for IDENTIFY command. | |
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; | |
// Compute the drive number. | |
pSCIP->irDriveRegs.bDriveHeadReg = 0xA0 | ((bDriveNum & 1) << 4); | |
// The command can either be IDE identify or ATAPI identify. | |
pSCIP->irDriveRegs.bCommandReg = bIDCmd; | |
pSCIP->bDriveNumber = bDriveNum; | |
pSCIP->cBufferSize = IDENTIFY_BUFFER_SIZE; | |
return DeviceIoControl( | |
hPhysicalDriveIOCTL, | |
DFP_RECEIVE_DRIVE_DATA, | |
(LPVOID)pSCIP, | |
sizeof(SENDCMDINPARAMS) - 1, | |
(LPVOID)pSCOP, | |
sizeof(SENDCMDOUTPARAMS) + IDENTIFY_BUFFER_SIZE - 1, | |
lpcbBytesReturned, | |
nullptr | |
); | |
} | |
// --------------------------------------------------- | |
// (* Output Bbuffer for the VxD (rt_IdeDinfo record) *) | |
typedef struct _rt_IdeDInfo_ | |
{ | |
BYTE IDEExists[4]; | |
BYTE DiskExists[8]; | |
WORD DisksRawInfo[8 * 256]; | |
} rt_IdeDInfo, *pt_IdeDInfo; | |
// (* IdeDinfo "data fields" *) | |
typedef struct _rt_DiskInfo_ | |
{ | |
BOOL DiskExists; | |
BOOL ATAdevice; | |
BOOL RemovableDevice; | |
WORD TotLogCyl; | |
WORD TotLogHeads; | |
WORD TotLogSPT; | |
char SerialNumber[20]; | |
char FirmwareRevision[8]; | |
char ModelNumber[40]; | |
WORD CurLogCyl; | |
WORD CurLogHeads; | |
WORD CurLogSPT; | |
} rt_DiskInfo; | |
#define m_cVxDFunctionIdesDInfo 1 | |
// --------------------------------------------------- | |
int ReadDrivePortsInWin9X() | |
{ | |
auto done = FALSE; | |
DWORD lpBytesReturned = 0; | |
// set the thread priority high so that we get exclusive access to the disk | |
const auto status = | |
// SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); | |
SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS); | |
// SetPriorityClass (GetCurrentProcess (), HIGH_PRIORITY_CLASS); | |
#ifdef PRINTING_TO_CONSOLE_ALLOWED | |
if (0 == status) | |
// printf ("\nERROR: Could not SetThreadPriority, LastError: %d\n", GetLastError ()); | |
printf("\nERROR: Could not SetPriorityClass, LastError: %lu\n", GetLastError()); | |
#endif | |
// 1. Make an output buffer for the VxD | |
rt_IdeDInfo info; | |
auto pOutBufVxD = &info; | |
// ***************** | |
// KLUDGE WARNING!!! | |
// HAVE to zero out the buffer space for the IDE information! | |
// If this is NOT done then garbage could be in the memory | |
// locations indicating if a disk exists or not. | |
ZeroMemory(&info, sizeof(info)); | |
// 1. Try to load the VxD | |
// must use the short file name path to open a VXD file | |
//char StartupDirectory [2048]; | |
//char shortFileNamePath [2048]; | |
//char *p = NULL; | |
//char vxd [2048]; | |
// get the directory that the exe was started from | |
//GetModuleFileName (hInst, (LPSTR) StartupDirectory, sizeof (StartupDirectory)); | |
// cut the exe name from string | |
//p = &(StartupDirectory [strlen (StartupDirectory) - 1]); | |
//while (p >= StartupDirectory && *p && '\\' != *p) p--; | |
//*p = '\0'; | |
//GetShortPathName (StartupDirectory, shortFileNamePath, 2048); | |
//sprintf (vxd, "\\\\.\\%s\\IDE21201.VXD", shortFileNamePath); | |
//VxDHandle = CreateFile (vxd, 0, 0, 0, | |
// 0, FILE_FLAG_DELETE_ON_CLOSE, 0); | |
const auto VxDHandle = CreateFile( | |
"\\\\.\\IDE21201.VXD", | |
0, | |
0, | |
nullptr, | |
0, | |
FILE_FLAG_DELETE_ON_CLOSE, | |
nullptr | |
); | |
if (VxDHandle != INVALID_HANDLE_VALUE) | |
{ | |
// 2. Run VxD function | |
DeviceIoControl( | |
VxDHandle, | |
m_cVxDFunctionIdesDInfo, | |
nullptr, | |
0, | |
pOutBufVxD, | |
sizeof(pt_IdeDInfo), | |
&lpBytesReturned, | |
nullptr | |
); | |
// 3. Unload VxD | |
CloseHandle(VxDHandle); | |
} | |
else | |
MessageBox( | |
nullptr, | |
"ERROR: Could not open IDE21201.VXD file", | |
TITLE, | |
MB_ICONSTOP | |
); | |
// 4. Translate and store data | |
for (auto i = 0; i < 8; i++) | |
{ | |
if ((pOutBufVxD->DiskExists[i]) && (pOutBufVxD->IDEExists[i / 2])) | |
{ | |
DWORD diskinfo [256]; | |
for (auto j = 0; j < 256; j++) | |
diskinfo[j] = pOutBufVxD->DisksRawInfo[i * 256 + j]; | |
// process the information for this buffer | |
PrintIdeInfo(i, diskinfo); | |
done = TRUE; | |
} | |
} | |
// reset the thread priority back to normal | |
// SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_NORMAL); | |
SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS); | |
return done; | |
} | |
#define SENDIDLENGTH (sizeof (SENDCMDOUTPARAMS) + IDENTIFY_BUFFER_SIZE) | |
int ReadIdeDriveAsScsiDriveInNT() | |
{ | |
auto done = FALSE; | |
for (auto controller = 0; controller < 16; controller++) | |
{ | |
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 | |
const auto hScsiDriveIOCTL = CreateFile( | |
driveName, | |
GENERIC_READ | GENERIC_WRITE, | |
FILE_SHARE_READ | FILE_SHARE_WRITE, | |
nullptr, | |
OPEN_EXISTING, | |
0, | |
nullptr | |
); | |
// if (hScsiDriveIOCTL == INVALID_HANDLE_VALUE) | |
// printf ("Unable to open SCSI controller %d, error code: 0x%lX\n", | |
// controller, GetLastError ()); | |
if (hScsiDriveIOCTL != INVALID_HANDLE_VALUE) | |
{ | |
for (auto drive = 0; drive < 2; drive++) | |
{ | |
char buffer [sizeof(SRB_IO_CONTROL) + SENDIDLENGTH]; | |
const auto p = (SRB_IO_CONTROL *)buffer; | |
const auto 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, | |
nullptr | |
)) | |
{ | |
const auto pOut = | |
(SENDCMDOUTPARAMS *)(buffer + sizeof(SRB_IO_CONTROL)); | |
auto pId = (IDSECTOR *)(pOut->bBuffer); | |
if (pId->sModelNumber[0]) | |
{ | |
DWORD diskdata [256]; | |
const auto pIdSector = (USHORT *)pId; | |
for (auto ijk = 0; ijk < 256; ijk++) | |
diskdata[ijk] = pIdSector[ijk]; | |
PrintIdeInfo(controller * 2 + drive, diskdata); | |
done = TRUE; | |
} | |
} | |
} | |
CloseHandle(hScsiDriveIOCTL); | |
} | |
} | |
return done; | |
} | |
void PrintIdeInfo(int drive, DWORD diskdata [256]) | |
{ | |
char serialNumber [1024]; | |
char modelNumber [1024]; | |
char revisionNumber [1024]; | |
char bufferSize [32]; | |
LONG64 sectors = 0; | |
LONG64 bytes = 0; | |
// copy the hard drive serial number to the buffer | |
ConvertToString(diskdata, 10, 19, serialNumber); | |
ConvertToString(diskdata, 27, 46, modelNumber); | |
ConvertToString(diskdata, 23, 26, revisionNumber); | |
sprintf(bufferSize, "%lu", diskdata[21] * 512); | |
if (0 == HardDriveSerialNumber[0] && | |
// serial number must be alphanumeric | |
// (but there can be leading spaces on IBM drives) | |
(isalnum(serialNumber[0]) || isalnum(serialNumber[19]))) | |
{ | |
strcpy(HardDriveSerialNumber, serialNumber); | |
strcpy(HardDriveModelNumber, modelNumber); | |
} | |
#ifdef PRINTING_TO_CONSOLE_ALLOWED | |
printf("\nDrive %d - ", drive); | |
switch (drive / 2) | |
{ | |
case 0: printf("Primary Controller - "); | |
break; | |
case 1: printf("Secondary Controller - "); | |
break; | |
case 2: printf("Tertiary Controller - "); | |
break; | |
case 3: printf("Quaternary Controller - "); | |
break; | |
} | |
switch (drive % 2) | |
{ | |
case 0: printf("Master drive\n\n"); | |
break; | |
case 1: printf("Slave drive\n\n"); | |
break; | |
} | |
printf( | |
"Drive Model Number________________: [%s]\n", | |
modelNumber | |
); | |
printf( | |
"Drive Serial Number_______________: [%s]\n", | |
serialNumber | |
); | |
printf( | |
"Drive Controller Revision Number__: [%s]\n", | |
revisionNumber | |
); | |
printf( | |
"Controller Buffer Size on Drive___: %s bytes\n", | |
bufferSize | |
); | |
printf("Drive Type________________________: "); | |
if (diskdata[0] & 0x0080) | |
printf("Removable\n"); | |
else if (diskdata[0] & 0x0040) | |
printf("Fixed\n"); | |
else | |
printf("Unknown\n"); | |
// calculate size based on 28 bit or 48 bit addressing | |
// 48 bit addressing is reflected by bit 10 of word 83 | |
if (diskdata[83] & 0x400) | |
sectors = diskdata[103] * 65536I64 * 65536I64 * 65536I64 + | |
diskdata[102] * 65536I64 * 65536I64 + | |
diskdata[101] * 65536I64 + | |
diskdata[100]; | |
else | |
sectors = diskdata[61] * 65536I64 + diskdata[60]; | |
// there are 512 bytes in a sector | |
bytes = sectors * 512; | |
printf( | |
"Drive Size________________________: %I64d bytes\n", | |
bytes | |
); | |
#endif // PRINTING_TO_CONSOLE_ALLOWED | |
char string1 [1000]; | |
sprintf(string1, "Drive%dModelNumber", drive); | |
WriteConstantString(string1, modelNumber); | |
sprintf(string1, "Drive%dSerialNumber", drive); | |
WriteConstantString(string1, serialNumber); | |
sprintf(string1, "Drive%dControllerRevisionNumber", drive); | |
WriteConstantString(string1, revisionNumber); | |
sprintf(string1, "Drive%dControllerBufferSize", drive); | |
WriteConstantString(string1, bufferSize); | |
sprintf(string1, "Drive%dType", drive); | |
if (diskdata[0] & 0x0080) | |
WriteConstantString(string1, "Removable"); | |
else if (diskdata[0] & 0x0040) | |
WriteConstantString(string1, "Fixed"); | |
else | |
WriteConstantString(string1, "Unknown"); | |
} | |
char* ConvertToString( | |
const DWORD diskdata [256], | |
int firstIndex, | |
int lastIndex, | |
char* buf | |
) | |
{ | |
auto position = 0; | |
// each integer has two characters stored in it backwards | |
for (auto index = firstIndex; index <= lastIndex; index++) | |
{ | |
// get high byte for 1st character | |
buf[position++] = (char)(diskdata[index] / 256); | |
// get low byte for 2nd character | |
buf[position++] = (char)(diskdata[index] % 256); | |
} | |
// end the string | |
buf[position] = '\0'; | |
// cut off the trailing blanks | |
for (auto index = position - 1; index > 0 && isspace(buf[index]); index--) | |
buf[index] = '\0'; | |
return buf; | |
} | |
void getHardDriveComputerID() | |
{ | |
auto done = FALSE; | |
// char string [1024]; | |
LONGLONG id = 0; | |
OSVERSIONINFO version; | |
strcpy(HardDriveSerialNumber, ""); | |
memset(&version, 0, sizeof (version)); | |
version.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); | |
#pragma warning(push) | |
#pragma warning(suppress: 4996) | |
GetVersionEx(&version); | |
#pragma warning(pop) | |
if (version.dwPlatformId == VER_PLATFORM_WIN32_NT) | |
{ | |
// this works under WinNT4 or Win2K if you have admin rights | |
#ifdef PRINTING_TO_CONSOLE_ALLOWED | |
printf("\nTrying to read the drive IDs using physical access with admin rights\n"); | |
#endif | |
done = ReadPhysicalDriveInNTWithAdminRights(); | |
// this should work in WinNT or Win2K if previous did not work | |
// this is kind of a backdoor via the SCSI mini port driver into | |
// the IDE drives | |
#ifdef PRINTING_TO_CONSOLE_ALLOWED | |
printf("\nTrying to read the drive IDs using the SCSI back door\n"); | |
#endif | |
// if ( ! done) | |
done = ReadIdeDriveAsScsiDriveInNT(); | |
// this works under WinNT4 or Win2K or WinXP if you have any rights | |
#ifdef PRINTING_TO_CONSOLE_ALLOWED | |
printf("\nTrying to read the drive IDs using physical access with zero rights\n"); | |
#endif | |
//if ( ! done) | |
done = ReadPhysicalDriveInNTWithZeroRights(); | |
// this works under WinNT4 or Win2K or WinXP or Windows Server 2003 or Vista if you have any rights | |
#ifdef PRINTING_TO_CONSOLE_ALLOWED | |
printf("\nTrying to read the drive IDs using Smart\n"); | |
#endif | |
//if ( ! done) | |
done = ReadPhysicalDriveInNTUsingSmart(); | |
} | |
else | |
{ | |
// this works under Win9X and calls a VXD | |
auto attempt = 0; | |
// try this up to 10 times to get a hard drive serial number | |
for (attempt = 0; | |
attempt < 10 && ! done && 0 == HardDriveSerialNumber[0]; | |
attempt++) | |
done = ReadDrivePortsInWin9X(); | |
} | |
if (HardDriveSerialNumber[0] > 0) | |
{ | |
auto p = HardDriveSerialNumber; | |
WriteConstantString("HardDriveSerialNumber", HardDriveSerialNumber); | |
} | |
#ifdef PRINTING_TO_CONSOLE_ALLOWED | |
printf( | |
"\nHard Drive Serial Number__________: %s\n", | |
HardDriveSerialNumber | |
); | |
printf( | |
"\nHard Drive Model Number___________: %s\n", | |
HardDriveModelNumber | |
); | |
#endif | |
} | |
static void PrintMACaddress(PBYTE MACData) | |
{ | |
#ifdef PRINTING_TO_CONSOLE_ALLOWED | |
printf( | |
"\nMAC Address: %02X-%02X-%02X-%02X-%02X-%02X\n", | |
MACData[0], | |
MACData[1], | |
MACData[2], | |
MACData[3], | |
MACData[4], | |
MACData[5] | |
); | |
#endif | |
char string[256]; | |
sprintf( | |
string, | |
"%02X-%02X-%02X-%02X-%02X-%02X", | |
MACData[0], | |
MACData[1], | |
MACData[2], | |
MACData[3], | |
MACData[4], | |
MACData[5] | |
); | |
WriteConstantString("MACaddress", string); | |
} | |
void GetMACaddress() | |
{ | |
DWORD dwBufLen = 0; | |
auto dwStatus = GetAdaptersInfo( | |
nullptr, // [out] buffer to receive data | |
&dwBufLen // [in] size of receive data buffer | |
); | |
PIP_ADAPTER_INFO pAdapterInfo = nullptr; | |
while(dwStatus == ERROR_BUFFER_OVERFLOW) | |
{ | |
LocalFree(pAdapterInfo); | |
pAdapterInfo = (PIP_ADAPTER_INFO)LocalAlloc(LMEM_FIXED, dwBufLen); | |
dwStatus = GetAdaptersInfo( | |
pAdapterInfo, // [out] buffer to receive data | |
&dwBufLen // [in] size of receive data buffer | |
); | |
} | |
// Fail reason could be the lack of adapters too | |
if(dwStatus == ERROR_SUCCESS) | |
for (auto pInfo = pAdapterInfo; pInfo; pInfo = pInfo->Next) | |
PrintMACaddress(pInfo->Address); | |
LocalFree(pAdapterInfo); | |
} | |
static void dump_buffer( | |
const char* title, | |
const unsigned char* buffer, | |
int len | |
) | |
{ | |
auto i = 0; | |
int j; | |
printf("\n-- %s --\n", title); | |
if (len > 0) | |
{ | |
printf("%8.8s ", " "); | |
for (j = 0; j < 16; ++j) | |
{ | |
printf(" %2X", j); | |
} | |
printf(" "); | |
for (j = 0; j < 16; ++j) | |
{ | |
printf("%1X", j); | |
} | |
printf("\n"); | |
} | |
while (i < len) | |
{ | |
printf("%08x ", i); | |
for (j = 0; j < 16; ++j) | |
{ | |
if ((i + j) < len) | |
printf(" %02x", (int)buffer[i + j]); | |
else | |
printf(" "); | |
} | |
printf(" "); | |
for (j = 0; j < 16; ++j) | |
{ | |
if ((i + j) < len) | |
printf("%c", isprint(buffer[i + j]) ? buffer[i + j] : '.'); | |
else | |
printf(" "); | |
} | |
printf("\n"); | |
i += 16; | |
} | |
printf("-- DONE --\n"); | |
} | |
int main(int argc, char* argv []) | |
{ | |
printf("To get all details use \"diskid32 /d\"\n"); | |
if (argc > 1 && strstr(argv[1], "/d")) | |
PRINT_DEBUG = true; | |
else | |
PRINT_DEBUG = false; | |
getHardDriveComputerID(); | |
GetMACaddress(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment