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
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import contextlib
|
|
1
2
|
import hashlib
|
|
2
3
|
import logging
|
|
3
4
|
import time
|
|
@@ -14,9 +15,9 @@ from pymobiledevice3.restore.consts import lpol_file
|
|
|
14
15
|
from pymobiledevice3.restore.device import Device
|
|
15
16
|
from pymobiledevice3.restore.tss import TSSRequest, TSSResponse
|
|
16
17
|
|
|
17
|
-
RESTORE_VARIANT_ERASE_INSTALL =
|
|
18
|
-
RESTORE_VARIANT_UPGRADE_INSTALL =
|
|
19
|
-
RESTORE_VARIANT_MACOS_RECOVERY_OS =
|
|
18
|
+
RESTORE_VARIANT_ERASE_INSTALL = "Erase Install (IPSW)"
|
|
19
|
+
RESTORE_VARIANT_UPGRADE_INSTALL = "Upgrade Install (IPSW)"
|
|
20
|
+
RESTORE_VARIANT_MACOS_RECOVERY_OS = "macOS Customer"
|
|
20
21
|
|
|
21
22
|
|
|
22
23
|
class Recovery(BaseRestore):
|
|
@@ -27,21 +28,21 @@ class Recovery(BaseRestore):
|
|
|
27
28
|
self.restore_boot_args = None
|
|
28
29
|
|
|
29
30
|
def reconnect_irecv(self, is_recovery=None):
|
|
30
|
-
self.logger.debug(
|
|
31
|
+
self.logger.debug("waiting for device to reconnect...")
|
|
31
32
|
self.device.irecv = IRecv(ecid=self.device.ecid, is_recovery=is_recovery)
|
|
32
|
-
self.logger.debug(f
|
|
33
|
+
self.logger.debug(f"connected mode: {self.device.irecv.mode}")
|
|
33
34
|
|
|
34
35
|
def get_preboard_manifest(self):
|
|
35
36
|
overrides = {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
"@APTicket": True,
|
|
38
|
+
"ApProductionMode": 0,
|
|
39
|
+
"ApSecurityDomain": 0,
|
|
39
40
|
}
|
|
40
41
|
|
|
41
42
|
parameters = {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
"ApProductionMode": False,
|
|
44
|
+
"ApSecurityMode": False,
|
|
45
|
+
"ApSupportsImg4": True,
|
|
45
46
|
}
|
|
46
47
|
|
|
47
48
|
self.populate_tss_request_from_manifest(parameters)
|
|
@@ -49,7 +50,7 @@ class Recovery(BaseRestore):
|
|
|
49
50
|
tss = TSSRequest()
|
|
50
51
|
tss.add_common_tags(parameters, overrides)
|
|
51
52
|
|
|
52
|
-
parameters[
|
|
53
|
+
parameters["_OnlyFWComponents"] = True
|
|
53
54
|
|
|
54
55
|
tss.add_ap_tags(parameters)
|
|
55
56
|
|
|
@@ -57,22 +58,22 @@ class Recovery(BaseRestore):
|
|
|
57
58
|
|
|
58
59
|
async def get_tss_response(self) -> TSSResponse:
|
|
59
60
|
# populate parameters
|
|
60
|
-
parameters =
|
|
61
|
+
parameters = {}
|
|
61
62
|
|
|
62
|
-
parameters[
|
|
63
|
+
parameters["ApECID"] = self.device.ecid
|
|
63
64
|
if self.device.ap_nonce is not None:
|
|
64
|
-
parameters[
|
|
65
|
+
parameters["ApNonce"] = self.device.ap_nonce
|
|
65
66
|
|
|
66
67
|
if self.device.sep_nonce is not None:
|
|
67
|
-
parameters[
|
|
68
|
+
parameters["ApSepNonce"] = self.device.sep_nonce
|
|
68
69
|
|
|
69
|
-
parameters[
|
|
70
|
+
parameters["ApProductionMode"] = True
|
|
70
71
|
|
|
71
72
|
if self.device.is_image4_supported:
|
|
72
|
-
parameters[
|
|
73
|
-
parameters[
|
|
73
|
+
parameters["ApSecurityMode"] = True
|
|
74
|
+
parameters["ApSupportsImg4"] = True
|
|
74
75
|
else:
|
|
75
|
-
parameters[
|
|
76
|
+
parameters["ApSupportsImg4"] = False
|
|
76
77
|
|
|
77
78
|
self.populate_tss_request_from_manifest(parameters)
|
|
78
79
|
|
|
@@ -95,48 +96,48 @@ class Recovery(BaseRestore):
|
|
|
95
96
|
if self.device.lockdown is not None:
|
|
96
97
|
pinfo = self.device.firmware_preflight_info
|
|
97
98
|
if pinfo:
|
|
98
|
-
self.logger.debug(
|
|
99
|
+
self.logger.debug("adding firmware preflight info")
|
|
99
100
|
|
|
100
|
-
node = pinfo.get(
|
|
101
|
+
node = pinfo.get("Nonce")
|
|
101
102
|
if node is not None:
|
|
102
|
-
parameters[
|
|
103
|
+
parameters["BbNonce"] = node
|
|
103
104
|
|
|
104
|
-
node = pinfo.get(
|
|
105
|
+
node = pinfo.get("ChipID")
|
|
105
106
|
if node is not None:
|
|
106
|
-
parameters[
|
|
107
|
+
parameters["BbChipID"] = node
|
|
107
108
|
|
|
108
|
-
node = pinfo.get(
|
|
109
|
+
node = pinfo.get("CertID")
|
|
109
110
|
if node is not None:
|
|
110
|
-
parameters[
|
|
111
|
+
parameters["BbGoldCertId"] = node
|
|
111
112
|
|
|
112
|
-
node = pinfo.get(
|
|
113
|
+
node = pinfo.get("ChipSerialNo")
|
|
113
114
|
if node is not None:
|
|
114
|
-
parameters[
|
|
115
|
+
parameters["BbSNUM"] = node
|
|
115
116
|
|
|
116
117
|
# add baseband parameters
|
|
117
118
|
tss.add_baseband_tags(parameters)
|
|
118
119
|
|
|
119
|
-
euiccchipid = pinfo.get(
|
|
120
|
+
euiccchipid = pinfo.get("EUICCChipID")
|
|
120
121
|
if euiccchipid:
|
|
121
|
-
self.logger.debug(
|
|
122
|
-
parameters[
|
|
122
|
+
self.logger.debug("adding EUICCChipID info")
|
|
123
|
+
parameters["eUICC,ChipID"] = euiccchipid
|
|
123
124
|
|
|
124
125
|
if euiccchipid >= 5:
|
|
125
|
-
node = pinfo.get(
|
|
126
|
+
node = pinfo.get("EUICCCSN")
|
|
126
127
|
if node is not None:
|
|
127
|
-
parameters[
|
|
128
|
+
parameters["eUICC,EID"] = node
|
|
128
129
|
|
|
129
|
-
node = pinfo.get(
|
|
130
|
+
node = pinfo.get("EUICCCertIdentifier")
|
|
130
131
|
if node is not None:
|
|
131
|
-
parameters[
|
|
132
|
+
parameters["eUICC,RootKeyIdentifier"] = node
|
|
132
133
|
|
|
133
|
-
node = pinfo.get(
|
|
134
|
+
node = pinfo.get("EUICCGoldNonce")
|
|
134
135
|
if node is not None:
|
|
135
|
-
parameters[
|
|
136
|
+
parameters["EUICCGoldNonce"] = node
|
|
136
137
|
|
|
137
|
-
node = pinfo.get(
|
|
138
|
+
node = pinfo.get("EUICCMainNonce")
|
|
138
139
|
if node is not None:
|
|
139
|
-
parameters[
|
|
140
|
+
parameters["EUICCMainNonce"] = node
|
|
140
141
|
|
|
141
142
|
tss.add_vinyl_tags(parameters)
|
|
142
143
|
|
|
@@ -146,40 +147,40 @@ class Recovery(BaseRestore):
|
|
|
146
147
|
def get_local_policy_tss_response(self):
|
|
147
148
|
# populate parameters
|
|
148
149
|
parameters = {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
150
|
+
"ApECID": self.device.ecid,
|
|
151
|
+
"Ap,LocalBoot": False,
|
|
152
|
+
"ApProductionMode": True,
|
|
152
153
|
}
|
|
153
154
|
|
|
154
155
|
if self.device.ap_nonce:
|
|
155
|
-
parameters[
|
|
156
|
+
parameters["ApNonce"] = self.device.ap_nonce
|
|
156
157
|
|
|
157
158
|
sep_nonce = self.device.sep_nonce
|
|
158
159
|
|
|
159
160
|
if sep_nonce:
|
|
160
|
-
parameters[
|
|
161
|
+
parameters["ApSepNonce"] = sep_nonce
|
|
161
162
|
|
|
162
163
|
if self.device.is_image4_supported:
|
|
163
|
-
parameters[
|
|
164
|
-
parameters[
|
|
164
|
+
parameters["ApSecurityMode"] = True
|
|
165
|
+
parameters["ApSupportsImg4"] = True
|
|
165
166
|
else:
|
|
166
|
-
parameters[
|
|
167
|
+
parameters["ApSupportsImg4"] = False
|
|
167
168
|
|
|
168
169
|
self.populate_tss_request_from_manifest(parameters)
|
|
169
170
|
|
|
170
171
|
# Add Ap,LocalPolicy
|
|
171
172
|
lpol = {
|
|
172
|
-
|
|
173
|
-
|
|
173
|
+
"Digest": hashlib.sha384(lpol_file).digest(),
|
|
174
|
+
"Trusted": True,
|
|
174
175
|
}
|
|
175
176
|
|
|
176
|
-
parameters[
|
|
177
|
+
parameters["Ap,LocalPolicy"] = lpol
|
|
177
178
|
|
|
178
179
|
# Add Ap,NextStageIM4MHash
|
|
179
180
|
# Get previous TSS ticket
|
|
180
181
|
ticket = self.tss.ap_img4_ticket
|
|
181
182
|
# Hash it and add it as Ap,NextStageIM4MHash
|
|
182
|
-
parameters[
|
|
183
|
+
parameters["Ap,NextStageIM4MHash"] = hashlib.sha384(ticket).digest()
|
|
183
184
|
|
|
184
185
|
# create basic request
|
|
185
186
|
request = TSSRequest()
|
|
@@ -192,24 +193,24 @@ class Recovery(BaseRestore):
|
|
|
192
193
|
def get_recoveryos_root_ticket_tss_response(self):
|
|
193
194
|
# populate parameters
|
|
194
195
|
parameters = {
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
196
|
+
"ApECID": self.device.ecid,
|
|
197
|
+
"Ap,LocalBoot": False,
|
|
198
|
+
"ApProductionMode": True,
|
|
198
199
|
}
|
|
199
200
|
|
|
200
201
|
if self.device.ap_nonce:
|
|
201
|
-
parameters[
|
|
202
|
+
parameters["ApNonce"] = self.device.ap_nonce
|
|
202
203
|
|
|
203
204
|
sep_nonce = self.device.sep_nonce
|
|
204
205
|
|
|
205
206
|
if sep_nonce:
|
|
206
|
-
parameters[
|
|
207
|
+
parameters["ApSepNonce"] = sep_nonce
|
|
207
208
|
|
|
208
209
|
if self.device.is_image4_supported:
|
|
209
|
-
parameters[
|
|
210
|
-
parameters[
|
|
210
|
+
parameters["ApSecurityMode"] = True
|
|
211
|
+
parameters["ApSupportsImg4"] = True
|
|
211
212
|
else:
|
|
212
|
-
parameters[
|
|
213
|
+
parameters["ApSupportsImg4"] = False
|
|
213
214
|
|
|
214
215
|
self.populate_tss_request_from_manifest(parameters)
|
|
215
216
|
|
|
@@ -231,10 +232,9 @@ class Recovery(BaseRestore):
|
|
|
231
232
|
return request.send_receive()
|
|
232
233
|
|
|
233
234
|
async def fetch_tss_record(self) -> TSSResponse:
|
|
234
|
-
if self.ipsw.build_manifest.build_major > 8:
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
self.logger.info('NOTE: Unable to get nonce from device')
|
|
235
|
+
if self.ipsw.build_manifest.build_major > 8 and self.device.ap_nonce is None:
|
|
236
|
+
# the first nonce request with older firmware releases can fail, and it's OK
|
|
237
|
+
self.logger.info("NOTE: Unable to get nonce from device")
|
|
238
238
|
|
|
239
239
|
self.tss = await self.get_tss_response()
|
|
240
240
|
|
|
@@ -242,7 +242,7 @@ class Recovery(BaseRestore):
|
|
|
242
242
|
self.tss_localpolicy = self.get_local_policy_tss_response()
|
|
243
243
|
self.tss_recoveryos_root_ticket = self.get_recoveryos_root_ticket_tss_response()
|
|
244
244
|
else:
|
|
245
|
-
recovery_variant = self.build_identity[
|
|
245
|
+
recovery_variant = self.build_identity["Info"].get("RecoveryVariant")
|
|
246
246
|
if recovery_variant is not None:
|
|
247
247
|
self.tss_recoveryos_root_ticket = await self.get_tss_response()
|
|
248
248
|
|
|
@@ -252,13 +252,13 @@ class Recovery(BaseRestore):
|
|
|
252
252
|
# Use a specific TSS ticket for the Ap,LocalPolicy component
|
|
253
253
|
data = None
|
|
254
254
|
tss = self.tss
|
|
255
|
-
if name ==
|
|
255
|
+
if name == "Ap,LocalPolicy":
|
|
256
256
|
tss = self.tss_localpolicy
|
|
257
257
|
# If Ap,LocalPolicy => Inject an empty policy
|
|
258
258
|
data = lpol_file
|
|
259
259
|
|
|
260
260
|
data = self.get_personalized_data(name, data=data, tss=tss)
|
|
261
|
-
self.logger.info(f
|
|
261
|
+
self.logger.info(f"Sending {name} ({len(data)} bytes)...")
|
|
262
262
|
self.device.irecv.send_buffer(data)
|
|
263
263
|
|
|
264
264
|
def send_component_and_command(self, name, command):
|
|
@@ -266,114 +266,110 @@ class Recovery(BaseRestore):
|
|
|
266
266
|
self.device.irecv.send_command(command)
|
|
267
267
|
|
|
268
268
|
def send_ibec(self):
|
|
269
|
-
component =
|
|
269
|
+
component = "iBEC"
|
|
270
270
|
self.send_component(component)
|
|
271
|
-
self.device.irecv.send_command(
|
|
271
|
+
self.device.irecv.send_command("go", b_request=1)
|
|
272
272
|
self.device.irecv.ctrl_transfer(0x21, 1)
|
|
273
273
|
|
|
274
274
|
def send_applelogo(self, allow_missing=True):
|
|
275
|
-
component =
|
|
275
|
+
component = "RestoreLogo"
|
|
276
276
|
|
|
277
277
|
if not self.build_identity.has_component(component):
|
|
278
278
|
if allow_missing:
|
|
279
|
-
logging.warning(f
|
|
279
|
+
logging.warning(f"build_identity has no {component}")
|
|
280
280
|
return
|
|
281
281
|
else:
|
|
282
|
-
raise PyMobileDevice3Exception(f
|
|
282
|
+
raise PyMobileDevice3Exception(f"missing component: {component}")
|
|
283
283
|
|
|
284
284
|
self.send_component(component)
|
|
285
|
-
self.device.irecv.send_command(
|
|
286
|
-
self.device.irecv.send_command(
|
|
285
|
+
self.device.irecv.send_command("setpicture 4")
|
|
286
|
+
self.device.irecv.send_command("bgcolor 0 0 0")
|
|
287
287
|
|
|
288
288
|
def send_loaded_by_iboot(self):
|
|
289
|
-
manifest = self.build_identity[
|
|
289
|
+
manifest = self.build_identity["Manifest"]
|
|
290
290
|
for key, node in manifest.items():
|
|
291
|
-
iboot = node[
|
|
292
|
-
iboot_stg1 = node[
|
|
291
|
+
iboot = node["Info"].get("IsLoadedByiBoot", False)
|
|
292
|
+
iboot_stg1 = node["Info"].get("IsLoadedByiBootStage1", False)
|
|
293
293
|
|
|
294
294
|
assert isinstance(iboot, bool)
|
|
295
295
|
assert isinstance(iboot_stg1, bool)
|
|
296
296
|
|
|
297
297
|
if iboot and not iboot_stg1:
|
|
298
|
-
self.logger.debug(f
|
|
299
|
-
self.send_component_and_command(key,
|
|
298
|
+
self.logger.debug(f"{key} is loaded by iBoot")
|
|
299
|
+
self.send_component_and_command(key, "firmware")
|
|
300
300
|
|
|
301
301
|
def send_iboot_stage1_components(self):
|
|
302
|
-
manifest = self.build_identity[
|
|
302
|
+
manifest = self.build_identity["Manifest"]
|
|
303
303
|
for key, node in manifest.items():
|
|
304
|
-
iboot = node[
|
|
305
|
-
iboot_stg1 = node[
|
|
304
|
+
iboot = node["Info"].get("IsLoadedByiBoot", False)
|
|
305
|
+
iboot_stg1 = node["Info"].get("IsLoadedByiBootStage1", False)
|
|
306
306
|
|
|
307
307
|
assert isinstance(iboot, bool)
|
|
308
308
|
assert isinstance(iboot_stg1, bool)
|
|
309
309
|
|
|
310
310
|
if iboot and iboot_stg1:
|
|
311
|
-
self.logger.debug(f
|
|
312
|
-
self.send_component_and_command(key,
|
|
311
|
+
self.logger.debug(f"{key} is loaded by iBoot Stage 1")
|
|
312
|
+
self.send_component_and_command(key, "firmware")
|
|
313
313
|
|
|
314
314
|
def send_ramdisk(self):
|
|
315
|
-
component =
|
|
316
|
-
ramdisk_size = self.device.irecv.getenv(
|
|
317
|
-
self.logger.info(f
|
|
315
|
+
component = "RestoreRamDisk"
|
|
316
|
+
ramdisk_size = self.device.irecv.getenv("ramdisk-size")
|
|
317
|
+
self.logger.info(f"ramdisk-size: {ramdisk_size}")
|
|
318
318
|
|
|
319
319
|
self.send_component(component)
|
|
320
|
-
ramdisk_delay = self.device.irecv.getenv(
|
|
321
|
-
self.logger.info(f
|
|
320
|
+
ramdisk_delay = self.device.irecv.getenv("ramdisk-delay")
|
|
321
|
+
self.logger.info(f"ramdisk-delay: {ramdisk_delay}")
|
|
322
322
|
|
|
323
|
-
self.device.irecv.send_command(
|
|
323
|
+
self.device.irecv.send_command("ramdisk")
|
|
324
324
|
|
|
325
325
|
time.sleep(2)
|
|
326
326
|
|
|
327
327
|
def send_kernelcache(self):
|
|
328
|
-
component =
|
|
328
|
+
component = "RestoreKernelCache"
|
|
329
329
|
|
|
330
330
|
self.send_component(component)
|
|
331
|
-
|
|
331
|
+
with contextlib.suppress(USBError):
|
|
332
332
|
self.device.irecv.ctrl_transfer(0x21, 1)
|
|
333
|
-
except USBError:
|
|
334
|
-
pass
|
|
335
333
|
|
|
336
334
|
if self.restore_boot_args:
|
|
337
|
-
self.device.irecv.send_command(f
|
|
335
|
+
self.device.irecv.send_command(f"setenv boot-args {self.restore_boot_args}")
|
|
338
336
|
|
|
339
|
-
|
|
340
|
-
self.device.irecv.send_command(
|
|
341
|
-
except USBError:
|
|
342
|
-
pass
|
|
337
|
+
with contextlib.suppress(USBError):
|
|
338
|
+
self.device.irecv.send_command("bootx", b_request=1)
|
|
343
339
|
|
|
344
340
|
def set_autoboot(self, enable: bool):
|
|
345
341
|
self.device.irecv.set_autoboot(enable)
|
|
346
342
|
|
|
347
343
|
def enter_restore(self):
|
|
348
344
|
if self.macos_variant:
|
|
349
|
-
self.restore_boot_args =
|
|
345
|
+
self.restore_boot_args = "rd=md0 nand-enable-reformat=1 -progress -restore"
|
|
350
346
|
elif self.ipsw.build_manifest.build_major >= 8:
|
|
351
|
-
self.restore_boot_args =
|
|
347
|
+
self.restore_boot_args = "rd=md0 nand-enable-reformat=1 -progress"
|
|
352
348
|
|
|
353
349
|
# upload data to make device boot restore mode
|
|
354
350
|
|
|
355
351
|
# Recovery Mode Environment:
|
|
356
352
|
build_version = None
|
|
357
353
|
while not build_version:
|
|
358
|
-
self.logger.debug(
|
|
354
|
+
self.logger.debug("build-version not yet supported. reconnecting...")
|
|
359
355
|
time.sleep(1)
|
|
360
356
|
|
|
361
357
|
# sometimes we manage to connect before iBEC actually started running
|
|
362
|
-
build_version = self.device.irecv.getenv(
|
|
358
|
+
build_version = self.device.irecv.getenv("build-version")
|
|
363
359
|
self.reconnect_irecv()
|
|
364
360
|
|
|
365
|
-
self.logger.info(f
|
|
361
|
+
self.logger.info(f"iBoot build-version={build_version}")
|
|
366
362
|
|
|
367
|
-
build_style = self.device.irecv.getenv(
|
|
368
|
-
self.logger.info(f
|
|
363
|
+
build_style = self.device.irecv.getenv("build-style")
|
|
364
|
+
self.logger.info(f"iBoot build-style={build_style}")
|
|
369
365
|
|
|
370
|
-
radio_error = self.device.irecv.getenv(
|
|
366
|
+
radio_error = self.device.irecv.getenv("radio-error")
|
|
371
367
|
if radio_error:
|
|
372
368
|
radio_error = int(radio_error)
|
|
373
|
-
self.logger.info(f
|
|
374
|
-
radio_error_string = self.device.irecv.getenv(
|
|
369
|
+
self.logger.info(f"radio-error: {radio_error}")
|
|
370
|
+
radio_error_string = self.device.irecv.getenv("radio-error-string")
|
|
375
371
|
if radio_error_string:
|
|
376
|
-
self.logger.info(f
|
|
372
|
+
self.logger.info(f"radio-error-string: {radio_error_string}")
|
|
377
373
|
|
|
378
374
|
self.set_autoboot(False)
|
|
379
375
|
|
|
@@ -387,23 +383,21 @@ class Recovery(BaseRestore):
|
|
|
387
383
|
self.send_ramdisk()
|
|
388
384
|
|
|
389
385
|
# send devicetree and load it
|
|
390
|
-
self.send_component_and_command(
|
|
386
|
+
self.send_component_and_command("RestoreDeviceTree", "devicetree")
|
|
391
387
|
|
|
392
|
-
if self.build_identity.has_component(
|
|
388
|
+
if self.build_identity.has_component("RestoreSEP"):
|
|
393
389
|
# attempt to send rsepfirmware and load it, otherwise continue
|
|
394
|
-
|
|
395
|
-
self.send_component_and_command(
|
|
396
|
-
except USBError:
|
|
397
|
-
pass
|
|
390
|
+
with contextlib.suppress(USBError):
|
|
391
|
+
self.send_component_and_command("RestoreSEP", "rsepfirmware")
|
|
398
392
|
|
|
399
393
|
self.send_kernelcache()
|
|
400
394
|
|
|
401
395
|
async def dfu_enter_recovery(self) -> None:
|
|
402
|
-
self.send_component(
|
|
396
|
+
self.send_component("iBSS")
|
|
403
397
|
self.reconnect_irecv()
|
|
404
398
|
|
|
405
|
-
if
|
|
406
|
-
raise PyMobileDevice3Exception(
|
|
399
|
+
if "SRTG" in self.device.irecv._device_info:
|
|
400
|
+
raise PyMobileDevice3Exception("Device failed to enter recovery")
|
|
407
401
|
|
|
408
402
|
if self.build_identity.build_manifest.build_major > 8:
|
|
409
403
|
old_nonce = self.device.irecv.ap_nonce
|
|
@@ -421,43 +415,41 @@ class Recovery(BaseRestore):
|
|
|
421
415
|
# Now, before sending iBEC, we must send necessary firmwares on new versions.
|
|
422
416
|
if self.macos_variant:
|
|
423
417
|
# Without this empty policy file & its special signature, iBEC won't start.
|
|
424
|
-
self.send_component_and_command(
|
|
418
|
+
self.send_component_and_command("Ap,LocalPolicy", "lpolrestore")
|
|
425
419
|
self.send_iboot_stage1_components()
|
|
426
420
|
self.device.irecv.set_autoboot(False)
|
|
427
|
-
self.device.irecv.send_command(
|
|
421
|
+
self.device.irecv.send_command("setenvnp boot-args rd=md0 nand-enable-reformat=1 -progress -restore")
|
|
428
422
|
self.send_applelogo(allow_missing=False)
|
|
429
423
|
|
|
430
424
|
mode = self.device.irecv.mode
|
|
431
425
|
# send iBEC
|
|
432
|
-
self.send_component(
|
|
426
|
+
self.send_component("iBEC")
|
|
433
427
|
|
|
434
428
|
if self.device.irecv and mode.is_recovery:
|
|
435
429
|
time.sleep(1)
|
|
436
|
-
self.device.irecv.send_command(
|
|
430
|
+
self.device.irecv.send_command("go", b_request=1)
|
|
437
431
|
|
|
438
432
|
if self.build_identity.build_manifest.build_major < 20:
|
|
439
|
-
|
|
433
|
+
with contextlib.suppress(USBError):
|
|
440
434
|
self.device.irecv.ctrl_transfer(0x21, 1, timeout=5000)
|
|
441
|
-
except USBError:
|
|
442
|
-
pass
|
|
443
435
|
|
|
444
|
-
self.logger.debug(
|
|
436
|
+
self.logger.debug("Waiting for device to disconnect...")
|
|
445
437
|
time.sleep(10)
|
|
446
438
|
|
|
447
|
-
self.logger.debug(
|
|
439
|
+
self.logger.debug("Waiting for device to reconnect in recovery mode...")
|
|
448
440
|
self.reconnect_irecv(is_recovery=True)
|
|
449
441
|
|
|
450
442
|
async def boot_ramdisk(self) -> None:
|
|
451
443
|
if self.tss is None:
|
|
452
|
-
self.logger.info(
|
|
444
|
+
self.logger.info("fetching TSS record")
|
|
453
445
|
await self.fetch_tss_record()
|
|
454
446
|
|
|
455
447
|
if self.device.lockdown:
|
|
456
448
|
# normal mode
|
|
457
|
-
self.logger.info(
|
|
449
|
+
self.logger.info("going into Recovery")
|
|
458
450
|
|
|
459
451
|
# In case lockdown has disconnected while waiting for a ticket
|
|
460
|
-
self.device.lockdown = create_using_usbmux(serial=self.device.lockdown.udid, connection_type=
|
|
452
|
+
self.device.lockdown = create_using_usbmux(serial=self.device.lockdown.udid, connection_type="USB")
|
|
461
453
|
self.device.lockdown.enter_recovery()
|
|
462
454
|
|
|
463
455
|
self.device.lockdown = None
|
|
@@ -470,14 +462,12 @@ class Recovery(BaseRestore):
|
|
|
470
462
|
|
|
471
463
|
elif self.device.irecv.mode.is_recovery:
|
|
472
464
|
# now we load the iBEC
|
|
473
|
-
|
|
465
|
+
with contextlib.suppress(USBError):
|
|
474
466
|
self.send_ibec()
|
|
475
|
-
except USBError:
|
|
476
|
-
pass
|
|
477
467
|
|
|
478
468
|
self.reconnect_irecv(is_recovery=True)
|
|
479
469
|
|
|
480
|
-
self.logger.info(
|
|
470
|
+
self.logger.info("device booted into recovery")
|
|
481
471
|
|
|
482
472
|
# now finally do the magic to put the device into restore mode
|
|
483
473
|
self.enter_restore()
|