MobileDevice Library

From The iPhone Wiki
Revision as of 18:51, 27 May 2010 by DarkMalloc (talk | contribs)
Jump to: navigation, search

MobileDevice Library is used by iTunes to transfer data between iPhone and computer over the USB connection.

PC Windows : iTunesMobileDevice.dll

  • Location : Location is stored in iTunesMobileDeviceDLL registry value under HKLM\SOFTWARE\Apple Inc.\Apple Mobile Device Support\Shared key. Usually - C:\Program Files\Common Files\Apple\Mobile Device Support\bin\iTunesMobileDevice.dll.
  • Supporting CoreFoundation.dll (used for CFStringRef, CFPropertyListRef management) is located in the same dir (when using iTunes prior 9.0).
  • For iTunes 9.0 location of CoreFoundation.dll is stored in InstallDir registry value under HKLM\SOFTWARE\Apple Inc.\Apple Application Support key, usually C:\Program Files\Common Files\Apple\Apple Application Support\. CoreFoundation.dll from Mobile Device Support\bin should not be used.

Mac OSX : MobileDevice.framework

  • Location : /System/Library/PrivateFrameworks/MobileDevice.framework
  • Export command : "nm /System/Library/PrivateFrameworks/MobileDevice.framework/Versions/A/MobileDevice"

MobileDevice Header (mobiledevice.h)

Reverse engineered C header for MobileDevice Library.

#ifndef MOBILEDEVICE_H
#define MOBILEDEVICE_H

#define CF_BUILDING_CF_AS_LIB
#include <CoreFoundation/CoreFoundation.h>

//typedef unsigned int unsigned int;

/* Error codes */
#define MDERR_APPLE_MOBILE  (err_system(0x3a))
#define MDERR_IPHONE        (err_sub(0))

/* Apple Mobile (AM*) errors */
#define MDERR_OK                ERR_SUCCESS
#define MDERR_SYSCALL           (ERR_MOBILE_DEVICE | 0x01)
#define MDERR_OUT_OF_MEMORY     (ERR_MOBILE_DEVICE | 0x03)
#define MDERR_QUERY_FAILED      (ERR_MOBILE_DEVICE | 0x04) 
#define MDERR_INVALID_ARGUMENT  (ERR_MOBILE_DEVICE | 0x0b)
#define MDERR_DICT_NOT_LOADED   (ERR_MOBILE_DEVICE | 0x25)

/* Messages passed to device notification callbacks: passed as part of
 * am_device_notification_callback_info. */
#define ADNCI_MSG_CONNECTED     1
#define ADNCI_MSG_DISCONNECTED  2
#define ADNCI_MSG_UNKNOWN       3

typedef struct am_recovery_device am_recovery_device;

struct am_device_notification_callback_info {
    struct am_device *dev;  /* 0    device */ 
    unsigned int msg;       /* 4    one of ADNCI_MSG_* */
} __attribute__ ((packed));

/* The type of the device notification callback function. */
typedef void(*am_device_notification_callback)(struct
											   am_device_notification_callback_info *);

/* The type of the device restore notification callback functions.
 * TODO: change to correct type. */
typedef void (*am_restore_device_notification_callback)(am_recovery_device *);

/* This is a CoreFoundation object of class AMRecoveryModeDevice. */
struct am_recovery_device {
    unsigned char unknown0[8];                          /* 0 */
    am_restore_device_notification_callback callback;   /* 8 */
    void *user_info;                                    /* 12 */
    unsigned char unknown1[12];                         /* 16 */
    unsigned int readwrite_pipe;                        /* 28 */
    unsigned char read_pipe;                            /* 32 */
    unsigned char write_ctrl_pipe;                      /* 33 */
    unsigned char read_unknown_pipe;                    /* 34 */
    unsigned char write_file_pipe;                      /* 35 */
    unsigned char write_input_pipe;                     /* 36 */
} __attribute__ ((packed));

struct afc_connection {
	unsigned int handle;            /* 0 */
	unsigned int unknown0;          /* 4 */
	unsigned char unknown1;         /* 8 */
	unsigned char padding[3];       /* 9 */
	unsigned int unknown2;          /* 12 */
	unsigned int unknown3;          /* 16 */
	unsigned int unknown4;          /* 20 */
	unsigned int fs_block_size;     /* 24 */
	unsigned int sock_block_size;   /* 28: always 0x3c */
	unsigned int io_timeout;        /* 32: from AFCConnectionOpen, usu. 0 */
	void *afc_lock;                 /* 36 */
	unsigned int context;           /* 40 */
} __attribute__ ((packed));

/* A CoreFoundation object of class AMRestoreModeDevice. */
struct am_restore_device {
    unsigned char unknown[32];
    int port;
} __attribute__ ((packed));


/* The type of the _AMDDeviceAttached function.
 * TODO: change to correct type. */
typedef void *amd_device_attached_callback;

struct am_device {
	unsigned char unknown0[16]; /* 0 - zero */
	unsigned int device_id;     /* 16 */
	unsigned int product_id;    /* 20 - set to AMD_IPHONE_PRODUCT_ID */
	char *serial;               /* 24 - set to UDID, Unique Device Identifier */
	unsigned int unknown1;      /* 28 */
	unsigned int unknown2;      /* 32 - reference counter, increased by AMDeviceRetain, decreased by AMDeviceRelease*/
	unsigned int lockdown_conn; /* 36 */
	unsigned char unknown3[8];  /* 40 */
	unsigned int unknown4;      /* 48 - used to store CriticalSection Handle*/
	unsigned char unknown5[24];  /* 52 */
} __attribute__ ((packed));

struct am_device_notification {
    unsigned int unknown0;                      /* 0 */
    unsigned int unknown1;                      /* 4 */
    unsigned int unknown2;                      /* 8 */
    am_device_notification_callback callback;   /* 12 */ 
    unsigned int unknown3;                      /* 16 */
} __attribute__ ((packed));

unsigned int AMDeviceNotificationSubscribe(am_device_notification_callback
										   callback, unsigned int unused0, unsigned int unused1, unsigned int
										   dn_unknown3, struct am_device_notification **notification);

unsigned int AMRestoreRegisterForDeviceNotifications(
													 am_restore_device_notification_callback dfu_connect_callback,
													 am_restore_device_notification_callback recovery_connect_callback,
													 am_restore_device_notification_callback dfu_disconnect_callback,
													 am_restore_device_notification_callback recovery_disconnect_callback,
													 unsigned int unknown0,
													 void *user_info);

CFMutableDictionaryRef AMRestoreCreateDefaultOptions(CFAllocatorRef allocator);

unsigned int AMRestoreEnableFileLogging(char *path);
unsigned int AMDeviceEnterRecovery(struct am_device *device);

unsigned int AMDeviceRetain(struct am_device *device);
CFStringRef AMDeviceCopyValue(struct am_device *device, CFStringRef domain, CFStringRef cfstring);

unsigned int AMDeviceStartService(struct am_device *device, CFStringRef service_name, void **handle, int *socket_fd);

unsigned int AMDPostNotification(int socket, CFStringRef  notification, CFStringRef userinfo);
unsigned int AMDeviceConnect(struct am_device *device);

unsigned int AMDShutdownNotificationProxy(int socket);

unsigned int AMDeviceIsPaired(struct am_device *device);
unsigned int AMDevicePair(struct am_device *device);
unsigned int AMDeviceValidatePairing(struct am_device *device);
unsigned int AMDeviceStartSession(struct am_device *device);

unsigned int AMRestorePerformDFURestore(struct am_recovery_device *rdev, CFDictionaryRef opts, void *callback, void *user_info);

int sendCommandToDevice(am_recovery_device *rdev, CFStringRef cfs, int block);
int sendFileToDevice(am_recovery_device *rdev, CFStringRef filename);

#endif

AFC Connection

...

Locking the Device for Sync

When iTunes sends a new song to the device, the device shows a "Sync in progress" screen and when complete, the Music app on the device re-reads the iTunesDB file so it picks up the new song.

To get this behaviour, first start the notification service:

SOCKET socket;
AMDeviceStartService(dev, CFSTR("com.apple.mobile.notification_proxy"), &socket, NULL);

Now we post a notificaton message to signal that we are going to start a sync:

AMDPostNotification(socket, CFSTR("com.apple.itunes-mobdev.syncWillStart"), NULL);

Next we open the itunes lock file:

afc_file_ref lockref;
AFCFileRefOpen(conn, "/com.apple.itunes.lock_sync", 2, &lockref);

Now post a notification to say we are going to lock this file, and try and lock it. If the AFCFileRefLock call fails, pause and repeat.

AMDPostNotification(socket, CFSTR("com.apple.itunes-mobdev.syncLockRequest"), NULL);
mach_error_t error = AFCFileRefLock(conn, lockref);

When the file is successfully locked, post another notification, and stop the notification service.

AMDPostNotification(socket,CFSTR("com.apple.itunes-mobdev.syncDidStart"), NULL);
AMDShutdownNotificationProxy(socket);

Now the sync can proceed, so copy your files across and make the changes to the iTunesDB.

To release the lock, start the notification system again, unlock and close the lock file, and send a sync finished notification message:

AFCFileRefUnlock(conn, lockref);
AFCFileRefClose(conn, lockref);
AMDeviceStartService(dev, CFSTR("com.apple.mobile.notification_proxy"), &socket, NULL);
AMDPostNotification(socket, &CFSTR("com.apple.itunes-mobdev.syncDidFinish"), NULL);
AMDShutdownNotificationProxy(socket);

To handle "Slide to Cancel" and terminate sync when user slides cancel switch, use AMDObserveNotification to subscribe notifications about “com.apple.itunes-client.syncCancelRequest”. Then start listening for notifications (AMDListenForNotifications) until you get “AMDNotificationFaceplant”. When notification got, you should unlock and close lock file handle (don’t sure if you need to post “syncDidFinish” to proxy, seems it doesn’t matter) and terminate sync gracefully. The same notification is also got when you unplug your device, so you should always be ready for errors.

NOTE: You may find that starting the notification_proxy service once and once only at the start of your app and using the same socket in calls to AMDPostNotification works better. iTunes opens and closes the notification_proxy regularly, but it appears to be a bit flakey when you open/close it all the time.

Private Functions

How to find address of privates functions in iTunesMobileDevice.dll or MobileDevice.framework

In order to obtain the address of a usable private function in MobileDevice, you will have to be able to understand x86-64 assembly to reverse engineer it. A private function will not have its name exported in the mach-o symbol table, so in a debugger, like GDB, it will show up as part of another function. However, you will know that it is a separate function as a new stack frame is set up.

Private Function Address List

OSX.6 - iTunes 9.0.2(25)
unsigned int sendCommandToiBoot(struct am_recovery_device *rdev, CFStringRef command, int u);

Address is obtainable by adding 868(0x364) to the address of AMRecoveryDeviceGetProductType(), a public symbol that you can obtain via nlist() or dlsym(). Address: 0x1000245ea

Parameters 1. rdev - the device you wish to send the command to. 2. a CFStringRef of the command to send. 3. an integer, whose use is currently unknown, but should be set to 0 to work.

unsigned int sendFileToiDevice(struct am_recovery_device *rdev, CFStringRef filename);

Address is obtainable by adding 1763(0x6e3) to the address of AMRecoveryDeviceGetProductType(), a public symbol that you can obtain via nlist() or dlsym(). Address: 0x100024969

Parameters 1. rdev - the device you wish to send the file to. 2. a CFStringRef of the path to the file to send.


OSX.6 - iTunes 9.0.3(15)
unsigned int sendCommandToiBoot(struct am_recovery_device *rdev, CFStringRef command, int u);

Addresss: AMRecoveryDeviceGetProductType() + 0x37f(895); full offset: 0x2a0ed

unsigned int sendFileToiDevice(struct am_recovery_device *rdev, CFStringRef filename);

Address: AMRecoveryDeviceGetProductType()+0x6f3(1790); full offset: 0x2a46c

Libraries Implementations