Sign in to follow this  
starnamer

HDD serial number flipped every 2 bytes! What's wrong? Help!

Recommended Posts

Hi, Sorry if I had post this in the wrong website but just hoping to get some help here. I wrote a Windows CE.NET 4.2 program to get the firmware serial number from an IDE harddisk. The platform isn't pocket pc. It is a CE.NET embedded device using AMD Geode (x86-based) CPU with Single-board computer and an IDE harddisk. The reason to get the serial number is to use it as a key for licensing a software. I used the DeviceIoControl Win32 API with the io control code of IOCTL_DISK_GET_STORAGEID (0x709). It worked. However, when I double check with the actual serial number printed on the hdd itself, I found that every 2 bytes of the number was flipped. A simple solution could be to simply flip the bytes back but I wish to know the exact reason why the bytes were flipped. Is it because the API actually reads every 2 bytes of the serial number as WORD? This could be the case since probably the number is stored as a character string on the firmware. e.g. "1234" But if the API reads word by word, and the Geode is x86-based (little endian), the flipping will occur which will cause it to be "2143". In that case, I would need to check the processor's endianness before reading the serial number. What then is the way to get the CPU's endianness? I would wish to develop a generic solution and not be tied down to a certain hardware platform. So I would like to ask if any of you had encountered such a similar case be it on an embedded CE.NET device or PPC 2003 device. Your help is greatly appreciated. Thanks in advance. Best Regards, Charles Wong

Share this post


Link to post
Share on other sites
Make sure you aren't somehow switching between ASCII and Unicode. That's the only reason I can think of why you would be reading the string 2 bytes at a time. The docs say the ID is an ASCII string.

If you can't find the cause of the swapping, then I would leave the ID alone. It may be disconcerting, but it doesn't hurt anything, does it? Swapping the bytes back will only result in complicated code.

Share this post


Link to post
Share on other sites
Thanks for you reply.

Below is my code. It is an EVC 4.0 project.
-------------------------------------------------------------------------

// hddserial.cpp : Defines the entry point for the application.
//

#include <windows.h>
#include <winioctl.h>

// From DISKIO.H of the Windows CE 3.0 Platform Builder *************
#define IOCTL_DISK_BASE FILE_DEVICE_DISK
#define IOCTL_DISK_GET_STORAGEID CTL_CODE(IOCTL_DISK_BASE, 0x709, METHOD_BUFFERED, FILE_ANY_ACCESS)
// From DISKIO.H of the Windows CE 3.0 Platform Builder *************


typedef struct _STORAGE_IDENTIFICATION {
DWORD dwSize;
DWORD dwFlags;
DWORD dwManufactureIDOffset;
DWORD dwSerialNumOffset;
} STORAGE_IDENTIFICATION, *PSTORAGE_IDENTIFICATION;
//
// And bits for the dwFlags field:
#define MANUFACTUREID_INVALID 0x01
#define SERIALNUM_INVALID 0x02


int WINAPI WinMain( HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
// TODO: Place code here.
HANDLE hDisk = CreateFile(_T("DSK1:"), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if (!hDisk)
return -1;

PSTORAGE_IDENTIFICATION pStoreInfo = (PSTORAGE_IDENTIFICATION) new BYTE[3000];
if (!pStoreInfo)
{
CloseHandle(hDisk);
return -1;
}

DWORD dwBytesRet;

if (!DeviceIoControl(hDisk, IOCTL_DISK_GET_STORAGEID, NULL, 0, pStoreInfo, 3000, &dwBytesRet, NULL))
{
DWORD err = GetLastError();
delete [] pStoreInfo;
CloseHandle(hDisk);
return -1;
}

BYTE *ManuID = (((BYTE *)pStoreInfo) + pStoreInfo->dwManufactureIDOffset);

HANDLE hFile = CreateFile(_T("\\serial.txt"), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);

DWORD dwBytes;

char spaces[] = "********";

WriteFile(hFile, ManuID, pStoreInfo->dwSerialNumOffset - pStoreInfo->dwManufactureIDOffset, &dwBytes, NULL);

WriteFile(hFile, spaces, strlen(spaces), &dwBytes, NULL);

BYTE *SerialNo = (((BYTE *)pStoreInfo) + pStoreInfo->dwSerialNumOffset);

WriteFile(hFile, SerialNo, dwBytesRet - pStoreInfo->dwSerialNumOffset, &dwBytes, NULL);

delete [] pStoreInfo;
CloseHandle(hDisk);

CloseHandle(hFile);

return 0;
}

==================================
_UNICODE and UNICODE are defined in the project settings.

As you can see, only the device name and output text file name have unicode strings. the rest is all byte strings (or ascii).

The output text file contains ascii text and not unicode strings.

Anyway, it doesn't really hurt anything (yet). I can't be sure if it will hurt later, depending on whether the ordering of the characters is important in the license checking. Just hoping to get a generic and correct method to get the serial out.

Share this post


Link to post
Share on other sites
I have done the exact same ting before, for the exact same purposes.

I seem to recall that I read it directly into a long using some API, then did a printf to convert the whole thing to hex. There were no endian issues.

However, in your case simply use a pointer to a short instead of a pointer to a byte, and read and write a short at a time, that way it will work fine.

Or simply don't worry about it. If all you're doing is storing the value and comparing it to the one on the drive on each successive launch of the program, then it'll be fine as-is.
[grin]So what if it'll be read and stored and read funny! So long as they match when they should right?[grin]

Share this post


Link to post
Share on other sites
Quote:
Original post by iMalc
I have done the exact same ting before, for the exact same purposes.

I seem to recall that I read it directly into a long using some API, then did a printf to convert the whole thing to hex. There were no endian issues.

However, in your case simply use a pointer to a short instead of a pointer to a byte, and read and write a short at a time, that way it will work fine.

Or simply don't worry about it. If all you're doing is storing the value and comparing it to the one on the drive on each successive launch of the program, then it'll be fine as-is.
[grin]So what if it'll be read and stored and read funny! So long as they match when they should right?[grin]


Thanks iMalc for your suggestion, but actually, I didn't quite get what you meant by reading the serial number into a long. A long var is usually 4 bytes and 8 bytes at most in some systems. How can the serial number which can be up to 20 bytes be stored into a long? Unless you meant a long pointer or a long array.

I also didn't quite get your point about using a short pointer. Do you mean the following:

......
short *SerialNo = (short*)((BYTE *)pStoreInfo + pStoreInfo->dwSerialNumOffset);

WriteFile(hFile, SerialNo, dwBytesRet - pStoreInfo->dwSerialNumOffset, &dwBytes, NULL);
......

Is that what you meant? Please elaborate. Thanks.

Share this post


Link to post
Share on other sites
The endianness problem might not be too big an issue. However, there is another question.

As mentioned, my current program runs on the WinCE.NET 4.2 platform to grab the hdd serial number attached to the board. It is pretty troublesome. Another way is to attach the hdd to my pc using a usb cable and access like a portable usb harddisk. This is the way the system was designed.

http://www.winsim.com/diskid32/diskid32.html

The diskid32 program above runs on desktop PC but it can only read SCSI, IDE and SATA fixed disks, not USB disks (as the website claimed). I looked at their source codes and seems to be the case.

Does anyone knows how to read the serial number of a usb hdd?

Many thanks.

Share this post


Link to post
Share on other sites
Quote:
Original post by starnamer
Quote:
Original post by iMalc
I have done the exact same ting before, for the exact same purposes.

I seem to recall that I read it directly into a long using some API, then did a printf to convert the whole thing to hex. There were no endian issues.

However, in your case simply use a pointer to a short instead of a pointer to a byte, and read and write a short at a time, that way it will work fine.

Or simply don't worry about it. If all you're doing is storing the value and comparing it to the one on the drive on each successive launch of the program, then it'll be fine as-is.
[grin]So what if it'll be read and stored and read funny! So long as they match when they should right?[grin]


Thanks iMalc for your suggestion, but actually, I didn't quite get what you meant by reading the serial number into a long. A long var is usually 4 bytes and 8 bytes at most in some systems. How can the serial number which can be up to 20 bytes be stored into a long? Unless you meant a long pointer or a long array.

I also didn't quite get your point about using a short pointer. Do you mean the following:

......
short *SerialNo = (short*)((BYTE *)pStoreInfo + pStoreInfo->dwSerialNumOffset);

WriteFile(hFile, SerialNo, dwBytesRet - pStoreInfo->dwSerialNumOffset, &dwBytes, NULL);
......

Is that what you meant? Please elaborate. Thanks.
A volume serial number is only 8 nibbles, i.e 4 bytes. e.g 184F-2A0C That's what thought you were talking about. I guess you must be talking about something slightly different.

Yes that first line is what I meant by accessing it as shorts. However, you'd have to write it in a different manner to the file. You basically need an endian conversion function. It's pretty simple:
unsigned short endianSwap(unsigned short inVal)
{
return (inVal>>8) || (inVal<<8);
}

Share this post


Link to post
Share on other sites
Quote:
Original post by iMalc
A volume serial number is only 8 nibbles, i.e 4 bytes. e.g 184F-2A0C That's what thought you were talking about. I guess you must be talking about something slightly different.

Yes that first line is what I meant by accessing it as shorts. However, you'd have to write it in a different manner to the file. You basically need an endian conversion function. It's pretty simple:
unsigned short endianSwap(unsigned short inVal)
{
return (inVal>>8) || (inVal<<8);
}


Nope. I wasn't talking about the volume serial number. It is the serial number that is stored in the HDD firmware. It is the same number that you would see on the serial number sticker on the outside of the drive. It cannot be changed even if the drive is formatted, whereas a volume serial number can change. That's why usually people use this firmware number for licensing a software. And that's what I hope to do too.

Anyway, I am temporarily putting this endianness issue aside first. I wish to look at a desktop PC version to get the serial number from the same drive (now connected to the PC as a USB device). If this could work, then hopefully the endianness issue can be automatically resolved. If not, then I would have to come back to this.

Thanks anyway.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this