private void ReadProperties(PlistHandle node) { Properties = PlistReader.ReadPlistDictFromNode(node, new string[4] { "DeviceName", "ProductType", "ProductVersion", "HostAttached" }); }
public void EnableDeveloperMode(string deviceImagePath, string deviceImageSignaturePath) { if (!File.Exists(deviceImagePath) || !File.Exists(deviceImageSignaturePath)) { throw new FileNotFoundException("The specified device image files do not exist."); } iDeviceHandle deviceHandle = null; LockdownClientHandle lockdownHandle = null; LockdownServiceDescriptorHandle serviceDescriptor = null; MobileImageMounterClientHandle mounterHandle = null; AfcClientHandle afcHandle = null; PlistHandle plistHandle = null; FileStream imageStream = null; // Use upload image for iOS 7 and above, otherwise use AFC DiskImageUploadMode mode = int.Parse(((string)Properties["ProductVersion"]).Split('.')[0]) >= 7 ? DiskImageUploadMode.UploadImage : DiskImageUploadMode.AFC; var idevice = LibiMobileDevice.Instance.iDevice; var lockdown = LibiMobileDevice.Instance.Lockdown; var service = LibiMobileDevice.Instance.Service; var mounter = LibiMobileDevice.Instance.MobileImageMounter; var afc = LibiMobileDevice.Instance.Afc; try { // Get device handle if (idevice.idevice_new(out deviceHandle, UDID) != iDeviceError.Success) { throw new Exception("Unable to open device, is it connected?"); } // Get lockdownd handle if (lockdown.lockdownd_client_new_with_handshake(deviceHandle, out lockdownHandle, "iFakeLocation") != LockdownError.Success) { throw new Exception("Unable to connect to lockdownd."); } // Start image mounter service if (lockdown.lockdownd_start_service(lockdownHandle, "com.apple.mobile.mobile_image_mounter", out serviceDescriptor) != LockdownError.Success) { throw new Exception("Unable to start the mobile image mounter service."); } // Create mounter instance if (mounter.mobile_image_mounter_new(deviceHandle, serviceDescriptor, out mounterHandle) != MobileImageMounterError.Success) { throw new Exception("Unable to create mobile image mounter instance."); } // Close service descriptor serviceDescriptor.Close(); serviceDescriptor = null; // Start the AFC service if (mode == DiskImageUploadMode.AFC) { if (lockdown.lockdownd_start_service(lockdownHandle, "com.apple.afc", out serviceDescriptor) != LockdownError.Success) { throw new Exception("Unable to start AFC service."); } if (afc.afc_client_new(deviceHandle, serviceDescriptor, out afcHandle) != AfcError.Success) { throw new Exception("Unable to connect to AFC service."); } serviceDescriptor.Close(); serviceDescriptor = null; } // Close lockdown handle lockdownHandle.Close(); lockdownHandle = null; // Check if the developer image has already been mounted const string imageType = "Developer"; if (mounter.mobile_image_mounter_lookup_image(mounterHandle, imageType, out plistHandle) == MobileImageMounterError.Success) { var results = PlistReader.ReadPlistDictFromNode(plistHandle, new[] { "ImagePresent", "ImageSignature" }); // Some iOS use ImagePresent to verify presence, while others use ImageSignature instead // Ensure to check the content of the ImageSignature value as iOS 14 returns a value even // if it is empty. if ((results.ContainsKey("ImagePresent") && results["ImagePresent"] is bool && (bool)results["ImagePresent"]) || (results.ContainsKey("ImageSignature") && results["ImageSignature"] is string && ((string)results["ImageSignature"]).IndexOf("<data>", StringComparison.InvariantCulture) >= 0)) { return; } } plistHandle.Close(); plistHandle = null; // Configure paths for upload const string PkgPath = "PublicStaging"; const string PathPrefix = "/private/var/mobile/Media"; var targetName = PkgPath + "/staging.dimage"; var mountName = PathPrefix + "/" + targetName; imageStream = new FileStream(deviceImagePath, FileMode.Open, FileAccess.Read, FileShare.Read); var sig = File.ReadAllBytes(deviceImageSignaturePath); switch (mode) { case DiskImageUploadMode.UploadImage: // Create stream for device image and wrap as a pointer for callback var handle = GCHandle.Alloc(imageStream); // Upload the image and then free unmanaged wrapper mounter.mobile_image_mounter_upload_image(mounterHandle, imageType, (uint)imageStream.Length, sig, (ushort)sig.Length, MounterUploadCallback, GCHandle.ToIntPtr(handle)); handle.Free(); break; case DiskImageUploadMode.AFC: // Create directory for package ReadOnlyCollection <string> strs; if (afc.afc_get_file_info(afcHandle, PkgPath, out strs) != AfcError.Success || afc.afc_make_directory(afcHandle, PkgPath) != AfcError.Success) { throw new Exception("Unable to create directory '" + PkgPath + "' on the device."); } // Create the target file ulong af = 0; if (afc.afc_file_open(afcHandle, targetName, AfcFileMode.FopenWronly, ref af) != AfcError.Success) { throw new Exception("Unable to create file '" + targetName + "'."); } // Read the file in chunks and write via AFC uint amount = 0; byte[] buf = new byte[8192]; do { amount = (uint)imageStream.Read(buf, 0, buf.Length); if (amount > 0) { uint written = 0, total = 0; while (total < amount) { // Write and ensure that it succeeded if (afc.afc_file_write(afcHandle, af, buf, amount, ref written) != AfcError.Success) { afc.afc_file_close(afcHandle, af); throw new Exception("An AFC write error occurred."); } total += written; } if (total != amount) { afc.afc_file_close(afcHandle, af); throw new Exception("The developer image was not written completely."); } } } while (amount > 0); afc.afc_file_close(afcHandle, af); break; } // Mount the image if (mounter.mobile_image_mounter_mount_image(mounterHandle, mountName, sig, (ushort)sig.Length, imageType, out plistHandle) != MobileImageMounterError.Success) { throw new Exception("Unable to mount developer image."); } // Parse the plist result var result = PlistReader.ReadPlistDictFromNode(plistHandle); if (!result.ContainsKey("Status") || result["Status"] as string != "Complete") { throw new Exception("Mount failed with status: " + (result.ContainsKey("Status") ? result["Status"] : "N/A") + " and error: " + (result.ContainsKey("Error") ? result["Error"] : "N/A")); } } finally { if (imageStream != null) { imageStream.Close(); } if (plistHandle != null) { plistHandle.Close(); } if (afcHandle != null) { afcHandle.Close(); } if (mounterHandle != null) { mounterHandle.Close(); } if (serviceDescriptor != null) { serviceDescriptor.Close(); } if (lockdownHandle != null) { lockdownHandle.Close(); } if (deviceHandle != null) { deviceHandle.Close(); } } }
public void EnableDeveloperMode(string deviceImagePath, string deviceImageSignaturePath) { if (!File.Exists(deviceImagePath) || !File.Exists(deviceImageSignaturePath)) { throw new FileNotFoundException("The specified device image files do not exist."); } iDeviceHandle device = null; LockdownClientHandle client = null; LockdownServiceDescriptorHandle service = null; MobileImageMounterClientHandle client2 = null; AfcClientHandle client3 = null; PlistHandle result = null; FileStream fileStream = null; DiskImageUploadMode diskImageUploadMode = (int.Parse(((string)Properties["ProductVersion"]).Split('.')[0]) >= 7) ? DiskImageUploadMode.UploadImage : DiskImageUploadMode.AFC; IiDeviceApi iDevice = LibiMobileDevice.Instance.iDevice; ILockdownApi lockdown = LibiMobileDevice.Instance.Lockdown; IServiceApi service2 = LibiMobileDevice.Instance.Service; IMobileImageMounterApi mobileImageMounter = LibiMobileDevice.Instance.MobileImageMounter; IAfcApi afc = LibiMobileDevice.Instance.Afc; try { if (iDevice.idevice_new(out device, UDID) != 0) { throw new Exception("Unable to open device, is it connected?"); } if (lockdown.lockdownd_client_new_with_handshake(device, out client, "iFakeLocation") != 0) { throw new Exception("Unable to connect to lockdownd."); } if (lockdown.lockdownd_start_service(client, "com.apple.mobile.mobile_image_mounter", out service) != 0) { throw new Exception("Unable to start the mobile image mounter service."); } if (mobileImageMounter.mobile_image_mounter_new(device, service, out client2) != 0) { throw new Exception("Unable to create mobile image mounter instance."); } service.Close(); service = null; if (diskImageUploadMode == DiskImageUploadMode.AFC) { if (lockdown.lockdownd_start_service(client, "com.apple.afc", out service) != 0) { throw new Exception("Unable to start AFC service."); } if (afc.afc_client_new(device, service, out client3) != 0) { throw new Exception("Unable to connect to AFC service."); } service.Close(); service = null; } client.Close(); client = null; if (mobileImageMounter.mobile_image_mounter_lookup_image(client2, "Developer", out result) != 0) { goto IL_01c7; } Dictionary <string, object> dictionary = PlistReader.ReadPlistDictFromNode(result, new string[2] { "ImagePresent", "ImageSignature" }); if ((!dictionary.ContainsKey("ImagePresent") || !(dictionary["ImagePresent"] is bool) || !(bool)dictionary["ImagePresent"]) && !dictionary.ContainsKey("ImageSignature")) { goto IL_01c7; } goto end_IL_0094; IL_01c7: result.Close(); result = null; string text = "PublicStaging/staging.dimage"; string imagePath = "/private/var/mobile/Media/" + text; fileStream = new FileStream(deviceImagePath, FileMode.Open, FileAccess.Read, FileShare.Read); byte[] array = File.ReadAllBytes(deviceImageSignaturePath); switch (diskImageUploadMode) { case DiskImageUploadMode.UploadImage: { GCHandle value = GCHandle.Alloc(fileStream); mobileImageMounter.mobile_image_mounter_upload_image(client2, "Developer", uint.Parse(fileStream.Length.ToString()), array, ushort.Parse(array.Length.ToString()), MounterUploadCallback, GCHandle.ToIntPtr(value)); value.Free(); break; } case DiskImageUploadMode.AFC: { ReadOnlyCollection <string> fileInformation; if (afc.afc_get_file_info(client3, "PublicStaging", out fileInformation) != 0 || afc.afc_make_directory(client3, "PublicStaging") != 0) { throw new Exception("Unable to create directory 'PublicStaging' on the device."); } ulong handle = 0uL; if (afc.afc_file_open(client3, text, AfcFileMode.FopenWronly, ref handle) != 0) { throw new Exception("Unable to create file '" + text + "'."); } uint num = 0u; byte[] array2 = new byte[8192]; do { num = (uint)fileStream.Read(array2, 0, array2.Length); if (num != 0) { uint bytesWritten = 0u; uint num2; for (num2 = 0u; num2 < num; num2 += bytesWritten) { if (afc.afc_file_write(client3, handle, array2, num, ref bytesWritten) != 0) { afc.afc_file_close(client3, handle); throw new Exception("An AFC write error occurred."); } } if (num2 != num) { afc.afc_file_close(client3, handle); throw new Exception("The developer image was not written completely."); } } }while (num != 0); afc.afc_file_close(client3, handle); break; } } if (mobileImageMounter.mobile_image_mounter_mount_image(client2, imagePath, array, ushort.Parse(array.Length.ToString()), "Developer", out result) != 0) { throw new Exception("Unable to mount developer image."); } Dictionary <string, object> dictionary2 = PlistReader.ReadPlistDictFromNode(result); if (!dictionary2.ContainsKey("Status") || dictionary2["Status"] as string != "Complete") { object obj = dictionary2.ContainsKey("Status") ? dictionary2["Status"] : "N/A"; string str = (obj != null) ? obj.ToString() : null; object obj2 = dictionary2.ContainsKey("Error") ? dictionary2["Error"] : "N/A"; throw new Exception("Mount failed with status: " + str + " and error: " + ((obj2 != null) ? obj2.ToString() : null)); } end_IL_0094 :; } finally { if (fileStream != null) { fileStream.Close(); } if (result != null) { result.Close(); } if (client3 != null) { client3.Close(); } if (client2 != null) { client2.Close(); } if (service != null) { service.Close(); } if (client != null) { client.Close(); } if (device != null) { device.Close(); } } }