GetDeviceUniqueID

There is a new API available for retrieving a device id in Windows Mobile 5.0 for both Pocket PC and Smartphone. The first question: why do we need a new way of getting the device ID, what’s wrong with the old? To answer this you need to know what a device ID is. There is a very good and detailed explanation here, but in essence it’s a 16 byte code derived from hardware specific information that is unique to each device. This ID is not the same as an IMEI or a phone number found on a phone based device, both of which can be changed, but instead this code lives and dies with the device.

So the device ID is a very useful thing for software that wants to target just your device, e.g. copy protection, or to provide immutable identity to web service calls. Equally so it’s a resource that should be protected to mitigate the risk of identity theft.

Getting at the device id is relatively straight forward but requires either some C++ or a reasonable amount of interop code. The api is something like this:

KernelIoControl(IOCTL_HAL_GET_DEVICEID, 0, 0, buffer, GuidLength,out, bytesReturned);

Protecting Device ID has always been present as part of the Smartphone security model by making the KernelIoControl API a privileged operation, meaning your code must be running in the trusted code group to be able to access this API. But there are two problems with this:

1> Up to and including Pocket PC 2003SE there is no security model to protect the API, so Pocket PC didn’t have any protection on the Device ID.

2> what do untrusted applications do when they want to get access to this API?

3> having lots of applications read and use the device id potentially increases the attack surface for identity theft.

GetDeviceUniqueID attempts to address these issues and to reduce applications dependency on the precious device id. Firstly GetDeviceUniqueID can be called from the trusted or untrusted code group, but the code returned is not the same as a call to KernelIoControl, its a 20 byte code not a 16 byte code. GetDeviceUniqueID takes an additional parameters of an application defined char array, and uses a one way hash to combine the real device id and the char array parameter to generate the new 20 byte code. This means that an application will always get the same 20 byte code if it calls GetDeviceUniqueID on the same device, with the same char array. It also means there is no practical way of asserting the true device id from the 20 byte key an application uses.

This is a native API exposed by coredll.dll so here is a managed code snippet showing how to get the info through interop. Standard Code disclaimer applies

/*

HRESULT GetDeviceUniqueID(

  LPBYTE pbApplicationData,

  DWORD cbApplictionData,

  DWORD dwDeviceIDVersion,

  LPBYTE pbDeviceIDOutput,

  DWORD* pcbDeviceIDOutput

);

*/

[DllImport("coredll.dll")]

private extern static int GetDeviceUniqueID([In, Out] byte[] appdata,

                                            int cbApplictionData,

                                            int dwDeviceIDVersion,

                                            [In, Out] byte[] deviceIDOuput,

  out uint pcbDeviceIDOutput);

private byte[] GetDeviceID(string AppString)

{

    // Call the GetDeviceUniqueID

    byte[] AppData = new byte[AppString.Length];

    for (int count = 0; count < AppString.Length; count++)

        AppData[count] = (byte)AppString[count];

    int appDataSize = AppData.Length;

    byte[] DeviceOutput = new byte[20];

    uint SizeOut = 20;

    GetDeviceUniqueID(AppData, appDataSize, 1, DeviceOutput, out SizeOut);

    return DeviceOutput;

}

The full project code is here.

 

Marcus