├── README.md ├── others ├── __pycache__ │ ├── api.cpython-39.pyc │ ├── dependencies.cpython-39.pyc │ ├── device.cpython-39.pyc │ ├── error.cpython-39.pyc │ ├── ipsw.cpython-39.pyc │ ├── irecv_devices_struct.cpython-39.pyc │ ├── kerneldiff.cpython-39.pyc │ ├── manifest.cpython-39.pyc │ └── restore.cpython-39.pyc ├── api.py ├── dependencies.py ├── device.py ├── ipsw.py ├── irecv_devices_struct.py ├── kerneldiff.py ├── manifest.py ├── restore.py └── signcert.p12 ├── ra1nstorm └── requirements.txt /README.md: -------------------------------------------------------------------------------- 1 | # ra1nstorm 2 | Tethered downgrade 64-bit iDevices vulnerable to checkm8 3 | 4 | ## Project temporarily abandoned. Use [sunst0rm](https://github.com/Mineek/sunst0rm) instead 5 | 6 | Since the purpose of this tool is to tethered downgrade a device, after restoring please use one of the tools listed below to tethered boot it: 7 | * [Ramiel](https://github.com/MatthewPierson/Ramiel) 8 | * [PyBoot](https://github.com/MatthewPierson/PyBoot) 9 | * [ra1nsn0w](https://github.com/tihmstar/ra1nsn0w) 10 | 11 | ra1nstorm now supports downgrading untethered from any iOS to iOS 10.3.3 on some A7 devices 12 | ## Before using it, please keep in mind 13 | YOU are fully responsible to any data loss or damaged cause to your device while using ra1nstorm 14 | ## Usage 15 | ``` 16 | usage: ra1nstorm iPSW [-u] [-s PATH] [-t BLOB] 17 | 18 | ra1nstorm - Tethered downgrade 64-bit iDevices vulnerable to checkm8 19 | 20 | positional arguments: 21 | iPSW iPSW file used for restoring 22 | 23 | optional arguments: 24 | -h, --help show this help message and exit 25 | -t BLOB, --blob BLOB Manually specify SHSH used for restoring (SHSH will be 26 | automatically saved if this argument is skipped) 27 | -s PATH, --save-log PATH 28 | Specify path for saving futurerestore log 29 | -u, --update Keep data while restoring (Untested) 30 | ``` 31 | ## Supported version 32 | All iOS versions from iOS 11 - iOS 14 are supported 33 | 34 | NOTE: Due to SEP limitation, you can only restore to an iOS version which its SEP firmware is still being signed 35 | ## Success 36 | | Device | From | To | 37 | |-----------|--------|--------| 38 | | iPhone9,1 | 15.2.1 | 14.3 | 39 | | iPad4,2 | 12.5.4 | 10.3.3 | 40 | | iPad4,2 | 12.5.4 | 12.0 | 41 | ## Requirements 42 | * A computer running macOS 43 | * 3 gigabytes free space on the computer 44 | * 64-bit iDevice (vulnerable to checkm8) 45 | * Binaries: 46 | 1. [futurerestore(fork)](https://github.com/Mini-Exploit/futurerestore) (you can use [futurerestore-compiler](https://github.com/Mini-Exploit/futurerestore-compiler) to compile it) 47 | 2. [img4tool](https://github.com/tihmstar/img4tool) 48 | 3. [img4](https://github.com/xerub/img4lib) (img4lib) 49 | 4. [kairos](https://github.com/dayt0n/kairos) 50 | 5. [iBoot64Patcher](https://github.com/tihmstar/iBoot64Patcher) 51 | 6. [ldid](https://drive.google.com/uc?export=download&id=1_amZww5ypZ9gcdHDlNmEL2Zh-t3eLKXi) 52 | 7. [Kernel64Patcher](https://github.com/Ralph0045/Kernel64Patcher) 53 | 8. [asr64_patcher](https://github.com/exploit3dguy/asr64_patcher) 54 | 9. [tsschecker](https://github.com/1Conan/tsschecker) 55 | 56 | After downloading the binaries above, you have to move them to PATH (e.g. ```/usr/local/bin```) 57 | 58 | * [Python3](https://www.python.org/downloads/) 59 | * Install ra1nstorm requirements: ```pip3 install -r requirements.txt``` 60 | ## Issue 61 | There are 2 ways for you to get support: 62 | 1. Open an issue 63 | 2. [Join my Discord server](https://discord.gg/nK3Uu6BaDN) 64 | 65 | ## Credits 66 | * Special thanks to [m1stadev](https://github.com/m1stadev) for wikiproxy and buildmanifest parser 67 | * [mcg29](https://github.com/mcg29) for [kerneldiff](https://github.com/mcg29/kerneldiff) 68 | -------------------------------------------------------------------------------- /others/__pycache__/api.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miniexploit/ra1nstorm/b5aac45c9b0afcc8cffbdaf533c901682445ec4d/others/__pycache__/api.cpython-39.pyc -------------------------------------------------------------------------------- /others/__pycache__/dependencies.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miniexploit/ra1nstorm/b5aac45c9b0afcc8cffbdaf533c901682445ec4d/others/__pycache__/dependencies.cpython-39.pyc -------------------------------------------------------------------------------- /others/__pycache__/device.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miniexploit/ra1nstorm/b5aac45c9b0afcc8cffbdaf533c901682445ec4d/others/__pycache__/device.cpython-39.pyc -------------------------------------------------------------------------------- /others/__pycache__/error.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miniexploit/ra1nstorm/b5aac45c9b0afcc8cffbdaf533c901682445ec4d/others/__pycache__/error.cpython-39.pyc -------------------------------------------------------------------------------- /others/__pycache__/ipsw.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miniexploit/ra1nstorm/b5aac45c9b0afcc8cffbdaf533c901682445ec4d/others/__pycache__/ipsw.cpython-39.pyc -------------------------------------------------------------------------------- /others/__pycache__/irecv_devices_struct.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miniexploit/ra1nstorm/b5aac45c9b0afcc8cffbdaf533c901682445ec4d/others/__pycache__/irecv_devices_struct.cpython-39.pyc -------------------------------------------------------------------------------- /others/__pycache__/kerneldiff.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miniexploit/ra1nstorm/b5aac45c9b0afcc8cffbdaf533c901682445ec4d/others/__pycache__/kerneldiff.cpython-39.pyc -------------------------------------------------------------------------------- /others/__pycache__/manifest.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miniexploit/ra1nstorm/b5aac45c9b0afcc8cffbdaf533c901682445ec4d/others/__pycache__/manifest.cpython-39.pyc -------------------------------------------------------------------------------- /others/__pycache__/restore.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miniexploit/ra1nstorm/b5aac45c9b0afcc8cffbdaf533c901682445ec4d/others/__pycache__/restore.cpython-39.pyc -------------------------------------------------------------------------------- /others/api.py: -------------------------------------------------------------------------------- 1 | import requests 2 | from remotezip import RemoteZip 3 | 4 | def get_keys(identifier, board, buildid): 5 | f = requests.get(f"https://api.m1sta.xyz/wikiproxy/{identifier}/{board}/{buildid}").json() 6 | for dev in f['keys']: 7 | if dev['image'] == "iBSS": 8 | iBSS_iv = dev['iv'] 9 | iBSS_key = dev['key'] 10 | if dev['image'] == "iBEC": 11 | iBEC_iv = dev['iv'] 12 | iBEC_key = dev['key'] 13 | try: 14 | return iBSS_iv, iBSS_key, iBEC_iv, iBEC_key 15 | except UnboundLocalError: 16 | print("[WARNING] Unable to get firmware keys, either the bootchain is not encrypted or the wikiproxy does not have it.") 17 | input("Continue or not? (Press ENTER to continue, Ctrl-C to quit)") 18 | 19 | def partialzip_download(url, file, dest): 20 | with RemoteZip(url) as zip: 21 | data = zip.read(file) 22 | with open(dest, 'wb') as f: 23 | f.write(data) 24 | -------------------------------------------------------------------------------- /others/dependencies.py: -------------------------------------------------------------------------------- 1 | import os, sys 2 | import shutil 3 | import psutil 4 | import subprocess 5 | from m1n1Exception import * 6 | 7 | class check_requirements: 8 | def __init__(self): 9 | print("Checking dependencies...") 10 | self.check_bin('futurerestore') 11 | self.check_bin('img4') 12 | self.check_bin('img4tool') 13 | self.check_bin('tsschecker') 14 | self.check_bin('Kernel64Patcher') 15 | self.check_bin('kairos') 16 | self.check_bin('iBoot64Patcher') 17 | self.check_bin('ldid') 18 | self.check_bin('asr64_patcher') 19 | print("Checking hard disk free space...") 20 | self.check_space() 21 | 22 | def check_bin(self, binary): 23 | retassure(shutil.which(binary) is not None, f"{binary} not found, make sure it's in PATH") 24 | if binary == "futurerestore": 25 | fr_usage = subprocess.run((binary), stdout=subprocess.PIPE, universal_newlines=True).stdout 26 | retassure("Specific for ra1nstorm" in fr_usage, "This futurerestore does not allow specifying custom bootchain") 27 | 28 | def check_space(self): 29 | disk = psutil.disk_usage('/') 30 | retassure(disk.free / (2**30) >= 3, "Less than 3GB free space on this computer") 31 | -------------------------------------------------------------------------------- /others/device.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | import sys 3 | import time 4 | import subprocess 5 | import usb.core, usb.util 6 | from m1n1Exception import * 7 | from others.irecv_devices_struct import irecv_device, irecv_devices 8 | 9 | 10 | class Device: 11 | def __init__(self): 12 | self.cpid = None 13 | self.bdid = None 14 | self.ecid = None 15 | self.identifier = None 16 | self.board = None 17 | self.otaable = False 18 | self.get_device() 19 | retassure(not any((self.cpid is None, self.bdid is None, self.ecid is None, self.identifier is None, self.board is None)), "Could not get device info") 20 | self.check_bb() 21 | 22 | def get_device(self): 23 | self.usb_device = usb.core.find(idVendor=0x5AC, idProduct=0x1227) 24 | retassure(self.usb_device is not None, "No DFU device found") 25 | print("Device info:", self.usb_device.serial_number) 26 | self.cpid = [int(info.replace('CPID:','')) for info in self.usb_device.serial_number.split(' ') if 'CPID' in info][0] 27 | self.bdid = [int(info.replace('BDID:',''), 16) for info in self.usb_device.serial_number.split(' ') if 'BDID' in info][0] 28 | self.ecid = [info.replace('ECID:','') for info in self.usb_device.serial_number.split(' ') if 'ECID' in info][0] 29 | self.apnonce = usb.util.get_string(self.usb_device, 1).split(f'NONC:')[1].split(' ')[0] 30 | retassure(any((8010 <= self.cpid <= 8015, self.cpid == 8960, self.cpid == 7000, self.cpid == 8000, self.cpid == 8003)), "Device is not supported") 31 | retassure("PWND:[" in self.usb_device.serial_number, "Device's not in pwned DFU mode") 32 | for device in irecv_devices: 33 | if device.cpid == self.cpid and device.bdid == self.bdid: 34 | self.identifier = device.product_type 35 | self.board = device.hardware_model 36 | break 37 | if any((self.identifier == "iPad4,1", self.identifier == "iPad4,2", self.identifier == "iPad4,3", self.identifier == "iPhone6,1", self.identifier == "iPhone6,2")): 38 | self.otaable = True 39 | 40 | def check_bb(self): 41 | cellular_ipads = [ 42 | 'iPad4,2', 43 | 'iPad4,3', 44 | 'iPad4,5', 45 | 'iPad4,6', 46 | 'iPad4,8', 47 | 'iPad4,9', 48 | 'iPad5,2', 49 | 'iPad5,4', 50 | 'iPad6,8', 51 | 'iPad6,4', 52 | 'iPad7,2', 53 | 'iPad7,4', 54 | 'iPad8,3', 55 | 'iPad8,4', 56 | 'iPad8,7', 57 | 'iPad8,8', 58 | 'iPad8,10', 59 | 'iPad8,12', 60 | 'iPad11,2', 61 | 'iPad11,4', 62 | 'iPad13,2'] 63 | if "iPhone" in self.identifier: 64 | self.baseband = True 65 | return 66 | self.baseband = self.identifier in cellular_ipads 67 | 68 | def free_device(self): 69 | usb.util.dispose_resources(self.usb_device) 70 | 71 | -------------------------------------------------------------------------------- /others/ipsw.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | from typing import Optional 3 | import sys, os 4 | import hashlib 5 | import json 6 | import shutil 7 | import plistlib 8 | import os, sys 9 | from m1n1Exception import * 10 | from zipfile import ZipFile, is_zipfile 11 | 12 | 13 | class IPSW: 14 | def __init__(self, ipsw: Path): 15 | self.ipsw = ipsw 16 | self.otaable = False 17 | self.verify_ipsw() 18 | 19 | def __str__(self) -> str: 20 | return str(self.ipsw) 21 | 22 | def read_file(self, file: str) -> Optional[bytes]: 23 | try: 24 | with ZipFile(self.ipsw, 'r') as ipsw: 25 | return ipsw.read(file) 26 | except KeyError: 27 | reterror(f"File not in IPSW: {file}") 28 | 29 | def extract_file(self, file, location): 30 | try: 31 | print(f"Extracting '{file}'...") 32 | with ZipFile(self.ipsw, 'r') as ipsw, open(location, 'wb') as f: 33 | f.write(ipsw.read(file)) 34 | except: 35 | reterror(f"Couldn't extract {file}") 36 | 37 | def verify_ipsw(self): 38 | print("Verifying iPSW...") 39 | retassure(os.path.exists(self.ipsw), f"iPSW not found at: {self.ipsw}") 40 | retassure(is_zipfile(self.ipsw), f"'{self.ipsw}' is not a valid iPSW") 41 | 42 | def get_ipswinfo(self, buildmanifest): 43 | ios_ver = "" 44 | for ver in buildmanifest.version: 45 | ios_ver += f"{ver}." 46 | self.version = ios_ver[:-1] 47 | print(f"iPSW info: Version: {self.version} BuildID: {buildmanifest.buildid}") 48 | self.int_version = buildmanifest.version[0] 49 | retassure(10 <= buildmanifest.version[0] <= 14, f"iOS {self.version} is not supported") 50 | if self.version == "10.3.3": 51 | self.otaable = True 52 | -------------------------------------------------------------------------------- /others/irecv_devices_struct.py: -------------------------------------------------------------------------------- 1 | # Thanks to doronz88 2 | 3 | from collections import namedtuple 4 | 5 | irecv_device = namedtuple('irecv_device', 'product_type hardware_model bdid cpid display_name') 6 | 7 | irecv_devices = ( 8 | # iPhone 9 | irecv_device(product_type='iPhone1,1', hardware_model='m68ap', bdid=0x00, cpid=8900, 10 | display_name='iPhone 2G'), 11 | irecv_device(product_type='iPhone1,2', hardware_model='n82ap', bdid=0x04, cpid=8900, 12 | display_name='iPhone 3G'), 13 | irecv_device(product_type='iPhone2,1', hardware_model='n88ap', bdid=0x00, cpid=8920, 14 | display_name='iPhone 3Gs'), 15 | irecv_device(product_type='iPhone3,1', hardware_model='n90ap', bdid=0x00, cpid=8930, 16 | display_name='iPhone 4 (GSM)'), 17 | irecv_device(product_type='iPhone3,2', hardware_model='n90bap', bdid=0x04, cpid=8930, 18 | display_name='iPhone 4 (GSM) R2 2012'), 19 | irecv_device(product_type='iPhone3,3', hardware_model='n92ap', bdid=0x06, cpid=8930, 20 | display_name='iPhone 4 (CDMA)'), 21 | irecv_device(product_type='iPhone4,1', hardware_model='n94ap', bdid=0x08, cpid=8940, 22 | display_name='iPhone 4s'), 23 | irecv_device(product_type='iPhone5,1', hardware_model='n41ap', bdid=0x00, cpid=8950, 24 | display_name='iPhone 5 (GSM)'), 25 | irecv_device(product_type='iPhone5,2', hardware_model='n42ap', bdid=0x02, cpid=8950, 26 | display_name='iPhone 5 (Global)'), 27 | irecv_device(product_type='iPhone5,3', hardware_model='n48ap', bdid=0x0a, cpid=8950, 28 | display_name='iPhone 5c (GSM)'), 29 | irecv_device(product_type='iPhone5,4', hardware_model='n49ap', bdid=0x0e, cpid=8950, 30 | display_name='iPhone 5c (Global)'), 31 | irecv_device(product_type='iPhone6,1', hardware_model='n51ap', bdid=0x00, cpid=8960, 32 | display_name='iPhone 5s (GSM)'), 33 | irecv_device(product_type='iPhone6,2', hardware_model='n53ap', bdid=0x02, cpid=8960, 34 | display_name='iPhone 5s (Global)'), 35 | irecv_device(product_type='iPhone7,1', hardware_model='n56ap', bdid=0x04, cpid=7000, 36 | display_name='iPhone 6 Plus'), 37 | irecv_device(product_type='iPhone7,2', hardware_model='n61ap', bdid=0x06, cpid=7000, 38 | display_name='iPhone 6'), 39 | irecv_device(product_type='iPhone8,1', hardware_model='n71ap', bdid=0x04, cpid=8000, 40 | display_name='iPhone 6s'), 41 | irecv_device(product_type='iPhone8,1', hardware_model='n71map', bdid=0x04, cpid=8003, 42 | display_name='iPhone 6s'), 43 | irecv_device(product_type='iPhone8,2', hardware_model='n66ap', bdid=0x06, cpid=8000, 44 | display_name='iPhone 6s Plus'), 45 | irecv_device(product_type='iPhone8,2', hardware_model='n66map', bdid=0x06, cpid=8003, 46 | display_name='iPhone 6s Plus'), 47 | irecv_device(product_type='iPhone8,4', hardware_model='n69ap', bdid=0x02, cpid=8003, 48 | display_name='iPhone SE'), 49 | irecv_device(product_type='iPhone8,4', hardware_model='n69uap', bdid=0x02, cpid=8000, 50 | display_name='iPhone SE'), 51 | irecv_device(product_type='iPhone9,1', hardware_model='d10ap', bdid=0x08, cpid=8010, 52 | display_name='iPhone 7 (Global)'), 53 | irecv_device(product_type='iPhone9,2', hardware_model='d11ap', bdid=0x0a, cpid=8010, 54 | display_name='iPhone 7 Plus (Global)'), 55 | irecv_device(product_type='iPhone9,3', hardware_model='d101ap', bdid=0x0c, cpid=8010, 56 | display_name='iPhone 7 (GSM)'), 57 | irecv_device(product_type='iPhone9,4', hardware_model='d111ap', bdid=0x0e, cpid=8010, 58 | display_name='iPhone 7 Plus (GSM)'), 59 | irecv_device(product_type='iPhone10,1', hardware_model='d20ap', bdid=0x02, cpid=8015, 60 | display_name='iPhone 8 (Global)'), 61 | irecv_device(product_type='iPhone10,2', hardware_model='d21ap', bdid=0x04, cpid=8015, 62 | display_name='iPhone 8 Plus (Global)'), 63 | irecv_device(product_type='iPhone10,3', hardware_model='d22ap', bdid=0x06, cpid=8015, 64 | display_name='iPhone X (Global)'), 65 | irecv_device(product_type='iPhone10,4', hardware_model='d201ap', bdid=0x0a, cpid=8015, 66 | display_name='iPhone 8 (GSM)'), 67 | irecv_device(product_type='iPhone10,5', hardware_model='d211ap', bdid=0x0c, cpid=8015, 68 | display_name='iPhone 8 Plus (GSM)'), 69 | irecv_device(product_type='iPhone10,6', hardware_model='d221ap', bdid=0x0e, cpid=8015, 70 | display_name='iPhone X (GSM)'), 71 | irecv_device(product_type='iPhone11,2', hardware_model='d321ap', bdid=0x0e, cpid=8020, 72 | display_name='iPhone XS'), 73 | irecv_device(product_type='iPhone11,4', hardware_model='d331ap', bdid=0x0a, cpid=8020, 74 | display_name='iPhone XS Max (China)'), 75 | irecv_device(product_type='iPhone11,6', hardware_model='d331pap', bdid=0x1a, cpid=8020, 76 | display_name='iPhone XS Max'), 77 | irecv_device(product_type='iPhone11,8', hardware_model='n841ap', bdid=0x0c, cpid=8020, 78 | display_name='iPhone XR'), 79 | irecv_device(product_type='iPhone12,1', hardware_model='n104ap', bdid=0x04, cpid=8030, 80 | display_name='iPhone 11'), 81 | irecv_device(product_type='iPhone12,3', hardware_model='d421ap', bdid=0x06, cpid=8030, 82 | display_name='iPhone 11 Pro'), 83 | irecv_device(product_type='iPhone12,5', hardware_model='d431ap', bdid=0x02, cpid=8030, 84 | display_name='iPhone 11 Pro Max'), 85 | irecv_device(product_type='iPhone12,8', hardware_model='d79ap', bdid=0x10, cpid=8030, 86 | display_name='iPhone SE (2020)'), 87 | irecv_device(product_type='iPhone13,1', hardware_model='d52gap', bdid=0x0A, cpid=8101, 88 | display_name='iPhone 12 mini'), 89 | irecv_device(product_type='iPhone13,2', hardware_model='d53gap', bdid=0x0C, cpid=8101, 90 | display_name='iPhone 12'), 91 | irecv_device(product_type='iPhone13,3', hardware_model='d53pap', bdid=0x0E, cpid=8101, 92 | display_name='iPhone 12 Pro'), 93 | irecv_device(product_type='iPhone13,4', hardware_model='d54pap', bdid=0x08, cpid=8101, 94 | display_name='iPhone 12 Pro Max'), 95 | irecv_device(product_type='iPhone14,2', hardware_model='d63ap', bdid=0x0C, cpid=8110, 96 | display_name='iPhone 13 Pro'), 97 | irecv_device(product_type='iPhone14,3', hardware_model='d64ap', bdid=0x0E, cpid=8110, 98 | display_name='iPhone 13 Pro Max'), 99 | irecv_device(product_type='iPhone14,4', hardware_model='d16ap', bdid=0x08, cpid=8110, 100 | display_name='iPhone 13 mini'), 101 | irecv_device(product_type='iPhone14,5', hardware_model='d17ap', bdid=0x0A, cpid=8110, 102 | display_name='iPhone 13'), 103 | # iPod 104 | irecv_device(product_type='iPod1,1', hardware_model='n45ap', bdid=0x02, cpid=8900, 105 | display_name='iPod Touch (1st gen)'), 106 | irecv_device(product_type='iPod2,1', hardware_model='n72ap', bdid=0x00, cpid=8720, 107 | display_name='iPod Touch (2nd gen)'), 108 | irecv_device(product_type='iPod3,1', hardware_model='n18ap', bdid=0x02, cpid=8922, 109 | display_name='iPod Touch (3rd gen)'), 110 | irecv_device(product_type='iPod4,1', hardware_model='n81ap', bdid=0x08, cpid=8930, 111 | display_name='iPod Touch (4th gen)'), 112 | irecv_device(product_type='iPod5,1', hardware_model='n78ap', bdid=0x00, cpid=8942, 113 | display_name='iPod Touch (5th gen)'), 114 | irecv_device(product_type='iPod7,1', hardware_model='n102ap', bdid=0x10, cpid=7000, 115 | display_name='iPod Touch (6th gen)'), 116 | irecv_device(product_type='iPod9,1', hardware_model='n112ap', bdid=0x16, cpid=8010, 117 | display_name='iPod Touch (7th gen)'), 118 | # iPad 119 | irecv_device(product_type='iPad1,1', hardware_model='k48ap', bdid=0x02, cpid=8930, display_name='iPad'), 120 | irecv_device(product_type='iPad2,1', hardware_model='k93ap', bdid=0x04, cpid=8940, 121 | display_name='iPad 2 (WiFi)'), 122 | irecv_device(product_type='iPad2,2', hardware_model='k94ap', bdid=0x06, cpid=8940, 123 | display_name='iPad 2 (GSM)'), 124 | irecv_device(product_type='iPad2,3', hardware_model='k95ap', bdid=0x02, cpid=8940, 125 | display_name='iPad 2 (CDMA)'), 126 | irecv_device(product_type='iPad2,4', hardware_model='k93aap', bdid=0x06, cpid=8942, 127 | display_name='iPad 2 (WiFi) R2 2012'), 128 | irecv_device(product_type='iPad2,5', hardware_model='p105ap', bdid=0x0a, cpid=8942, 129 | display_name='iPad mini (WiFi)'), 130 | irecv_device(product_type='iPad2,6', hardware_model='p106ap', bdid=0x0c, cpid=8942, 131 | display_name='iPad mini (GSM)'), 132 | irecv_device(product_type='iPad2,7', hardware_model='p107ap', bdid=0x0e, cpid=8942, 133 | display_name='iPad mini (Global)'), 134 | irecv_device(product_type='iPad3,1', hardware_model='j1ap', bdid=0x00, cpid=8945, 135 | display_name='iPad (3rd gen, WiFi)'), 136 | irecv_device(product_type='iPad3,2', hardware_model='j2ap', bdid=0x02, cpid=8945, 137 | display_name='iPad (3rd gen, CDMA)'), 138 | irecv_device(product_type='iPad3,3', hardware_model='j2aap', bdid=0x04, cpid=8945, 139 | display_name='iPad (3rd gen, GSM)'), 140 | irecv_device(product_type='iPad3,4', hardware_model='p101ap', bdid=0x00, cpid=8955, 141 | display_name='iPad (4th gen, WiFi)'), 142 | irecv_device(product_type='iPad3,5', hardware_model='p102ap', bdid=0x02, cpid=8955, 143 | display_name='iPad (4th gen, GSM)'), 144 | irecv_device(product_type='iPad3,6', hardware_model='p103ap', bdid=0x04, cpid=8955, 145 | display_name='iPad (4th gen, Global)'), 146 | irecv_device(product_type='iPad4,1', hardware_model='j71ap', bdid=0x10, cpid=8960, 147 | display_name='iPad Air (WiFi)'), 148 | irecv_device(product_type='iPad4,2', hardware_model='j72ap', bdid=0x12, cpid=8960, 149 | display_name='iPad Air (Cellular)'), 150 | irecv_device(product_type='iPad4,3', hardware_model='j73ap', bdid=0x14, cpid=8960, 151 | display_name='iPad Air (China)'), 152 | irecv_device(product_type='iPad4,4', hardware_model='j85ap', bdid=0x0a, cpid=8960, 153 | display_name='iPad mini 2 (WiFi)'), 154 | irecv_device(product_type='iPad4,5', hardware_model='j86ap', bdid=0x0c, cpid=8960, 155 | display_name='iPad mini 2 (Cellular)'), 156 | irecv_device(product_type='iPad4,6', hardware_model='j87ap', bdid=0x0e, cpid=8960, 157 | display_name='iPad mini 2 (China)'), 158 | irecv_device(product_type='iPad4,7', hardware_model='j85map', bdid=0x32, cpid=8960, 159 | display_name='iPad mini 3 (WiFi)'), 160 | irecv_device(product_type='iPad4,8', hardware_model='j86map', bdid=0x34, cpid=8960, 161 | display_name='iPad mini 3 (Cellular)'), 162 | irecv_device(product_type='iPad4,9', hardware_model='j87map', bdid=0x36, cpid=8960, 163 | display_name='iPad mini 3 (China)'), 164 | irecv_device(product_type='iPad5,1', hardware_model='j96ap', bdid=0x08, cpid=7000, 165 | display_name='iPad mini 4 (WiFi)'), 166 | irecv_device(product_type='iPad5,2', hardware_model='j97ap', bdid=0x0A, cpid=7000, 167 | display_name='iPad mini 4 (Cellular)'), 168 | irecv_device(product_type='iPad5,3', hardware_model='j81ap', bdid=0x06, cpid=7001, 169 | display_name='iPad Air 2 (WiFi)'), 170 | irecv_device(product_type='iPad5,4', hardware_model='j82ap', bdid=0x02, cpid=7001, 171 | display_name='iPad Air 2 (Cellular)'), 172 | irecv_device(product_type='iPad6,3', hardware_model='j127ap', bdid=0x08, cpid=8001, 173 | display_name='iPad Pro 9.7-inch (WiFi)'), 174 | irecv_device(product_type='iPad6,4', hardware_model='j128ap', bdid=0x0a, cpid=8001, 175 | display_name='iPad Pro 9.7-inch (Cellular)'), 176 | irecv_device(product_type='iPad6,7', hardware_model='j98aap', bdid=0x10, cpid=8001, 177 | display_name='iPad Pro 12.9-inch (1st gen, WiFi)'), 178 | irecv_device(product_type='iPad6,8', hardware_model='j99aap', bdid=0x12, cpid=8001, 179 | display_name='iPad Pro 12.9-inch (1st gen, Cellular)'), 180 | irecv_device(product_type='iPad6,11', hardware_model='j71sap', bdid=0x10, cpid=8000, 181 | display_name='iPad (5th gen, WiFi)'), 182 | irecv_device(product_type='iPad6,11', hardware_model='j71tap', bdid=0x10, cpid=8003, 183 | display_name='iPad (5th gen, WiFi)'), 184 | irecv_device(product_type='iPad6,12', hardware_model='j72sap', bdid=0x12, cpid=8000, 185 | display_name='iPad (5th gen, Cellular)'), 186 | irecv_device(product_type='iPad6,12', hardware_model='j72tap', bdid=0x12, cpid=8003, 187 | display_name='iPad (5th gen, Cellular)'), 188 | irecv_device(product_type='iPad7,1', hardware_model='j120ap', bdid=0x0C, cpid=8011, 189 | display_name='iPad Pro 12.9-inch (2nd gen, WiFi)'), 190 | irecv_device(product_type='iPad7,2', hardware_model='j121ap', bdid=0x0E, cpid=8011, 191 | display_name='iPad Pro 12.9-inch (2nd gen, Cellular)'), 192 | irecv_device(product_type='iPad7,3', hardware_model='j207ap', bdid=0x04, cpid=8011, 193 | display_name='iPad Pro 10.5-inch (WiFi)'), 194 | irecv_device(product_type='iPad7,4', hardware_model='j208ap', bdid=0x06, cpid=8011, 195 | display_name='iPad Pro 10.5-inch (Cellular)'), 196 | irecv_device(product_type='iPad7,5', hardware_model='j71bap', bdid=0x18, cpid=8010, 197 | display_name='iPad (6th gen, WiFi)'), 198 | irecv_device(product_type='iPad7,6', hardware_model='j72bap', bdid=0x1A, cpid=8010, 199 | display_name='iPad (6th gen, Cellular)'), 200 | irecv_device(product_type='iPad7,11', hardware_model='j171ap', bdid=0x1C, cpid=8010, 201 | display_name='iPad (7th gen, WiFi)'), 202 | irecv_device(product_type='iPad7,12', hardware_model='j172ap', bdid=0x1E, cpid=8010, 203 | display_name='iPad (7th gen, Cellular)'), 204 | irecv_device(product_type='iPad8,1', hardware_model='j317ap', bdid=0x0C, cpid=8027, 205 | display_name='iPad Pro 11-inch (1st gen, WiFi)'), 206 | irecv_device(product_type='iPad8,2', hardware_model='j317xap', bdid=0x1C, cpid=8027, 207 | display_name='iPad Pro 11-inch (1st gen, WiFi, 1TB)'), 208 | irecv_device(product_type='iPad8,3', hardware_model='j318ap', bdid=0x0E, cpid=8027, 209 | display_name='iPad Pro 11-inch (1st gen, Cellular)'), 210 | irecv_device(product_type='iPad8,4', hardware_model='j318xap', bdid=0x1E, cpid=8027, 211 | display_name='iPad Pro 11-inch (1st gen, Cellular, 1TB)'), 212 | irecv_device(product_type='iPad8,5', hardware_model='j320ap', bdid=0x08, cpid=8027, 213 | display_name='iPad Pro 12.9-inch (3rd gen, WiFi)'), 214 | irecv_device(product_type='iPad8,6', hardware_model='j320xap', bdid=0x18, cpid=8027, 215 | display_name='iPad Pro 12.9-inch (3rd gen, WiFi, 1TB)'), 216 | irecv_device(product_type='iPad8,7', hardware_model='j321ap', bdid=0x0A, cpid=8027, 217 | display_name='iPad Pro 12.9-inch (3rd gen, Cellular)'), 218 | irecv_device(product_type='iPad8,8', hardware_model='j321xap', bdid=0x1A, cpid=8027, 219 | display_name='iPad Pro 12.9-inch (3rd gen, Cellular, 1TB)'), 220 | irecv_device(product_type='iPad8,9', hardware_model='j417ap', bdid=0x3C, cpid=8027, 221 | display_name='iPad Pro 11-inch (2nd gen, WiFi)'), 222 | irecv_device(product_type='iPad8,10', hardware_model='j418ap', bdid=0x3E, cpid=8027, 223 | display_name='iPad Pro 11-inch (2nd gen, Cellular)'), 224 | irecv_device(product_type='iPad8,11', hardware_model='j420ap', bdid=0x38, cpid=8027, 225 | display_name='iPad Pro 12.9-inch (4th gen, WiFi)'), 226 | irecv_device(product_type='iPad8,12', hardware_model='j421ap', bdid=0x3A, cpid=8027, 227 | display_name='iPad Pro 12.9-inch (4th gen, Cellular)'), 228 | irecv_device(product_type='iPad11,1', hardware_model='j210ap', bdid=0x14, cpid=8020, 229 | display_name='iPad mini (5th gen, WiFi)'), 230 | irecv_device(product_type='iPad11,2', hardware_model='j211ap', bdid=0x16, cpid=8020, 231 | display_name='iPad mini (5th gen, Cellular)'), 232 | irecv_device(product_type='iPad11,3', hardware_model='j217ap', bdid=0x1C, cpid=8020, 233 | display_name='iPad Air (3rd gen, WiFi)'), 234 | irecv_device(product_type='iPad11,4', hardware_model='j218ap', bdid=0x1E, cpid=8020, 235 | display_name='iPad Air (3rd gen, Celluar)'), 236 | irecv_device(product_type='iPad11,6', hardware_model='j171aap', bdid=0x24, cpid=8020, 237 | display_name='iPad (8th gen, WiFi)'), 238 | irecv_device(product_type='iPad11,7', hardware_model='j172aap', bdid=0x26, cpid=8020, 239 | display_name='iPad (8th gen, Cellular)'), 240 | irecv_device(product_type='iPad12,1', hardware_model='j181ap', bdid=0x18, cpid=8030, 241 | display_name='iPad (9th gen, WiFi)'), 242 | irecv_device(product_type='iPad12,2', hardware_model='j182ap', bdid=0x1A, cpid=8030, 243 | display_name='iPad (9th gen, Cellular)'), 244 | irecv_device(product_type='iPad13,1', hardware_model='j307ap', bdid=0x04, cpid=8101, 245 | display_name='iPad Air (4th gen, WiFi)'), 246 | irecv_device(product_type='iPad13,2', hardware_model='j308ap', bdid=0x06, cpid=8101, 247 | display_name='iPad Air (4th gen, Celluar)'), 248 | irecv_device(product_type='iPad13,4', hardware_model='j517ap', bdid=0x08, cpid=8103, 249 | display_name='iPad Pro 11-inch (3rd gen, WiFi)'), 250 | irecv_device(product_type='iPad13,5', hardware_model='j517xap', bdid=0x0A, cpid=8103, 251 | display_name='iPad Pro 11-inch (3rd gen, WiFi, 2TB)'), 252 | irecv_device(product_type='iPad13,6', hardware_model='j518ap', bdid=0x0C, cpid=8103, 253 | display_name='iPad Pro 11-inch (3rd gen, Cellular)'), 254 | irecv_device(product_type='iPad13,7', hardware_model='j518xap', bdid=0x0E, cpid=8103, 255 | display_name='iPad Pro 11-inch (3rd gen, Cellular, 2TB)'), 256 | irecv_device(product_type='iPad13,8', hardware_model='j522ap', bdid=0x18, cpid=8103, 257 | display_name='iPad Pro 12.9-inch (5th gen, WiFi)'), 258 | irecv_device(product_type='iPad13,9', hardware_model='j522xap', bdid=0x1A, cpid=8103, 259 | display_name='iPad Pro 12.9-inch (5th gen, WiFi, 2TB)'), 260 | irecv_device(product_type='iPad13,10', hardware_model='j523ap', bdid=0x1C, cpid=8103, 261 | display_name='iPad Pro 12.9-inch (5th gen, Cellular)'), 262 | irecv_device(product_type='iPad13,11', hardware_model='j523xap', bdid=0x1E, cpid=8103, 263 | display_name='iPad Pro 12.9-inch (5th gen, Cellular, 2TB)'), 264 | irecv_device(product_type='iPad14,1', hardware_model='j310ap', bdid=0x04, cpid=8110, 265 | display_name='iPad mini (6th gen, WiFi)'), 266 | irecv_device(product_type='iPad14,2', hardware_model='j311ap', bdid=0x06, cpid=8110, 267 | display_name='iPad mini (6th gen, Cellular)'), 268 | # Apple TV 269 | irecv_device(product_type='AppleTV2,1', hardware_model='k66ap', bdid=0x10, cpid=8930, 270 | display_name='Apple TV 2'), 271 | irecv_device(product_type='AppleTV3,1', hardware_model='j33ap', bdid=0x08, cpid=8942, 272 | display_name='Apple TV 3'), 273 | irecv_device(product_type='AppleTV3,2', hardware_model='j33iap', bdid=0x00, cpid=8947, 274 | display_name='Apple TV 3 (2013)'), 275 | irecv_device(product_type='AppleTV5,3', hardware_model='j42dap', bdid=0x34, cpid=7000, 276 | display_name='Apple TV 4'), 277 | irecv_device(product_type='AppleTV6,2', hardware_model='j105aap', bdid=0x02, cpid=8011, 278 | display_name='Apple TV 4K'), 279 | irecv_device(product_type='AppleTV11,1', hardware_model='j305ap', bdid=0x08, cpid=8020, 280 | display_name='Apple TV 4K (2nd gen)'), 281 | # HomePod 282 | irecv_device(product_type='AudioAccessory1,1', hardware_model='b238aap', bdid=0x38, cpid=7000, 283 | display_name='HomePod'), 284 | irecv_device(product_type='AudioAccessory1,2', hardware_model='b238ap', bdid=0x1A, cpid=7000, 285 | display_name='HomePod'), 286 | irecv_device(product_type='AudioAccessory5,1', hardware_model='b520ap', bdid=0x22, cpid=8006, 287 | display_name='HomePod mini'), 288 | # Apple Watch 289 | irecv_device(product_type='Watch1,1', hardware_model='n27aap', bdid=0x02, cpid=7002, 290 | display_name='Apple Watch 38mm (1st gen)'), 291 | irecv_device(product_type='Watch1,2', hardware_model='n28aap', bdid=0x04, cpid=7002, 292 | display_name='Apple Watch 42mm (1st gen)'), 293 | irecv_device(product_type='Watch2,6', hardware_model='n27dap', bdid=0x02, cpid=8002, 294 | display_name='Apple Watch Series 1 (38mm)'), 295 | irecv_device(product_type='Watch2,7', hardware_model='n28dap', bdid=0x04, cpid=8002, 296 | display_name='Apple Watch Series 1 (42mm)'), 297 | irecv_device(product_type='Watch2,3', hardware_model='n74ap', bdid=0x0C, cpid=8002, 298 | display_name='Apple Watch Series 2 (38mm)'), 299 | irecv_device(product_type='Watch2,4', hardware_model='n75ap', bdid=0x0E, cpid=8002, 300 | display_name='Apple Watch Series 2 (42mm)'), 301 | irecv_device(product_type='Watch3,1', hardware_model='n111sap', bdid=0x1C, cpid=8004, 302 | display_name='Apple Watch Series 3 (38mm Cellular)'), 303 | irecv_device(product_type='Watch3,2', hardware_model='n111bap', bdid=0x1E, cpid=8004, 304 | display_name='Apple Watch Series 3 (42mm Cellular)'), 305 | irecv_device(product_type='Watch3,3', hardware_model='n121sap', bdid=0x18, cpid=8004, 306 | display_name='Apple Watch Series 3 (38mm)'), 307 | irecv_device(product_type='Watch3,4', hardware_model='n121bap', bdid=0x1A, cpid=8004, 308 | display_name='Apple Watch Series 3 (42mm)'), 309 | irecv_device(product_type='Watch4,1', hardware_model='n131sap', bdid=0x08, cpid=8006, 310 | display_name='Apple Watch Series 4 (40mm)'), 311 | irecv_device(product_type='Watch4,2', hardware_model='n131bap', bdid=0x0A, cpid=8006, 312 | display_name='Apple Watch Series 4 (44mm)'), 313 | irecv_device(product_type='Watch4,3', hardware_model='n141sap', bdid=0x0C, cpid=8006, 314 | display_name='Apple Watch Series 4 (40mm Cellular)'), 315 | irecv_device(product_type='Watch4,4', hardware_model='n141bap', bdid=0x0E, cpid=8006, 316 | display_name='Apple Watch Series 4 (44mm Cellular)'), 317 | irecv_device(product_type='Watch5,1', hardware_model='n144sap', bdid=0x10, cpid=8006, 318 | display_name='Apple Watch Series 5 (40mm)'), 319 | irecv_device(product_type='Watch5,2', hardware_model='n144bap', bdid=0x12, cpid=8006, 320 | display_name='Apple Watch Series 5 (44mm)'), 321 | irecv_device(product_type='Watch5,3', hardware_model='n146sap', bdid=0x14, cpid=8006, 322 | display_name='Apple Watch Series 5 (40mm Cellular)'), 323 | irecv_device(product_type='Watch5,4', hardware_model='n146bap', bdid=0x16, cpid=8006, 324 | display_name='Apple Watch Series 5 (44mm Cellular)'), 325 | irecv_device(product_type='Watch5,9', hardware_model='n140sap', bdid=0x28, cpid=8006, 326 | display_name='Apple Watch SE (40mm)'), 327 | irecv_device(product_type='Watch5,10', hardware_model='n140bap', bdid=0x2A, cpid=8006, 328 | display_name='Apple Watch SE (44mm)'), 329 | irecv_device(product_type='Watch5,11', hardware_model='n142sap', bdid=0x2C, cpid=8006, 330 | display_name='Apple Watch SE (40mm Cellular)'), 331 | irecv_device(product_type='Watch5,12', hardware_model='n142bap', bdid=0x2E, cpid=8006, 332 | display_name='Apple Watch SE (44mm Cellular)'), 333 | irecv_device(product_type='Watch6,1', hardware_model='n157sap', bdid=0x08, cpid=8301, 334 | display_name='Apple Watch Series 6 (40mm)'), 335 | irecv_device(product_type='Watch6,2', hardware_model='n157bap', bdid=0x0A, cpid=8301, 336 | display_name='Apple Watch Series 6 (44mm)'), 337 | irecv_device(product_type='Watch6,3', hardware_model='n158sap', bdid=0x0C, cpid=8301, 338 | display_name='Apple Watch Series 6 (40mm Cellular)'), 339 | irecv_device(product_type='Watch6,4', hardware_model='n158bap', bdid=0x0E, cpid=8301, 340 | display_name='Apple Watch Series 6 (44mm Cellular)'), 341 | irecv_device(product_type='Watch6,6', hardware_model='n187sap', bdid=0x10, cpid=8301, 342 | display_name='Apple Watch Series 7 (41mm)'), 343 | irecv_device(product_type='Watch6,7', hardware_model='n187bap', bdid=0x12, cpid=8301, 344 | display_name='Apple Watch Series 7 (45mm)'), 345 | irecv_device(product_type='Watch6,8', hardware_model='n188sap', bdid=0x14, cpid=8301, 346 | display_name='Apple Watch Series 7 (41mm Cellular)'), 347 | irecv_device(product_type='Watch6,9', hardware_model='n188bap', bdid=0x16, cpid=8301, 348 | display_name='Apple Watch Series 7 (45mm Cellular)'), 349 | # Apple Silicon Macs 350 | irecv_device(product_type='ADP3,2', hardware_model='j273aap', bdid=0x42, cpid=8027, 351 | display_name='Developer Transition Kit (2020)'), 352 | irecv_device(product_type='Macmini9,1', hardware_model='j274ap', bdid=0x22, cpid=8103, 353 | display_name='Mac mini (M1, 2020)'), 354 | irecv_device(product_type='MacBookPro17,1', hardware_model='j293ap', bdid=0x24, cpid=8103, 355 | display_name='MacBook Pro (M1, 2020)'), 356 | irecv_device(product_type='MacBookPro18,1', hardware_model='j316sap', bdid=0x0A, cpid=6000, 357 | display_name='MacBook Pro (M1 Pro, 16-inch, 2021)'), 358 | irecv_device(product_type='MacBookPro18,2', hardware_model='j316cap', bdid=0x0A, cpid=6001, 359 | display_name='MacBook Pro (M1 Max, 16-inch, 2021)'), 360 | irecv_device(product_type='MacBookPro18,3', hardware_model='j314sap', bdid=0x08, cpid=6000, 361 | display_name='MacBook Pro (M1 Pro, 14-inch, 2021)'), 362 | irecv_device(product_type='MacBookPro18,4', hardware_model='j314cap', bdid=0x08, cpid=6001, 363 | display_name='MacBook Pro (M1 Max, 14-inch, 2021)'), 364 | irecv_device(product_type='MacBookAir10,1', hardware_model='j313ap', bdid=0x26, cpid=8103, 365 | display_name='MacBook Air (M1, 2020)'), 366 | irecv_device(product_type='iMac21,1', hardware_model='j456ap', bdid=0x28, cpid=8103, 367 | display_name='iMac 24-inch (M1, Two Ports, 2021)'), 368 | irecv_device(product_type='iMac21,2', hardware_model='j457ap', bdid=0x2A, cpid=8103, 369 | display_name='iMac 24-inch (M1, Four Ports, 2021)'), 370 | # Apple T2 Coprocessor 371 | irecv_device(product_type='iBridge2,1', hardware_model='j137ap', bdid=0x0A, cpid=8012, 372 | display_name='Apple T2 iMacPro1,1 (j137)'), 373 | irecv_device(product_type='iBridge2,3', hardware_model='j680ap', bdid=0x0B, cpid=8012, 374 | display_name='Apple T2 MacBookPro15,1 (j680)'), 375 | irecv_device(product_type='iBridge2,4', hardware_model='j132ap', bdid=0x0C, cpid=8012, 376 | display_name='Apple T2 MacBookPro15,2 (j132)'), 377 | irecv_device(product_type='iBridge2,5', hardware_model='j174ap', bdid=0x0E, cpid=8012, 378 | display_name='Apple T2 Macmini8,1 (j174)'), 379 | irecv_device(product_type='iBridge2,6', hardware_model='j160ap', bdid=0x0F, cpid=8012, 380 | display_name='Apple T2 MacPro7,1 (j160)'), 381 | irecv_device(product_type='iBridge2,7', hardware_model='j780ap', bdid=0x07, cpid=8012, 382 | display_name='Apple T2 MacBookPro15,3 (j780)'), 383 | irecv_device(product_type='iBridge2,8', hardware_model='j140kap', bdid=0x17, cpid=8012, 384 | display_name='Apple T2 MacBookAir8,1 (j140k)'), 385 | irecv_device(product_type='iBridge2,10', hardware_model='j213ap', bdid=0x18, cpid=8012, 386 | display_name='Apple T2 MacBookPro15,4 (j213)'), 387 | irecv_device(product_type='iBridge2,12', hardware_model='j140aap', bdid=0x37, cpid=8012, 388 | display_name='Apple T2 MacBookAir8,2 (j140a)'), 389 | irecv_device(product_type='iBridge2,14', hardware_model='j152fap', bdid=0x3A, cpid=8012, 390 | display_name='Apple T2 MacBookPro16,1 (j152f)'), 391 | irecv_device(product_type='iBridge2,15', hardware_model='j230kap', bdid=0x3F, cpid=8012, 392 | display_name='Apple T2 MacBookAir9,1 (j230k)'), 393 | irecv_device(product_type='iBridge2,16', hardware_model='j214kap', bdid=0x3E, cpid=8012, 394 | display_name='Apple T2 MacBookPro16,2 (j214k)'), 395 | irecv_device(product_type='iBridge2,19', hardware_model='j185ap', bdid=0x22, cpid=8012, 396 | display_name='Apple T2 iMac20,1 (j185)'), 397 | irecv_device(product_type='iBridge2,20', hardware_model='j185fap', bdid=0x23, cpid=8012, 398 | display_name='Apple T2 iMac20,2 (j185f)'), 399 | irecv_device(product_type='iBridge2,21', hardware_model='j223ap', bdid=0x3B, cpid=8012, 400 | display_name='Apple T2 MacBookPro16,3 (j223)'), 401 | irecv_device(product_type='iBridge2,22', hardware_model='j215ap', bdid=0x38, cpid=8012, 402 | display_name='Apple T2 MacBookPro16,4 (j215)'), 403 | ) -------------------------------------------------------------------------------- /others/kerneldiff.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import shutil 4 | 5 | def diff_kernel(org, patchfile, output): 6 | patched = open(patchfile, "rb").read() 7 | original = open(org, "rb").read() 8 | newfile = output 9 | test1 = open(patchfile, "rb").read(28) 10 | test2 = open(org, "rb").read(28) 11 | lenP = len(patched) 12 | lenO = len(original) 13 | if test1 != test2 or lenP != lenO: 14 | raw = open(org, "rb") 15 | fix = b"\xca\xfe\xba\xbe\x00\x00\x00\x01\x01\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x40\x00\x02\x31\x96\x78\x00\x00\x00\x0e" 16 | testPatched = open(f"{patchfile}.new", "w+b") 17 | 18 | testPatched.write(test2 + patched) 19 | 20 | testPatched.close() 21 | 22 | os.remove(patchfile) 23 | shutil.move(f"{patchfile}.new", patchfile) 24 | 25 | patched = open(patchfile, "rb").read() 26 | original = open(org, "rb").read() 27 | lenP = len(patched) 28 | lenO = len(original) 29 | if lenP != lenO: 30 | # CAFEBABE 00000001 0100000C 00000000 00004000 02319678 0000000E 31 | fix = b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" 32 | testPatched = open(f"{patchfile}", "w+b") 33 | testPatched.seek(41020239) 34 | testPatched.write(fix) 35 | 36 | testPatched.close() 37 | 38 | 39 | diff = [] 40 | for i in range(lenO): 41 | originalByte = original[i] 42 | patchedByte = patched[i] 43 | if originalByte != patchedByte: 44 | diff.append([hex(i),hex(originalByte), hex(patchedByte)]) 45 | diffFile = open(newfile, 'w+') 46 | diffFile.write('#AMFI\n\n') 47 | for d in diff: 48 | data = str(d[0]) + " " + (str(d[1])) + " " + (str(d[2])) 49 | diffFile.write(data+ '\n') 50 | -------------------------------------------------------------------------------- /others/restore.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | import subprocess 3 | import glob 4 | import time 5 | from m1n1Exception import * 6 | import time 7 | 8 | class RestoreBootchain: 9 | def __init__(self, ibss, ibec, ramdisk=None, kernelcache=None): 10 | self.ibss = ibss 11 | self.ibec = ibec 12 | if ramdisk and kernelcache: 13 | self.ramdisk = ramdisk 14 | self.kernelcache = kernelcache 15 | 16 | class Restore: 17 | def __init__(self, device_struct, bootchain, ipsw, update): 18 | self.device = device_struct 19 | self.bootchain = bootchain 20 | self.ipsw = ipsw 21 | self.update = update 22 | 23 | def save_blobs(self, save_path, bm=None): 24 | print("Saving temporary SHSH...") 25 | args = [ 26 | 'tsschecker', 27 | '-d', 28 | self.device.identifier, 29 | '-B', 30 | self.device.board, 31 | '-e', 32 | self.device.ecid, 33 | '-s', 34 | '--save-path', 35 | save_path, 36 | '--nocache' 37 | ] 38 | if bm: 39 | args.append('-m') 40 | args.append(bm) 41 | args.append('--apnonce') 42 | args.append(self.device.apnonce) 43 | 44 | else: 45 | args.append('-l') 46 | retassure(subprocess.run(args, stdout=subprocess.DEVNULL, universal_newlines=True).returncode == 0, "Failed to save SHSH blobs") 47 | if bm: 48 | self.ota_blob = glob.glob(f"{save_path}/*.shsh*")[0] 49 | else: 50 | self.blob = glob.glob(f"{save_path}/*.shsh*")[0] 51 | 52 | 53 | def sign_bootloader(self, path, output, type): 54 | print(f"Signing {type}...") 55 | args = [ 56 | 'img4', 57 | '-i', 58 | path, 59 | '-o', 60 | output, 61 | '-M', 62 | self.im4m, 63 | '-A', 64 | '-T', 65 | type.lower() 66 | ] 67 | retassure(subprocess.run(args, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).returncode == 0, "Failed to sign bootloader") 68 | 69 | def save_im4m(self, output, custom_blob=None): 70 | print("Saving IM4M for signing bootchain...") 71 | if custom_blob: 72 | args = [ 73 | 'img4tool', 74 | '-e', 75 | '-s', 76 | custom_blob, 77 | '-m', 78 | output 79 | ] 80 | else: 81 | args = [ 82 | 'img4tool', 83 | '-e', 84 | '-s', 85 | self.blob, 86 | '-m', 87 | output 88 | ] 89 | retassure(subprocess.run(args, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).returncode == 0, "Failed to save IM4M") 90 | self.im4m = output 91 | 92 | def restore(self, custom_blob=None, log_path=None, ota=False, sep=None, bb=None, bm=None): 93 | if sep: 94 | print("Restoring device with OTA method...") 95 | else: 96 | print("Restoring device...") 97 | if custom_blob and not ota: 98 | args = [ 99 | 'futurerestore', 100 | '-t', 101 | custom_blob, 102 | '--skip-blob', 103 | '--use-pwndfu', 104 | '--custom-ibss', 105 | self.bootchain.ibss, 106 | '--custom-ibec', 107 | self.bootchain.ibec 108 | ] 109 | else: 110 | args = [ 111 | 'futurerestore', 112 | '-t', 113 | self.blob if not ota else self.ota_blob, 114 | '--use-pwndfu', 115 | '--skip-blob', 116 | '--custom-ibss', 117 | self.bootchain.ibss, 118 | '--custom-ibec', 119 | self.bootchain.ibec 120 | ] 121 | 122 | if sep and bb and bm: 123 | args.append('-s') 124 | args.append(sep) 125 | args.append('-m') 126 | args.append(bm) 127 | args.append('-b') 128 | args.append(bb) 129 | args.append('-p') 130 | args.append(bm) 131 | else: 132 | args.append('--latest-sep') 133 | args.append('--rdsk') 134 | args.append(self.bootchain.ramdisk) 135 | args.append('--rkrn') 136 | args.append(self.bootchain.kernelcache) 137 | if self.device.baseband: 138 | args.append('--latest-baseband') 139 | else: 140 | args.append('--no-baseband') 141 | if self.update: 142 | args.append('-u') 143 | args.append(self.ipsw) 144 | if log_path: 145 | if log_path.endswith('/'): 146 | log_path = log_path[:-1] 147 | result = subprocess.run(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding="utf8") 148 | with open(f'{log_path}/restore.log', 'w') as f: 149 | f.write(result.stdout) 150 | retassure(result.returncode == 0, f'Restore failed ({result.returncode}). Log saved to {log_path}/restore.log') 151 | print(f'Restore succeeded! Log saved to {log_path}/restore.log') 152 | else: 153 | result = subprocess.run(args, universal_newlines=True) 154 | retassure(result.returncode == 0, f'Restore failed ({result.returncode})') 155 | print('Restore succeeded!') 156 | -------------------------------------------------------------------------------- /others/signcert.p12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miniexploit/ra1nstorm/b5aac45c9b0afcc8cffbdaf533c901682445ec4d/others/signcert.p12 -------------------------------------------------------------------------------- /ra1nstorm: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Made by MiniExploit 4 | 5 | import shutil 6 | import os, sys, platform 7 | from tempfile import TemporaryDirectory 8 | import subprocess 9 | from others.ipsw import IPSW 10 | from others.manifest import Manifest, ota_manifests 11 | from others.restore import Restore, RestoreBootchain 12 | from others.dependencies import check_requirements 13 | from others.kerneldiff import diff_kernel 14 | from m1n1Exception import * 15 | from others.device import Device 16 | from others import device, api 17 | import argparse 18 | import time 19 | 20 | set_package_name('ra1nstorm') 21 | 22 | retassure(platform.system() == 'Darwin', 'This OS is not supported') 23 | 24 | os.chdir(os.path.dirname(sys.argv[0])) 25 | 26 | def decrypt(path, type, tmpdir, iv=None, key=None): 27 | dargs = [ 28 | 'img4', 29 | '-i', 30 | path, 31 | '-o', 32 | f'{tmpdir}/{type}.dec' 33 | ] 34 | if iv and key: 35 | dargs.append('-k') 36 | dargs.append(f'{iv}{key}') 37 | retassure(subprocess.run(dargs, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).returncode == 0, f"Failed to decrypt {type}") 38 | 39 | def patch_bootloader(path, type, device, buildid, version, tmpdir): 40 | print(f"Patching {type}...") 41 | try: 42 | iBSS_iv, iBSS_key, iBEC_iv, iBEC_key = api.get_keys(device.identifier, device.board, buildid) 43 | no_key = False 44 | except TypeError: 45 | no_key = True 46 | if not no_key: 47 | if type == "iBSS": 48 | decrypt(path, type, tmpdir, iBSS_iv, iBSS_key) 49 | if type == "iBEC": 50 | decrypt(path, type, tmpdir, iBEC_iv, iBEC_key) 51 | else: 52 | if type == "iBSS": 53 | decrypt(path, type, tmpdir) 54 | if type == "iBEC": 55 | decrypt(path, type, tmpdir) 56 | patcher = "kairos" if version >= 13 else "iBoot64Patcher" 57 | retassure(subprocess.run((patcher,f'{tmpdir}/{type}.dec',f'{tmpdir}/{type}.patched','-n'), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).returncode == 0, f"Failed to patch {type}") 58 | 59 | def patch_kernel(kernelcache, kernelorg, output, tmpdir): 60 | print("Patching kernelcache...") 61 | patch_kcache = subprocess.run(('Kernel64Patcher',kernelcache,f'{tmpdir}/kcache.patched','-a'), stdout=subprocess.DEVNULL) 62 | retassure(patch_kcache.returncode == 0, "Failed to patch kernelcache AMFI") 63 | diff_kernel(kernelcache, f'{tmpdir}/kcache.patched', f"{tmpdir}/kcache.diff") 64 | pack_krnl = subprocess.run(('img4','-i',kernelorg,'-o',output,'-T','rkrn','-P', f'{tmpdir}/kcache.diff'), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) 65 | retassure(pack_krnl.returncode == 0, "Failed to pack kernelcache") 66 | 67 | def patch_ramdisk(ramdisk, output, tmpdir): 68 | print("Patching ramdisk...") 69 | os.makedirs(f"{tmpdir}/rdsk_mnpt") 70 | # Attach ramdisk to the mountpoint 71 | attach_rdsk = subprocess.run(('hdiutil','attach', ramdisk, '-mountpoint',f'{tmpdir}/rdsk_mnpt'), stdout=subprocess.DEVNULL) 72 | retassure(attach_rdsk.returncode == 0, "Failed to mount ramdisk") 73 | # Patch asr 74 | shutil.move(f'{tmpdir}/rdsk_mnpt/usr/sbin/asr', f'{tmpdir}/asr.extracted') 75 | asr64 = subprocess.run(('asr64_patcher',f'{tmpdir}/asr.extracted',f'{tmpdir}/patched_asr'), stdout=subprocess.DEVNULL) 76 | detachret(asr64.returncode == 0, "Failed to patch asr", f'{tmpdir}/rdsk_mnpt') 77 | ents = subprocess.run(('ldid', '-e', f'{tmpdir}/asr.extracted'), stdout=subprocess.PIPE, universal_newlines=True) 78 | detachret(ents.returncode == 0, "Failed to extract ASR entitlements", f'{tmpdir}/rdsk_mnpt') 79 | with open(f'{tmpdir}/asr.xml', 'w') as f: 80 | f.write(ents.stdout) 81 | sign_asr = subprocess.run(('ldid','-Cadhoc',f'-Kothers/signcert.p12',f'-S{tmpdir}/asr.xml',f'{tmpdir}/patched_asr'), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, universal_newlines=True) # Thanks Cryptic 82 | detachret(sign_asr.returncode == 0, "Failed to sign patched ASR", f'{tmpdir}/rdsk_mnpt') 83 | os.chmod(f'{tmpdir}/patched_asr', 0o755) 84 | shutil.move(f'{tmpdir}/patched_asr', f'{tmpdir}/rdsk_mnpt/usr/sbin/asr') 85 | time.sleep(3) 86 | # NEW: Patch libimg4 87 | if os.path.exists(f'{tmpdir}/rdsk_mnpt/usr/lib/libimg4.dylib'): 88 | tohex = subprocess.run(f'hexdump {tmpdir}/rdsk_mnpt/usr/lib/libimg4.dylib > {tmpdir}/libimg4.hex', shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) 89 | retassure(tohex.returncode == 0, "Failed to patch libimg4") 90 | with open(f'{tmpdir}/libimg4.hex', 'r') as f: 91 | data = f.read() 92 | try: 93 | topatch = [line for line in data.splitlines() if 'b1b0' in line][0] 94 | except IndexError: 95 | reterror("Failed to patch libimg4") 96 | patch = topatch.replace('c0 00 80 52', '00 00 80 52') 97 | data = data.replace(topatch, patch) 98 | with open(f'{tmpdir}/libimg4.hex', 'w') as f: 99 | f.write(data) 100 | tobin = subprocess.run(('xxd','-r',f'{tmpdir}/libimg4.hex',f'{tmpdir}/patched_libimg4.dylib'), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) 101 | retassure(tobin.returncode == 0, "Failed to patch libimg4") 102 | os.remove(f'{tmpdir}/rdsk_mnpt/usr/lib/libimg4.dylib') 103 | shutil.move(f'{tmpdir}/patched_libimg4.dylib', f'{tmpdir}/rdsk_mnpt/usr/lib/libimg4.dylib') 104 | time.sleep(3) 105 | # Detach ramdisk 106 | detach = subprocess.run(('hdiutil','detach',f'{tmpdir}/rdsk_mnpt'), stdout=subprocess.DEVNULL) 107 | retassure(detach.returncode == 0, "Failed to ummount ramdisk") 108 | os.rmdir(f"{tmpdir}/rdsk_mnpt") 109 | pack_rdsk = subprocess.run(('img4','-i',ramdisk,'-o',output,'-A','-T','rdsk'), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) 110 | retassure(pack_rdsk.returncode == 0, "Failed to pack ramdisk") 111 | 112 | def main(): 113 | parser = argparse.ArgumentParser(description='ra1nstorm - Tethered downgrade 64-bit iDevices vulnerable to checkm8', usage="ra1nstorm iPSW [-u] [-s PATH] [-t BLOB]") 114 | parser.add_argument('-t','--blob',nargs=1, metavar='BLOB', help='Manually specify SHSH used for restoring (SHSH will be automatically saved if this argument is skipped)') 115 | parser.add_argument('ipsw', metavar='iPSW', nargs=1, help='iPSW file used for restoring') 116 | parser.add_argument('-s','--save-log',nargs=1, metavar='PATH', help='Specify path for saving futurerestore log') 117 | parser.add_argument('-u', '--update', help='Keep data while restoring (Untested)', action='store_true') 118 | args = parser.parse_args() 119 | ota = False 120 | if args.save_log: 121 | retassure(os.path.isdir(args.save_log[0]), "Provided path to save log is not a directory") 122 | 123 | check_requirements() 124 | device = Device() 125 | ipsw = IPSW(args.ipsw[0]) 126 | buildmanifest = Manifest(ipsw.read_file('BuildManifest.plist')) 127 | retassure(device.identifier in buildmanifest.supported_devices, "This iPSW can't be used to restore the connected device") 128 | ipsw.get_ipswinfo(buildmanifest) 129 | if device.otaable and ipsw.otaable: 130 | ota = True 131 | #retassure(buildmanifest.version[0] == 10 and ota, "Restoring to iOS 10.x on this device is not available") 132 | if ota: 133 | print("[NOTE] About to restore device with OTA method, custom SHSH blob won't be used") 134 | with TemporaryDirectory() as tmpdir: 135 | if args.update: 136 | print("[WARNING] -u/--update option is untested, use it at your own risk!") 137 | _ibss = buildmanifest.get_comp(device.board, 'iBSS') 138 | _ibec = buildmanifest.get_comp(device.board, 'iBEC') 139 | ipsw.extract_file(_ibss, f'{tmpdir}/ibss.extracted') 140 | ipsw.extract_file(_ibec, f'{tmpdir}/ibec.extracted') 141 | patch_bootloader(f'{tmpdir}/ibss.extracted', 'iBSS', device, buildmanifest.buildid, ipsw.int_version, tmpdir) 142 | patch_bootloader(f'{tmpdir}/ibec.extracted', 'iBEC', device, buildmanifest.buildid, ipsw.int_version, tmpdir) 143 | if not ota: 144 | ramdisk_path = buildmanifest.get_comp(device.board, 'RestoreRamDisk') 145 | ipsw.extract_file(ramdisk_path, f"{tmpdir}/ramdisk_org.dmg") 146 | unpack_rdsk = subprocess.run(('img4','-i',f"{tmpdir}/ramdisk_org.dmg",'-o',f"{tmpdir}/ramdisk.dmg"), stdout=subprocess.DEVNULL) 147 | retassure(unpack_rdsk.returncode == 0, "Failed to unpack ramdisk") 148 | kernelcache = buildmanifest.get_comp(device.board, 'RestoreKernelCache') 149 | ipsw.extract_file(kernelcache ,f"{tmpdir}/kernelcache.release.extracted") 150 | unpack_krnl = subprocess.run(('img4','-i',f"{tmpdir}/kernelcache.release.extracted",'-o',f"{tmpdir}/kcache.raw"), stdout=subprocess.DEVNULL) 151 | retassure(unpack_krnl.returncode == 0, "Failed to unpack kernelcache") 152 | patch_ramdisk(f'{tmpdir}/ramdisk.dmg', f'{tmpdir}/ramdisk.im4p', tmpdir) 153 | patch_kernel(f'{tmpdir}/kcache.raw', f'{tmpdir}/kernelcache.release.extracted', f'{tmpdir}/kernelcache.im4p', tmpdir) 154 | 155 | bootchain = RestoreBootchain( 156 | f'{tmpdir}/ibss.{device.board}.patched.img4', # This path hasn't existed yet since we haven't signed the bootloaders. 157 | f'{tmpdir}/ibec.{device.board}.patched.img4', # However, it will be saved before it's passed to futurerestore 158 | f'{tmpdir}/ramdisk.im4p', 159 | f'{tmpdir}/kernelcache.im4p' 160 | ) 161 | else: 162 | ota_manifests(device.identifier, f'{tmpdir}/OTABuildManifest.plist') 163 | bootchain = RestoreBootchain( 164 | f'{tmpdir}/ibss.{device.board}.ota.im4p', 165 | f'{tmpdir}/ibec.{device.board}.ota.im4p' 166 | ) 167 | device.free_device() 168 | restore = Restore(device, bootchain, args.ipsw[0], args.update) 169 | if not os.path.exists(f"{tmpdir}/tempblobs"): 170 | os.makedirs(f'{tmpdir}/tempblobs') 171 | if not os.path.exists(f'{tmpdir}/otablobs'): 172 | os.makedirs(f'{tmpdir}/otablobs') 173 | if ota: 174 | restore.save_blobs(f'{tmpdir}/tempblobs') 175 | restore.save_im4m(f'{tmpdir}/im4m') 176 | restore.sign_bootloader(f'{tmpdir}/iBSS.patched', f'{tmpdir}/ibss.{device.board}.ota.im4p', 'iBSS') 177 | restore.sign_bootloader(f'{tmpdir}/iBEC.patched', f'{tmpdir}/ibec.{device.board}.ota.im4p', 'iBEC') 178 | restore.save_blobs(f'{tmpdir}/otablobs', f'{tmpdir}/OTABuildManifest.plist') 179 | sep = buildmanifest.get_comp(device.board, 'RestoreSEP') 180 | bb = buildmanifest.get_comp(device.board, 'BasebandFirmware') 181 | ipsw.extract_file(sep, f'{tmpdir}/sep.im4p') 182 | ipsw.extract_file(bb, f'{tmpdir}/baseband.bbfw') 183 | if args.save_log: 184 | restore.restore(ota=True, log_path=args.save_log[0], sep=f'{tmpdir}/sep.im4p', bb=f'{tmpdir}/baseband.bbfw', bm=f'{tmpdir}/OTABuildManifest.plist') 185 | else: 186 | restore.restore(ota=True, sep=f'{tmpdir}/sep.im4p', bb=f'{tmpdir}/baseband.bbfw', bm=f'{tmpdir}/OTABuildManifest.plist') 187 | else: 188 | if not args.blob: 189 | restore.save_blobs(f'{tmpdir}/tempblobs') 190 | restore.save_im4m(f'{tmpdir}/im4m') 191 | else: 192 | restore.save_im4m(f'{tmpdir}/im4m', args.blob[0]) 193 | restore.sign_bootloader(f'{tmpdir}/iBSS.patched', f'{tmpdir}/ibss.{device.board}.patched.img4', 'iBSS') 194 | restore.sign_bootloader(f'{tmpdir}/iBEC.patched', f'{tmpdir}/ibec.{device.board}.patched.img4', 'iBEC') 195 | if not args.blob: 196 | if args.save_log: 197 | restore.restore(log_path=args.save_log[0]) 198 | else: 199 | restore.restore() 200 | else: 201 | if args.save_log: 202 | restore.restore(custom_blob=args.blob[0], log_path=args.save_log[0]) 203 | else: 204 | restore.restore(custom_blob=args.blob[0]) 205 | 206 | if __name__ == '__main__': 207 | try: 208 | main() 209 | except m1n1Exception as e: 210 | print(e) 211 | 212 | 213 | 214 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | requests 2 | psutil 3 | argparse 4 | pyusb 5 | remotezip 6 | m1n1Exception 7 | --------------------------------------------------------------------------------