Search code examples
javacjnalibimobiledevice

libimobiledevice returning weird characters


I'm trying to pair with a connected iOS device and get the UDID using libimobiledevice and JNA. This is how I have declared the native functions:

static native int idevice_new(PointerByReference device, Pointer udid);
static native int lockdownd_client_new(Pointer device, PointerByReference client, String label);
static native int idevice_get_udid(Pointer idevice, StringByReference udid);
static native int lockdownd_query_type(Pointer lockdownd_client, StringByReference type);

For testing, I'm trying to do exactly what running the command idevicepair pair does.

This is my main method:

PointerByReference device = new PointerByReference();
System.out.println("idevice_new error code: " + idevice_new(device, Pointer.NULL));
PointerByReference client = new PointerByReference();
System.out.println("lockdownd_client_new error code: " + lockdownd_client_new(device.getValue(), client, "java"));
StringByReference udid = new StringByReference();
System.out.println("idevice_get_udid error code: " + idevice_get_udid(device.getValue(), udid));
System.out.println("udid: " + udid.getValue());
StringByReference type = new StringByReference();
System.out.println("lockdownd_query_type error code: " + lockdownd_query_type(client.getValue(), type));
System.out.println("lockdownd_query_type: " + type.getValue());
System.out.println("lockdownd_pair error code: " + lockdownd_pair(client.getValue(), Pointer.NULL));

Whenever I try to get any string value, it outputs these weird question mark characters:

idevice_new error code: 0
lockdownd_client_new error code: 0
idevice_get_udid error code: 0
udid: ��AZ�
lockdownd_query_type error code: 0
lockdownd_query_type: �HbZ�
lockdownd_pair error code: 0

The characters are different each time.

In case you can't see it:

program output


Solution

  • The UUID changes every time because it is unique! Each new one generated is different.

    As for the strange characters, your mapping of the uuid (and also type) to StringByReference is the culprit here, as you're not getting the data in the format it's stored in natively.

    The method signature in C (which you should have posted with your question) notes that the type of uuid is **char, a Pointer to a pointer to a string of 8-bit C values. Digging into the source code, it appears they are the digits 0-9 and A-F in a string representation, and either 32 bytes (without hyphens) or 36 bytes (with) plus the null terminator. (Note this isn't always obvious; they could have been stored in 16 bytes as the full byte value, something the API should actually document.)

    Internally, the StringByReference class uses the Pointer.getString() method:

    public String getValue() {
        return getPointer().getString(0);
    }
    

    The getString() method with only an offset uses your platform's default encoding, which is probably a multi-byte character set. This may not (and obviously doesn't, in your case) match the 8-bit encoding of the UUID.

    You should map the UUID as a PointerByReference and use uuid.getValue().getString(0, "UTF-8") or uuid.getValue().getString(0, "US-ASCII") to fetch the String as the 8-bit characters they represent.

    (Alternately, you could get a byte array and create a String from it, although I'm not sure if you'll get the 32- or 36-byte result, so have fun if you go that route. For true fun, you can iterate the offset and read byte-by-byte until you get 0. But I digress.)

    Doing the same thing for the type field is left as an exercise for the reader.