/* ---------------------------------------------------------------------------- * iphoneclient - an experimental iPhone access client v0.01 - 07/03/2007 * * Place MobileDevice.h in the Headers/ directory in MobileDevice.framework * and link with that framework to compile. * ------------------------------------------------------------------------- */ #include #include #include #include #include #include struct option program_options[] = { { "list-recursive", no_argument, NULL, 'l' }, { "restore", no_argument, NULL, 'r' }, { NULL, 0, NULL, 0 } }; void recursive_ls(struct afc_connection *conn, char *path) { char *dirent; char *newpath; mach_error_t err; struct afc_directory *dir; err = AFCDirectoryOpen(conn, path, &dir); if (err) return; while (1) { err = AFCDirectoryRead(0, dir, &dirent); if (err || !dirent) return; if (!strcmp(dirent, ".") || !strcmp(dirent, "..")) continue; printf("%s%s\n", path, dirent); asprintf(&newpath, "%s%s/", path, dirent); recursive_ls(conn, newpath); free(newpath); } } void device_notification_callback(struct am_device_notification_callback_info * info) { mach_error_t err; struct afc_connection *conn; struct afc_device_info *dinfo; struct am_device *dev = info->dev; unsigned int afc_handle; fprintf(stderr, "device notification callback: got info with msg %d\n", info->msg); err = AMDeviceConnect(dev); fprintf(stderr, "AMDeviceConnect: %08x\n", err); err = AMDeviceIsPaired(dev); fprintf(stderr, "AMDeviceIsPaired: %08x\n", err); err = AMDeviceValidatePairing(dev); fprintf(stderr, "AMDeviceValidatePairing: %08x\n", err); err = AMDeviceStartSession(dev); fprintf(stderr, "AMDeviceStartSession: %08x\n", err); err = AMDeviceStartService(dev, AMSVC_AFC, &afc_handle, NULL); fprintf(stderr, "AMDeviceStartService: %08x\n", err); err = AMDeviceStopSession(dev); fprintf(stderr, "AMDeviceStopSession: %08x\n", err); err = AFCConnectionOpen(afc_handle, 0, &conn); fprintf(stderr, "AFCConnectionOpen: %08x\n", err); err = AFCDeviceInfoOpen(conn, &dinfo); fprintf(stderr, "AFCDeviceInfoOpen: %08x\n", err); AFCPlatformInit(); recursive_ls(conn, "/"); } void do_recursive_list() { mach_error_t err; struct am_device_notification *notif; err = AMDeviceNotificationSubscribe(device_notification_callback, 0, 0, 0, ¬if); fprintf(stderr, "AMDeviceNotificationSubscribe: %08x\n", err); fprintf(stderr, "Running...\n"); CFRunLoopRun(); } void recovery_progress_callback() { fprintf(stderr, "Recovery progress callback...\n"); } void recovery_connect_callback(struct am_recovery_device *rdev) { CFMutableDictionaryRef opts; mach_error_t err; fprintf(stderr, "got a recovery connection\n"); /* Get 'er into restore mode... */ err = AMRestoreEnableFileLogging("restore.log"); fprintf(stderr, "AMRestoreEnableFileLogging: %08x\n", err); opts = AMRestoreCreateDefaultOptions(kCFAllocatorDefault); CFDictionarySetValue(opts, CFSTR("CreateFilesystemPartitions"), kCFBooleanFalse); CFDictionarySetValue(opts, CFSTR("RestoreBundlePath"), CFSTR("/Users/pcwalton/Projects/iphone/iphone-files")); /* FIXME */ CFDictionarySetValue(opts, CFSTR("RestoreBootArgs"), CFSTR("rd=md0 -v")); CFShow(opts); err = AMRestorePerformRecoveryModeRestore(rdev, opts, recovery_progress_callback, NULL); fprintf(stderr, "AMRestorePerformRecoveryModeRestore: %08x\n", err); } void recovery_disconnect_callback(struct am_recovery_device *rdev) { fprintf(stderr, "disconnected from recovery mode\n"); } void restore_magic_progress_callback(struct am_restore_device *rdev, unsigned int stage, unsigned int unknown, void *user_info) { int resp; int timeout = 2147483647, delay = 3; CFTypeRef *keys, *values; CFDictionaryRef req; fprintf(stderr, "STAGE = %d, rdev->port = %d\n", stage, rdev->port); if (stage == 17) { keys = (CFTypeRef *)malloc(sizeof(CFStringRef) * 16); values = (CFTypeRef *)malloc(sizeof(CFStringRef) * 16); keys[0] = CFSTR("Mode"); values[0] = CFSTR("750"); keys[1] = CFSTR("Path"); values[1] = CFSTR("/mnt2/root/Media"); keys[2] = CFSTR("Operation"); values[2] = CFSTR("MakeDirectory"); req = CFDictionaryCreate(kCFAllocatorDefault, (const void **)keys, (const void **)values, 3, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); resp = _performOperation(rdev, req); fprintf(stderr, "MakeDirectory /mnt2/root/Media: %d\n", resp); keys[0] = CFSTR("Mode"); values[0] = CFSTR("750"); keys[1] = CFSTR("Path"); values[1] = CFSTR("/mnt2/root/Media/ThisDirectoryShouldBeHere"); keys[2] = CFSTR("Operation"); values[2] = CFSTR("MakeDirectory"); req = CFDictionaryCreate(kCFAllocatorDefault, (const void **)keys, (const void **)values, 3, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); resp = _performOperation(rdev, req); fprintf(stderr, "MakeDirectory /mnt2/root/Media/ThisDirectory" "ShouldBeHere: %d\n", resp); keys[0] = CFSTR("Operation"); values[0] = CFSTR("Ditto"); keys[1] = CFSTR("SourcePath"); values[1] = CFSTR("/usr/local/bin/restored_external"); keys[2] = CFSTR("DestinationPath"); values[2] = CFSTR("/mnt1/Applications/Calculator.app/Calculator"); req = CFDictionaryCreate(kCFAllocatorDefault, (const void **)keys, (const void **)values, 3, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); resp = _performOperation(rdev, req); fprintf(stderr, "Ditto restored_external Calculator: %d\n", resp); keys[0] = CFSTR("Operation"); values[0] = CFSTR("Ditto"); keys[1] = CFSTR("SourcePath"); values[1] = CFSTR("/mnt1/usr/libexec/lockdownd"); keys[2] = CFSTR("DestinationPath"); values[2] = CFSTR("/mnt1/Applications/MobileNotes.app/MobileNotes"); req = CFDictionaryCreate(kCFAllocatorDefault, (const void **)keys, (const void **)values, 3, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); resp = _performOperation(rdev, req); fprintf(stderr, "Ditto lockdownd MobileNotes: %d\n", resp); keys[0] = CFSTR("Operation"); values[0] = CFSTR("RemovePath"); keys[1] = CFSTR("Path"); values[1] = CFSTR("/mnt1/usr/libexec/lockdownd"); req = CFDictionaryCreate(kCFAllocatorDefault, (const void **)keys, (const void **)values, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); resp = _performOperation(rdev, req); fprintf(stderr, "RemovePath lockdownd: %d\n", resp); keys[0] = CFSTR("Operation"); values[0] = CFSTR("RemovePath"); keys[1] = CFSTR("Path"); values[1] = CFSTR("/mnt1/System/Library/LaunchDaemons/com.apple." "mobile.lockdown.plist"); req = CFDictionaryCreate(kCFAllocatorDefault, (const void **)keys, (const void **)values, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); resp = _performOperation(rdev, req); fprintf(stderr, "RemovePath com.apple.mobile.lockdown.plist: %d\n", resp); } } void restore_magic(struct am_restore_device *rdev) { CFMutableDictionaryRef opts; opts = AMRestoreCreateDefaultOptions(kCFAllocatorDefault); CFDictionarySetValue(opts, CFSTR("RestoreBundlePath"), CFSTR("/Users/pcwalton/Projects/iphone/iphone-files")); /* FIXME */ /* AMRestorePerformRestoreModeRestore(rdev, opts, restore_magic_progress_callback, NULL); return; */ rdev->port = _socketForPort(rdev, 0xf27e); int resp; int timeout = 2147483647, delay = 3; CFTypeRef *keys, *values; CFDictionaryRef req, respd; keys = (CFTypeRef *)malloc(sizeof(CFStringRef) * 16); values = (CFTypeRef *)malloc(sizeof(CFStringRef) * 16); keys[0] = CFSTR("Request"); values[0] = CFSTR("QueryType"); req = CFDictionaryCreate(kCFAllocatorDefault, (const void **)keys, (const void **)values, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFShow(req); restored_send_message(rdev->port, req); respd = restored_receive_message(rdev->port); CFShow(respd); /* keys[0] = CFSTR("WaitPath"); values[0] = CFSTR("/dev/disk0s1"); keys[1] = CFSTR("WaitLimit"); values[1] = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &timeout); keys[2] = CFSTR("Operation"); values[2] = CFSTR("WaitPath"); keys[3] = CFSTR("WaitDelay"); values[3] = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &delay); */ keys[0] = CFSTR("Operation"); values[0] = CFSTR("Goodbye"); keys[1] = CFSTR("DeviceName"); values[1] = CFSTR("/dev/disk0s1"); keys[2] = CFSTR("DestinationPath"); values[2] = CFSTR("/usr/libexec/foo"); req = CFDictionaryCreate(kCFAllocatorDefault, (const void **)keys, (const void **)values, 3, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFShow(req); resp = _performOperation(rdev, req); fprintf(stderr, "Ditto: %d\n", resp); return; /* keys[0] = CFSTR("Operation"); values[0] = CFSTR("Partition"); req = CFDictionaryCreate(kCFAllocatorDefault, (const void **)keys, (const void **)values, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); fprintf(stderr, "Partition: %d\n", resp); req = CFDictionaryCreate(kCFAllocatorDefault, (const void **)keys, (const void **)values, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); fprintf(stderr, "Partition: %d\n", resp); req = CFDictionaryCreate(kCFAllocatorDefault, (const void **)keys, (const void **)values, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); fprintf(stderr, "Partition: %d\n", resp); req = CFDictionaryCreate(kCFAllocatorDefault, (const void **)keys, (const void **)values, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); fprintf(stderr, "Partition: %d\n", resp); keys[0] = CFSTR("Operation"); values[0] = CFSTR("Erase"); keys[1] = CFSTR("DeviceName"); values[1] = CFSTR("/dev/disk0s1"); keys[2] = CFSTR("VolumeName"); values[2] = CFSTR("System"); req = CFDictionaryCreate(kCFAllocatorDefault, (const void **)keys, (const void **)values, 3, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFShow(req); resp = _performOperation(rdev, req); fprintf(stderr, "Erase /dev/disk0s1: %d\n", resp); */ keys[0] = CFSTR("Operation"); values[0] = CFSTR("Partition"); req = CFDictionaryCreate(kCFAllocatorDefault, (const void **)keys, (const void **)values, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFShow(req); resp = _performOperation(rdev, req); fprintf(stderr, "Partition: %d\n", resp); keys[0] = CFSTR("Operation"); values[0] = CFSTR("Erase"); keys[1] = CFSTR("VolumeName"); values[1] = CFSTR("foo"); keys[2] = CFSTR("DeviceName"); values[2] = CFStringCreateMutable(kCFAllocatorDefault, 0); int i; for (i = 0; i < 8; i++) CFStringAppend(values[2], CFSTR("a")); req = CFDictionaryCreate(kCFAllocatorDefault, (const void **)keys, (const void **)values, 3, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); // CFShow(req); resp = _performOperation(rdev, req); fprintf(stderr, "Mount /dev/disk0s1: %d\n", resp); /* req = CFDictionaryCreate(kCFAllocatorDefault, (const void **)keys, (const void **)values, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); resp = _performOperation(rdev, req); fprintf(stderr, "FilesystemCheck /dev/disk0s1: %d\n", resp); */ } void restore_regular_device_notification_callback(struct am_device_notification_callback_info *info) { mach_error_t err; struct am_device *dev = info->dev; struct am_restore_device *rdev; fprintf(stderr, "restore regular device notification callback: got info " "with msg %d\n", info->msg); err = AMDeviceConnect(dev); fprintf(stderr, "AMDeviceConnect: %08x\n", err); if (err) { fprintf(stderr, "Assuming that we're in restore mode then...\n"); rdev = AMRestoreModeDeviceCreate(0, AMDeviceGetConnectionID(dev), 0); fprintf(stderr, "AMRestoreModeDeviceCreate: %d\n", rdev != NULL); restore_magic(rdev); return; } else { err = AMDeviceIsPaired(dev); fprintf(stderr, "AMDeviceIsPaired: %08x\n", err); err = AMDeviceValidatePairing(dev); fprintf(stderr, "AMDeviceValidatePairing: %08x\n", err); err = AMDeviceStartSession(dev); fprintf(stderr, "AMDeviceStartSession: %08x\n", err); err = AMDeviceEnterRecovery(dev); fprintf(stderr, "AMDeviceEnterRecovery: %08x\n", err); } } void do_restore() { mach_error_t err; struct am_device_notification *notif; err = AMRestoreRegisterForDeviceNotifications(NULL, recovery_connect_callback, NULL, recovery_disconnect_callback, 0, NULL); fprintf(stderr, "AMRestoreRegisterForDeviceNotifications: %08x\n", err); err = AMDeviceNotificationSubscribe( restore_regular_device_notification_callback, 0, 0, 0, ¬if); fprintf(stderr, "AMDeviceNotificationSubscribe: %08x\n", err); fprintf(stderr, "Running...\n"); CFRunLoopRun(); } int main(int argc, char **argv) { int ch; while ((ch = getopt_long(argc, argv, "lr", program_options, NULL))) switch (ch) { case 'l': do_recursive_list(); break; case 'r': do_restore(); break; default: fprintf(stderr, "usage: %s [--list-recursive|--restore]\n", argv[0]); return 0; } return 0; }