pymobiledevice3 4.27.4__py3-none-any.whl → 5.1.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- misc/plist_sniffer.py +15 -15
- misc/remotexpc_sniffer.py +29 -28
- pymobiledevice3/__main__.py +123 -98
- pymobiledevice3/_version.py +2 -2
- pymobiledevice3/bonjour.py +351 -117
- pymobiledevice3/ca.py +32 -24
- pymobiledevice3/cli/activation.py +7 -7
- pymobiledevice3/cli/afc.py +19 -19
- pymobiledevice3/cli/amfi.py +4 -4
- pymobiledevice3/cli/apps.py +51 -39
- pymobiledevice3/cli/backup.py +58 -32
- pymobiledevice3/cli/bonjour.py +27 -20
- pymobiledevice3/cli/cli_common.py +112 -81
- pymobiledevice3/cli/companion_proxy.py +4 -4
- pymobiledevice3/cli/completions.py +10 -10
- pymobiledevice3/cli/crash.py +37 -31
- pymobiledevice3/cli/developer.py +601 -519
- pymobiledevice3/cli/diagnostics.py +38 -33
- pymobiledevice3/cli/lockdown.py +82 -72
- pymobiledevice3/cli/mounter.py +84 -67
- pymobiledevice3/cli/notification.py +10 -10
- pymobiledevice3/cli/pcap.py +19 -14
- pymobiledevice3/cli/power_assertion.py +12 -10
- pymobiledevice3/cli/processes.py +10 -10
- pymobiledevice3/cli/profile.py +88 -77
- pymobiledevice3/cli/provision.py +17 -17
- pymobiledevice3/cli/remote.py +188 -111
- pymobiledevice3/cli/restore.py +43 -40
- pymobiledevice3/cli/springboard.py +30 -28
- pymobiledevice3/cli/syslog.py +85 -58
- pymobiledevice3/cli/usbmux.py +21 -20
- pymobiledevice3/cli/version.py +3 -2
- pymobiledevice3/cli/webinspector.py +156 -78
- pymobiledevice3/common.py +1 -1
- pymobiledevice3/exceptions.py +154 -60
- pymobiledevice3/irecv.py +49 -53
- pymobiledevice3/irecv_devices.py +1489 -492
- pymobiledevice3/lockdown.py +400 -251
- pymobiledevice3/lockdown_service_provider.py +5 -7
- pymobiledevice3/osu/os_utils.py +18 -9
- pymobiledevice3/osu/posix_util.py +28 -15
- pymobiledevice3/osu/win_util.py +14 -8
- pymobiledevice3/pair_records.py +19 -19
- pymobiledevice3/remote/common.py +4 -4
- pymobiledevice3/remote/core_device/app_service.py +94 -67
- pymobiledevice3/remote/core_device/core_device_service.py +17 -14
- pymobiledevice3/remote/core_device/device_info.py +5 -5
- pymobiledevice3/remote/core_device/diagnostics_service.py +10 -8
- pymobiledevice3/remote/core_device/file_service.py +47 -33
- pymobiledevice3/remote/remote_service_discovery.py +53 -35
- pymobiledevice3/remote/remotexpc.py +64 -42
- pymobiledevice3/remote/tunnel_service.py +383 -297
- pymobiledevice3/remote/utils.py +14 -13
- pymobiledevice3/remote/xpc_message.py +145 -125
- pymobiledevice3/resources/dsc_uuid_map.py +19 -19
- pymobiledevice3/resources/firmware_notifications.py +16 -16
- pymobiledevice3/restore/asr.py +27 -27
- pymobiledevice3/restore/base_restore.py +90 -47
- pymobiledevice3/restore/consts.py +87 -66
- pymobiledevice3/restore/device.py +11 -11
- pymobiledevice3/restore/fdr.py +46 -46
- pymobiledevice3/restore/ftab.py +19 -19
- pymobiledevice3/restore/img4.py +130 -133
- pymobiledevice3/restore/mbn.py +587 -0
- pymobiledevice3/restore/recovery.py +125 -135
- pymobiledevice3/restore/restore.py +535 -523
- pymobiledevice3/restore/restore_options.py +122 -115
- pymobiledevice3/restore/restored_client.py +25 -22
- pymobiledevice3/restore/tss.py +378 -270
- pymobiledevice3/service_connection.py +50 -46
- pymobiledevice3/services/accessibilityaudit.py +137 -127
- pymobiledevice3/services/afc.py +352 -292
- pymobiledevice3/services/amfi.py +21 -18
- pymobiledevice3/services/companion.py +23 -19
- pymobiledevice3/services/crash_reports.py +61 -47
- pymobiledevice3/services/debugserver_applist.py +3 -3
- pymobiledevice3/services/device_arbitration.py +8 -8
- pymobiledevice3/services/device_link.py +56 -48
- pymobiledevice3/services/diagnostics.py +971 -968
- pymobiledevice3/services/dtfetchsymbols.py +8 -8
- pymobiledevice3/services/dvt/dvt_secure_socket_proxy.py +4 -4
- pymobiledevice3/services/dvt/dvt_testmanaged_proxy.py +4 -4
- pymobiledevice3/services/dvt/instruments/activity_trace_tap.py +85 -74
- pymobiledevice3/services/dvt/instruments/application_listing.py +2 -3
- pymobiledevice3/services/dvt/instruments/condition_inducer.py +7 -6
- pymobiledevice3/services/dvt/instruments/core_profile_session_tap.py +466 -384
- pymobiledevice3/services/dvt/instruments/device_info.py +11 -11
- pymobiledevice3/services/dvt/instruments/energy_monitor.py +1 -1
- pymobiledevice3/services/dvt/instruments/graphics.py +1 -1
- pymobiledevice3/services/dvt/instruments/location_simulation.py +1 -1
- pymobiledevice3/services/dvt/instruments/location_simulation_base.py +10 -10
- pymobiledevice3/services/dvt/instruments/network_monitor.py +17 -17
- pymobiledevice3/services/dvt/instruments/notifications.py +1 -1
- pymobiledevice3/services/dvt/instruments/process_control.py +25 -10
- pymobiledevice3/services/dvt/instruments/screenshot.py +2 -2
- pymobiledevice3/services/dvt/instruments/sysmontap.py +15 -15
- pymobiledevice3/services/dvt/testmanaged/xcuitest.py +42 -52
- pymobiledevice3/services/file_relay.py +10 -10
- pymobiledevice3/services/heartbeat.py +8 -7
- pymobiledevice3/services/house_arrest.py +12 -15
- pymobiledevice3/services/installation_proxy.py +119 -100
- pymobiledevice3/services/lockdown_service.py +12 -5
- pymobiledevice3/services/misagent.py +22 -19
- pymobiledevice3/services/mobile_activation.py +84 -72
- pymobiledevice3/services/mobile_config.py +331 -301
- pymobiledevice3/services/mobile_image_mounter.py +137 -116
- pymobiledevice3/services/mobilebackup2.py +188 -150
- pymobiledevice3/services/notification_proxy.py +11 -11
- pymobiledevice3/services/os_trace.py +128 -74
- pymobiledevice3/services/pcapd.py +306 -306
- pymobiledevice3/services/power_assertion.py +10 -9
- pymobiledevice3/services/preboard.py +4 -4
- pymobiledevice3/services/remote_fetch_symbols.py +16 -14
- pymobiledevice3/services/remote_server.py +176 -146
- pymobiledevice3/services/restore_service.py +16 -16
- pymobiledevice3/services/screenshot.py +13 -10
- pymobiledevice3/services/simulate_location.py +7 -7
- pymobiledevice3/services/springboard.py +15 -15
- pymobiledevice3/services/syslog.py +5 -5
- pymobiledevice3/services/web_protocol/alert.py +3 -3
- pymobiledevice3/services/web_protocol/automation_session.py +183 -179
- pymobiledevice3/services/web_protocol/cdp_screencast.py +44 -36
- pymobiledevice3/services/web_protocol/cdp_server.py +19 -19
- pymobiledevice3/services/web_protocol/cdp_target.py +411 -373
- pymobiledevice3/services/web_protocol/driver.py +47 -45
- pymobiledevice3/services/web_protocol/element.py +74 -63
- pymobiledevice3/services/web_protocol/inspector_session.py +106 -102
- pymobiledevice3/services/web_protocol/selenium_api.py +3 -3
- pymobiledevice3/services/web_protocol/session_protocol.py +15 -10
- pymobiledevice3/services/web_protocol/switch_to.py +11 -12
- pymobiledevice3/services/webinspector.py +142 -116
- pymobiledevice3/tcp_forwarder.py +35 -22
- pymobiledevice3/tunneld/api.py +20 -15
- pymobiledevice3/tunneld/server.py +310 -193
- pymobiledevice3/usbmux.py +197 -148
- pymobiledevice3/utils.py +14 -11
- {pymobiledevice3-4.27.4.dist-info → pymobiledevice3-5.1.2.dist-info}/METADATA +1 -2
- pymobiledevice3-5.1.2.dist-info/RECORD +173 -0
- pymobiledevice3-4.27.4.dist-info/RECORD +0 -172
- {pymobiledevice3-4.27.4.dist-info → pymobiledevice3-5.1.2.dist-info}/WHEEL +0 -0
- {pymobiledevice3-4.27.4.dist-info → pymobiledevice3-5.1.2.dist-info}/entry_points.txt +0 -0
- {pymobiledevice3-4.27.4.dist-info → pymobiledevice3-5.1.2.dist-info}/licenses/LICENSE +0 -0
- {pymobiledevice3-4.27.4.dist-info → pymobiledevice3-5.1.2.dist-info}/top_level.txt +0 -0
|
@@ -8,9 +8,18 @@ from developer_disk_image.repo import DeveloperDiskImageRepository
|
|
|
8
8
|
from packaging.version import Version
|
|
9
9
|
|
|
10
10
|
from pymobiledevice3.common import get_home_folder
|
|
11
|
-
from pymobiledevice3.exceptions import
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
from pymobiledevice3.exceptions import (
|
|
12
|
+
AlreadyMountedError,
|
|
13
|
+
DeveloperDiskImageNotFoundError,
|
|
14
|
+
DeveloperModeIsNotEnabledError,
|
|
15
|
+
InternalError,
|
|
16
|
+
MessageNotSupportedError,
|
|
17
|
+
MissingManifestError,
|
|
18
|
+
NoSuchBuildIdentityError,
|
|
19
|
+
NotMountedError,
|
|
20
|
+
PyMobileDevice3Exception,
|
|
21
|
+
UnsupportedCommandError,
|
|
22
|
+
)
|
|
14
23
|
from pymobiledevice3.lockdown import LockdownClient
|
|
15
24
|
from pymobiledevice3.lockdown_service_provider import LockdownServiceProvider
|
|
16
25
|
from pymobiledevice3.restore.tss import TSSRequest
|
|
@@ -18,13 +27,13 @@ from pymobiledevice3.services.lockdown_service import LockdownService
|
|
|
18
27
|
|
|
19
28
|
logger = logging.getLogger(__name__)
|
|
20
29
|
|
|
21
|
-
LATEST_DDI_BUILD_ID =
|
|
30
|
+
LATEST_DDI_BUILD_ID = "17B5045g"
|
|
22
31
|
|
|
23
32
|
|
|
24
33
|
class MobileImageMounterService(LockdownService):
|
|
25
34
|
# implemented in /usr/libexec/mobile_storage_proxy
|
|
26
|
-
SERVICE_NAME =
|
|
27
|
-
RSD_SERVICE_NAME =
|
|
35
|
+
SERVICE_NAME = "com.apple.mobile.mobile_image_mounter"
|
|
36
|
+
RSD_SERVICE_NAME = "com.apple.mobile.mobile_image_mounter.shim.remote"
|
|
28
37
|
IMAGE_TYPE: Optional[str] = None
|
|
29
38
|
|
|
30
39
|
def __init__(self, lockdown: LockdownServiceProvider):
|
|
@@ -40,21 +49,20 @@ class MobileImageMounterService(LockdownService):
|
|
|
40
49
|
raise DeveloperModeIsNotEnabledError()
|
|
41
50
|
|
|
42
51
|
def copy_devices(self) -> list[dict]:
|
|
43
|
-
"""
|
|
52
|
+
"""Copy mounted devices list."""
|
|
44
53
|
try:
|
|
45
|
-
return self.service.send_recv_plist({
|
|
54
|
+
return self.service.send_recv_plist({"Command": "CopyDevices"})["EntryList"]
|
|
46
55
|
except KeyError as e:
|
|
47
56
|
raise MessageNotSupportedError from e
|
|
48
57
|
|
|
49
58
|
def lookup_image(self, image_type: str) -> bytes:
|
|
50
|
-
"""
|
|
51
|
-
response = self.service.send_recv_plist({
|
|
52
|
-
'ImageType': image_type})
|
|
59
|
+
"""Lookup mounted image by its name."""
|
|
60
|
+
response = self.service.send_recv_plist({"Command": "LookupImage", "ImageType": image_type})
|
|
53
61
|
|
|
54
|
-
if not response or not response.get(
|
|
62
|
+
if not response or not response.get("ImagePresent", True):
|
|
55
63
|
raise NotMountedError()
|
|
56
64
|
|
|
57
|
-
signature = response.get(
|
|
65
|
+
signature = response.get("ImageSignature", [])
|
|
58
66
|
if isinstance(signature, list):
|
|
59
67
|
if not signature:
|
|
60
68
|
raise NotMountedError()
|
|
@@ -64,125 +72,128 @@ class MobileImageMounterService(LockdownService):
|
|
|
64
72
|
def is_image_mounted(self, image_type: str) -> bool:
|
|
65
73
|
try:
|
|
66
74
|
self.lookup_image(image_type)
|
|
67
|
-
return True
|
|
68
75
|
except NotMountedError:
|
|
69
76
|
return False
|
|
77
|
+
return True
|
|
70
78
|
|
|
71
79
|
def unmount_image(self, mount_path: str) -> None:
|
|
72
|
-
"""
|
|
73
|
-
request = {
|
|
80
|
+
"""umount image (Added on iOS 14.0)"""
|
|
81
|
+
request = {"Command": "UnmountImage", "MountPath": mount_path}
|
|
74
82
|
response = self.service.send_recv_plist(request)
|
|
75
83
|
|
|
76
|
-
error = response.get(
|
|
84
|
+
error = response.get("Error")
|
|
77
85
|
if error:
|
|
78
|
-
if error ==
|
|
86
|
+
if error == "UnknownCommand":
|
|
79
87
|
raise UnsupportedCommandError()
|
|
80
|
-
elif
|
|
88
|
+
elif "There is no matching entry" in response.get("DetailedError", ""):
|
|
81
89
|
raise NotMountedError(response)
|
|
82
|
-
elif error ==
|
|
90
|
+
elif error == "InternalError":
|
|
83
91
|
raise InternalError(response)
|
|
84
92
|
else:
|
|
85
93
|
raise PyMobileDevice3Exception(response)
|
|
86
94
|
|
|
87
95
|
def mount_image(self, image_type: str, signature: bytes, extras: Optional[dict] = None) -> None:
|
|
88
|
-
"""
|
|
96
|
+
"""Upload image into device."""
|
|
89
97
|
|
|
90
98
|
if self.is_image_mounted(image_type):
|
|
91
99
|
raise AlreadyMountedError()
|
|
92
100
|
|
|
93
|
-
request = {
|
|
94
|
-
'ImageType': image_type,
|
|
95
|
-
'ImageSignature': signature}
|
|
101
|
+
request = {"Command": "MountImage", "ImageType": image_type, "ImageSignature": signature}
|
|
96
102
|
|
|
97
103
|
if extras is not None:
|
|
98
104
|
request.update(extras)
|
|
99
105
|
response = self.service.send_recv_plist(request)
|
|
100
106
|
|
|
101
|
-
if
|
|
107
|
+
if "Developer mode is not enabled" in response.get("DetailedError", ""):
|
|
102
108
|
raise DeveloperModeIsNotEnabledError()
|
|
103
109
|
|
|
104
|
-
status = response.get(
|
|
110
|
+
status = response.get("Status")
|
|
105
111
|
|
|
106
|
-
if status !=
|
|
107
|
-
raise PyMobileDevice3Exception(f
|
|
112
|
+
if status != "Complete":
|
|
113
|
+
raise PyMobileDevice3Exception(f"command MountImage failed with: {response}")
|
|
108
114
|
|
|
109
115
|
def upload_image(self, image_type: str, image: bytes, signature: bytes) -> None:
|
|
110
|
-
"""
|
|
111
|
-
self.service.send_plist({
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
116
|
+
"""Upload image into device."""
|
|
117
|
+
self.service.send_plist({
|
|
118
|
+
"Command": "ReceiveBytes",
|
|
119
|
+
"ImageType": image_type,
|
|
120
|
+
"ImageSize": len(image),
|
|
121
|
+
"ImageSignature": signature,
|
|
122
|
+
})
|
|
115
123
|
result = self.service.recv_plist()
|
|
116
124
|
|
|
117
|
-
status = result.get(
|
|
125
|
+
status = result.get("Status")
|
|
118
126
|
|
|
119
|
-
if status !=
|
|
120
|
-
raise PyMobileDevice3Exception(f
|
|
127
|
+
if status != "ReceiveBytesAck":
|
|
128
|
+
raise PyMobileDevice3Exception(f"command ReceiveBytes failed with: {result}")
|
|
121
129
|
|
|
122
130
|
self.service.sendall(image)
|
|
123
131
|
result = self.service.recv_plist()
|
|
124
132
|
|
|
125
|
-
status = result.get(
|
|
133
|
+
status = result.get("Status")
|
|
126
134
|
|
|
127
|
-
if status !=
|
|
128
|
-
raise PyMobileDevice3Exception(f
|
|
135
|
+
if status != "Complete":
|
|
136
|
+
raise PyMobileDevice3Exception(f"command ReceiveBytes failed to send bytes with: {result}")
|
|
129
137
|
|
|
130
138
|
def query_developer_mode_status(self) -> bool:
|
|
131
|
-
response = self.service.send_recv_plist({
|
|
139
|
+
response = self.service.send_recv_plist({"Command": "QueryDeveloperModeStatus"})
|
|
132
140
|
|
|
133
141
|
try:
|
|
134
|
-
return response[
|
|
142
|
+
return response["DeveloperModeStatus"]
|
|
135
143
|
except KeyError as e:
|
|
136
144
|
raise MessageNotSupportedError from e
|
|
137
145
|
|
|
138
146
|
def query_nonce(self, personalized_image_type: Optional[str] = None) -> bytes:
|
|
139
|
-
request = {
|
|
147
|
+
request = {"Command": "QueryNonce"}
|
|
140
148
|
if personalized_image_type is not None:
|
|
141
|
-
request[
|
|
149
|
+
request["PersonalizedImageType"] = personalized_image_type
|
|
142
150
|
response = self.service.send_recv_plist(request)
|
|
143
151
|
try:
|
|
144
|
-
return response[
|
|
152
|
+
return response["PersonalizationNonce"]
|
|
145
153
|
except KeyError as e:
|
|
146
154
|
raise MessageNotSupportedError from e
|
|
147
155
|
|
|
148
156
|
def query_personalization_identifiers(self, image_type: Optional[str] = None) -> dict:
|
|
149
|
-
request = {
|
|
157
|
+
request = {"Command": "QueryPersonalizationIdentifiers"}
|
|
150
158
|
|
|
151
159
|
if image_type is not None:
|
|
152
|
-
request[
|
|
160
|
+
request["PersonalizedImageType"] = image_type
|
|
153
161
|
|
|
154
162
|
response = self.service.send_recv_plist(request)
|
|
155
163
|
|
|
156
164
|
try:
|
|
157
|
-
return response[
|
|
165
|
+
return response["PersonalizationIdentifiers"]
|
|
158
166
|
except KeyError as e:
|
|
159
167
|
raise MessageNotSupportedError from e
|
|
160
168
|
|
|
161
169
|
def query_personalization_manifest(self, image_type: str, signature: bytes) -> bytes:
|
|
162
170
|
response = self.service.send_recv_plist({
|
|
163
|
-
|
|
164
|
-
|
|
171
|
+
"Command": "QueryPersonalizationManifest",
|
|
172
|
+
"PersonalizedImageType": image_type,
|
|
173
|
+
"ImageType": image_type,
|
|
174
|
+
"ImageSignature": signature,
|
|
175
|
+
})
|
|
165
176
|
try:
|
|
166
177
|
# The response "ImageSignature" is actually an IM4M
|
|
167
|
-
return response[
|
|
168
|
-
except KeyError:
|
|
169
|
-
raise MissingManifestError()
|
|
178
|
+
return response["ImageSignature"]
|
|
179
|
+
except KeyError as e:
|
|
180
|
+
raise MissingManifestError() from e
|
|
170
181
|
|
|
171
182
|
def roll_personalization_nonce(self) -> None:
|
|
172
183
|
try:
|
|
173
|
-
self.service.send_recv_plist({
|
|
184
|
+
self.service.send_recv_plist({"Command": "RollPersonalizationNonce"})
|
|
174
185
|
except ConnectionAbortedError:
|
|
175
186
|
return
|
|
176
187
|
|
|
177
188
|
def roll_cryptex_nonce(self) -> None:
|
|
178
189
|
try:
|
|
179
|
-
self.service.send_recv_plist({
|
|
190
|
+
self.service.send_recv_plist({"Command": "RollCryptexNonce"})
|
|
180
191
|
except ConnectionAbortedError:
|
|
181
192
|
return
|
|
182
193
|
|
|
183
194
|
|
|
184
195
|
class DeveloperDiskImageMounter(MobileImageMounterService):
|
|
185
|
-
IMAGE_TYPE =
|
|
196
|
+
IMAGE_TYPE = "Developer"
|
|
186
197
|
|
|
187
198
|
def mount(self, image: Path, signature: Path) -> None:
|
|
188
199
|
self.raise_if_cannot_mount()
|
|
@@ -193,14 +204,15 @@ class DeveloperDiskImageMounter(MobileImageMounterService):
|
|
|
193
204
|
self.mount_image(self.IMAGE_TYPE, signature)
|
|
194
205
|
|
|
195
206
|
def umount(self) -> None:
|
|
196
|
-
self.unmount_image(
|
|
207
|
+
self.unmount_image("/Developer")
|
|
197
208
|
|
|
198
209
|
|
|
199
210
|
class PersonalizedImageMounter(MobileImageMounterService):
|
|
200
|
-
IMAGE_TYPE =
|
|
211
|
+
IMAGE_TYPE = "Personalized"
|
|
201
212
|
|
|
202
|
-
async def mount(
|
|
203
|
-
|
|
213
|
+
async def mount(
|
|
214
|
+
self, image: Path, build_manifest: Path, trust_cache: Path, info_plist: Optional[dict] = None
|
|
215
|
+
) -> None:
|
|
204
216
|
self.raise_if_cannot_mount()
|
|
205
217
|
|
|
206
218
|
image = image.read_bytes()
|
|
@@ -210,7 +222,7 @@ class PersonalizedImageMounter(MobileImageMounterService):
|
|
|
210
222
|
# in case of failure, the service will close the socket, so we'll have to reestablish the connection
|
|
211
223
|
# and query the manifest from Apple's ticket server instead
|
|
212
224
|
try:
|
|
213
|
-
manifest = self.query_personalization_manifest(
|
|
225
|
+
manifest = self.query_personalization_manifest("DeveloperDiskImage", hashlib.sha384(image).digest())
|
|
214
226
|
except MissingManifestError:
|
|
215
227
|
self.service = self.lockdown.start_lockdown_service(self.service_name)
|
|
216
228
|
manifest = await self.get_manifest_from_tss(plistlib.loads(build_manifest.read_bytes()))
|
|
@@ -219,107 +231,110 @@ class PersonalizedImageMounter(MobileImageMounterService):
|
|
|
219
231
|
|
|
220
232
|
extras = {}
|
|
221
233
|
if info_plist is not None:
|
|
222
|
-
extras[
|
|
223
|
-
extras[
|
|
234
|
+
extras["ImageInfoPlist"] = info_plist
|
|
235
|
+
extras["ImageTrustCache"] = trust_cache
|
|
224
236
|
self.mount_image(self.IMAGE_TYPE, manifest, extras=extras)
|
|
225
237
|
|
|
226
238
|
def umount(self) -> None:
|
|
227
|
-
self.unmount_image(
|
|
239
|
+
self.unmount_image("/System/Developer")
|
|
228
240
|
|
|
229
241
|
async def get_manifest_from_tss(self, build_manifest: dict) -> bytes:
|
|
230
242
|
request = TSSRequest()
|
|
231
243
|
|
|
232
244
|
personalization_identifiers = self.query_personalization_identifiers()
|
|
233
245
|
for key, value in personalization_identifiers.items():
|
|
234
|
-
if key.startswith(
|
|
246
|
+
if key.startswith("Ap,"):
|
|
235
247
|
request.update({key: value})
|
|
236
248
|
|
|
237
|
-
board_id = personalization_identifiers[
|
|
238
|
-
chip_id = personalization_identifiers[
|
|
249
|
+
board_id = personalization_identifiers["BoardId"]
|
|
250
|
+
chip_id = personalization_identifiers["ChipID"]
|
|
239
251
|
|
|
240
252
|
build_identity = None
|
|
241
|
-
for tmp_build_identity in build_manifest[
|
|
242
|
-
if
|
|
243
|
-
|
|
253
|
+
for tmp_build_identity in build_manifest["BuildIdentities"]:
|
|
254
|
+
if (
|
|
255
|
+
int(tmp_build_identity["ApBoardID"], 0) == board_id
|
|
256
|
+
and int(tmp_build_identity["ApChipID"], 0) == chip_id
|
|
257
|
+
):
|
|
244
258
|
build_identity = tmp_build_identity
|
|
245
259
|
break
|
|
246
260
|
else:
|
|
247
|
-
raise NoSuchBuildIdentityError(f
|
|
248
|
-
manifest = build_identity[
|
|
261
|
+
raise NoSuchBuildIdentityError(f"Could not find the manifest for board {board_id} and chip {chip_id}")
|
|
262
|
+
manifest = build_identity["Manifest"]
|
|
249
263
|
|
|
250
264
|
parameters = {
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
265
|
+
"ApProductionMode": True,
|
|
266
|
+
"ApSecurityDomain": 1,
|
|
267
|
+
"ApSecurityMode": True,
|
|
268
|
+
"ApSupportsImg4": True,
|
|
255
269
|
}
|
|
256
270
|
|
|
257
271
|
request.update({
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
272
|
+
"@ApImg4Ticket": True,
|
|
273
|
+
"@BBTicket": True,
|
|
274
|
+
"ApBoardID": board_id,
|
|
275
|
+
"ApChipID": chip_id,
|
|
276
|
+
"ApECID": self.lockdown.ecid,
|
|
277
|
+
"ApNonce": self.query_nonce("DeveloperDiskImage"),
|
|
278
|
+
"ApProductionMode": True,
|
|
279
|
+
"ApSecurityDomain": 1,
|
|
280
|
+
"ApSecurityMode": True,
|
|
281
|
+
"SepNonce": b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
|
|
282
|
+
"UID_MODE": False,
|
|
269
283
|
})
|
|
270
284
|
|
|
271
285
|
for key, manifest_entry in manifest.items():
|
|
272
|
-
info_dict = manifest_entry.get(
|
|
286
|
+
info_dict = manifest_entry.get("Info")
|
|
273
287
|
if info_dict is None:
|
|
274
288
|
continue
|
|
275
289
|
|
|
276
|
-
if not manifest_entry.get(
|
|
277
|
-
self.logger.debug(f
|
|
290
|
+
if not manifest_entry.get("Trusted", False):
|
|
291
|
+
self.logger.debug(f"skipping {key} as it is not trusted")
|
|
278
292
|
continue
|
|
279
293
|
|
|
280
294
|
# copy this entry
|
|
281
295
|
tss_entry = dict(manifest_entry)
|
|
282
296
|
|
|
283
297
|
# remove obsolete Info node
|
|
284
|
-
tss_entry.pop(
|
|
298
|
+
tss_entry.pop("Info")
|
|
285
299
|
|
|
286
300
|
# handle RestoreRequestRules
|
|
287
|
-
if
|
|
288
|
-
rules = manifest[
|
|
301
|
+
if "RestoreRequestRules" in manifest["LoadableTrustCache"]["Info"]:
|
|
302
|
+
rules = manifest["LoadableTrustCache"]["Info"]["RestoreRequestRules"]
|
|
289
303
|
if rules:
|
|
290
|
-
self.logger.debug(f
|
|
304
|
+
self.logger.debug(f"Applying restore request rules for entry {key}")
|
|
291
305
|
tss_entry = request.apply_restore_request_rules(tss_entry, parameters, rules)
|
|
292
306
|
|
|
293
307
|
# Make sure we have a Digest key for Trusted items even if empty
|
|
294
|
-
if manifest_entry.get(
|
|
295
|
-
tss_entry[
|
|
308
|
+
if manifest_entry.get("Digest") is None:
|
|
309
|
+
tss_entry["Digest"] = b""
|
|
296
310
|
|
|
297
311
|
request.update({key: tss_entry})
|
|
298
312
|
|
|
299
313
|
response = await request.send_receive()
|
|
300
|
-
return response[
|
|
314
|
+
return response["ApImg4Ticket"]
|
|
301
315
|
|
|
302
316
|
|
|
303
317
|
def auto_mount_developer(
|
|
304
|
-
|
|
305
|
-
|
|
318
|
+
lockdown: LockdownServiceProvider, xcode: Optional[str] = None, version: Optional[str] = None
|
|
319
|
+
) -> None:
|
|
320
|
+
"""auto-detect correct DeveloperDiskImage and mount it"""
|
|
306
321
|
if xcode is None:
|
|
307
322
|
# avoid "default"-ing this option, because Windows and Linux won't have this path
|
|
308
|
-
xcode = Path(
|
|
323
|
+
xcode = Path("/Applications/Xcode.app")
|
|
309
324
|
if not (xcode.exists()):
|
|
310
|
-
xcode = get_home_folder() /
|
|
325
|
+
xcode = get_home_folder() / "Xcode.app"
|
|
311
326
|
xcode.mkdir(parents=True, exist_ok=True)
|
|
312
327
|
|
|
313
328
|
image_mounter = DeveloperDiskImageMounter(lockdown=lockdown)
|
|
314
|
-
if image_mounter.is_image_mounted(
|
|
329
|
+
if image_mounter.is_image_mounted("Developer"):
|
|
315
330
|
raise AlreadyMountedError()
|
|
316
331
|
|
|
317
332
|
if version is None:
|
|
318
333
|
version = Version(lockdown.product_version)
|
|
319
|
-
version = f
|
|
320
|
-
image_dir = f
|
|
321
|
-
image_path = f
|
|
322
|
-
signature = f
|
|
334
|
+
version = f"{version.major}.{version.minor}"
|
|
335
|
+
image_dir = f"{xcode}/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport/{version}"
|
|
336
|
+
image_path = f"{image_dir}/DeveloperDiskImage.dmg"
|
|
337
|
+
signature = f"{image_path}.signature"
|
|
323
338
|
developer_disk_image_dir = Path(image_path).parent
|
|
324
339
|
|
|
325
340
|
image_path = Path(image_path)
|
|
@@ -342,15 +357,17 @@ def auto_mount_developer(
|
|
|
342
357
|
|
|
343
358
|
|
|
344
359
|
async def auto_mount_personalized(lockdown: LockdownServiceProvider) -> None:
|
|
345
|
-
local_path = get_home_folder() /
|
|
360
|
+
local_path = get_home_folder() / "Xcode_iOS_DDI_Personalized"
|
|
346
361
|
local_path.mkdir(parents=True, exist_ok=True)
|
|
347
362
|
|
|
348
|
-
image = local_path /
|
|
349
|
-
build_manifest = local_path /
|
|
350
|
-
trustcache = local_path /
|
|
363
|
+
image = local_path / "Image.dmg"
|
|
364
|
+
build_manifest = local_path / "BuildManifest.plist"
|
|
365
|
+
trustcache = local_path / "Image.trustcache"
|
|
351
366
|
|
|
352
|
-
if (
|
|
353
|
-
|
|
367
|
+
if (
|
|
368
|
+
not build_manifest.exists()
|
|
369
|
+
or plistlib.loads(build_manifest.read_bytes()).get("ProductBuildVersion") != LATEST_DDI_BUILD_ID
|
|
370
|
+
):
|
|
354
371
|
# download the Personalized image from our repository
|
|
355
372
|
repo = DeveloperDiskImageRepository.create()
|
|
356
373
|
personalized_image = repo.get_personalized_disk_image()
|
|
@@ -358,16 +375,20 @@ async def auto_mount_personalized(lockdown: LockdownServiceProvider) -> None:
|
|
|
358
375
|
image.write_bytes(personalized_image.image)
|
|
359
376
|
build_manifest.write_bytes(personalized_image.build_manifest)
|
|
360
377
|
trustcache.write_bytes(personalized_image.trustcache)
|
|
361
|
-
downloaded_ddi_build_id = plistlib.loads(personalized_image.build_manifest).get(
|
|
378
|
+
downloaded_ddi_build_id = plistlib.loads(personalized_image.build_manifest).get("ProductBuildVersion")
|
|
362
379
|
if downloaded_ddi_build_id != LATEST_DDI_BUILD_ID:
|
|
363
|
-
logger.warning(
|
|
364
|
-
|
|
380
|
+
logger.warning(
|
|
381
|
+
"Downloaded personalized image has unexpected ProductBuildVersion "
|
|
382
|
+
f"{downloaded_ddi_build_id}. Please update pymobiledevice3!"
|
|
383
|
+
)
|
|
365
384
|
|
|
366
385
|
await PersonalizedImageMounter(lockdown=lockdown).mount(image, build_manifest, trustcache)
|
|
367
386
|
|
|
368
387
|
|
|
369
|
-
async def auto_mount(
|
|
370
|
-
|
|
388
|
+
async def auto_mount(
|
|
389
|
+
lockdown: LockdownServiceProvider, xcode: Optional[str] = None, version: Optional[str] = None
|
|
390
|
+
) -> None:
|
|
391
|
+
if Version(lockdown.product_version) < Version("17.0"):
|
|
371
392
|
auto_mount_developer(lockdown, xcode=xcode, version=version)
|
|
372
393
|
else:
|
|
373
394
|
await auto_mount_personalized(lockdown)
|