Пример #1
0
 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();
                }
            }
        }
Пример #3
0
        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();
                }
            }
        }