Skip to content
This repository has been archived by the owner on Jan 20, 2025. It is now read-only.

Commit

Permalink
Merge pull request #76 from leminlimez/18_1-beta5
Browse files Browse the repository at this point in the history
v4.0
  • Loading branch information
leminlimez authored Oct 28, 2024
2 parents 3211db2 + 95b388c commit 8339f1f
Show file tree
Hide file tree
Showing 17 changed files with 4,255 additions and 689 deletions.
Binary file removed .DS_Store
Binary file not shown.
15 changes: 11 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# Nugget
Unlock your device's full potential! Works on all versions iOS 17.0-18.1 beta 4
Unlock your device's full potential!

Sparserestore was patched in iOS 18.1 beta 5. It will not be supported, please stop asking.
Sparserestore works on all versions iOS 17.0-17.7 and iOS 18.0-18.1 beta 4. There is partial support for iOS 17.7.1 and iOS 18.1 beta 5+.

This uses the sparserestore exploit to write to files outside of the intended restore location, like mobilegestalt.

Note: I am not responsible if your device bootloops. Please back up your data before using.
Note: I am not responsible if your device bootloops. Please back up your data before using!

## Features
- Enable Dynamic Island on any device
Expand All @@ -27,14 +27,20 @@ Note: I am not responsible if your device bootloops. Please back up your data be
- Enabling lock screen clock animation, lock screen page duplication button, and more!
- Disabling the new iOS 18 Photos UI
- EU Enabler
- AI Enabler
- Springboard Options (from Cowabunga Lite)
- Internal Options (from Cowabunga Lite)

## Running the Program
Requirements:
**Requirements:**
- pymobiledevice3
- Python 3.8 or newer

- **Windows:**
- Either [Apple Devices (from Microsoft Store)](https://apps.microsoft.com/detail/9np83lwlpz9k%3Fhl%3Den-US%26gl%3DUS&ved=2ahUKEwjE-svo7qyJAxWTlYkEHQpbH3oQFnoECBoQAQ&usg=AOvVaw0rZTXCFmRaHAifkEEu9tMI) app or [iTunes (from Apple website)](https://support.apple.com/en-us/106372)
- **Linux:**
- [usbmuxd](https://github.com/libimobiledevice/usbmuxd) and [libimobiledevice](https://github.com/libimobiledevice/libimobiledevice)

Note: It is highly recommended to use a virtual environment:
```
python3 -m venv .env # only needed once
Expand Down Expand Up @@ -67,4 +73,5 @@ The application itself can be compiled by running `compile.py`.
- [JJTech](https://github.com/JJTech0130) for Sparserestore/[TrollRestore](https://github.com/JJTech0130/TrollRestore)
- [pymobiledevice3](https://github.com/doronz88/pymobiledevice3)
- [disfordottie](https://x.com/disfordottie) for some global flag features
- [sneakyf1shy](https://github.com/f1shy-dev) for [AI Enabler](https://gist.github.com/f1shy-dev/23b4a78dc283edd30ae2b2e6429129b5)

15 changes: 10 additions & 5 deletions Sparserestore/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@

from . import backup

def reboot_device(reboot: bool = False, lockdown_client: LockdownClient = None):
if reboot and lockdown_client != None:
print("Success! Rebooting your device...")
with DiagnosticsService(lockdown_client) as diagnostics_service:
diagnostics_service.restart()
print("Remember to turn Find My back on!")

def perform_restore(backup: backup.Backup, reboot: bool = False, lockdown_client: LockdownClient = None):
try:
with TemporaryDirectory() as backup_dir:
Expand All @@ -18,6 +25,8 @@ def perform_restore(backup: backup.Backup, reboot: bool = False, lockdown_client
lockdown_client = create_using_usbmux()
with Mobilebackup2Service(lockdown_client) as mb:
mb.restore(backup_dir, system=True, reboot=False, copy=False, source=".")
# reboot the device
reboot_device(reboot, lockdown_client)
except PyMobileDevice3Exception as e:
if "Find My" in str(e):
print("Find My must be disabled in order to use this tool.")
Expand All @@ -26,8 +35,4 @@ def perform_restore(backup: backup.Backup, reboot: bool = False, lockdown_client
elif "crash_on_purpose" not in str(e):
raise e
else:
if reboot and lockdown_client != None:
print("Success! Rebooting your device...")
with DiagnosticsService(lockdown_client) as diagnostics_service:
diagnostics_service.restart()
print("Remember to turn Find My back on!")
reboot_device(reboot, lockdown_client)
111 changes: 82 additions & 29 deletions Sparserestore/restore.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,81 @@
import os

class FileToRestore:
def __init__(self, contents: str, restore_path: str, owner: int = 501, group: int = 501):
def __init__(self, contents: str, restore_path: str, domain: str = None, owner: int = 501, group: int = 501):
self.contents = contents
self.restore_path = restore_path
self.domain = domain
self.owner = owner
self.group = group

def concat_exploit_file(file: FileToRestore, files_list: list[FileToRestore], last_domain: str) -> str:
base_path = "/var/backup"
# set it to work in the separate volumes (prevents a bootloop)
if file.restore_path.startswith("/var/mobile/"):
# required on iOS 17.0+ since /var/mobile is on a separate partition
base_path = "/var/mobile/backup"
elif file.restore_path.startswith("/private/var/mobile/"):
base_path = "/private/var/mobile/backup"
elif file.restore_path.startswith("/private/var/"):
base_path = "/private/var/backup"
# don't append the directory if it has already been added (restore will fail)
path, name = os.path.split(file.restore_path)
domain_path = f"SysContainerDomain-../../../../../../../..{base_path}{path}/"
new_last_domain = last_domain
if last_domain != domain_path:
files_list.append(backup.Directory(
"",
f"{domain_path}/",
owner=file.owner,
group=file.group
))
new_last_domain = domain_path
files_list.append(backup.ConcreteFile(
"",
f"{domain_path}/{name}",
owner=file.owner,
group=file.group,
contents=file.contents
))
return new_last_domain

def concat_regular_file(file: FileToRestore, files_list: list[FileToRestore], last_domain: str, last_path: str):
path, name = os.path.split(file.restore_path)
paths = path.split("/")
new_last_domain = last_domain
# append the domain first
if last_domain != file.domain:
files_list.append(backup.Directory(
"",
file.domain,
owner=file.owner,
group=file.group
))
new_last_domain = file.domain
# append each part of the path if it is not already there
full_path = ""
for path_item in paths:
if full_path != "":
full_path += "/"
full_path += path_item
if not last_path.startswith(full_path):
files_list.append(backup.Directory(
full_path,
file.domain,
owner=file.owner,
group=file.group
))
last_path = full_path
# finally, append the file
files_list.append(backup.ConcreteFile(
f"{full_path}/{name}",
file.domain,
owner=file.owner,
group=file.group,
contents=file.contents
))
return new_last_domain, full_path

# files is a list of FileToRestore objects
def restore_files(files: list, reboot: bool = False, lockdown_client: LockdownClient = None):
# create the files to be backed up
Expand All @@ -17,42 +86,26 @@ def restore_files(files: list, reboot: bool = False, lockdown_client: LockdownCl
sorted_files = sorted(files, key=lambda x: x.restore_path, reverse=True)
# add the file paths
last_domain = ""
last_path = ""
exploit_only = True
for file in sorted_files:
base_path = "/var/backup"
# set it to work in the separate volumes (prevents a bootloop)
if file.restore_path.startswith("/var/mobile/"):
# required on iOS 17.0+ since /var/mobile is on a separate partition
base_path = "/var/mobile/backup"
elif file.restore_path.startswith("/private/var/mobile/"):
base_path = "/private/var/mobile/backup"
elif file.restore_path.startswith("/private/var/"):
base_path = "/private/var/backup"
# don't append the directory if it has already been added (restore will fail)
path, name = os.path.split(file.restore_path)
domain_path = f"SysContainerDomain-../../../../../../../..{base_path}{path}/"
if last_domain != domain_path:
files_list.append(backup.Directory(
"",
f"{domain_path}/",
owner=file.owner,
group=file.group
))
last_domain = domain_path
files_list.append(backup.ConcreteFile(
"",
f"{domain_path}/{name}",
owner=file.owner,
group=file.group,
contents=file.contents
))
files_list.append(backup.ConcreteFile("", "SysContainerDomain-../../../../../../../.." + "/crash_on_purpose", contents=b""))
if file.domain == None:
last_domain = concat_exploit_file(file, files_list, last_domain)
else:
last_domain, last_path = concat_regular_file(file, files_list, last_domain, last_path)
exploit_only = False

# crash the restore to skip the setup (only works for exploit files)
if exploit_only:
files_list.append(backup.ConcreteFile("", "SysContainerDomain-../../../../../../../.." + "/crash_on_purpose", contents=b""))

# create the backup
back = backup.Backup(files=files_list)

perform_restore(backup=back, reboot=reboot, lockdown_client=lockdown_client)


# DEPRICATED
def restore_file(fp: str, restore_path: str, restore_name: str, reboot: bool = False, lockdown_client: LockdownClient = None):
# open the file and read the contents
contents = open(fp, "rb").read()
Expand Down
Loading

0 comments on commit 8339f1f

Please sign in to comment.