Example #1
0
def img4stuff(deviceModel, iOSVersion, useCustomLogo, bootlogoPath):
    bootchainVariants = {  # iBoot64Patcher doesn't work for iOS 13 iBSS/iBEC so we have to get 12.x iBSS/iBEC to use for booting, but still grab kernel/trustcache (If needed)/devicetree for downgraded iOS version
        'iPhone8,1': '12.4',
        'iPhone8,2':
        '13.1.3',  # This device has NO keys for 11.x/12.x but i'll keep it here for when it does
        'iPhone9,1': '12.4',
        'iPhone9,2': '12.3.1',
        'iPhone9,3': '12.3.1',
        'iPhone9,4': '12.3.1',
        'iPhone10,3': '12.3.1',
        'iPhone10,6': '12.4',
        'iPod7,1': '12.3.1',
        'iPad7,5': '12.3.1',
        'iPad7,6': '12.3.1',
        'iPhone6,2':
        iOSVersion,  # Since these have all keys up, we can just use whatever the downgraded version is =)
        'iPhone6,1': iOSVersion,
        'iPhone7,2': iOSVersion,
        'iPhone7,1':
        iOSVersion  # This device has NO keys for 11.x/12.x but i'll keep it here for when it does
    }
    screenSize = {
        'iPhone8,1': '1334x750',
        'iPhone8,2': '1920x1080',
        'iPhone9,1': '1334x750',
        'iPhone9,2': '1920x1080',
        'iPhone9,3': '1334x750',
        'iPhone9,4': '1920x1080',
        'iPhone10,3': '2436x1125',
        'iPhone10,6': '2436x1125',
        'iPhone6,2': '1136x640',
        'iPhone6,1': '1136x640',
        'iPhone7,2': '1334x750',
        'iPhone7,1': '1920x1080',
    }
    try:
        iosBootChainVersion = bootchainVariants[
            deviceModel]  # Have to use a 12.x iBSS/iBEC for now since iBoot64Patcher can't patch 13.x stuff yet
    except:
        print(
            "Sorry your device has no 12.x or lower keys meaning tether booting isn't possible\nThat or I forgot to add your device to the list, please let me know if thats the case!"
        )
        exit(2)
    print(f"Checking theiphonewiki for {iosBootChainVersion} keys...")
    wiki = iphonewiki.iPhoneWiki(deviceModel, iosBootChainVersion)
    keys = wiki.getWikiKeys()

    iBECName = keys["IBEC"]
    iBECKey = keys["IBECKEY"]
    iBECIV = keys["IBECIV"]

    iBSSName = keys["IBSS"]
    iBSSKey = keys["IBSSKEY"]
    iBSSIV = keys["IBSSIV"]
    if iBECIV == "Unknown":  # Just making sure that there is keys, some key pages have keys for one model but not the other which could cause issues
        print(
            "Keys for the other device model are present but not for yours sorry\nFeel free to get them and add them to theiphonewiki =)"
        )
        exit(2)

    ipswurl = requests.get(
        f"https://api.ipsw.me/v2.1/{deviceModel}/{iOSVersion}/url").text
    iburl = requests.get(
        f"https://api.ipsw.me/v2.1/{deviceModel}/{iosBootChainVersion}/url"
    ).text

    # geting shsh
    print("Getting SHSH for signing images")
    so = subprocess.Popen(
        f"./resources/bin/tsschecker -d iPhone6,2 -e 12326262 -l -s",
        stdout=subprocess.PIPE,
        shell=True)
    getshsh = so.stdout.read()
    dir_name = os.getcwd()
    test = os.listdir(dir_name)
    for item in test:
        if item.endswith(".shsh2"):
            shutil.move(os.path.join(dir_name, item), "./resources/shsh.shsh")
    shsh = "./resources/shsh.shsh"
    if os.path.exists(shsh):
        # Always good to check it saved properly
        pass
    else:
        sys.exit("ERROR: Failed to save shsh")
    print(f"Downloading and patching {iosBootChainVersion}'s iBSS/iBEC")
    #pzb to get ibss and ibec
    downloadImages(iburl, f"Firmware/dfu/{iBECName}", "resources/ibec.im4p")

    downloadImages(iburl, f"Firmware/dfu/{iBSSName}", "resources/ibss.im4p")

    # Assuming that worked (add checks) we now need to decrpyt and patch iBSS/iBEC for booting
    so = subprocess.Popen(
        f"./resources/bin/img4tool -e -o resources/ibss.raw --iv {iBSSIV} --key {iBSSKey} resources/ibss.im4p",
        stdout=subprocess.PIPE,
        shell=True)
    output = so.stdout.read()
    if useCustomLogo:
        so = subprocess.Popen(
            f'./resources/bin/iBoot64Patcher resources/ibss.raw resources/ibss.pwn',
            stdout=subprocess.PIPE,
            shell=True)
        output = so.stdout.read()
    else:
        so = subprocess.Popen(
            f'./resources/bin/iBoot64Patcher resources/ibss.raw resources/ibss.pwn -b "-v"',
            stdout=subprocess.PIPE,
            shell=True)
        output = so.stdout.read()

    so = subprocess.Popen(
        f"./resources/bin/img4tool -e -o resources/ibec.raw --iv {iBECIV} --key {iBECKey} resources/ibec.im4p",
        stdout=subprocess.PIPE,
        shell=True)
    output = so.stdout.read()
    if useCustomLogo:
        so = subprocess.Popen(
            f'./resources/bin/iBoot64Patcher resources/ibec.raw resources/ibec.pwn',
            stdout=subprocess.PIPE,
            shell=True)
        output = so.stdout.read()
    else:
        so = subprocess.Popen(
            f'./resources/bin/iBoot64Patcher resources/ibec.raw resources/ibec.pwn -b "-v"',
            stdout=subprocess.PIPE,
            shell=True)
        output = so.stdout.read()

    so = subprocess.Popen(
        f"./resources/bin/img4tool -c resources/ibec.patched -t ibec resources/ibec.pwn",
        stdout=subprocess.PIPE,
        shell=True)
    output = so.stdout.read()

    so = subprocess.Popen(
        f"./resources/bin/img4tool -c resources/ibss.patched -t ibss resources/ibss.pwn",
        stdout=subprocess.PIPE,
        shell=True)
    output = so.stdout.read()

    so = subprocess.Popen(
        f"./resources/bin/img4tool -c resources/ibss.img4 -p resources/ibss.patched -s resources/shsh.shsh",
        stdout=subprocess.PIPE,
        shell=True)
    output = so.stdout.read()

    so = subprocess.Popen(
        f"./resources/bin/img4tool -c resources/ibec.img4 -p resources/ibec.patched -s resources/shsh.shsh",
        stdout=subprocess.PIPE,
        shell=True)
    output = so.stdout.read()

    if useCustomLogo:
        # Now need to convert the .PNG to a img4 format to use while booting
        # check png dimensions, make sure its the proper size even though we won't stop if its not
        im = Image.open(bootlogoPath)
        w, h = im.size
        check = f"{h}x{w}"
        if screenSize[deviceModel] == check:
            print("Image is correct size and format")
        else:
            print(
                f"Image is {check} but screen is {screenSize[deviceModel]}.\nContinuing anyway, although image may look strange on the device"
            )
        # Now run ibootim
        if str(bootlogoPath).lower().endswith(".png"):
            so = subprocess.Popen(
                f"./resources/bin/ibootim {bootlogoPath} resources/bootlogo.ibootim",
                stdout=subprocess.PIPE,
                shell=True)  # Thanks to realnp for ibootim!
            output = so.stdout.read()
            # now create im4p
            so = subprocess.Popen(
                f"./resources/bin/img4tool -c resources/bootlogo.im4p -t logo resources/bootlogo.ibootim",
                stdout=subprocess.PIPE,
                shell=True)
            output = so.stdout.read()
            # Add signature from shsh
            so = subprocess.Popen(
                f"./resources/bin/img4tool -c resources/bootlogo.img4 -p resources/bootlogo.im4p -s resources/shsh.shsh",
                stdout=subprocess.PIPE,
                shell=True)
            output = so.stdout.read()
            bootlogoPath = "resources/bootlogo.img4"
        else:
            print(
                "Please provide a .png file, other image types are not supported"
            )
            exit(2)
    else:
        pass
    # iBSS/iBEC stuff is done, we now need to get devicetree, trustcache and kernel
    print(f"Downloading {iOSVersion}'s BuildManifest.plist")
    try:
        downloadImages(ipswurl, "BuildManifest.plist",
                       "resources/manifest.plist")
    except:
        print(
            "ERROR: Failed to download BuildManifest.plist\nPlease re-run PyBoot again and it should work (might take a few tries)"
        )
        exit(2)
    line_number = 0
    with open("./resources/manifest.plist", mode="rt") as read_plist:
        for line in read_plist:
            line_number += 1
            if re.search("kernelcache.release.+", line):
                kernelname = line.rstrip()
                read_plist.close()
                break
    kernelname = kernelname[14:-9]
    print(f"Downloading {iOSVersion}'s KernelCache")
    try:
        downloadImages(ipswurl, kernelname, "resources/kernel.im4p")
    except:
        print(
            "ERROR: Failed to download Kernel\nPlease re-run PyBoot again and it should work (might take a few tries)"
        )
        exit(2)
    devicetreename = f"DeviceTree.{iBSSName[5:-13]}ap.im4p"
    if deviceModel == "iPhone6,2":
        devicetreename = "DeviceTree.n53ap.im4p"
    elif deviceModel == "iPhone6,1":
        devicetreename = "DeviceTree.n51ap.im4p"
    print(f"Downloading {iOSVersion}'s DeviceTree")
    try:
        downloadImages(ipswurl, f"Firmware/all_flash/{devicetreename}",
                       "resources/devicetree.im4p")
    except:
        print(
            "ERROR: Failed to download DeviceTree\nPlease re-run PyBoot again and it should work (might take a few tries)"
        )
        exit(2)
    so = check_output(
        f"./resources/bin/pzb list {ipswurl}", shell=True
    )  # Need to check the downgraded IPSW to get the rootfs trustcache for booting
    so = str(so)
    rootfsoffset = so.find(
        "GB"
    ) - 24  # This should always work, unless for some reason another file in the IPSW is > 1GB
    rootfsName = so[
        int(rootfsoffset):
        -51]  # This should be the correct number to cut from, will test more

    if '11.' in iOSVersion:
        print("iOS version is 11.x, not downloading trustcache")
        pass
    elif '10.' in iOSVersion:
        print("iOS version is 10.x, not downloading trustcache")
        pass
    else:
        if rootfsName.endswith(".dmg"):
            # just making sure string was cut correctly
            keys["ROOTFSNAME"] = rootfsName
            print(f"Downloading {iOSVersion}'s TrustCache")
            try:
                downloadImages(ipswurl, f'Firmware/{rootfsName}.trustcache',
                               "resources/trustcache.im4p")
            except:
                print(
                    "ERROR: Failed to download TrustCache\nPlease re-run PyBoot again and it should work (might take a few tries)"
                )
                exit(2)
            time.sleep(5)
        else:
            print(
                "Failed to get RootFS name\nPlease read through this output and enter the name of the largest .dmg file\n"
            )
            rootfsName = input()
            if rootfsName.endswith(".dmg"):
                # checking again and exiting if you enter wrong because you suck
                keys["ROOTFSNAME"] = rootfsName
                downloadImages(ipswurl, f'Firmware/{rootfsName}.trustcache',
                               "resources/trustcache.im4p")
                time.sleep(5)
            else:
                print("Start again from the beggining =)")
                exit(2)
    # Can add a verification for after the patching to make sure it was applied correctly and in the right place just in case
    patchFiles(iOSVersion)
    print("Signing boot files")
    signImages()
Example #2
0
def img4stuff(deviceModel, iOSVersion, useCustomLogo, bootlogoPath, areWeLocal,
              bootOtherOS, bootArgs):
    api = ipswapi.APIParser(deviceModel, iOSVersion)

    print(f"Checking theiphonewiki for {iOSVersion} keys...")
    wiki = iphonewiki.iPhoneWiki(deviceModel, iOSVersion)
    keys = wiki.getWikiKeys()
    if 'failed' in keys:
        print(
            "Keys weren't found for your device, PyBoot will place your device into PWNDFU mode and retrieve the needed keys...\n"
        )
        print("Please ensure your device is connected in DFU mode...")
        time.sleep(5)
        pwndfumodeKeys()
        needKeys = True
    else:

        needKeys = False

        iBECName = keys["IBEC"]
        iBECKey = keys["IBECKEY"]
        iBECIV = keys["IBECIV"]

        iBSSName = keys["IBSS"]
        iBSSKey = keys["IBSSKEY"]
        iBSSIV = keys["IBSSIV"]
        if iBECIV == "Unknown":  # Just making sure that there is keys, some key pages have keys for one model but not the other which could cause issues
            print(
                "Keys for the other device model are present but not for your model.\nPyBoot will place your device into PWNDFU mode and retrieve the needed keys..."
            )
            print("Please ensure your device is connected in DFU mode...")
            time.sleep(5)
            pwndfumodeKeys()
            needKeys = True

    ipswurl = api.printURLForArchive()

    # geting shsh
    if areWeLocal == False:
        print(f"Downloading {iOSVersion}'s BuildManifest.plist")
        try:
            api.downloadFileFromArchive("BuildManifest.plist",
                                        "resources/manifest.plist")
        except:
            print(
                "ERROR: Failed to download BuildManifest.plist\nPlease re-run PyBoot again and it should work (might take a few tries)"
            )
            exit(2)
    else:
        if os.path.exists("IPSW/BuildManifest.plist"):
            shutil.move("IPSW/BuildManifest.plist", "resources/manifest.plist")
        else:
            sys.exit("ERROR: Couldn't find local BuildManifest")
    if needKeys:
        line_number = 0
        count = 0
        thing = False
        models = []
        with open("./resources/manifest.plist", mode="rt") as read_plist:
            for line in read_plist:
                line_number += 1
                if thing == True:
                    deviceModel = line.rstrip()
                    models.append(deviceModel)
                    thing = False
                    if count == 2:
                        break
                if re.search("DeviceClass", line):
                    line_number += 1
                    thing = True
                    count += 1
            read_plist.close()

        choice1 = models[0]
        choice2 = models[1]
        choice1 = str(choice1.strip('\t\t\t'))
        choice2 = str(choice2.strip('\t\t\t'))
        choice1 = choice1[8:-9]
        choice2 = choice2[8:-9]
        print(f"Found multiple device models...\nWhich is your device?\n")
        print(f"1: {choice1}\n2: {choice2}\n")
        modelchoice = input("Enter 1 or 2: ")
        if modelchoice == "1":
            print(f"Device set to {choice1}")
            iBECName = f"iBEC.{choice1[:-2]}.RELEASE.im4p"
            iBSSName = f"iBSS.{choice1[:-2]}.RELEASE.im4p"
        elif modelchoice == "2":
            print(f"Device set to {choice2}")
            iBECName = f"iBEC.{choice2[:-2]}.RELEASE.im4p"
            iBSSName = f"iBSS.{choice2[:-2]}.RELEASE.im4p"
        else:
            print("Invalid input...\nExiting...")
            exit(0)
    print("Getting SHSH for signing images")
    so = subprocess.Popen(
        f"./resources/bin/tsschecker -d iPhone6,2 -e 12326262 -l -s",
        stdout=subprocess.PIPE,
        shell=True)
    output = so.stdout.read()
    dir_name = os.getcwd()
    test = os.listdir(dir_name)
    for item in test:
        if item.endswith(".shsh2"):
            shutil.move(os.path.join(dir_name, item), "./resources/shsh.shsh")
    shsh = "./resources/shsh.shsh"
    if os.path.exists(shsh):
        # Always good to check it saved properly
        pass
    else:
        sys.exit("ERROR: Failed to save shsh")

    if areWeLocal == False:

        print(f"Downloading and patching {iOSVersion}'s iBSS/iBEC")

        api.downloadFileFromArchive(f"Firmware/dfu/{iBECName}",
                                    "resources/ibec.im4p")

        api.downloadFileFromArchive(f"Firmware/dfu/{iBSSName}",
                                    "resources/ibss.im4p")

    else:
        # We need to move the correct iBSS/iBEC from IPSW/ to resources/
        print("Moving iBSS/iBEC...")
        shutil.move(f"IPSW/{iBECName}", "resources/ibec.im4p")
        shutil.move(f"IPSW/{iBSSName}", "resources/ibss.im4p")

    if needKeys:
        so = subprocess.Popen(
            "./resources/bin/img4tool -a resources/ibss.im4p",
            stdout=subprocess.PIPE,
            shell=True)
        output = so.stdout.read()
        output = output.decode("utf-8")

        offset1 = output.find("num: 1")
        offset2 = output.find("num: 2")
        offset1 += 7
        iBSSKBAG = output[offset1:offset2]
        iBSSKBAG = iBSSKBAG.strip('\n')
        iBSSKBAG = iBSSKBAG[0:32:] + iBSSKBAG[32 + 1::]

        so = subprocess.Popen(
            "./resources/bin/img4tool -a resources/ibec.im4p",
            stdout=subprocess.PIPE,
            shell=True)
        output = so.stdout.read()
        output = output.decode("utf-8")

        offset1 = output.find("num: 1")
        offset2 = output.find("num: 2")
        offset1 += 7
        iBECKBAG = output[offset1:offset2]
        iBECKBAG = iBECKBAG.strip('\n')
        iBECKBAG = iBECKBAG[0:32:] + iBECKBAG[32 + 1::]

        ibssIVKEY = decryptKBAG(iBSSKBAG)
        ibecIVKEY = decryptKBAG(iBECKBAG)

        if len(ibssIVKEY) != 96 or len(ibecIVKEY) != 96:
            print(ibssIVKEY)
            print(ibecIVKEY)
            sys.exit('String provided is not 96 bytes!')
        else:
            iBSSIV = ibssIVKEY[:32]
            iBSSKey = ibssIVKEY[-64:]
            iBECIV = ibecIVKEY[:32]
            iBECKey = ibecIVKEY[-64:]

        print(
            "\n\nDevice needs to be rebooted in order to continue, please re-enter DFU mode and then press enter to continue..."
        )
        print(
            "If you do not reboot the device into DFU mode, PyBoot will fail to send the needed boot components"
        )
        print("Waiting for user to press enter...")
        input()

    so = subprocess.Popen(
        f"./resources/bin/img4tool -e -o resources/ibss.raw --iv {iBSSIV} --key {iBSSKey} resources/ibss.im4p",
        stdout=subprocess.PIPE,
        shell=True)
    output = so.stdout.read()
    if useCustomLogo:
        if bootOtherOS:
            so = subprocess.Popen(
                f'./resources/bin/kairos resources/ibss.raw resources/ibss.pwn -b "{bootArgs}"',
                stdout=subprocess.PIPE,
                shell=True)
            output = so.stdout.read()
        else:
            so = subprocess.Popen(
                f'./resources/bin/kairos resources/ibss.raw resources/ibss.pwn',
                stdout=subprocess.PIPE,
                shell=True)
            output = so.stdout.read()
    else:
        so = subprocess.Popen(
            f'./resources/bin/kairos resources/ibss.raw resources/ibss.pwn -b "{bootArgs}"',
            stdout=subprocess.PIPE,
            shell=True)
        output = so.stdout.read()

    so = subprocess.Popen(
        f"./resources/bin/img4tool -e -o resources/ibec.raw --iv {iBECIV} --key {iBECKey} resources/ibec.im4p",
        stdout=subprocess.PIPE,
        shell=True)
    output = so.stdout.read()
    if useCustomLogo:
        if bootOtherOS:
            so = subprocess.Popen(
                f'./resources/bin/kairos resources/ibec.raw resources/ibec.pwn -b "{bootArgs}"',
                stdout=subprocess.PIPE,
                shell=True)
            output = so.stdout.read()
        else:
            so = subprocess.Popen(
                f'./resources/bin/kairos resources/ibec.raw resources/ibec.pwn',
                stdout=subprocess.PIPE,
                shell=True)
            output = so.stdout.read()
    else:
        so = subprocess.Popen(
            f'./resources/bin/kairos resources/ibec.raw resources/ibec.pwn -b "{bootArgs}"',
            stdout=subprocess.PIPE,
            shell=True)
        output = so.stdout.read()

    so = subprocess.Popen(
        f"./resources/bin/img4tool -c resources/ibec.patched -t ibec resources/ibec.pwn",
        stdout=subprocess.PIPE,
        shell=True)
    output = so.stdout.read()

    so = subprocess.Popen(
        f"./resources/bin/img4tool -c resources/ibss.patched -t ibss resources/ibss.pwn",
        stdout=subprocess.PIPE,
        shell=True)
    output = so.stdout.read()

    so = subprocess.Popen(
        f"./resources/bin/img4tool -c resources/ibss.img4 -p resources/ibss.patched -s resources/shsh.shsh",
        stdout=subprocess.PIPE,
        shell=True)
    output = so.stdout.read()

    so = subprocess.Popen(
        f"./resources/bin/img4tool -c resources/ibec.img4 -p resources/ibec.patched -s resources/shsh.shsh",
        stdout=subprocess.PIPE,
        shell=True)
    output = so.stdout.read()

    if useCustomLogo:
        # Now need to convert the .PNG to a img4 format to use while booting

        if str(bootlogoPath).lower().endswith(".png"):
            so = subprocess.Popen(
                f"./resources/bin/ibootim {bootlogoPath} resources/bootlogo.ibootim",
                stdout=subprocess.PIPE,
                shell=True)  # Thanks to realnp for ibootim!
            output = so.stdout.read()
            # now create im4p
            so = subprocess.Popen(
                f"./resources/bin/img4tool -c resources/bootlogo.im4p -t logo resources/bootlogo.ibootim",
                stdout=subprocess.PIPE,
                shell=True)
            output = so.stdout.read()
            # Add signature from shsh
            so = subprocess.Popen(
                f"./resources/bin/img4tool -c resources/bootlogo.img4 -p resources/bootlogo.im4p -s resources/shsh.shsh",
                stdout=subprocess.PIPE,
                shell=True)
            output = so.stdout.read()
            bootlogoPath = "resources/bootlogo.img4"
        else:
            print(
                "Please provide a .png file, other image types are not supported"
            )
            exit(2)
    else:
        pass
    # iBSS/iBEC stuff is done, we now need to get devicetree, trustcache and kernel
    line_number = 0
    with open("./resources/manifest.plist", mode="rt") as read_plist:
        for line in read_plist:
            line_number += 1
            if re.search("kernelcache.release.+", line):
                kernelname = line.rstrip()
                read_plist.close()
                break
    kernelname = kernelname[14:-9]
    if areWeLocal == False:

        print(f"Downloading {iOSVersion}'s KernelCache")
        try:
            if deviceModel == "iPhone8,4":
                kernelname = "kernelcache.release.iphone8b"
            api.downloadFileFromArchive(kernelname, "resources/kernel.im4p")
        except:
            print(
                "ERROR: Failed to download Kernel\nPlease re-run PyBoot again and it should work (might take a few tries)"
            )
            exit(2)
    else:
        if os.path.exists(f"IPSW/{kernelname}"):
            shutil.move(f"IPSW/{kernelname}", "resources/kernel.im4p")
        else:
            sys.exit("ERROR: Couldn't find local kernelcache")
    devicetreename = f"DeviceTree.{iBSSName[5:-13]}ap.im4p"
    if deviceModel == "iPhone6,2":
        devicetreename = "DeviceTree.n53ap.im4p"
    elif deviceModel == "iPhone6,1":
        devicetreename = "DeviceTree.n51ap.im4p"
    if areWeLocal == False:

        print(f"Downloading {iOSVersion}'s DeviceTree")
        try:
            api.downloadFileFromArchive(f"Firmware/all_flash/{devicetreename}",
                                        "resources/devicetree.im4p")
        except:
            print(
                "ERROR: Failed to download DeviceTree\nPlease re-run PyBoot again and it should work (might take a few tries)"
            )
            exit(2)
    else:
        if os.path.exists(f"IPSW/Firmware/all_flash/{devicetreename}"):
            shutil.move(f"IPSW/Firmware/all_flash/{devicetreename}",
                        "resources/devicetree.im4p")
        else:
            sys.exit("ERROR: Couldn't find local devicetree")
    if areWeLocal == False:
        so = check_output(
            f"./resources/bin/pzb list {ipswurl}", shell=True
        )  # Need to check the downgraded IPSW to get the rootfs trustcache for booting
        so = str(so)
        rootfsoffset = so.find(
            "GB"
        ) - 24  # This should always work, unless for some reason another file in the IPSW is > 1GB
        rootfsName = so[int(
            rootfsoffset
        ):-51]  # This should be the correct number to cut from, will test more

        if '11.' in iOSVersion:
            print("iOS version is 11.x, not downloading trustcache")
            pass
        elif '10.' in iOSVersion:
            print("iOS version is 10.x, not downloading trustcache")
            pass
        else:
            if rootfsName.endswith(".dmg"):
                # just making sure string was cut correctly
                keys["ROOTFSNAME"] = rootfsName
                print(f"Downloading {iOSVersion}'s TrustCache")
                try:
                    api.downloadFileFromArchive(
                        f'Firmware/{rootfsName}.trustcache',
                        "resources/trustcache.im4p")
                except:
                    print(
                        "ERROR: Failed to download TrustCache\nPlease re-run PyBoot again and it should work (might take a few tries)"
                    )
                    exit(2)
                time.sleep(5)
            else:
                print(
                    f"\nFailed to get RootFS name\nPlease look up the RootFS filename on the key page for {deviceModel} - iOS {iOSVersion} theiphonewiki and type it here then press enter:\n"
                )
                rootfsName = input()
                if rootfsName.endswith(".dmg"):
                    # checking again and exiting if you enter wrong because you suck
                    keys["ROOTFSNAME"] = rootfsName
                    api.downloadFileFromArchive(
                        f'Firmware/{rootfsName}.trustcache',
                        "resources/trustcache.im4p")
                    time.sleep(5)
                else:
                    print("Start again from the beggining =)")
                    exit(2)
    else:
        # Find largest .dmg file in IPSW/ then add .trustcache to the end of the string

        objects = os.listdir("IPSW")

        sofar = 0
        name = ""

        for item in objects:
            if item.endswith(".dmg"):
                size = os.path.getsize(f"IPSW/{item}")
                if size > sofar:
                    sofar = size
                    name = item

        print(f"Largest file is {name}, getting correct trustcache...")
        trustcachename = f"{name}.trustcache"
        if os.path.exists(f"IPSW/Firmware/{trustcachename}"):
            shutil.move(f"IPSW/Firmware/{trustcachename}",
                        "resources/trustcache.im4p")
        else:
            sys.exit("ERROR: Couldn't find local trustcache")

    # Can add a verification for after the patching to make sure it was applied correctly and in the right place just in case
    patchFiles(iOSVersion)
    print("Signing boot files")
    signImages()
Example #3
0
def img4stuff(deviceModel, iOSVersion, useCustomLogo, bootlogoPath, areWeLocal, bootOtherOS, bootArgs, amfiPatches):

    if deviceModel == "iPhone10,1" or deviceModel == "iPhone10,2" or deviceModel == "iPhone10,3" or deviceModel == "iPhone10,4" or deviceModel == "iPhone10,5" or deviceModel == "iPhone10,6" or deviceModel == "iPhone9,1" or deviceModel == "iPhone9,2" or deviceModel == "iPhone9,3" or deviceModel == "iPhone9,4":
        A10A11Check = True
    else:
        A10A11Check = False 

    api = ipswapi.APIParser(deviceModel, iOSVersion)

    print(f"Checking theiphonewiki for {iOSVersion} keys...")
    wiki = iphonewiki.iPhoneWiki(deviceModel, iOSVersion)
    keys = wiki.getWikiKeys()
    if 'failed' in keys:
        print("Keys weren't found for your device, PyBoot will place your device into PWNDFU mode and retrieve the needed keys...\n")
        print("Please ensure your device is connected in DFU mode...")
        time.sleep(5)
        pwndfumodeKeys()
        needKeys = True
    else:

        needKeys = False

        iBECName = keys["IBEC"]
        iBECKey = keys["IBECKEY"]
        iBECIV = keys["IBECIV"]

        iBSSName = keys["IBSS"]
        iBSSKey = keys["IBSSKEY"]
        iBSSIV = keys["IBSSIV"]
        if iBECIV == "Unknown":  # Just making sure that there is keys, some key pages have keys for one model but not the other which could cause issues
            print("Keys for the other device model are present but not for your model.\nPyBoot will place your device into PWNDFU mode and retrieve the needed keys...")
            print("Please ensure your device is connected in DFU mode...")
            time.sleep(5)
            pwndfumodeKeys()
            needKeys = True

    # geting shsh
    modelAP = ''
    if areWeLocal == False:
        print(f"Downloading {iOSVersion}'s BuildManifest.plist")
        try:
            api.downloadFileFromArchive("BuildManifest.plist", "resources/manifest.plist")
        except:
            print("ERROR: Failed to download BuildManifest.plist\nPlease re-run PyBoot again and it should work (might take a few tries)")
            exit(2)
    else:
        if os.path.exists("IPSW/BuildManifest.plist"):
            shutil.move("IPSW/BuildManifest.plist", "resources/manifest.plist")
        else:
            sys.exit("ERROR: Couldn't find local BuildManifest")
    if needKeys:
        line_number = 0
        num_lines = sum(1 for line in open('./resources/manifest.plist'))
        save_value = False
        models = []

        with open("./resources/manifest.plist", mode="rt") as read_plist:

            while line_number < num_lines:

                for line in read_plist:
                    
                    if save_value:

                        apModel = line.rstrip()

                        if not apModel in models:

                            models.append(apModel)

                        save_value = False

                    if re.search("DeviceClass", line):
                        save_value = True

                    line_number += 1
        read_plist.close()

        length = len(models) 
        i = 0

        while i < length: 
            temp_name = models[i]
            str(temp_name.strip('\t\t\t'))
            temp_name = temp_name[12:-9]
            models[i] = temp_name
            i += 1

        print(f"Found multiple device models...\nWhich is your device?\n")
        length = len(models) 
        i = 0

        while i < length:
            print(f"{i + 1}: {models[i]}")
            i += 1
        modelchoice = input("\nEnter the number that corresponds with your device: ")
        if (int(modelchoice) - 1) <= length and int(modelchoice) > 0:
            print(f"Device set to {models[int(modelchoice) - 1]}")
            modelAP = models[int(modelchoice) - 1]
            ibxxName = False
            firmwareName = []
            line_number = 0
            with open("./resources/manifest.plist", mode="rt") as read_plist:

                while line_number < num_lines:

                    for line in read_plist:
                        
                        if ibxxName:
                            temp = line.rstrip()
                            if re.search("<string>Firmware/dfu/iBEC", temp):
                                str(temp.strip('\t\t\t'))
                                temp = temp[27:-9]
                                firmwareName.append(temp)
                                line_number = num_lines + 1
                                ibxxName = False
                                break

                        if save_value:

                            apModel = line.rstrip()
                            str(apModel.strip('\t\t\t'))
                            apModel = apModel[12:-9]
                            if modelAP == apModel:
                                ibxxName = True
                            save_value = False

                        if re.search("DeviceClass", line):
                            save_value = True

                        line_number += 1
            read_plist.close()
            modelAP = modelAP
            iBECName = firmwareName[0]
            iBSSName = iBECName.replace("iBEC", "iBSS")
            print(iBECName)
            print(iBSSName)
        else:
            print("Error: Invalid input, Exiting...")
            exit(0)

    if modelAP == '':
        line_number = 0
        num_lines = sum(1 for line in open('./resources/manifest.plist'))
        save_value = False
        models = []

        with open("./resources/manifest.plist", mode="rt") as read_plist:

            while line_number < num_lines:

                for line in read_plist:
                    
                    if save_value:

                        apModel = line.rstrip()

                        if not apModel in models:

                            models.append(apModel)

                        save_value = False

                    if re.search("DeviceClass", line):
                        save_value = True

                    line_number += 1
        read_plist.close()

        length = len(models) 
        i = 0

        while i < length: 
            temp_name = models[i]
            str(temp_name.strip('\t\t\t'))
            temp_name = temp_name[12:-9]
            models[i] = temp_name
            i += 1

        print(f"Found multiple device models...\nWhich is your device?\n")
        length = len(models) 
        i = 0

        while i < length:
            print(f"{i + 1}: {models[i]}")
            i += 1
        modelchoice = input("\nEnter the number that corresponds with your device: ")
        if (int(modelchoice) - 1) <= length and int(modelchoice) > 0:
            print(f"Device set to {models[int(modelchoice) - 1]}")
            modelAP = models[int(modelchoice) - 1]
        else:
            print("Error: Invalid input, Exiting...")
            exit(0)


    print("Getting SHSH for signing images")

    # We need to get SHSH for A11 devices using the current device model otherwise it will not boot :/
    if (deviceModel == "iPhone10,3"):
        tssmodel = "iPhone10,3"
    elif (deviceModel == "iPhone10,6"):
        tssmodel = "iPhone10,6"
    elif (deviceModel == "iPhone10,1"):
        tssmodel = "iPhone10,1"
    elif (deviceModel == "iPhone10,2"):
        tssmodel = "iPhone10,2"
    elif (deviceModel == "iPhone10,4"):
        tssmodel = "iPhone10,4"
    elif (deviceModel == "iPhone10,5"):
        tssmodel = "iPhone10,5"
    elif (deviceModel == "iPhone9,1"):
        tssmodel = "iPhone9,1"
    elif (deviceModel == "iPhone9,2"):
        tssmodel = "iPhone9,2"
    elif (deviceModel == "iPhone9,3"):
        tssmodel = "iPhone9,3"
    elif (deviceModel == "iPhone9,4"):
        tssmodel = "iPhone9,4"
    else:
        tssmodel = "iPhone6,2" # iPhone6,2 seems to work for all non-A11 device, if not let me know

    so = subprocess.Popen(f"./resources/bin/tsschecker -d {tssmodel} -e 85888280a402e -l -s", stdout=subprocess.PIPE, shell=True)
    output = so.stdout.read()
    dir_name = os.getcwd()
    test = os.listdir(dir_name)
    for item in test:
        if item.endswith(".shsh2"):
            shutil.move(os.path.join(dir_name, item), "./resources/shsh.shsh")
    shsh = "./resources/shsh.shsh"
    if os.path.exists(shsh):
        # Always good to check it saved properly
        pass
    else:
        sys.exit("ERROR: Failed to save shsh")

    if areWeLocal == False:

        print(f"Downloading and patching {iOSVersion}'s iBSS/iBEC")

        api.downloadFileFromArchive(f"Firmware/dfu/{iBECName}", "resources/ibec.im4p")
        api.downloadFileFromArchive(f"Firmware/dfu/{iBSSName}", "resources/ibss.im4p")
        test = False

    else:
        # We need to move the correct iBSS/iBEC from IPSW/ to resources/
        print("Moving iBSS/iBEC...")
        shutil.move(f"IPSW/{iBECName}", "resources/ibec.im4p")
        shutil.move(f"IPSW/{iBSSName}", "resources/ibss.im4p")

    if needKeys:
        so = subprocess.Popen("./resources/bin/img4tool -a resources/ibss.im4p", stdout=subprocess.PIPE, shell=True)
        output = so.stdout.read()
        output = output.decode("utf-8")

        offset1 = output.find("num: 1")
        offset2 = output.find("num: 2")
        offset1 += 7
        iBSSKBAG = output[offset1:offset2]
        iBSSKBAG = iBSSKBAG.strip('\n')
        iBSSKBAG = iBSSKBAG[0 : 32 : ] + iBSSKBAG[32 + 1 : :]

        so = subprocess.Popen("./resources/bin/img4tool -a resources/ibec.im4p", stdout=subprocess.PIPE, shell=True)
        output = so.stdout.read()
        output = output.decode("utf-8")

        offset1 = output.find("num: 1")
        offset2 = output.find("num: 2")
        offset1 += 7
        iBECKBAG = output[offset1:offset2]
        iBECKBAG = iBECKBAG.strip(  '\n')
        iBECKBAG = iBECKBAG[0 : 32 : ] + iBECKBAG[32 + 1 : :]

        ibssIVKEY = decryptKBAG(iBSSKBAG)
        ibecIVKEY = decryptKBAG(iBECKBAG)

        if len(ibssIVKEY) != 96 or len(ibecIVKEY) != 96:
            print(ibssIVKEY)
            print(ibecIVKEY)
            sys.exit('String provided is not 96 bytes!')
        else:
            iBSSIV = ibssIVKEY[:32]
            iBSSKey = ibssIVKEY[-64:]
            iBECIV = ibecIVKEY[:32]
            iBECKey = ibecIVKEY[-64:]

        print("\n\nDevice needs to be rebooted in order to continue, please re-enter DFU mode and then press enter to continue...")
        print("If you do not reboot the device into DFU mode, PyBoot will fail to send the needed boot components")
        print("Waiting for user to press enter...")
        input()

    patcher = "kairos" # Just allows me to change what boot image patcher I use with ease (mainly for A11 tests)
    if (deviceModel == "iPhone10,1" or deviceModel == "iPhone10,2" or deviceModel == "iPhone10,3" or deviceModel == "iPhone10,4" or deviceModel == "iPhone10,5" or deviceModel == "iPhone10,6"):
        patcher = "iBoot64Patcher"
        print("A11 detected, using iBoot64Patcher...")
    so = subprocess.Popen(f"./resources/bin/img4tool -e -o resources/ibss.raw --iv {iBSSIV} --key {iBSSKey} resources/ibss.im4p", stdout=subprocess.PIPE, shell=True)
    output = so.stdout.read()    
    if useCustomLogo:
        if bootOtherOS:
            so = subprocess.Popen(f'./resources/bin/{patcher} resources/ibss.raw resources/ibss.pwn -b "{bootArgs}"', stdout=subprocess.PIPE, shell=True)
            output = so.stdout.read()
        else:
            so = subprocess.Popen(f'./resources/bin/{patcher} resources/ibss.raw resources/ibss.pwn', stdout=subprocess.PIPE, shell=True)
            output = so.stdout.read()
    else:
        so = subprocess.Popen(f'./resources/bin/{patcher} resources/ibss.raw resources/ibss.pwn -b "{bootArgs}"', stdout=subprocess.PIPE, shell=True)
        output = so.stdout.read()

    so = subprocess.Popen(f"./resources/bin/img4tool -e -o resources/ibec.raw --iv {iBECIV} --key {iBECKey} resources/ibec.im4p", stdout=subprocess.PIPE, shell=True)
    output = so.stdout.read()
    if useCustomLogo:
        if bootOtherOS:
            so = subprocess.Popen(f'./resources/bin/{patcher} resources/ibec.raw resources/ibec.pwn -b "{bootArgs}"', stdout=subprocess.PIPE, shell=True)
            output = so.stdout.read()
        else:
            so = subprocess.Popen(f'./resources/bin/{patcher} resources/ibec.raw resources/ibec.pwn', stdout=subprocess.PIPE, shell=True)
            output = so.stdout.read()
    else:
        so = subprocess.Popen(f'./resources/bin/{patcher} resources/ibec.raw resources/ibec.pwn -b "{bootArgs}"', stdout=subprocess.PIPE, shell=True)
        output = so.stdout.read()
    if bootOtherOS and "13." in iOSVersion:
        # Excuse the long byte strings, just want to be sure that we patch the correct thing :)

        # This conversion from bootarg to byte was a nightware to get working -_- needed to be done though for full 13.x dualbooting support
        # Glad its over. Basically it will take the last char from your disk0s1sX and convert it to a value that can be written to ibec 
        length = len(bootArgs)
        last_char = bootArgs[length -1]
        last_char = str(int(last_char) - 1)
        last_char = format((ord(last_char)), "x")

        bootpartitionString = b"\x30\x00\x2F\x53\x79\x73\x74\x65\x6D\x2F\x4C\x69\x62\x72\x61\x72\x79\x2F\x43\x61\x63\x68\x65\x73\x2F\x63\x6F\x6D\x2E\x61\x70\x70\x6C\x65\x2E\x6B\x65\x72\x6E\x65\x6C\x63\x61\x63\x68\x65\x73\x2F\x6B\x65\x72\x6E\x65\x6C\x63\x61\x63\x68\x65"
        bootpartitionPatch = bytes([int(last_char) + 18]) # Only way I found to get the users disk from a string, to an int -1, back to a string, then to hex minus the 0x,
                                                          # then to an int then to that int + 18 to be a byte value that will actually write and work
                                                          # This needed to be added though, as some 13.x devices will have SystemB as disk0s1s7 not always disk0s1s6 as I had hardcoded before
        if os.path.isfile("resources/ibec.pwn"):
            print("Patching boot-partition in iBEC")
            with open("resources/ibec.pwn", "r+b") as fh:
                file = fh.read()
                try:
                    offset = hex(file.index(bootpartitionString))  # getting offset for start of string
                    offset = int(offset, 16)
                    fh.seek(offset, 0)
                    fh.write(bootpartitionPatch)  # writing the disk0s1sX value to iBEC
                    fh.close()
                    print("boot-partition patch complete")
                except:
                    print("iBEC patching failed!")
                    exit(2)

    so = subprocess.Popen(f"./resources/bin/img4tool -c resources/ibec.patched -t ibec resources/ibec.pwn", stdout=subprocess.PIPE, shell=True)
    output = so.stdout.read()

    so = subprocess.Popen(f"./resources/bin/img4tool -c resources/ibss.patched -t ibss resources/ibss.pwn", stdout=subprocess.PIPE, shell=True)
    output = so.stdout.read()

    so = subprocess.Popen(f"./resources/bin/img4tool -c resources/ibss.img4 -p resources/ibss.patched -s resources/shsh.shsh", stdout=subprocess.PIPE, shell=True)
    output = so.stdout.read()

    so = subprocess.Popen(f"./resources/bin/img4tool -c resources/ibec.img4 -p resources/ibec.patched -s resources/shsh.shsh", stdout=subprocess.PIPE, shell=True)
    output = so.stdout.read()

    if useCustomLogo:
        # Now need to convert the .PNG to a img4 format to use while booting

        if str(bootlogoPath).lower().endswith(".png"):
            so = subprocess.Popen(f"./resources/bin/ibootim {bootlogoPath} resources/bootlogo.ibootim", stdout=subprocess.PIPE, shell=True)  # Thanks to realnp for ibootim!
            output = so.stdout.read()
            # now create im4p
            so = subprocess.Popen(f"./resources/bin/img4tool -c resources/bootlogo.im4p -t logo resources/bootlogo.ibootim", stdout=subprocess.PIPE, shell=True)
            output = so.stdout.read()
            # Add signature from shsh
            so = subprocess.Popen(f"./resources/bin/img4tool -c resources/bootlogo.img4 -p resources/bootlogo.im4p -s resources/shsh.shsh", stdout=subprocess.PIPE, shell=True)
            output = so.stdout.read()
            bootlogoPath = "resources/bootlogo.img4"
        else:
            print("Please provide a .png file, other image types are not supported")
            exit(2)
    else:
        if (os.path.exists("resources/bootlogo.png")):
            so = subprocess.Popen(f"./resources/bin/ibootim resources/bootlogo.png resources/bootlogo.ibootim", stdout=subprocess.PIPE, shell=True)  # Thanks to realnp for ibootim!
            output = so.stdout.read()
            # now create im4p
            so = subprocess.Popen(f"./resources/bin/img4tool -c resources/bootlogo.im4p -t logo resources/bootlogo.ibootim", stdout=subprocess.PIPE, shell=True)
            output = so.stdout.read()
            # Add signature from shsh
            so = subprocess.Popen(f"./resources/bin/img4tool -c resources/bootlogo.img4 -p resources/bootlogo.im4p -s resources/shsh.shsh", stdout=subprocess.PIPE, shell=True)
            output = so.stdout.read()
            bootlogoPath = "resources/bootlogo.img4"
        else:
            print("Please either add your own image to ./resources/bootlogo.png or redownload the one that comes with PyBoot")
            exit(0)
    # iBSS/iBEC stuff is done, we now need to get devicetree, trustcache and kernel

    line_number = 0
    num_lines = sum(1 for line in open('./resources/manifest.plist'))
    kernSave = False
    kernelname = ""
    save_value = False

    with open("./resources/manifest.plist", mode="rt") as read_plist:

        while line_number < num_lines:

            for line in read_plist:
                
                if kernSave:
                    temp = line.rstrip()
                    if re.search("<string>kernelcache.release.", temp):
                        str(temp.strip('\t\t\t'))
                        temp = temp[14:-9]
                        kernelname = temp
                        line_number = num_lines + 1
                        kernSave = False
                        break

                if save_value:

                    deviceModel = line.rstrip()
                    str(deviceModel.strip('\t\t\t'))
                    deviceModel = deviceModel[12:-9]
                    if modelAP == deviceModel:
                        kernSave = True
                    save_value = False

                if re.search("DeviceClass", line):
                    save_value = True

                line_number += 1
    read_plist.close()

    if areWeLocal == False:

        print(f"Downloading {iOSVersion}'s KernelCache")
        try:
            api.downloadFileFromArchive(kernelname, "resources/kernel.im4p")
        except:
            print("ERROR: Failed to download Kernel\nPlease re-run PyBoot again and it should work (might take a few tries)")
            exit(2)
    else:
        if os.path.exists(f"IPSW/{kernelname}"):
            shutil.move(f"IPSW/{kernelname}", "resources/kernel.im4p")
        else:
            sys.exit("ERROR: Couldn't find local kernelcache")
    if amfiPatches:
        print("Applying AMFI patches to kernel (Thanks to Ralph and mcg29_)")
        so = subprocess.Popen(f"./resources/bin/img4 -i resources/kernel.im4p -o resources/kernel.raw", stdout=subprocess.PIPE, shell=True)
        output = so.stdout.read()
        time.sleep(5)
        if os.path.exists("resources/kernel.raw"):
            print("Saved raw kernel to 'resources/kernel.raw'")
            so = subprocess.Popen(f"./resources/bin/Kernel64Patcher resources/kernel.raw resources/kernel.patched -a", stdout=subprocess.PIPE, shell=True)
            output = so.stdout.read()
            patchThing()
            so = subprocess.Popen(f"./resources/bin/img4tool -e -s resources/shsh.shsh -m resources/IM4M", stdout=subprocess.PIPE, shell=True)
            output = so.stdout.read()
            print("Patched AMFI from kernel")
            so = subprocess.Popen(f"./resources/bin/img4 -i resources/kernel.im4p -o resources/kernel.img4 -M resources/IM4M -T krnl -P resources/kc.bpatch", stdout=subprocess.PIPE, shell=True)
            output = so.stdout.read()
            print("Finished patching kernel!\nContinuing with PyBoot...\n")
        else:
            print("Failed to extract raw kernel, continuing without AMFI kernel patches...")

    line_number = 0
    num_lines = sum(1 for line in open('./resources/manifest.plist'))
    dtreeSave = False
    devicetreename = ""
    save_value = False

    with open("./resources/manifest.plist", mode="rt") as read_plist:

        while line_number < num_lines:

            for line in read_plist:
                
                if dtreeSave:
                    temp = line.rstrip()
                    if re.search("<string>Firmware/all_flash/DeviceTree", temp):
                        str(temp.strip('\t\t\t'))
                        temp = temp[33:-9]
                        devicetreename = temp
                        line_number = num_lines + 1
                        dtreeSave = False
                        break

                if save_value:

                    deviceModel = line.rstrip()
                    str(deviceModel.strip('\t\t\t'))
                    deviceModel = deviceModel[12:-9]
                    if modelAP == deviceModel:
                        dtreeSave = True
                    save_value = False

                if re.search("DeviceClass", line):
                    save_value = True

                line_number += 1
    read_plist.close()

    if areWeLocal == False:

        print(f"Downloading {iOSVersion}'s DeviceTree")
        try:
            api.downloadFileFromArchive(f"Firmware/all_flash/{devicetreename}", "resources/devicetree.im4p")
        except:
            print("ERROR: Failed to download DeviceTree\nPlease re-run PyBoot again and it should work (might take a few tries)")
            exit(2)
    else:
        if os.path.exists(f"IPSW/Firmware/all_flash/{devicetreename}"):
            shutil.move(f"IPSW/Firmware/all_flash/{devicetreename}", "resources/devicetree.im4p")
        else:
            sys.exit("ERROR: Couldn't find local devicetree")

    if bootOtherOS and "13." in iOSVersion:

        print("Patching Devicetree to allow for new Data partition to be mounted (13.x Only)...")
        # Unpack devicetree so Ralph's patcher will work
        so = subprocess.Popen(f"./resources/bin/img4tool -e -o resources/devicetree.raw resources/devicetree.im4p", stdout=subprocess.PIPE, shell=True)
        output = so.stdout.read()
        # Patch it
        so = subprocess.Popen(f"./resources/bin/dtree_patcher resources/devicetree.raw resources/devicetree.patched -d", stdout=subprocess.PIPE, shell=True)
        output = so.stdout.read()
        # Repack it to im4p
        so = subprocess.Popen(f"./resources/bin/img4tool -c resources/devicetree.im4p -t dtre resources/devicetree.patched", stdout=subprocess.PIPE, shell=True)
        output = so.stdout.read()

    line_number = 0
    num_lines = sum(1 for line in open('./resources/manifest.plist'))
    tcachesave = False
    trustcachename = ""
    save_value = False
    tcache = False

    with open("./resources/manifest.plist", mode="rt") as read_plist:

        while line_number < num_lines:

            for line in read_plist:

                if tcache:
                    temp = line.rstrip()
                    if re.search("<string>Firmware/", temp):
                        str(temp.strip('\t\t\t'))
                        temp = temp[23:-9]
                        trustcachename = temp
                        line_number = num_lines + 1
                        tcache = False
                        break
                
                if tcachesave:
                    temp = line.rstrip()
                    if re.search("<key>StaticTrustCache</key>", temp):
                        tcachesave = False
                        tcache = True

                if save_value:

                    deviceModel = line.rstrip()
                    str(deviceModel.strip('\t\t\t'))
                    deviceModel = deviceModel[12:-9]
                    if modelAP == deviceModel:
                        tcachesave = True
                    save_value = False

                if re.search("DeviceClass", line):
                    save_value = True

                line_number += 1
    read_plist.close()

    if areWeLocal == False:

        if '11.' in iOSVersion:
            print("iOS version is 11.x, not downloading trustcache")
            pass
        elif '10.' in iOSVersion:
            print("iOS version is 10.x, not downloading trustcache")
            pass
        else:

            print(f"Downloading {iOSVersion}'s TrustCache")
            try:
                api.downloadFileFromArchive(f'Firmware/{trustcachename}', "resources/trustcache.im4p")
            except:
                print("ERROR: Failed to download TrustCache\nPlease re-run PyBoot again and it should work (might take a few tries)")
                exit(2)
            time.sleep(5)
    else:
        
        if os.path.exists(f"IPSW/Firmware/{trustcachename}"):
            shutil.move(f"IPSW/Firmware/{trustcachename}", "resources/trustcache.im4p")
        else:
            sys.exit("ERROR: Couldn't find local trustcache")

    if A10A11Check:

        # aopfw download 

        print(f"Downloading {iOSVersion}'s AOPFW")

        line_number = 0
        num_lines = sum(1 for line in open('./resources/manifest.plist'))
        aopfwSave = False
        aopfwName = ""
        save_value = False


        with open("./resources/manifest.plist", mode="rt") as read_plist:

            while line_number < num_lines:

                for line in read_plist:
                    
                    if aopfwSave:
                        temp = line.rstrip()
                        if re.search("<string>Firmware/AOP/", temp):
                            str(temp.strip('\t\t\t'))
                            temp = temp[27:-9]
                            aopfwName = temp
                            line_number = num_lines + 1
                            aopfwSave = False
                            break

                    if save_value:

                        deviceModel = line.rstrip()
                        str(deviceModel.strip('\t\t\t'))
                        deviceModel = deviceModel[12:-9]
                        if modelAP == deviceModel:
                            aopfwSave = True
                        save_value = False

                    if re.search("DeviceClass", line):
                        save_value = True

                    line_number += 1
        read_plist.close()

        try:
            api.downloadFileFromArchive(f'Firmware/AOP/{aopfwName}', "resources/aopfw.im4p")
        except:
            print("ERROR: Failed to download AOPFW\nPlease re-run PyBoot again and it should work (might take a few tries)")
            exit(2)

        # ISP download 

        print(f"Downloading {iOSVersion}'s ISP")

        line_number = 0
        num_lines = sum(1 for line in open('./resources/manifest.plist'))
        ispSave = False
        ispName = ""
        save_value = False


        with open("./resources/manifest.plist", mode="rt") as read_plist:

            while line_number < num_lines:

                for line in read_plist:
                    
                    if ispSave:
                        temp = line.rstrip()
                        if re.search("<string>Firmware/isp_bni/", temp):
                            str(temp.strip('\t\t\t'))
                            temp = temp[31:-9]
                            ispName = temp
                            line_number = num_lines + 1
                            ispSave = False
                            break

                    if save_value:

                        deviceModel = line.rstrip()
                        str(deviceModel.strip('\t\t\t'))
                        deviceModel = deviceModel[12:-9]
                        if modelAP == deviceModel:
                            ispSave = True
                        save_value = False

                    if re.search("DeviceClass", line):
                        save_value = True

                    line_number += 1
        read_plist.close()

        try:
            api.downloadFileFromArchive(f'Firmware/isp_bni/{ispName}', "resources/isp.im4p")
        except:
            print("ERROR: Failed to download ISP\nPlease re-run PyBoot again and it should work (might take a few tries)")
            exit(2)

        # Callan download 

        print(f"Downloading {iOSVersion}'s CallanFirmware")

        line_number = 0
        num_lines = sum(1 for line in open('./resources/manifest.plist'))
        callanSave = False
        callanName = ""
        save_value = False


        with open("./resources/manifest.plist", mode="rt") as read_plist:

            while line_number < num_lines:

                for line in read_plist:
                    
                    if callanSave:
                        temp = line.rstrip()
                        if re.search("CallanFirmware.im4p</string>", temp):
                            str(temp.strip('\t\t\t'))
                            temp = temp[23:-9]
                            callanName = temp
                            line_number = num_lines + 1
                            callanSave = False
                            break

                    if save_value:

                        deviceModel = line.rstrip()
                        str(deviceModel.strip('\t\t\t'))
                        deviceModel = deviceModel[12:-9]
                        if modelAP == deviceModel:
                            callanSave = True
                        save_value = False

                    if re.search("DeviceClass", line):
                        save_value = True

                    line_number += 1
        read_plist.close()

        try:
            api.downloadFileFromArchive(f'Firmware/{callanName}', "resources/callan.im4p")
        except:
            print("ERROR: Failed to download CallanFirmware\nPlease re-run PyBoot again and it should work (might take a few tries)")
            exit(2)

        # MultiTouch download 

        print(f"Downloading {iOSVersion}'s MultiTouch Firmware")

        line_number = 0
        num_lines = sum(1 for line in open('./resources/manifest.plist'))
        touchSave = False
        touchName = ""
        save_value = False


        with open("./resources/manifest.plist", mode="rt") as read_plist:

            while line_number < num_lines:

                for line in read_plist:
                    
                    if touchSave:
                        temp = line.rstrip()
                        if re.search("Multitouch.im4p</string>", temp):
                            str(temp.strip('\t\t\t'))
                            temp = temp[23:-9]
                            touchName = temp
                            line_number = num_lines + 1
                            touchSave = False
                            break

                    if save_value:

                        deviceModel = line.rstrip()
                        str(deviceModel.strip('\t\t\t'))
                        deviceModel = deviceModel[12:-9]
                        if modelAP == deviceModel:
                            touchSave = True
                        save_value = False

                    if re.search("DeviceClass", line):
                        save_value = True

                    line_number += 1
        read_plist.close()

        try:
            api.downloadFileFromArchive(f'Firmware/{touchName}', "resources/touch.im4p")
        except:
            print("ERROR: Failed to download MultiTouch Firmware\nPlease re-run PyBoot again and it should work (might take a few tries)")
            exit(2)

    patchFiles(iOSVersion)
    signImages(A10A11Check)
Example #4
0
def img4stuff(deviceModel, iOSVersion, useCustomLogo, bootlogoPath, areWeLocal, bootOtherOS, bootArgs, amfiPatches):

    api = ipswapi.APIParser(deviceModel, iOSVersion)

    print(f"Checking theiphonewiki for {iOSVersion} keys...")
    wiki = iphonewiki.iPhoneWiki(deviceModel, iOSVersion)
    keys = wiki.getWikiKeys()
    if 'failed' in keys:
        print("Keys weren't found for your device, PyBoot will place your device into PWNDFU mode and retrieve the needed keys...\n")
        print("Please ensure your device is connected in DFU mode...")
        time.sleep(5)
        pwndfumodeKeys()
        needKeys = True
    else:

        needKeys = False

        iBECName = keys["IBEC"]
        iBECKey = keys["IBECKEY"]
        iBECIV = keys["IBECIV"]

        iBSSName = keys["IBSS"]
        iBSSKey = keys["IBSSKEY"]
        iBSSIV = keys["IBSSIV"]
        if iBECIV == "Unknown":  # Just making sure that there is keys, some key pages have keys for one model but not the other which could cause issues
            print("Keys for the other device model are present but not for your model.\nPyBoot will place your device into PWNDFU mode and retrieve the needed keys...")
            print("Please ensure your device is connected in DFU mode...")
            time.sleep(5)
            pwndfumodeKeys()
            needKeys = True

    ipswurl = api.printURLForArchive()

    # geting shsh
    if areWeLocal == False:
        print(f"Downloading {iOSVersion}'s BuildManifest.plist")
        try:
            api.downloadFileFromArchive("BuildManifest.plist", "resources/manifest.plist")
        except:
            print("ERROR: Failed to download BuildManifest.plist\nPlease re-run PyBoot again and it should work (might take a few tries)")
            exit(2)
    else:
        if os.path.exists("IPSW/BuildManifest.plist"):
            shutil.move("IPSW/BuildManifest.plist", "resources/manifest.plist")
        else:
            sys.exit("ERROR: Couldn't find local BuildManifest")
    if needKeys:
        line_number = 0
        count = 0
        thing = False
        models = []
        with open("./resources/manifest.plist", mode="rt") as read_plist:
            for line in read_plist:
                line_number += 1
                if thing == True:
                    deviceModel = line.rstrip()
                    models.append(deviceModel)
                    thing = False
                    if count == 2:
                        break
                if re.search("DeviceClass", line):
                    line_number += 1
                    thing = True
                    count += 1
            read_plist.close()

        choice1 = models[0]
        choice2 = models[1]
        choice1 = str(choice1.strip('\t\t\t'))
        choice2 = str(choice2.strip('\t\t\t'))
        choice1 = choice1[8:-9]
        choice2 = choice2[8:-9]
        print(f"Found multiple device models...\nWhich is your device?\n")
        print(f"1: {choice1}\n2: {choice2}\n")
        modelchoice = input("Enter 1 or 2: ")
        if modelchoice == "1":
            print(f"Device set to {choice1}")
            iBECName = f"iBEC.{choice1[:-2]}.RELEASE.im4p"
            iBSSName = f"iBSS.{choice1[:-2]}.RELEASE.im4p"
        elif modelchoice == "2":
            print(f"Device set to {choice2}")
            iBECName = f"iBEC.{choice2[:-2]}.RELEASE.im4p"
            iBSSName = f"iBSS.{choice2[:-2]}.RELEASE.im4p"
        else:
            print("Invalid input...\nExiting...")
            exit(0)
    print("Getting SHSH for signing images")
    so = subprocess.Popen(f"./resources/bin/tsschecker -d iPhone6,2 -e 85888280a402e -l -s", stdout=subprocess.PIPE, shell=True)
    output = so.stdout.read()
    dir_name = os.getcwd()
    test = os.listdir(dir_name)
    for item in test:
        if item.endswith(".shsh2"):
            shutil.move(os.path.join(dir_name, item), "./resources/shsh.shsh")
    shsh = "./resources/shsh.shsh"
    if os.path.exists(shsh):
        # Always good to check it saved properly
        pass
    else:
        sys.exit("ERROR: Failed to save shsh")

    if areWeLocal == False:

        print(f"Downloading and patching {iOSVersion}'s iBSS/iBEC")

        api.downloadFileFromArchive(f"Firmware/dfu/{iBECName}", "resources/ibec.im4p")
        api.downloadFileFromArchive(f"Firmware/dfu/{iBSSName}", "resources/ibss.im4p")
        test = False

    else:
        # We need to move the correct iBSS/iBEC from IPSW/ to resources/
        print("Moving iBSS/iBEC...")
        shutil.move(f"IPSW/{iBECName}", "resources/ibec.im4p")
        shutil.move(f"IPSW/{iBSSName}", "resources/ibss.im4p")

    if needKeys:
        so = subprocess.Popen("./resources/bin/img4tool -a resources/ibss.im4p", stdout=subprocess.PIPE, shell=True)
        output = so.stdout.read()
        output = output.decode("utf-8")

        offset1 = output.find("num: 1")
        offset2 = output.find("num: 2")
        offset1 += 7
        iBSSKBAG = output[offset1:offset2]
        iBSSKBAG = iBSSKBAG.strip('\n')
        iBSSKBAG = iBSSKBAG[0 : 32 : ] + iBSSKBAG[32 + 1 : :]

        so = subprocess.Popen("./resources/bin/img4tool -a resources/ibec.im4p", stdout=subprocess.PIPE, shell=True)
        output = so.stdout.read()
        output = output.decode("utf-8")

        offset1 = output.find("num: 1")
        offset2 = output.find("num: 2")
        offset1 += 7
        iBECKBAG = output[offset1:offset2]
        iBECKBAG = iBECKBAG.strip(  '\n')
        iBECKBAG = iBECKBAG[0 : 32 : ] + iBECKBAG[32 + 1 : :]

        ibssIVKEY = decryptKBAG(iBSSKBAG)
        ibecIVKEY = decryptKBAG(iBECKBAG)

        if len(ibssIVKEY) != 96 or len(ibecIVKEY) != 96:
            print(ibssIVKEY)
            print(ibecIVKEY)
            sys.exit('String provided is not 96 bytes!')
        else:
            iBSSIV = ibssIVKEY[:32]
            iBSSKey = ibssIVKEY[-64:]
            iBECIV = ibecIVKEY[:32]
            iBECKey = ibecIVKEY[-64:]

        print("\n\nDevice needs to be rebooted in order to continue, please re-enter DFU mode and then press enter to continue...")
        print("If you do not reboot the device into DFU mode, PyBoot will fail to send the needed boot components")
        print("Waiting for user to press enter...")
        input()

    patcher = "kairos" # Just allows me to change what boot image patcher I use with ease (mainly for A11 tests)
    if test:
        print("F**k this")
        iBSSIV = "b4cb3336374505028c995acb9a565c45"
        iBSSKey = "877ce08c24e42ecf582d60719648ef4ef915809e1b0ccff518f5db3004a806ce"
        iBECIV = "8358a6ae2d477357a2f1eabc0287ddcb"
        iBECKey = "72fb077f67f61141cb4224ee0ed6e9a43578c13922937fc91d23ed4949862132"
    so = subprocess.Popen(f"./resources/bin/img4tool -e -o resources/ibss.raw --iv {iBSSIV} --key {iBSSKey} resources/ibss.im4p", stdout=subprocess.PIPE, shell=True)
    output = so.stdout.read()    
    if useCustomLogo:
        if bootOtherOS:
            so = subprocess.Popen(f'./resources/bin/{patcher} resources/ibss.raw resources/ibss.pwn -b "{bootArgs}"', stdout=subprocess.PIPE, shell=True)
            output = so.stdout.read()
        else:
            so = subprocess.Popen(f'./resources/bin/{patcher} resources/ibss.raw resources/ibss.pwn', stdout=subprocess.PIPE, shell=True)
            output = so.stdout.read()
    else:
        so = subprocess.Popen(f'./resources/bin/{patcher} resources/ibss.raw resources/ibss.pwn -b "{bootArgs}"', stdout=subprocess.PIPE, shell=True)
        output = so.stdout.read()

    so = subprocess.Popen(f"./resources/bin/img4tool -e -o resources/ibec.raw --iv {iBECIV} --key {iBECKey} resources/ibec.im4p", stdout=subprocess.PIPE, shell=True)
    output = so.stdout.read()
    if useCustomLogo:
        if bootOtherOS:
            so = subprocess.Popen(f'./resources/bin/{patcher} resources/ibec.raw resources/ibec.pwn -b "{bootArgs}"', stdout=subprocess.PIPE, shell=True)
            output = so.stdout.read()
        else:
            so = subprocess.Popen(f'./resources/bin/{patcher} resources/ibec.raw resources/ibec.pwn', stdout=subprocess.PIPE, shell=True)
            output = so.stdout.read()
    else:
        so = subprocess.Popen(f'./resources/bin/{patcher} resources/ibec.raw resources/ibec.pwn -b "{bootArgs}"', stdout=subprocess.PIPE, shell=True)
        output = so.stdout.read()
    if bootOtherOS and "13." in iOSVersion:
        # Excuse the long byte strings, just want to be sure that we patch the correct thing :)
        bootpartitionString = b"\x30\x00\x2F\x53\x79\x73\x74\x65\x6D\x2F\x4C\x69\x62\x72\x61\x72\x79\x2F\x43\x61\x63\x68\x65\x73\x2F\x63\x6F\x6D\x2E\x61\x70\x70\x6C\x65\x2E\x6B\x65\x72\x6E\x65\x6C\x63\x61\x63\x68\x65\x73\x2F\x6B\x65\x72\x6E\x65\x6C\x63\x61\x63\x68\x65"
        bootpartitionPatch = b"\x35"
        if os.path.isfile("resources/ibec.pwn"):
            print("Patching boot-partition from 0 to 5")
            with open("resources/ibec.pwn", "r+b") as fh:
                file = fh.read()
                try:
                    offset = hex(file.index(bootpartitionString))  # getting offset for start of string
                    offset = int(offset, 16)
                    fh.seek(offset, 0)
                    fh.write(bootpartitionPatch)  # writing 5 so we can boot the system partition
                    fh.close()
                    print("boot-partition patch complete")
                except:
                    print("iBEC patching failed!")
                    exit(2)

    so = subprocess.Popen(f"./resources/bin/img4tool -c resources/ibec.patched -t ibec resources/ibec.pwn", stdout=subprocess.PIPE, shell=True)
    output = so.stdout.read()

    so = subprocess.Popen(f"./resources/bin/img4tool -c resources/ibss.patched -t ibss resources/ibss.pwn", stdout=subprocess.PIPE, shell=True)
    output = so.stdout.read()

    so = subprocess.Popen(f"./resources/bin/img4tool -c resources/ibss.img4 -p resources/ibss.patched -s resources/shsh.shsh", stdout=subprocess.PIPE, shell=True)
    output = so.stdout.read()

    so = subprocess.Popen(f"./resources/bin/img4tool -c resources/ibec.img4 -p resources/ibec.patched -s resources/shsh.shsh", stdout=subprocess.PIPE, shell=True)
    output = so.stdout.read()

    if useCustomLogo:
        # Now need to convert the .PNG to a img4 format to use while booting

        if str(bootlogoPath).lower().endswith(".png"):
            so = subprocess.Popen(f"./resources/bin/ibootim {bootlogoPath} resources/bootlogo.ibootim", stdout=subprocess.PIPE, shell=True)  # Thanks to realnp for ibootim!
            output = so.stdout.read()
            # now create im4p
            so = subprocess.Popen(f"./resources/bin/img4tool -c resources/bootlogo.im4p -t logo resources/bootlogo.ibootim", stdout=subprocess.PIPE, shell=True)
            output = so.stdout.read()
            # Add signature from shsh
            so = subprocess.Popen(f"./resources/bin/img4tool -c resources/bootlogo.img4 -p resources/bootlogo.im4p -s resources/shsh.shsh", stdout=subprocess.PIPE, shell=True)
            output = so.stdout.read()
            bootlogoPath = "resources/bootlogo.img4"
        else:
            print("Please provide a .png file, other image types are not supported")
            exit(2)
    else:
        if (os.path.exists("resources/bootlogo.png")):
            so = subprocess.Popen(f"./resources/bin/ibootim resources/bootlogo.png resources/bootlogo.ibootim", stdout=subprocess.PIPE, shell=True)  # Thanks to realnp for ibootim!
            output = so.stdout.read()
            # now create im4p
            so = subprocess.Popen(f"./resources/bin/img4tool -c resources/bootlogo.im4p -t logo resources/bootlogo.ibootim", stdout=subprocess.PIPE, shell=True)
            output = so.stdout.read()
            # Add signature from shsh
            so = subprocess.Popen(f"./resources/bin/img4tool -c resources/bootlogo.img4 -p resources/bootlogo.im4p -s resources/shsh.shsh", stdout=subprocess.PIPE, shell=True)
            output = so.stdout.read()
            bootlogoPath = "resources/bootlogo.img4"
        else:
            print("Please either add your own image to ./resources/bootlogo.png or redownload the one that comes with PyBoot")
            exit(0)
    # iBSS/iBEC stuff is done, we now need to get devicetree, trustcache and kernel
    line_number = 0
    with open("./resources/manifest.plist", mode="rt") as read_plist:
        for line in read_plist:
            line_number += 1
            if re.search("kernelcache.release.+", line):
                kernelname = line.rstrip()
                read_plist.close()
                break
    kernelname = kernelname[14:-9]
    if areWeLocal == False:

        print(f"Downloading {iOSVersion}'s KernelCache")
        try:
            if deviceModel == "iPhone8,4":
                kernelname = "kernelcache.release.iphone8b"
            api.downloadFileFromArchive(kernelname, "resources/kernel.im4p")
        except:
            print("ERROR: Failed to download Kernel\nPlease re-run PyBoot again and it should work (might take a few tries)")
            exit(2)
    else:
        if os.path.exists(f"IPSW/{kernelname}"):
            shutil.move(f"IPSW/{kernelname}", "resources/kernel.im4p")
        else:
            sys.exit("ERROR: Couldn't find local kernelcache")
    if amfiPatches:
        print("Applying AMFI patches to kernel (Thanks to Ralph and mcg29_)")
        so = subprocess.Popen(f"./resources/bin/img4 -i resources/kernel.im4p -o resources/kernel.raw", stdout=subprocess.PIPE, shell=True)
        output = so.stdout.read()
        time.sleep(5)
        if os.path.exists("resources/kernel.raw"):
            print("Saved raw kernel to 'resources/kernel.raw'")
            so = subprocess.Popen(f"./resources/bin/Kernel64Patcher resources/kernel.raw resources/kernel.patched -a", stdout=subprocess.PIPE, shell=True)
            output = so.stdout.read()
            patchThing()
            so = subprocess.Popen(f"./resources/bin/img4tool -e -s resources/shsh.shsh -m resources/IM4M", stdout=subprocess.PIPE, shell=True)
            output = so.stdout.read()
            print("Patched AMFI from kernel")
            so = subprocess.Popen(f"./resources/bin/img4 -i resources/kernel.im4p -o resources/kernel.img4 -M resources/IM4M -T krnl -P resources/kc.bpatch", stdout=subprocess.PIPE, shell=True)
            output = so.stdout.read()
            print("Finished patching kernel!\nContinuing with PyBoot...\n")
        else:
            print("Failed to extract raw kernel, continuing without AMFI kernel patches...")

    devicetreename = f"DeviceTree.{iBSSName[5:-13]}ap.im4p"
    if deviceModel == "iPhone6,2":
        devicetreename = "DeviceTree.n53ap.im4p"
    elif deviceModel == "iPhone6,1":
        devicetreename = "DeviceTree.n51ap.im4p"
    elif deviceModel == "iPad7,5":
        devicetreename = "DeviceTree.j71bap.im4p"
    elif deviceModel == "iPad7,6":
        devicetreename = "DeviceTree.j72bap.im4p"
    if areWeLocal == False:

        print(f"Downloading {iOSVersion}'s DeviceTree")
        try:
            api.downloadFileFromArchive(f"Firmware/all_flash/{devicetreename}", "resources/devicetree.im4p")
        except:
            print("ERROR: Failed to download DeviceTree\nPlease re-run PyBoot again and it should work (might take a few tries)")
            exit(2)
    else:
        if os.path.exists(f"IPSW/Firmware/all_flash/{devicetreename}"):
            shutil.move(f"IPSW/Firmware/all_flash/{devicetreename}", "resources/devicetree.im4p")
        else:
            sys.exit("ERROR: Couldn't find local devicetree")

    if bootOtherOS and "13." in iOSVersion:

        #api.downloadFileFromArchive(f"Firmware/AOP/aopfw-s8000aop.im4p", "resources/aopfw.im4p")

        print("Patching Devicetree to allow for new Data partition to be mounted (13.x Only)...")
        # Unpack devicetree so Ralph's patcher will work
        so = subprocess.Popen(f"./resources/bin/img4tool -e -o resources/devicetree.raw resources/devicetree.im4p", stdout=subprocess.PIPE, shell=True)
        output = so.stdout.read()
        # Patch it
        so = subprocess.Popen(f"./resources/bin/dtree_patcher resources/devicetree.raw resources/devicetree.patched -d", stdout=subprocess.PIPE, shell=True)
        output = so.stdout.read()
        # Repack it to im4p
        so = subprocess.Popen(f"./resources/bin/img4tool -c resources/devicetree.im4p -t dtre resources/devicetree.patched", stdout=subprocess.PIPE, shell=True)
        output = so.stdout.read()
    if areWeLocal == False:
        so = check_output(f"./resources/bin/pzb list {ipswurl}", shell=True)  # Need to check the downgraded IPSW to get the rootfs trustcache for booting
        so = str(so)
        rootfsoffset = so.find("GB") - 24  # This should always work, unless for some reason another file in the IPSW is > 1GB
        rootfsName = so[int(rootfsoffset):-51]  # This should be the correct number to cut from, will test more

        if '11.' in iOSVersion:
            print("iOS version is 11.x, not downloading trustcache")
            pass
        elif '10.' in iOSVersion:
            print("iOS version is 10.x, not downloading trustcache")
            pass
        else:
            if rootfsName.endswith(".dmg"):
                # just making sure string was cut correctly
                keys["ROOTFSNAME"] = rootfsName
                print(f"Downloading {iOSVersion}'s TrustCache")
                try:
                    api.downloadFileFromArchive(f'Firmware/{rootfsName}.trustcache', "resources/trustcache.im4p")
                except:
                    print("ERROR: Failed to download TrustCache\nPlease re-run PyBoot again and it should work (might take a few tries)")
                    exit(2)
                time.sleep(5)
            else:
                print(f"\nFailed to get RootFS name\nPlease look up the RootFS filename on the key page for {deviceModel} - iOS {iOSVersion} theiphonewiki and type it here then press enter:\n")
                rootfsName = input()
                if rootfsName.endswith(".dmg"):
                    # checking again and exiting if you enter wrong because you suck
                    keys["ROOTFSNAME"] = rootfsName
                    api.downloadFileFromArchive(f'Firmware/{rootfsName}.trustcache', "resources/trustcache.im4p")
                    time.sleep(5)
                else:
                    print("Start again from the beggining =)")
                    exit(2)
    else:
        # Find largest .dmg file in IPSW/ then add .trustcache to the end of the string
        
        objects = os.listdir("IPSW")

        sofar = 0
        name = ""

        for item in objects:
            if item.endswith(".dmg"):
                size = os.path.getsize(f"IPSW/{item}")
                if size > sofar:
                        sofar = size
                        name = item

        print(f"Largest file is {name}, getting correct trustcache...")
        trustcachename = f"{name}.trustcache"
        if os.path.exists(f"IPSW/Firmware/{trustcachename}"):
            shutil.move(f"IPSW/Firmware/{trustcachename}", "resources/trustcache.im4p")
        else:
            sys.exit("ERROR: Couldn't find local trustcache")

    # Can add a verification for after the patching to make sure it was applied correctly and in the right place just in case
    patchFiles(iOSVersion)
    signImages()
Example #5
0
def img4stuff(deviceModel, iOSVersion, useCustomLogo, bootlogoPath,
              areWeLocal):
    api = ipswapi.APIParser(deviceModel, iOSVersion)

    print(f"Checking theiphonewiki for {iOSVersion} keys...")
    wiki = iphonewiki.iPhoneWiki(deviceModel, iOSVersion)
    keys = wiki.getWikiKeys()

    iBECName = keys["IBEC"]
    iBECKey = keys["IBECKEY"]
    iBECIV = keys["IBECIV"]

    iBSSName = keys["IBSS"]
    iBSSKey = keys["IBSSKEY"]
    iBSSIV = keys["IBSSIV"]
    if iBECIV == "Unknown":  # Just making sure that there is keys, some key pages have keys for one model but not the other which could cause issues
        print(
            "Keys for the other device model are present but not for yours sorry\nFeel free to get them and add them to theiphonewiki =)"
        )
        exit(2)

    ipswurl = api.printURLForArchive()

    # geting shsh
    print("Getting SHSH for signing images")
    so = subprocess.Popen(
        f"./resources/bin/tsschecker -d iPhone6,2 -e 12326262 -l -s",
        stdout=subprocess.PIPE,
        shell=True)
    output = so.stdout.read()
    dir_name = os.getcwd()
    test = os.listdir(dir_name)
    for item in test:
        if item.endswith(".shsh2"):
            shutil.move(os.path.join(dir_name, item), "./resources/shsh.shsh")
    shsh = "./resources/shsh.shsh"
    if os.path.exists(shsh):
        # Always good to check it saved properly
        pass
    else:
        sys.exit("ERROR: Failed to save shsh")

    if areWeLocal == False:

        print(f"Downloading and patching {iOSVersion}'s iBSS/iBEC")

        api.downloadFileFromArchive(f"Firmware/dfu/{iBECName}",
                                    "resources/ibec.im4p")

        api.downloadFileFromArchive(f"Firmware/dfu/{iBSSName}",
                                    "resources/ibss.im4p")

    else:
        # We need to move the correct iBSS/iBEC from IPSW/ to resources/
        print("Moving iBSS/iBEC...")
        shutil.move(f"IPSW/{iBECName}", "resources/ibec.im4p")
        shutil.move(f"IPSW/{iBSSName}", "resources/ibss.im4p")

    # Assuming that worked (add checks) we now need to decrpyt and patch iBSS/iBEC for booting
    so = subprocess.Popen(
        f"./resources/bin/img4tool -e -o resources/ibss.raw --iv {iBSSIV} --key {iBSSKey} resources/ibss.im4p",
        stdout=subprocess.PIPE,
        shell=True)
    output = so.stdout.read()
    if useCustomLogo:
        so = subprocess.Popen(
            f'./resources/bin/kairos resources/ibss.raw resources/ibss.pwn',
            stdout=subprocess.PIPE,
            shell=True)
        output = so.stdout.read()
    else:
        so = subprocess.Popen(
            f'./resources/bin/kairos resources/ibss.raw resources/ibss.pwn -b "-v"',
            stdout=subprocess.PIPE,
            shell=True)
        output = so.stdout.read()

    so = subprocess.Popen(
        f"./resources/bin/img4tool -e -o resources/ibec.raw --iv {iBECIV} --key {iBECKey} resources/ibec.im4p",
        stdout=subprocess.PIPE,
        shell=True)
    output = so.stdout.read()
    if useCustomLogo:
        so = subprocess.Popen(
            f'./resources/bin/kairos resources/ibec.raw resources/ibec.pwn',
            stdout=subprocess.PIPE,
            shell=True)
        output = so.stdout.read()
    else:
        so = subprocess.Popen(
            f'./resources/bin/kairos resources/ibec.raw resources/ibec.pwn -b "-v"',
            stdout=subprocess.PIPE,
            shell=True)
        output = so.stdout.read()

    so = subprocess.Popen(
        f"./resources/bin/img4tool -c resources/ibec.patched -t ibec resources/ibec.pwn",
        stdout=subprocess.PIPE,
        shell=True)
    output = so.stdout.read()

    so = subprocess.Popen(
        f"./resources/bin/img4tool -c resources/ibss.patched -t ibss resources/ibss.pwn",
        stdout=subprocess.PIPE,
        shell=True)
    output = so.stdout.read()

    so = subprocess.Popen(
        f"./resources/bin/img4tool -c resources/ibss.img4 -p resources/ibss.patched -s resources/shsh.shsh",
        stdout=subprocess.PIPE,
        shell=True)
    output = so.stdout.read()

    so = subprocess.Popen(
        f"./resources/bin/img4tool -c resources/ibec.img4 -p resources/ibec.patched -s resources/shsh.shsh",
        stdout=subprocess.PIPE,
        shell=True)
    output = so.stdout.read()

    if useCustomLogo:
        # Now need to convert the .PNG to a img4 format to use while booting

        if str(bootlogoPath).lower().endswith(".png"):
            so = subprocess.Popen(
                f"./resources/bin/ibootim {bootlogoPath} resources/bootlogo.ibootim",
                stdout=subprocess.PIPE,
                shell=True)  # Thanks to realnp for ibootim!
            output = so.stdout.read()
            # now create im4p
            so = subprocess.Popen(
                f"./resources/bin/img4tool -c resources/bootlogo.im4p -t logo resources/bootlogo.ibootim",
                stdout=subprocess.PIPE,
                shell=True)
            output = so.stdout.read()
            # Add signature from shsh
            so = subprocess.Popen(
                f"./resources/bin/img4tool -c resources/bootlogo.img4 -p resources/bootlogo.im4p -s resources/shsh.shsh",
                stdout=subprocess.PIPE,
                shell=True)
            output = so.stdout.read()
            bootlogoPath = "resources/bootlogo.img4"
        else:
            print(
                "Please provide a .png file, other image types are not supported"
            )
            exit(2)
    else:
        pass
    # iBSS/iBEC stuff is done, we now need to get devicetree, trustcache and kernel
    if areWeLocal == False:
        print(f"Downloading {iOSVersion}'s BuildManifest.plist")
        try:
            api.downloadFileFromArchive("BuildManifest.plist",
                                        "resources/manifest.plist")
        except:
            print(
                "ERROR: Failed to download BuildManifest.plist\nPlease re-run PyBoot again and it should work (might take a few tries)"
            )
            exit(2)
    else:
        if os.path.exists("IPSW/BuildManifest.plist"):
            shutil.move("IPSW/BuildManifest.plist", "resources/manifest.plist")
        else:
            sys.exit("ERROR: Couldn't find local BuildManifest")
    line_number = 0
    with open("./resources/manifest.plist", mode="rt") as read_plist:
        for line in read_plist:
            line_number += 1
            if re.search("kernelcache.release.+", line):
                kernelname = line.rstrip()
                read_plist.close()
                break
    kernelname = kernelname[14:-9]
    if areWeLocal == False:

        print(f"Downloading {iOSVersion}'s KernelCache")
        try:
            if deviceModel == "iPhone8,4":
                kernelname = "kernelcache.release.iphone8b"
            api.downloadFileFromArchive(kernelname, "resources/kernel.im4p")
        except:
            print(
                "ERROR: Failed to download Kernel\nPlease re-run PyBoot again and it should work (might take a few tries)"
            )
            exit(2)
    else:
        if os.path.exists(f"IPSW/{kernelname}"):
            shutil.move(f"IPSW/{kernelname}", "resources/kernel.im4p")
        else:
            sys.exit("ERROR: Couldn't find local kernelcache")
    devicetreename = f"DeviceTree.{iBSSName[5:-13]}ap.im4p"
    if deviceModel == "iPhone6,2":
        devicetreename = "DeviceTree.n53ap.im4p"
    elif deviceModel == "iPhone6,1":
        devicetreename = "DeviceTree.n51ap.im4p"
    if areWeLocal == False:

        print(f"Downloading {iOSVersion}'s DeviceTree")
        try:
            api.downloadFileFromArchive(f"Firmware/all_flash/{devicetreename}",
                                        "resources/devicetree.im4p")
        except:
            print(
                "ERROR: Failed to download DeviceTree\nPlease re-run PyBoot again and it should work (might take a few tries)"
            )
            exit(2)
    else:
        if os.path.exists(f"IPSW/Firmware/all_flash/{devicetreename}"):
            shutil.move(f"IPSW/Firmware/all_flash/{devicetreename}",
                        "resources/devicetree.im4p")
        else:
            sys.exit("ERROR: Couldn't find local devicetree")
    if areWeLocal == False:
        so = check_output(
            f"./resources/bin/pzb list {ipswurl}", shell=True
        )  # Need to check the downgraded IPSW to get the rootfs trustcache for booting
        so = str(so)
        rootfsoffset = so.find(
            "GB"
        ) - 24  # This should always work, unless for some reason another file in the IPSW is > 1GB
        rootfsName = so[int(
            rootfsoffset
        ):-51]  # This should be the correct number to cut from, will test more

        if '11.' in iOSVersion:
            print("iOS version is 11.x, not downloading trustcache")
            pass
        elif '10.' in iOSVersion:
            print("iOS version is 10.x, not downloading trustcache")
            pass
        else:
            if rootfsName.endswith(".dmg"):
                # just making sure string was cut correctly
                keys["ROOTFSNAME"] = rootfsName
                print(f"Downloading {iOSVersion}'s TrustCache")
                try:
                    api.downloadFileFromArchive(
                        f'Firmware/{rootfsName}.trustcache',
                        "resources/trustcache.im4p")
                except:
                    print(
                        "ERROR: Failed to download TrustCache\nPlease re-run PyBoot again and it should work (might take a few tries)"
                    )
                    exit(2)
                time.sleep(5)
            else:
                print(
                    "Failed to get RootFS name\nPlease read through this output and enter the name of the largest .dmg file\n"
                )
                rootfsName = input()
                if rootfsName.endswith(".dmg"):
                    # checking again and exiting if you enter wrong because you suck
                    keys["ROOTFSNAME"] = rootfsName
                    api.downloadFileFromArchive(
                        f'Firmware/{rootfsName}.trustcache',
                        "resources/trustcache.im4p")
                    time.sleep(5)
                else:
                    print("Start again from the beggining =)")
                    exit(2)
    else:
        # Find largest .dmg file in IPSW/ then add .trustcache to the end of the string

        objects = os.listdir("IPSW")

        sofar = 0
        name = ""

        for item in objects:
            if item.endswith(".dmg"):
                size = os.path.getsize(f"IPSW/{item}")
                if size > sofar:
                    sofar = size
                    name = item

        print(f"Largest file is {name}, getting correct trustcache...")
        trustcachename = f"{name}.trustcache"
        if os.path.exists(f"IPSW/Firmware/{trustcachename}"):
            shutil.move(f"IPSW/Firmware/{trustcachename}",
                        "resources/trustcache.im4p")
        else:
            sys.exit("ERROR: Couldn't find local trustcache")

    # Can add a verification for after the patching to make sure it was applied correctly and in the right place just in case
    patchFiles(iOSVersion)
    print("Signing boot files")
    signImages()