Compare commits

..

No commits in common. "main" and "dev" have entirely different histories.
main ... dev

15 changed files with 486 additions and 267 deletions

2
.gitignore vendored
View file

@ -1,5 +1,7 @@
.DS_Store
*/.DS_Store
binaries/Linux/futurerestore
binaries/Darwin/futurerestore
work
ramdisk
boot*

View file

@ -1,12 +1,12 @@
# downr1n
Downr1n enables tethered downgrades of checkm8 iOS devices to iOS 15, 14 and 13.4 upper.
Downr1n enables tethered downgrades of checkm8 iOS devices to iOS 15, 14 and 13.
there is dualra1n too, which is a dualboot for ios like having two different ios [dualra1n](https://github.com/dualra1n/dualra1n), i would recommend more dualra1n as it is very stable.
In general, dual booting is a better option than downgrading if you have the necessary storage. if you activate the localboot path it would be ultra better believe me xd.
# Usage
1: Download the IPSW file and place it in the ipsw/ directory.
2: execute: ./downr1n.sh --downgrade 14.3.
2: Execute the script without using 'sudo' on Linux. if it doesn't work please use sudo then.
Example: ./downr1n.sh --downgrade 14.3
@ -14,7 +14,9 @@ The various command-line options are as follows:
--downgrade : Downgrade your device to iOS 14 tethered.
--jailbreak : Jailbreak with dualra1n-loader. Usage: `./downr1n.sh --jailbreak 14.8`.
--dfuhelper : A helper tool to transition A11 devices from recovery mode to DFU mode.
--jailbreak : Jailbreak with pogo. Usage: `./downr1n.sh --jailbreak 14.8`.
--taurine : Jailbreak with taurine. Usage: `./downr1n.sh --jailbreak 14.3 --taurine`.
@ -24,15 +26,18 @@ The various command-line options are as follows:
--dont-restore : Avoids using futurerestore, this can be used to only create boot files. Example: `--downgrade 14.3 --dont-restore`.
--fixBoot : Boots the device using fsboot.
--debug : Debug the script.
---
# Dependencies
- unzip, python3, libimobiledevice-utils, libusbmuxd-tools, xz-utils, wget, curl, git, libssl-dev, usbmuxd.
- please execute this command: python3 -m pip install pyimg4[compression] fastapi aiohttp ujson wikitextparser uvicorn.
- A disabled passcode on A10 and A11 devices.
- An .iPSW file containing iOS 15, 14, 13.4 upper.
- A device running macOS or a Linux distro. It is recommended to use macOS, as it is likely more stable and faster. and for linux it is recommended to use ubuntu or debian.
- unzip, python3, libimobiledevice-utils, libusbmuxd-tools, xz-utils.
- An .iPSW file containing iOS 15, 14, 13.
- A device running macOS or a Linux distro. It is recommended to use macOS, as it is likely more stable and faster.
# Issues Putting Device in PwnDFU Mode
@ -40,13 +45,9 @@ The various command-line options are as follows:
# importants things
- A8/A8x devices downr1n is not recommended please instead use dualra1n with --downgrade option (if you don't have enough storage for a dualboot)
- downgrading ios 16 to 14 or another version, you will have to bypass the setup somehow. good luck on it.
- you can't downgrade an iphone x if the device is on ios 16
- downgrading ios 16 to 14 or another version, you should have backup your activations file in order to after downgrade and boot sucessfully restore them, you can use https://github.com/edwin170/bypassr1n.
- on ios 13 the touch id doesn't work so the home button will not work sadly.
- on ios 13 the touch id doesn't work so the home button on iphone 7 will not work sadly.
- you can't downgrade to ios 14.2 lower on a11 devices
@ -58,7 +59,7 @@ The various command-line options are as follows:
# fix some problems
- if it gives problem with server key please execute: 1: python3 -m pip install git+https://github.com/m1stadev/wikiproxy.git 2: wikiproxy &
- please execute wikiproxy.py manually if it gives problem with server key. for ex: sudo python3 wikiproxy.py
- if the error still after above fix, if this happend to you when you are downgrading with futurerestore again please add this arg --keyServer for example ./downr1n.sh --downgrade 14.5 --keyServer.
@ -68,9 +69,11 @@ The various command-line options are as follows:
- Join my discord server: [Dualra1nServer](https://discord.gg/Gjs2P7FBuk)
# How to Jailbreak?
- Jailbreak with dualra1n-loader: ./downr1n --jailbreak (YourVer = 14.3). Note: this does not actually jailbreak the device. When I say "jailbreak," I'm referring to the process of installing Sileo and bootstrapping the device. Dualra1n-loader only installs Sileo and bootstraps with the kpf kernel patch. (you will be able to use tweaks and most of things as normal).
- Jailbreak with dualra1n-loader: ./downr1n --jailbreak (YourVer = 14.3). Note: this does not actually jailbreak the device. When I say "jailbreak," I'm referring to the process of installing Sileo and bootstrapping the device. Dualra1n-loader only installs Sileo and bootstraps with the kernel patch.
- Taurine: ./downr1n --jailbreak (ex: 14.3 or YouVers) --taurine.
- Taurine: ./downr1n --jailbreak (YourVer = 14.3) --taurine. Note: this is not recommended.
# This project was created with love by Edwin :)
# Credits

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load diff

View file

@ -2,4 +2,4 @@
sudo systemctl stop usbmuxd
sudo usbmuxd -p -f 1>/dev/null
sudo usbmuxd -p -f

Binary file not shown.

29
other/post.sh Executable file
View file

@ -0,0 +1,29 @@
#!/jbin/binpack/bin/bash
binpack=/jbin/binpack
# uicache loader app
$binpack/bin/rm -rf /var/.palera1n/loader.app
$binpack/usr/bin/uicache -p /Applications/Pogo.app/
$binpack/usr/bin/uicache -p /Applications/trollstore.app/
# remount r/w
/sbin/mount -uw /
/sbin/mount -uw /private/preboot/
# lauching daemon automatically
/usr/bin/launchctl load /Library/LaunchDaemons/
# update repo
if [ -f /usr/bin/apt ]; then
apt-get update
fi
# activating tweaks
/etc/rc.d/substitute-launcher
# respring
$binpack/usr/bin/uicache -a
$binpack/usr/bin/killall -9 SpringBoard
echo "[post.sh] done"
exit

Binary file not shown.

Binary file not shown.

28
other/rootfs/jbin/post.sh Executable file
View file

@ -0,0 +1,28 @@
#!/jbin/binpack/bin/bash
binpack=/jbin/binpack
# uicache loader app
$binpack/bin/rm -rf /var/.palera1n/loader.app
$binpack/usr/bin/uicache -p /Applications/Pogo.app/
# remount r/w
/sbin/mount -uw /
/sbin/mount -uw /private/preboot/
# lauching daemon automatically
/usr/bin/launchctl load /Library/LaunchDaemons/
# update repo
if [ -f /usr/bin/apt ]; then
apt-get update
fi
# activating tweaks
/etc/rc.d/substitute-launcher
# respring
$binpack/usr/bin/uicache -a
$binpack/usr/bin/killall -9 SpringBoard
echo "[post.sh] done"
exit

181
wikiproxy.py Normal file
View file

@ -0,0 +1,181 @@
#!/usr/bin/env python3
from fastapi import FastAPI
from datetime import datetime
import aiohttp
import asyncio
import re
import time
import ujson
import wikitextparser as wtp
import uvicorn
DEVICE_REGEX = re.compile(r'(iPhone|AppleTV|iPad|iPod)[0-9]+,[0-9]+')
# Only allow 100 simultaneous HTTP requests
HTTP_SEMAPHORE = asyncio.Semaphore(100)
async def get_key_page(
session: aiohttp.ClientSession, identifier: str, buildid: str
) -> str:
params = {
'action': 'query',
'list': 'search',
'srsearch': f'Keys: {buildid} ({identifier})',
'srwhat': 'title',
'srlimit': '1',
'format': 'json',
'srnamespace': '2304',
}
async with HTTP_SEMAPHORE, session.get(
'https://theapplewiki.com/api.php', params=params
) as resp:
if resp.status != 200:
pass # raise error
else:
search = await resp.json()
if search['query']['searchinfo']['totalhits'] == 0:
raise ValueError(
f'No Firmware Keys page for device: {identifier}, buildid: {buildid}.'
)
params = {
'action': 'parse',
'prop': 'wikitext',
'page': search['query']['search'][0]['title'],
'format': 'json',
'formatversion': 2,
}
async with HTTP_SEMAPHORE, session.get(
'https://theapplewiki.com/api.php', params=params
) as resp:
if resp.status != 200:
pass # raise error
data = await resp.json()
return data['parse']['wikitext']
def parse_page(data: str, identifer: str, boardconfig: str = None) -> dict:
# Have to coerce wikitextparser into recognizing it as a table for easy parsing
data = (
' '.join([x for x in data.split(' ') if x != ''])
.replace('{{', '{| class="wikitable"')
.replace('}}', '|}')
)
page = wtp.parse(data)
page_data = {}
for entry in page.tables[0].data()[0]:
key, item = entry.split(' = ')
page_data[key] = item
if boardconfig is not None:
if ('Model' not in page_data.keys()) and ('Model2' not in page_data.keys()):
return page_data
if boardconfig.lower() not in [x.lower() for x in page_data.values()]:
raise ValueError(
f'Boardconfig: {boardconfig} for device: {identifer} is not valid!'
)
if page_data['Model2'].lower() == boardconfig.lower():
for key in page_data:
if '2' in key:
page_data[key.replace('2', '')] = page_data[key]
for key in list(page_data.keys()):
if '2' in key:
del page_data[key]
response = {
'identifier': page_data['Device'],
'buildid': page_data['Build'],
'codename': page_data['Codename'],
'restoreramdiskexists': 'RestoreRamdisk' in page_data,
'updateramdiskexists': 'UpdateRamdisk' in page_data,
'keys': [],
}
for component in page_data:
if component in (
'Version',
'Build',
'Device',
'Model',
'Codename',
'Baseband',
'DownloadURL',
):
continue
if any(component.endswith(x) for x in ('Key', 'IV', 'KBAG')):
continue
image = {
'image': component,
'filename': page_data[component],
'date': datetime.now().isoformat(),
}
if any(component == x for x in ('RootFS', 'RestoreRamdisk', 'UpdateRamdisk')):
image['filename'] += '.dmg'
for key in ('IV', 'Key') if component != 'RootFS' else ('Key',):
if component + key not in page_data.keys():
continue
if all(
x not in page_data[component + key]
for x in ('Unknown', 'Not Encrypted')
):
image[key.lower()] = page_data[component + key]
if (
('iv' not in image.keys())
and ('key' not in image.keys())
and not image['filename'].endswith('.dmg')
):
continue
if 'iv' in image and 'key' in image:
image['kbag'] = image['iv'] + image['key']
response['keys'].append(image)
return response
app = FastAPI()
@app.middleware('http')
async def add_process_time_header(request, call_next):
start_time = time.time()
response = await call_next(request)
response.headers['X-Process-Time'] = str(f'{time.time() - start_time:0.4f} sec')
return response
@app.get('/firmware/{identifier}/{buildid}')
async def get_firmware_keys(identifier: str, buildid: str) -> dict:
async with aiohttp.ClientSession() as session:
page = await get_key_page(session, identifier, buildid)
return parse_page(page, identifier)
@app.get('/firmware/{identifier}/{boardconfig}/{buildid}')
async def get_firmware_keys(identifier: str, boardconfig: str, buildid: str) -> dict:
async with aiohttp.ClientSession() as session:
page = await get_key_page(session, identifier, buildid)
return parse_page(page, identifier, boardconfig)
if __name__ == '__main__':
uvicorn.run(app='__main__:app', host='127.0.0.1', port='8888')