The trick to get the real serial number of hard drive

Friday, 22 February 2008 12:14 by Alan Mojab

Here is the solution that would save you hours of research without a success. I have already turned every page on google (literally but spent over 50 hours before I discovered my solution) without a success so you are in the right place right now.

There are two solutions to this so you can pick the one that fits your needs best. Both solutions works under user account on XP and Vista. Without google I wouldn’t know anything about windows registry forensic techniques that helped to find these solutions.

Solution 1: Getting the serial number from Windows Registry

The serial numbers are stored under the following path:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\IDE

Or

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\SCSI

This solution is much harder to dig out the serial number as it needs searching child keys and parsing strings.

The child nodes that are listed under the above keys can contain CDROM drives as well or any device has been categorised as IDE/SCSI but you can examine a Key value called ‘Class’ to see if the drive is ‘CDROM’ or  ‘DiskDrive’. Expand the child nodes until you find the Key called ‘Class’ in the left pane of Windows Registry.

On my machine I have two hard drives… In case you never thought about this every machine that is designed to be a development machine must have two hard drives. One is used by OS and other Programs and the second one for your data/source code. You would reduce the risk of losing your source code tremendously by this setup.

Here is one of key entries for one of my hard drives:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\IDE\

DiskMaxtor_6V160E0__________________________VA111630

Model Number: DiskMaxtor_6V160E0 (The word ‘Disk’ is a prefix that is added by PnP service)

Controller Revision Number: VA111630

You should be able to see another child node below the above key. Here is mine:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\IDE\

DiskMaxtor_6V160E0__________________________VA111630\
3356333038524743202020202020202020202020

The child node 3356333038524743202020202020202020202020 is your serial number in hexadecimal. At the time I had no idea what that number was until I used Smarties2008’s Hex tool to examine the value. I can assure you if it wasn’t for the Hex tool in Smarties 2008 not in a million year I would have guessed the number I was looking at was actually my hard drive serial number.

However, there is one more thing you need to know. Once you converted the Hex value to string then you need to reverse every two characters to get the serial number in the correct order, if that was needed.

Notes:

If there is no serial number returned by the Hard Drive the PnP service would generate a serial number for the Hard Drive. You might notice the ‘&0’ characters in the serial number. Depending where they appear they mean something but I don’t know what they mean as I have decided not to use the Windows Registry solution all together. The second solution is much easier.

If you decided to use this solution then make sure you always open a key for ‘read’ that way you never face security permission issue under user account privilege.

Solution 2: Getting the serial number from WMI

Here how is done in my way that works under User Account both on XP and Vista:


ManagementScope managementScope = new ManagementScope(@"\root\cimv2"); 
managementScope.Options.Impersonation = system.Management.ImpersonationLevel.Impersonate; 
ManagementObjectSearcher searcher = new ManagementObjectSearcher(managementScope, new ObjectQuery("SELECT * FROM Win32_DiskDrive WHERE InterfaceType=\"IDE\" or InterfaceType=\"SCSI\"")); 
foreach (ManagementObject disk in searcher.Get()) 
{ 
    if (disk["PNPDeviceID"] != null) 
    { 
       string pnpDeviceID = disk["PNPDeviceID"].ToString(); 
       string[] split = pnpDeviceID.Split('\\'); 
    } 
}

The serial numbers have been hidden in PNPDeviceID property of Win32_DiskDrive class all this time and if someone knew about it he/she never gave away the secret, not even the ‘Scripting Guy’ shared the secret with us.

Here is the value of PNPDeviceID property from the same hard drive that I used in Windows Registry example:

IDE\DISKMAXTOR_6V160E0__________________________VA111630\
3356333038524743202020202020202020202020

It looks familiar doesn’t it? Now you can split this string by ‘\’ character to get the serial number in the last element of the split. Once again the 3356333038524743202020202020202020202020 value needs to be converted from Hex to string then reverse every two characters to get the serial number in the right order.

Here is a quick dirty way to reverse it:

private string ReverseSerialNumber(string serialNumber) 
{ 
    serialNumber = serialNumber.Trim(); 
    StringBuilder sb = new StringBuilder(); 
    for (int i = 0; i < serialNumber.Length; i += 2) 
    { 
        sb.Append(serialNumber[i + 1].ToString() + serialNumber[i].ToString()); 
    } 
    serialNumber = sb.ToString(); 
    sb = null; 
    return serialNumber; 
}/[code] 


And here is the code to convert Hex to String 


[code=csharp]private static Byte[] GetHexStringBytes(string hex) 
{ 
    try 
    { 
        if (hex.Contains(String.Empty)) 
        { 
            hex = hex.Replace(" ", String.Empty); 
        } 
        if (hex.Length % 2 == 1) 
        { 
            hex = "0" + hex; 
        } 
        int size = hex.Length / 2; 
        Byte[] bytes = new Byte[size]; 
        for (int i = 0; i < size; i++) 
        { 
            bytes[i] = Convert.ToByte(hex.Substring(i * 2, 2), 16); 
        } 
        return bytes; 
    } 
    catch 
    { 
        return new byte[] { }; 
    } 
}


Here how you would use the methods after splitting the PNPDeviceID

byte[] bytes = this.GetHexStringBytes(split[2]); 
string serial = this.ReverseSerialNumber(Encoding.UTF8.GetString(bytes));

Notes:

If the serial number was generated by PnP service then the split[2] element needs to be handled differently. To examine the split[2] value to see if the value was generated by PnP service use the following if statement below:

if (split[2][1] == '&')

Please make sure you read the follow up article to this.

Happy Coding!

Comments

March 5. 2008 08:49

Thank you very much for this code. I have seen so many things similar that have all been found to be lacking, and I think this one might just do the trick. I've only got to convert it into Visual Basic 6, which seems pretty straight forward, and then I'll know from there.

I have two questions for you:
1. Have you also tested this on Windows 2000 machines. In my field, many still use it.
2. Have you been able to test this on many different kinds of hard drives? I've tested similar code (accessing the Win32_DiskDrive information), and have had some strange results. For example, getting information from an SATA drive using XP Professional and a different kind of drive from Vista Home Basic was fine, but from an SATA drive on Vista Business didn't work.

Matthew E. Taft

March 5. 2008 16:58

Hello Mathew,

Thank you for your response to my blog article.

<<
Have you also tested this on Windows 2000 machines. In my field, many still use it.
>>

I haven’t had the time to test it under Win2K as my users wouldn’t be using this OS version any more. However, if I may, I can suggest to you to download the Trial version of VM Workstation from http://vmware.com and create a VM Win2K machine. If the Windows Registry had the same format then WMI would mostly likely return the same result too. I’m just guessing that the Win2K saves Hard Drive information in Win Registry in the same manner WinXP does.

<<
Have you been able to test this on many different kinds of hard drives? I've tested similar code (accessing the Win32_DiskDrive information), and have had some strange results. For example, getting information from an SATA drive using XP Professional and a different kind of drive from Vista Home Basic was fine, but from an SATA drive on Vista Business didn't work.
>>

One of the hard drives that I use on my machine is SATA1 and I could return the serial number of it using the same technique under XP Pro, with WMI solution. I have tested the same routine under Vista but using VM machine that uses SCSI interface. With regards to SATA problem under Vita Business I can only say my solution may work because you would be working with the PnPDeviceID that contains all the data you need. I’m just thinking loudly now… Perhaps WMI classes have internal problem parsing the information when it comes to SATA hard drives. WMI classes would read the same information from the Windows Registry too, there is no other storage place that I’m aware of.

I can’t possibly create all possible test environments to see if my solution works for all. This is very time consuming and very expensive as you can imagine.

Alan Mojab

March 5. 2008 22:28

Thanks for your reply. And I understand the possibilities are endless. I've been somewhat successful at converting the code into Visual Basic 6.0, but I've found something confusing. On the PC I'm testing on, I know the hard drive serial number is WD-WCAMA2482594.

Using the above code, my PNPDeviceID Is:
IDE\DISKWDC_WD400BB-22JHC0______________________05.01C05\5&E14364&0&0.0.0

After splitting as described above, I'm left with 5&E14364&0&0.0.0. This doesn't seem right to me. It's not hexadecimal and looked even more awkward when it ran through the hex to string conversion. I tried to match it up with the registry, and found that 5&E14364&0&0.0.0 is actually a subkey of:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\IDE\DiskWDC_WD400BB-22JHC0______________________05.01C05

I looked around in that area of the registry for a while and cannot find the serial number I expect to find (WD-WCAMA2482594).

I realize I'm in my own boat here and just have to keep rowing till I get somewhere, but does something obvious stand out to you as where I may have erred with this?

Thanks again.

Matthew E. Taft

March 6. 2008 00:13

Hello Matthew,

The value "5&E14364&0&0.0.0" is the serial number that the PnP service generated because the hard drive in question didn't return a serial number. As I have explained in the article you can examine the serial number by looking at the the second letter to see if it macthes the '&' char, if it does then you need to handle it differently.

You can take the value between the first '&' and the second '&' as the serial number as it is, no need to convert it from hex to string. From what you have posted I can see that you can extract more information to increase your chances to create unique serial number from the available data.

Alan Mojab

Add comment


 

  Country flag

[b][/b] - [i][/i] - [u][/u]- [quote][/quote]



Live preview

December 5. 2008 06:45