pymobiledevice3 4.14.6__py3-none-any.whl → 7.0.6__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
- misc/understanding_idevice_protocol_layers.md +15 -10
- pymobiledevice3/__main__.py +317 -127
- pymobiledevice3/_version.py +22 -4
- pymobiledevice3/bonjour.py +358 -113
- pymobiledevice3/ca.py +253 -16
- pymobiledevice3/cli/activation.py +31 -23
- pymobiledevice3/cli/afc.py +49 -40
- pymobiledevice3/cli/amfi.py +16 -21
- pymobiledevice3/cli/apps.py +87 -42
- pymobiledevice3/cli/backup.py +160 -90
- pymobiledevice3/cli/bonjour.py +44 -40
- pymobiledevice3/cli/cli_common.py +204 -198
- pymobiledevice3/cli/companion_proxy.py +14 -14
- pymobiledevice3/cli/crash.py +105 -56
- pymobiledevice3/cli/developer/__init__.py +62 -0
- pymobiledevice3/cli/developer/accessibility/__init__.py +65 -0
- pymobiledevice3/cli/developer/accessibility/settings.py +43 -0
- pymobiledevice3/cli/developer/arbitration.py +50 -0
- pymobiledevice3/cli/developer/condition.py +33 -0
- pymobiledevice3/cli/developer/core_device.py +294 -0
- pymobiledevice3/cli/developer/debugserver.py +244 -0
- pymobiledevice3/cli/developer/dvt/__init__.py +438 -0
- pymobiledevice3/cli/developer/dvt/core_profile_session.py +295 -0
- pymobiledevice3/cli/developer/dvt/simulate_location.py +56 -0
- pymobiledevice3/cli/developer/dvt/sysmon/__init__.py +69 -0
- pymobiledevice3/cli/developer/dvt/sysmon/process.py +188 -0
- pymobiledevice3/cli/developer/fetch_symbols.py +108 -0
- pymobiledevice3/cli/developer/simulate_location.py +51 -0
- pymobiledevice3/cli/diagnostics/__init__.py +75 -0
- pymobiledevice3/cli/diagnostics/battery.py +47 -0
- pymobiledevice3/cli/idam.py +42 -0
- pymobiledevice3/cli/lockdown.py +108 -103
- pymobiledevice3/cli/mounter.py +158 -99
- pymobiledevice3/cli/notification.py +38 -26
- pymobiledevice3/cli/pcap.py +45 -24
- pymobiledevice3/cli/power_assertion.py +18 -17
- pymobiledevice3/cli/processes.py +17 -23
- pymobiledevice3/cli/profile.py +165 -109
- pymobiledevice3/cli/provision.py +35 -34
- pymobiledevice3/cli/remote.py +217 -129
- pymobiledevice3/cli/restore.py +159 -143
- pymobiledevice3/cli/springboard.py +63 -53
- pymobiledevice3/cli/syslog.py +193 -86
- pymobiledevice3/cli/usbmux.py +73 -33
- pymobiledevice3/cli/version.py +5 -7
- pymobiledevice3/cli/webinspector.py +376 -214
- pymobiledevice3/common.py +3 -1
- pymobiledevice3/exceptions.py +182 -58
- pymobiledevice3/irecv.py +52 -53
- pymobiledevice3/irecv_devices.py +1489 -464
- pymobiledevice3/lockdown.py +473 -275
- pymobiledevice3/lockdown_service_provider.py +15 -8
- pymobiledevice3/osu/os_utils.py +27 -9
- pymobiledevice3/osu/posix_util.py +34 -15
- pymobiledevice3/osu/win_util.py +14 -8
- pymobiledevice3/pair_records.py +102 -21
- pymobiledevice3/remote/common.py +8 -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 +19 -4
- pymobiledevice3/remote/core_device/file_service.py +53 -23
- pymobiledevice3/remote/remote_service_discovery.py +79 -45
- pymobiledevice3/remote/remotexpc.py +73 -44
- pymobiledevice3/remote/tunnel_service.py +442 -317
- 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 +20 -16
- pymobiledevice3/resources/notifications.txt +144 -0
- pymobiledevice3/restore/asr.py +27 -27
- pymobiledevice3/restore/base_restore.py +110 -21
- pymobiledevice3/restore/consts.py +87 -66
- pymobiledevice3/restore/device.py +59 -12
- pymobiledevice3/restore/fdr.py +46 -48
- pymobiledevice3/restore/ftab.py +19 -19
- pymobiledevice3/restore/img4.py +163 -0
- pymobiledevice3/restore/mbn.py +587 -0
- pymobiledevice3/restore/recovery.py +151 -151
- pymobiledevice3/restore/restore.py +562 -544
- pymobiledevice3/restore/restore_options.py +131 -110
- pymobiledevice3/restore/restored_client.py +51 -31
- pymobiledevice3/restore/tss.py +385 -267
- pymobiledevice3/service_connection.py +252 -59
- pymobiledevice3/services/accessibilityaudit.py +202 -120
- pymobiledevice3/services/afc.py +962 -365
- pymobiledevice3/services/amfi.py +24 -30
- pymobiledevice3/services/companion.py +23 -19
- pymobiledevice3/services/crash_reports.py +71 -47
- pymobiledevice3/services/debugserver_applist.py +3 -3
- pymobiledevice3/services/device_arbitration.py +8 -8
- pymobiledevice3/services/device_link.py +101 -79
- pymobiledevice3/services/diagnostics.py +973 -967
- 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 +20 -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 +35 -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 +9 -8
- pymobiledevice3/services/house_arrest.py +16 -15
- pymobiledevice3/services/idam.py +20 -0
- pymobiledevice3/services/installation_proxy.py +173 -81
- pymobiledevice3/services/lockdown_service.py +20 -10
- pymobiledevice3/services/misagent.py +22 -19
- pymobiledevice3/services/mobile_activation.py +147 -64
- pymobiledevice3/services/mobile_config.py +331 -294
- pymobiledevice3/services/mobile_image_mounter.py +141 -113
- pymobiledevice3/services/mobilebackup2.py +203 -145
- pymobiledevice3/services/notification_proxy.py +11 -11
- pymobiledevice3/services/os_trace.py +134 -74
- pymobiledevice3/services/pcapd.py +314 -302
- pymobiledevice3/services/power_assertion.py +10 -9
- pymobiledevice3/services/preboard.py +4 -4
- pymobiledevice3/services/remote_fetch_symbols.py +21 -14
- pymobiledevice3/services/remote_server.py +176 -146
- pymobiledevice3/services/restore_service.py +16 -16
- pymobiledevice3/services/screenshot.py +15 -12
- 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 +11 -11
- pymobiledevice3/services/web_protocol/automation_session.py +251 -239
- pymobiledevice3/services/web_protocol/cdp_screencast.py +46 -37
- pymobiledevice3/services/web_protocol/cdp_server.py +19 -19
- pymobiledevice3/services/web_protocol/cdp_target.py +411 -373
- pymobiledevice3/services/web_protocol/driver.py +114 -111
- pymobiledevice3/services/web_protocol/element.py +124 -111
- pymobiledevice3/services/web_protocol/inspector_session.py +106 -102
- pymobiledevice3/services/web_protocol/selenium_api.py +49 -49
- pymobiledevice3/services/web_protocol/session_protocol.py +18 -12
- pymobiledevice3/services/web_protocol/switch_to.py +30 -27
- pymobiledevice3/services/webinspector.py +189 -155
- pymobiledevice3/tcp_forwarder.py +87 -69
- pymobiledevice3/tunneld/__init__.py +0 -0
- pymobiledevice3/tunneld/api.py +63 -0
- pymobiledevice3/tunneld/server.py +603 -0
- pymobiledevice3/usbmux.py +198 -147
- pymobiledevice3/utils.py +14 -11
- {pymobiledevice3-4.14.6.dist-info → pymobiledevice3-7.0.6.dist-info}/METADATA +55 -28
- pymobiledevice3-7.0.6.dist-info/RECORD +188 -0
- {pymobiledevice3-4.14.6.dist-info → pymobiledevice3-7.0.6.dist-info}/WHEEL +1 -1
- pymobiledevice3/cli/developer.py +0 -1215
- pymobiledevice3/cli/diagnostics.py +0 -99
- pymobiledevice3/tunneld.py +0 -524
- pymobiledevice3-4.14.6.dist-info/RECORD +0 -168
- {pymobiledevice3-4.14.6.dist-info → pymobiledevice3-7.0.6.dist-info}/entry_points.txt +0 -0
- {pymobiledevice3-4.14.6.dist-info → pymobiledevice3-7.0.6.dist-info/licenses}/LICENSE +0 -0
- {pymobiledevice3-4.14.6.dist-info → pymobiledevice3-7.0.6.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,29 +28,29 @@ 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
|
-
self.
|
|
48
|
+
self.populate_tss_request_from_manifest(parameters)
|
|
48
49
|
|
|
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,29 +58,34 @@ 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
|
-
self.
|
|
78
|
+
self.populate_tss_request_from_manifest(parameters)
|
|
78
79
|
|
|
79
80
|
tss = TSSRequest()
|
|
80
81
|
tss.add_common_tags(parameters)
|
|
81
82
|
tss.add_ap_tags(parameters)
|
|
82
83
|
|
|
84
|
+
# TODO: This break updating iPhone 15P Pro. Consider re-adding it once we figure out what went wrong
|
|
85
|
+
# build_manifest_info = self.build_identity['Info']
|
|
86
|
+
# for manifest_property in build_manifest_info.get('RequestManifestProperties', []):
|
|
87
|
+
# tss.add_tags({manifest_property: build_manifest_info[manifest_property]})
|
|
88
|
+
|
|
83
89
|
# add personalized parameters
|
|
84
90
|
if self.device.is_image4_supported:
|
|
85
91
|
tss.add_ap_img4_tags(parameters)
|
|
@@ -88,51 +94,52 @@ class Recovery(BaseRestore):
|
|
|
88
94
|
|
|
89
95
|
# normal mode; request baseband ticket as well
|
|
90
96
|
if self.device.lockdown is not None:
|
|
91
|
-
pinfo = self.device.
|
|
97
|
+
pinfo = self.device.firmware_preflight_info
|
|
92
98
|
if pinfo:
|
|
93
|
-
self.logger.debug(
|
|
99
|
+
self.logger.debug("adding firmware preflight info")
|
|
94
100
|
|
|
95
|
-
node = pinfo.get(
|
|
101
|
+
node = pinfo.get("Nonce")
|
|
96
102
|
if node is not None:
|
|
97
|
-
parameters[
|
|
103
|
+
parameters["BbNonce"] = node
|
|
98
104
|
|
|
99
|
-
node = pinfo.get(
|
|
105
|
+
node = pinfo.get("ChipID")
|
|
100
106
|
if node is not None:
|
|
101
|
-
parameters[
|
|
107
|
+
parameters["BbChipID"] = node
|
|
102
108
|
|
|
103
|
-
node = pinfo.get(
|
|
109
|
+
node = pinfo.get("CertID")
|
|
104
110
|
if node is not None:
|
|
105
|
-
parameters[
|
|
111
|
+
parameters["BbGoldCertId"] = node
|
|
106
112
|
|
|
107
|
-
node = pinfo.get(
|
|
113
|
+
node = pinfo.get("ChipSerialNo")
|
|
108
114
|
if node is not None:
|
|
109
|
-
parameters[
|
|
115
|
+
parameters["BbSNUM"] = node
|
|
110
116
|
|
|
111
|
-
|
|
117
|
+
# add baseband parameters
|
|
118
|
+
tss.add_baseband_tags(parameters)
|
|
112
119
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
120
|
+
euiccchipid = pinfo.get("EUICCChipID")
|
|
121
|
+
if euiccchipid:
|
|
122
|
+
self.logger.debug("adding EUICCChipID info")
|
|
123
|
+
parameters["eUICC,ChipID"] = euiccchipid
|
|
117
124
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
125
|
+
if euiccchipid >= 5:
|
|
126
|
+
node = pinfo.get("EUICCCSN")
|
|
127
|
+
if node is not None:
|
|
128
|
+
parameters["eUICC,EID"] = node
|
|
122
129
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
130
|
+
node = pinfo.get("EUICCCertIdentifier")
|
|
131
|
+
if node is not None:
|
|
132
|
+
parameters["eUICC,RootKeyIdentifier"] = node
|
|
126
133
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
134
|
+
node = pinfo.get("EUICCGoldNonce")
|
|
135
|
+
if node is not None:
|
|
136
|
+
parameters["EUICCGoldNonce"] = node
|
|
130
137
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
138
|
+
node = pinfo.get("EUICCMainNonce")
|
|
139
|
+
if node is not None:
|
|
140
|
+
parameters["EUICCMainNonce"] = node
|
|
134
141
|
|
|
135
|
-
|
|
142
|
+
tss.add_vinyl_tags(parameters)
|
|
136
143
|
|
|
137
144
|
# send request and grab response
|
|
138
145
|
return await tss.send_receive()
|
|
@@ -140,40 +147,40 @@ class Recovery(BaseRestore):
|
|
|
140
147
|
def get_local_policy_tss_response(self):
|
|
141
148
|
# populate parameters
|
|
142
149
|
parameters = {
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
150
|
+
"ApECID": self.device.ecid,
|
|
151
|
+
"Ap,LocalBoot": False,
|
|
152
|
+
"ApProductionMode": True,
|
|
146
153
|
}
|
|
147
154
|
|
|
148
155
|
if self.device.ap_nonce:
|
|
149
|
-
parameters[
|
|
156
|
+
parameters["ApNonce"] = self.device.ap_nonce
|
|
150
157
|
|
|
151
158
|
sep_nonce = self.device.sep_nonce
|
|
152
159
|
|
|
153
160
|
if sep_nonce:
|
|
154
|
-
parameters[
|
|
161
|
+
parameters["ApSepNonce"] = sep_nonce
|
|
155
162
|
|
|
156
163
|
if self.device.is_image4_supported:
|
|
157
|
-
parameters[
|
|
158
|
-
parameters[
|
|
164
|
+
parameters["ApSecurityMode"] = True
|
|
165
|
+
parameters["ApSupportsImg4"] = True
|
|
159
166
|
else:
|
|
160
|
-
parameters[
|
|
167
|
+
parameters["ApSupportsImg4"] = False
|
|
161
168
|
|
|
162
|
-
self.
|
|
169
|
+
self.populate_tss_request_from_manifest(parameters)
|
|
163
170
|
|
|
164
171
|
# Add Ap,LocalPolicy
|
|
165
172
|
lpol = {
|
|
166
|
-
|
|
167
|
-
|
|
173
|
+
"Digest": hashlib.sha384(lpol_file).digest(),
|
|
174
|
+
"Trusted": True,
|
|
168
175
|
}
|
|
169
176
|
|
|
170
|
-
parameters[
|
|
177
|
+
parameters["Ap,LocalPolicy"] = lpol
|
|
171
178
|
|
|
172
179
|
# Add Ap,NextStageIM4MHash
|
|
173
180
|
# Get previous TSS ticket
|
|
174
181
|
ticket = self.tss.ap_img4_ticket
|
|
175
182
|
# Hash it and add it as Ap,NextStageIM4MHash
|
|
176
|
-
parameters[
|
|
183
|
+
parameters["Ap,NextStageIM4MHash"] = hashlib.sha384(ticket).digest()
|
|
177
184
|
|
|
178
185
|
# create basic request
|
|
179
186
|
request = TSSRequest()
|
|
@@ -186,26 +193,26 @@ class Recovery(BaseRestore):
|
|
|
186
193
|
def get_recoveryos_root_ticket_tss_response(self):
|
|
187
194
|
# populate parameters
|
|
188
195
|
parameters = {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
196
|
+
"ApECID": self.device.ecid,
|
|
197
|
+
"Ap,LocalBoot": False,
|
|
198
|
+
"ApProductionMode": True,
|
|
192
199
|
}
|
|
193
200
|
|
|
194
201
|
if self.device.ap_nonce:
|
|
195
|
-
parameters[
|
|
202
|
+
parameters["ApNonce"] = self.device.ap_nonce
|
|
196
203
|
|
|
197
204
|
sep_nonce = self.device.sep_nonce
|
|
198
205
|
|
|
199
206
|
if sep_nonce:
|
|
200
|
-
parameters[
|
|
207
|
+
parameters["ApSepNonce"] = sep_nonce
|
|
201
208
|
|
|
202
209
|
if self.device.is_image4_supported:
|
|
203
|
-
parameters[
|
|
204
|
-
parameters[
|
|
210
|
+
parameters["ApSecurityMode"] = True
|
|
211
|
+
parameters["ApSupportsImg4"] = True
|
|
205
212
|
else:
|
|
206
|
-
parameters[
|
|
213
|
+
parameters["ApSupportsImg4"] = False
|
|
207
214
|
|
|
208
|
-
self.
|
|
215
|
+
self.populate_tss_request_from_manifest(parameters)
|
|
209
216
|
|
|
210
217
|
# create basic request
|
|
211
218
|
# Adds @HostPlatformInfo, @VersionInfo, @UUID
|
|
@@ -225,16 +232,19 @@ class Recovery(BaseRestore):
|
|
|
225
232
|
return request.send_receive()
|
|
226
233
|
|
|
227
234
|
async def fetch_tss_record(self) -> TSSResponse:
|
|
228
|
-
if self.ipsw.build_manifest.build_major > 8:
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
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")
|
|
232
238
|
|
|
233
239
|
self.tss = await self.get_tss_response()
|
|
234
240
|
|
|
235
241
|
if self.macos_variant:
|
|
236
242
|
self.tss_localpolicy = self.get_local_policy_tss_response()
|
|
237
243
|
self.tss_recoveryos_root_ticket = self.get_recoveryos_root_ticket_tss_response()
|
|
244
|
+
else:
|
|
245
|
+
recovery_variant = self.build_identity["Info"].get("RecoveryVariant")
|
|
246
|
+
if recovery_variant is not None:
|
|
247
|
+
self.tss_recoveryos_root_ticket = await self.get_tss_response()
|
|
238
248
|
|
|
239
249
|
return self.tss
|
|
240
250
|
|
|
@@ -242,13 +252,13 @@ class Recovery(BaseRestore):
|
|
|
242
252
|
# Use a specific TSS ticket for the Ap,LocalPolicy component
|
|
243
253
|
data = None
|
|
244
254
|
tss = self.tss
|
|
245
|
-
if name ==
|
|
255
|
+
if name == "Ap,LocalPolicy":
|
|
246
256
|
tss = self.tss_localpolicy
|
|
247
257
|
# If Ap,LocalPolicy => Inject an empty policy
|
|
248
258
|
data = lpol_file
|
|
249
259
|
|
|
250
|
-
data = self.
|
|
251
|
-
self.logger.info(f
|
|
260
|
+
data = self.get_personalized_data(name, data=data, tss=tss)
|
|
261
|
+
self.logger.info(f"Sending {name} ({len(data)} bytes)...")
|
|
252
262
|
self.device.irecv.send_buffer(data)
|
|
253
263
|
|
|
254
264
|
def send_component_and_command(self, name, command):
|
|
@@ -256,114 +266,110 @@ class Recovery(BaseRestore):
|
|
|
256
266
|
self.device.irecv.send_command(command)
|
|
257
267
|
|
|
258
268
|
def send_ibec(self):
|
|
259
|
-
component =
|
|
269
|
+
component = "iBEC"
|
|
260
270
|
self.send_component(component)
|
|
261
|
-
self.device.irecv.send_command(
|
|
271
|
+
self.device.irecv.send_command("go", b_request=1)
|
|
262
272
|
self.device.irecv.ctrl_transfer(0x21, 1)
|
|
263
273
|
|
|
264
274
|
def send_applelogo(self, allow_missing=True):
|
|
265
|
-
component =
|
|
275
|
+
component = "RestoreLogo"
|
|
266
276
|
|
|
267
277
|
if not self.build_identity.has_component(component):
|
|
268
278
|
if allow_missing:
|
|
269
|
-
logging.warning(f
|
|
279
|
+
logging.warning(f"build_identity has no {component}")
|
|
270
280
|
return
|
|
271
281
|
else:
|
|
272
|
-
raise PyMobileDevice3Exception(f
|
|
282
|
+
raise PyMobileDevice3Exception(f"missing component: {component}")
|
|
273
283
|
|
|
274
284
|
self.send_component(component)
|
|
275
|
-
self.device.irecv.send_command(
|
|
276
|
-
self.device.irecv.send_command(
|
|
285
|
+
self.device.irecv.send_command("setpicture 4")
|
|
286
|
+
self.device.irecv.send_command("bgcolor 0 0 0")
|
|
277
287
|
|
|
278
288
|
def send_loaded_by_iboot(self):
|
|
279
|
-
manifest = self.build_identity[
|
|
289
|
+
manifest = self.build_identity["Manifest"]
|
|
280
290
|
for key, node in manifest.items():
|
|
281
|
-
iboot = node[
|
|
282
|
-
iboot_stg1 = node[
|
|
291
|
+
iboot = node["Info"].get("IsLoadedByiBoot", False)
|
|
292
|
+
iboot_stg1 = node["Info"].get("IsLoadedByiBootStage1", False)
|
|
283
293
|
|
|
284
294
|
assert isinstance(iboot, bool)
|
|
285
295
|
assert isinstance(iboot_stg1, bool)
|
|
286
296
|
|
|
287
297
|
if iboot and not iboot_stg1:
|
|
288
|
-
self.logger.debug(f
|
|
289
|
-
self.send_component_and_command(key,
|
|
298
|
+
self.logger.debug(f"{key} is loaded by iBoot")
|
|
299
|
+
self.send_component_and_command(key, "firmware")
|
|
290
300
|
|
|
291
301
|
def send_iboot_stage1_components(self):
|
|
292
|
-
manifest = self.build_identity[
|
|
302
|
+
manifest = self.build_identity["Manifest"]
|
|
293
303
|
for key, node in manifest.items():
|
|
294
|
-
iboot = node[
|
|
295
|
-
iboot_stg1 = node[
|
|
304
|
+
iboot = node["Info"].get("IsLoadedByiBoot", False)
|
|
305
|
+
iboot_stg1 = node["Info"].get("IsLoadedByiBootStage1", False)
|
|
296
306
|
|
|
297
307
|
assert isinstance(iboot, bool)
|
|
298
308
|
assert isinstance(iboot_stg1, bool)
|
|
299
309
|
|
|
300
310
|
if iboot and iboot_stg1:
|
|
301
|
-
self.logger.debug(f
|
|
302
|
-
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")
|
|
303
313
|
|
|
304
314
|
def send_ramdisk(self):
|
|
305
|
-
component =
|
|
306
|
-
ramdisk_size = self.device.irecv.getenv(
|
|
307
|
-
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}")
|
|
308
318
|
|
|
309
319
|
self.send_component(component)
|
|
310
|
-
ramdisk_delay = self.device.irecv.getenv(
|
|
311
|
-
self.logger.info(f
|
|
320
|
+
ramdisk_delay = self.device.irecv.getenv("ramdisk-delay")
|
|
321
|
+
self.logger.info(f"ramdisk-delay: {ramdisk_delay}")
|
|
312
322
|
|
|
313
|
-
self.device.irecv.send_command(
|
|
323
|
+
self.device.irecv.send_command("ramdisk")
|
|
314
324
|
|
|
315
325
|
time.sleep(2)
|
|
316
326
|
|
|
317
327
|
def send_kernelcache(self):
|
|
318
|
-
component =
|
|
328
|
+
component = "RestoreKernelCache"
|
|
319
329
|
|
|
320
330
|
self.send_component(component)
|
|
321
|
-
|
|
331
|
+
with contextlib.suppress(USBError):
|
|
322
332
|
self.device.irecv.ctrl_transfer(0x21, 1)
|
|
323
|
-
except USBError:
|
|
324
|
-
pass
|
|
325
333
|
|
|
326
334
|
if self.restore_boot_args:
|
|
327
|
-
self.device.irecv.send_command(f
|
|
335
|
+
self.device.irecv.send_command(f"setenv boot-args {self.restore_boot_args}")
|
|
328
336
|
|
|
329
|
-
|
|
330
|
-
self.device.irecv.send_command(
|
|
331
|
-
except USBError:
|
|
332
|
-
pass
|
|
337
|
+
with contextlib.suppress(USBError):
|
|
338
|
+
self.device.irecv.send_command("bootx", b_request=1)
|
|
333
339
|
|
|
334
340
|
def set_autoboot(self, enable: bool):
|
|
335
341
|
self.device.irecv.set_autoboot(enable)
|
|
336
342
|
|
|
337
343
|
def enter_restore(self):
|
|
338
|
-
if self.
|
|
339
|
-
self.restore_boot_args =
|
|
340
|
-
elif self.
|
|
341
|
-
self.restore_boot_args =
|
|
344
|
+
if self.macos_variant:
|
|
345
|
+
self.restore_boot_args = "rd=md0 nand-enable-reformat=1 -progress -restore"
|
|
346
|
+
elif self.ipsw.build_manifest.build_major >= 8:
|
|
347
|
+
self.restore_boot_args = "rd=md0 nand-enable-reformat=1 -progress"
|
|
342
348
|
|
|
343
349
|
# upload data to make device boot restore mode
|
|
344
350
|
|
|
345
351
|
# Recovery Mode Environment:
|
|
346
352
|
build_version = None
|
|
347
353
|
while not build_version:
|
|
348
|
-
self.logger.debug(
|
|
354
|
+
self.logger.debug("build-version not yet supported. reconnecting...")
|
|
349
355
|
time.sleep(1)
|
|
350
356
|
|
|
351
357
|
# sometimes we manage to connect before iBEC actually started running
|
|
352
|
-
build_version = self.device.irecv.getenv(
|
|
358
|
+
build_version = self.device.irecv.getenv("build-version")
|
|
353
359
|
self.reconnect_irecv()
|
|
354
360
|
|
|
355
|
-
self.logger.info(f
|
|
361
|
+
self.logger.info(f"iBoot build-version={build_version}")
|
|
356
362
|
|
|
357
|
-
build_style = self.device.irecv.getenv(
|
|
358
|
-
self.logger.info(f
|
|
363
|
+
build_style = self.device.irecv.getenv("build-style")
|
|
364
|
+
self.logger.info(f"iBoot build-style={build_style}")
|
|
359
365
|
|
|
360
|
-
radio_error = self.device.irecv.getenv(
|
|
366
|
+
radio_error = self.device.irecv.getenv("radio-error")
|
|
361
367
|
if radio_error:
|
|
362
368
|
radio_error = int(radio_error)
|
|
363
|
-
self.logger.info(f
|
|
364
|
-
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")
|
|
365
371
|
if radio_error_string:
|
|
366
|
-
self.logger.info(f
|
|
372
|
+
self.logger.info(f"radio-error-string: {radio_error_string}")
|
|
367
373
|
|
|
368
374
|
self.set_autoboot(False)
|
|
369
375
|
|
|
@@ -377,23 +383,21 @@ class Recovery(BaseRestore):
|
|
|
377
383
|
self.send_ramdisk()
|
|
378
384
|
|
|
379
385
|
# send devicetree and load it
|
|
380
|
-
self.send_component_and_command(
|
|
386
|
+
self.send_component_and_command("RestoreDeviceTree", "devicetree")
|
|
381
387
|
|
|
382
|
-
if self.build_identity.has_component(
|
|
388
|
+
if self.build_identity.has_component("RestoreSEP"):
|
|
383
389
|
# attempt to send rsepfirmware and load it, otherwise continue
|
|
384
|
-
|
|
385
|
-
self.send_component_and_command(
|
|
386
|
-
except USBError:
|
|
387
|
-
pass
|
|
390
|
+
with contextlib.suppress(USBError):
|
|
391
|
+
self.send_component_and_command("RestoreSEP", "rsepfirmware")
|
|
388
392
|
|
|
389
393
|
self.send_kernelcache()
|
|
390
394
|
|
|
391
395
|
async def dfu_enter_recovery(self) -> None:
|
|
392
|
-
self.send_component(
|
|
396
|
+
self.send_component("iBSS")
|
|
393
397
|
self.reconnect_irecv()
|
|
394
398
|
|
|
395
|
-
if
|
|
396
|
-
raise PyMobileDevice3Exception(
|
|
399
|
+
if "SRTG" in self.device.irecv._device_info:
|
|
400
|
+
raise PyMobileDevice3Exception("Device failed to enter recovery")
|
|
397
401
|
|
|
398
402
|
if self.build_identity.build_manifest.build_major > 8:
|
|
399
403
|
old_nonce = self.device.irecv.ap_nonce
|
|
@@ -411,43 +415,41 @@ class Recovery(BaseRestore):
|
|
|
411
415
|
# Now, before sending iBEC, we must send necessary firmwares on new versions.
|
|
412
416
|
if self.macos_variant:
|
|
413
417
|
# Without this empty policy file & its special signature, iBEC won't start.
|
|
414
|
-
self.send_component_and_command(
|
|
418
|
+
self.send_component_and_command("Ap,LocalPolicy", "lpolrestore")
|
|
415
419
|
self.send_iboot_stage1_components()
|
|
416
420
|
self.device.irecv.set_autoboot(False)
|
|
417
|
-
self.device.irecv.send_command(
|
|
421
|
+
self.device.irecv.send_command("setenvnp boot-args rd=md0 nand-enable-reformat=1 -progress -restore")
|
|
418
422
|
self.send_applelogo(allow_missing=False)
|
|
419
423
|
|
|
420
424
|
mode = self.device.irecv.mode
|
|
421
425
|
# send iBEC
|
|
422
|
-
self.send_component(
|
|
426
|
+
self.send_component("iBEC")
|
|
423
427
|
|
|
424
428
|
if self.device.irecv and mode.is_recovery:
|
|
425
429
|
time.sleep(1)
|
|
426
|
-
self.device.irecv.send_command(
|
|
430
|
+
self.device.irecv.send_command("go", b_request=1)
|
|
427
431
|
|
|
428
432
|
if self.build_identity.build_manifest.build_major < 20:
|
|
429
|
-
|
|
433
|
+
with contextlib.suppress(USBError):
|
|
430
434
|
self.device.irecv.ctrl_transfer(0x21, 1, timeout=5000)
|
|
431
|
-
except USBError:
|
|
432
|
-
pass
|
|
433
435
|
|
|
434
|
-
self.logger.debug(
|
|
436
|
+
self.logger.debug("Waiting for device to disconnect...")
|
|
435
437
|
time.sleep(10)
|
|
436
438
|
|
|
437
|
-
self.logger.debug(
|
|
439
|
+
self.logger.debug("Waiting for device to reconnect in recovery mode...")
|
|
438
440
|
self.reconnect_irecv(is_recovery=True)
|
|
439
441
|
|
|
440
442
|
async def boot_ramdisk(self) -> None:
|
|
441
443
|
if self.tss is None:
|
|
442
|
-
self.logger.info(
|
|
444
|
+
self.logger.info("fetching TSS record")
|
|
443
445
|
await self.fetch_tss_record()
|
|
444
446
|
|
|
445
447
|
if self.device.lockdown:
|
|
446
448
|
# normal mode
|
|
447
|
-
self.logger.info(
|
|
449
|
+
self.logger.info("going into Recovery")
|
|
448
450
|
|
|
449
|
-
#
|
|
450
|
-
self.device.lockdown = create_using_usbmux(serial=self.device.lockdown.udid, connection_type=
|
|
451
|
+
# In case lockdown has disconnected while waiting for a ticket
|
|
452
|
+
self.device.lockdown = create_using_usbmux(serial=self.device.lockdown.udid, connection_type="USB")
|
|
451
453
|
self.device.lockdown.enter_recovery()
|
|
452
454
|
|
|
453
455
|
self.device.lockdown = None
|
|
@@ -460,14 +462,12 @@ class Recovery(BaseRestore):
|
|
|
460
462
|
|
|
461
463
|
elif self.device.irecv.mode.is_recovery:
|
|
462
464
|
# now we load the iBEC
|
|
463
|
-
|
|
465
|
+
with contextlib.suppress(USBError):
|
|
464
466
|
self.send_ibec()
|
|
465
|
-
except USBError:
|
|
466
|
-
pass
|
|
467
467
|
|
|
468
468
|
self.reconnect_irecv(is_recovery=True)
|
|
469
469
|
|
|
470
|
-
self.logger.info(
|
|
470
|
+
self.logger.info("device booted into recovery")
|
|
471
471
|
|
|
472
472
|
# now finally do the magic to put the device into restore mode
|
|
473
473
|
self.enter_restore()
|