pymobiledevice3 5.0.0__py3-none-any.whl → 5.0.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.
Potentially problematic release.
This version of pymobiledevice3 might be problematic. Click here for more details.
- misc/plist_sniffer.py +15 -15
- misc/remotexpc_sniffer.py +29 -28
- pymobiledevice3/__main__.py +128 -102
- pymobiledevice3/_version.py +2 -2
- pymobiledevice3/bonjour.py +26 -49
- 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 +25 -18
- 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 +602 -520
- pymobiledevice3/cli/diagnostics.py +38 -33
- pymobiledevice3/cli/lockdown.py +79 -74
- pymobiledevice3/cli/mounter.py +85 -68
- 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 +186 -110
- 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 +157 -79
- pymobiledevice3/common.py +1 -1
- pymobiledevice3/exceptions.py +154 -60
- pymobiledevice3/irecv.py +49 -53
- pymobiledevice3/irecv_devices.py +1489 -492
- pymobiledevice3/lockdown.py +394 -241
- 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 +62 -41
- pymobiledevice3/remote/tunnel_service.py +371 -293
- pymobiledevice3/remote/utils.py +12 -11
- 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 +35 -54
- pymobiledevice3/restore/recovery.py +125 -135
- pymobiledevice3/restore/restore.py +524 -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 +136 -126
- pymobiledevice3/services/afc.py +350 -291
- pymobiledevice3/services/amfi.py +21 -18
- pymobiledevice3/services/companion.py +23 -19
- pymobiledevice3/services/crash_reports.py +60 -46
- pymobiledevice3/services/debugserver_applist.py +3 -3
- pymobiledevice3/services/device_arbitration.py +8 -8
- pymobiledevice3/services/device_link.py +55 -47
- 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 +40 -50
- 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 +330 -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 +69 -51
- 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 +180 -176
- 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 +2 -2
- pymobiledevice3/services/web_protocol/session_protocol.py +15 -10
- pymobiledevice3/services/web_protocol/switch_to.py +11 -12
- pymobiledevice3/services/webinspector.py +127 -116
- pymobiledevice3/tcp_forwarder.py +35 -22
- pymobiledevice3/tunneld/api.py +20 -15
- pymobiledevice3/tunneld/server.py +212 -133
- pymobiledevice3/usbmux.py +183 -138
- pymobiledevice3/utils.py +14 -11
- {pymobiledevice3-5.0.0.dist-info → pymobiledevice3-5.0.2.dist-info}/METADATA +1 -1
- pymobiledevice3-5.0.2.dist-info/RECORD +173 -0
- pymobiledevice3-5.0.0.dist-info/RECORD +0 -173
- {pymobiledevice3-5.0.0.dist-info → pymobiledevice3-5.0.2.dist-info}/WHEEL +0 -0
- {pymobiledevice3-5.0.0.dist-info → pymobiledevice3-5.0.2.dist-info}/entry_points.txt +0 -0
- {pymobiledevice3-5.0.0.dist-info → pymobiledevice3-5.0.2.dist-info}/licenses/LICENSE +0 -0
- {pymobiledevice3-5.0.0.dist-info → pymobiledevice3-5.0.2.dist-info}/top_level.txt +0 -0
|
@@ -7,10 +7,10 @@ from pymobiledevice3.lockdown import LockdownClient
|
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
class DtFetchSymbols:
|
|
10
|
-
SERVICE_NAME =
|
|
10
|
+
SERVICE_NAME = "com.apple.dt.fetchsymbols"
|
|
11
11
|
MAX_CHUNK = 1024 * 1024 * 10 # 10MB
|
|
12
|
-
CMD_LIST_FILES_PLIST = struct.pack(
|
|
13
|
-
CMD_GET_FILE = struct.pack(
|
|
12
|
+
CMD_LIST_FILES_PLIST = struct.pack(">I", 0x30303030)
|
|
13
|
+
CMD_GET_FILE = struct.pack(">I", 1)
|
|
14
14
|
|
|
15
15
|
def __init__(self, lockdown: LockdownClient):
|
|
16
16
|
self.logger = logging.getLogger(__name__)
|
|
@@ -18,16 +18,16 @@ class DtFetchSymbols:
|
|
|
18
18
|
|
|
19
19
|
def list_files(self) -> list[str]:
|
|
20
20
|
service = self._start_command(self.CMD_LIST_FILES_PLIST)
|
|
21
|
-
files = service.recv_plist().get(
|
|
21
|
+
files = service.recv_plist().get("files")
|
|
22
22
|
service.close()
|
|
23
23
|
return files
|
|
24
24
|
|
|
25
25
|
def get_file(self, fileno: int, stream: typing.IO):
|
|
26
26
|
service = self._start_command(self.CMD_GET_FILE)
|
|
27
|
-
service.sendall(struct.pack(
|
|
27
|
+
service.sendall(struct.pack(">I", fileno))
|
|
28
28
|
|
|
29
|
-
size = struct.unpack(
|
|
30
|
-
self.logger.debug(f
|
|
29
|
+
size = struct.unpack(">Q", service.recvall(8))[0]
|
|
30
|
+
self.logger.debug(f"file size: {size}")
|
|
31
31
|
|
|
32
32
|
received = 0
|
|
33
33
|
while received < size:
|
|
@@ -42,6 +42,6 @@ class DtFetchSymbols:
|
|
|
42
42
|
|
|
43
43
|
# receive same command as an ack
|
|
44
44
|
if cmd != service.recvall(len(cmd)):
|
|
45
|
-
raise PyMobileDevice3Exception(
|
|
45
|
+
raise PyMobileDevice3Exception("bad ack")
|
|
46
46
|
|
|
47
47
|
return service
|
|
@@ -6,15 +6,15 @@ from pymobiledevice3.services.remote_server import RemoteServer
|
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
class DvtSecureSocketProxyService(RemoteServer):
|
|
9
|
-
SERVICE_NAME =
|
|
10
|
-
OLD_SERVICE_NAME =
|
|
11
|
-
RSD_SERVICE_NAME =
|
|
9
|
+
SERVICE_NAME = "com.apple.instruments.remoteserver.DVTSecureSocketProxy"
|
|
10
|
+
OLD_SERVICE_NAME = "com.apple.instruments.remoteserver"
|
|
11
|
+
RSD_SERVICE_NAME = "com.apple.instruments.dtservicehub"
|
|
12
12
|
|
|
13
13
|
def __init__(self, lockdown: LockdownServiceProvider):
|
|
14
14
|
if isinstance(lockdown, RemoteServiceDiscoveryService):
|
|
15
15
|
service_name = self.RSD_SERVICE_NAME
|
|
16
16
|
remove_ssl_context = False
|
|
17
|
-
elif Version(lockdown.product_version) >= Version(
|
|
17
|
+
elif Version(lockdown.product_version) >= Version("14.0"):
|
|
18
18
|
service_name = self.SERVICE_NAME
|
|
19
19
|
remove_ssl_context = False
|
|
20
20
|
else:
|
|
@@ -6,9 +6,9 @@ from pymobiledevice3.services.remote_server import RemoteServer
|
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
class DvtTestmanagedProxyService(RemoteServer):
|
|
9
|
-
SERVICE_NAME =
|
|
10
|
-
OLD_SERVICE_NAME =
|
|
11
|
-
RSD_SERVICE_NAME =
|
|
9
|
+
SERVICE_NAME = "com.apple.testmanagerd.lockdown.secure"
|
|
10
|
+
OLD_SERVICE_NAME = "com.apple.testmanagerd.lockdown"
|
|
11
|
+
RSD_SERVICE_NAME = "com.apple.dt.testmanagerd.remote"
|
|
12
12
|
|
|
13
13
|
# TODO: there is also service named 'com.apple.dt.testmanagerd.remote.automation', but not used
|
|
14
14
|
|
|
@@ -16,7 +16,7 @@ class DvtTestmanagedProxyService(RemoteServer):
|
|
|
16
16
|
if isinstance(lockdown, RemoteServiceDiscoveryService): # only happends when >=17.0
|
|
17
17
|
service_name = self.RSD_SERVICE_NAME
|
|
18
18
|
remove_ssl_context = False
|
|
19
|
-
elif Version(lockdown.product_version) >= Version(
|
|
19
|
+
elif Version(lockdown.product_version) >= Version("14.0"):
|
|
20
20
|
service_name = self.SERVICE_NAME
|
|
21
21
|
remove_ssl_context = False
|
|
22
22
|
else:
|
|
@@ -13,8 +13,8 @@ CMD_TABLE_RESET = 0x64
|
|
|
13
13
|
CMD_COPY = 0x65
|
|
14
14
|
CMD_SENTINEL = 0x68
|
|
15
15
|
CMD_STRUCT = 0x69
|
|
16
|
-
CMD_PLACEHOLDER_COUNT =
|
|
17
|
-
CMD_DEBUG =
|
|
16
|
+
CMD_PLACEHOLDER_COUNT = 0x6A
|
|
17
|
+
CMD_DEBUG = 0x6B
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
@dataclasses.dataclass
|
|
@@ -26,7 +26,7 @@ class Table:
|
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
def decode_str(s: bytes):
|
|
29
|
-
return s.split(b
|
|
29
|
+
return s.split(b"\x00", 1)[0].decode()
|
|
30
30
|
|
|
31
31
|
|
|
32
32
|
def ignored_null(s: bytes) -> bytes:
|
|
@@ -39,35 +39,35 @@ def ignored_null(s: bytes) -> bytes:
|
|
|
39
39
|
|
|
40
40
|
|
|
41
41
|
def decode_message_format(message) -> str:
|
|
42
|
-
s =
|
|
42
|
+
s = ""
|
|
43
43
|
for type_, data in message:
|
|
44
44
|
if data and isinstance(data, bytes):
|
|
45
45
|
data = ignored_null(data)
|
|
46
46
|
type_ = decode_str(type_)
|
|
47
47
|
|
|
48
|
-
if type_ ==
|
|
49
|
-
type_ =
|
|
48
|
+
if type_ == "address":
|
|
49
|
+
type_ = "uint64-hex"
|
|
50
50
|
|
|
51
|
-
if type_ in (
|
|
51
|
+
if type_ in ("narrative-text", "string"):
|
|
52
52
|
if data is None:
|
|
53
|
-
s +=
|
|
53
|
+
s += "<None>"
|
|
54
54
|
else:
|
|
55
55
|
s += data.decode()
|
|
56
|
-
elif type_ ==
|
|
57
|
-
s +=
|
|
58
|
-
elif type_.startswith(
|
|
59
|
-
uint64 = struct.unpack(
|
|
60
|
-
if
|
|
56
|
+
elif type_ == "private":
|
|
57
|
+
s += "<private>"
|
|
58
|
+
elif type_.startswith("uint64"):
|
|
59
|
+
uint64 = struct.unpack("<Q", data.ljust(8, b"\x00"))[0]
|
|
60
|
+
if "hex" in type_:
|
|
61
61
|
uint64 = hex(uint64)[2:]
|
|
62
|
-
if
|
|
62
|
+
if "lowercase" in type_:
|
|
63
63
|
uint64 = uint64.lower()
|
|
64
64
|
s += str(uint64)
|
|
65
|
-
elif
|
|
66
|
-
uint64 = struct.unpack(
|
|
65
|
+
elif "decimal" in type_:
|
|
66
|
+
uint64 = struct.unpack("<Q", data.ljust(8, b"\x00"))[0]
|
|
67
67
|
s += str(uint64)
|
|
68
|
-
elif type_ in (
|
|
68
|
+
elif type_ in ("data", "uuid"):
|
|
69
69
|
if data is not None:
|
|
70
|
-
s += b
|
|
70
|
+
s += b"".join(data).hex()
|
|
71
71
|
else:
|
|
72
72
|
# by default, make sure the data can be concatenated
|
|
73
73
|
s += str(data)
|
|
@@ -75,7 +75,7 @@ def decode_message_format(message) -> str:
|
|
|
75
75
|
|
|
76
76
|
|
|
77
77
|
class ActivityTraceTap(Tap):
|
|
78
|
-
IDENTIFIER =
|
|
78
|
+
IDENTIFIER = "com.apple.instruments.server.services.activitytracetap"
|
|
79
79
|
|
|
80
80
|
def __init__(self, dvt, enable_http_archive_logging=False):
|
|
81
81
|
# TODO:
|
|
@@ -83,20 +83,20 @@ class ActivityTraceTap(Tap):
|
|
|
83
83
|
# to understand each row's structure.
|
|
84
84
|
|
|
85
85
|
config = {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
86
|
+
"bm": 0, # buffer mode
|
|
87
|
+
"combineDataScope": 0,
|
|
88
|
+
"machTimebaseDenom": 3,
|
|
89
|
+
"machTimebaseNumer": 125,
|
|
90
|
+
"onlySignposts": 0,
|
|
91
|
+
"pidToInjectCombineDYLIB": "-1",
|
|
92
|
+
"predicate": "(messageType == info OR messageType == debug OR messageType == default OR "
|
|
93
|
+
"messageType == error OR messageType == fault)",
|
|
94
|
+
"signpostsAndLogs": 1,
|
|
95
|
+
"trackPidToExecNameMapping": True,
|
|
96
|
+
"enableHTTPArchiveLogging": enable_http_archive_logging,
|
|
97
|
+
"targetPID": -3, # all Process
|
|
98
|
+
"trackExpiredPIDs": 1,
|
|
99
|
+
"ur": 500,
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
super().__init__(dvt, self.IDENTIFIER, config)
|
|
@@ -107,8 +107,8 @@ class ActivityTraceTap(Tap):
|
|
|
107
107
|
self.tables = []
|
|
108
108
|
|
|
109
109
|
def _get_next_message(self):
|
|
110
|
-
message = b
|
|
111
|
-
while message.startswith(b
|
|
110
|
+
message = b""
|
|
111
|
+
while message.startswith(b"bplist") or len(message) == 0:
|
|
112
112
|
# ignore heartbeat messages
|
|
113
113
|
message = self.channel.receive_message()
|
|
114
114
|
self._set_current_message(message)
|
|
@@ -123,7 +123,7 @@ class ActivityTraceTap(Tap):
|
|
|
123
123
|
buf = self._message.read(2)
|
|
124
124
|
if len(buf) != 2:
|
|
125
125
|
raise EOFError()
|
|
126
|
-
word, = struct.unpack(
|
|
126
|
+
(word,) = struct.unpack("<H", buf)
|
|
127
127
|
self._message.seek(-2, os.SEEK_CUR)
|
|
128
128
|
return word
|
|
129
129
|
|
|
@@ -133,45 +133,45 @@ class ActivityTraceTap(Tap):
|
|
|
133
133
|
return word
|
|
134
134
|
|
|
135
135
|
def _handle_push(self, word):
|
|
136
|
-
assert word >> 14 in (0b10, 0b11), f
|
|
136
|
+
assert word >> 14 in (0b10, 0b11), f"invalid magic for pushed item. word: {hex(word)}"
|
|
137
137
|
|
|
138
138
|
count = 0
|
|
139
139
|
imm = 0
|
|
140
140
|
bit_count = 0
|
|
141
141
|
while word >> 14 != 0b11:
|
|
142
142
|
# not end word
|
|
143
|
-
imm = (imm << 14) | (word &
|
|
143
|
+
imm = (imm << 14) | (word & 0x3FFF)
|
|
144
144
|
word = self._read_word()
|
|
145
145
|
count += 1
|
|
146
146
|
bit_count += 14
|
|
147
147
|
|
|
148
|
-
imm = (imm << 14) | (word &
|
|
148
|
+
imm = (imm << 14) | (word & 0x3FFF)
|
|
149
149
|
bit_count += 14
|
|
150
150
|
|
|
151
|
-
imm <<=
|
|
151
|
+
imm <<= 8 - bit_count % 8
|
|
152
152
|
bit_count += 8 - bit_count % 8
|
|
153
153
|
|
|
154
|
-
result = imm.to_bytes(math.ceil(bit_count / 8),
|
|
154
|
+
result = imm.to_bytes(math.ceil(bit_count / 8), "big")
|
|
155
155
|
self.stack.append(result)
|
|
156
156
|
|
|
157
157
|
return result
|
|
158
158
|
|
|
159
159
|
def _handle_table_reset(self, word):
|
|
160
|
-
"""
|
|
160
|
+
"""start new table vector"""
|
|
161
161
|
self.generation += 1
|
|
162
162
|
self.background = 0
|
|
163
163
|
self.stack = []
|
|
164
164
|
|
|
165
165
|
def _handle_sentinel(self, word):
|
|
166
|
-
"""
|
|
166
|
+
"""push a dummy"""
|
|
167
167
|
self.stack.append(None)
|
|
168
168
|
|
|
169
169
|
def _handle_struct(self, word):
|
|
170
|
-
"""
|
|
171
|
-
distance = word &
|
|
170
|
+
"""replace last `distance` items with a single one which represents them as a tuple"""
|
|
171
|
+
distance = word & 0xFF
|
|
172
172
|
|
|
173
|
-
if distance ==
|
|
174
|
-
raise NotImplementedError(
|
|
173
|
+
if distance == 0xFF:
|
|
174
|
+
raise NotImplementedError("long struct")
|
|
175
175
|
|
|
176
176
|
new_item = self.stack[-distance:]
|
|
177
177
|
|
|
@@ -179,71 +179,82 @@ class ActivityTraceTap(Tap):
|
|
|
179
179
|
self.stack.append(new_item)
|
|
180
180
|
|
|
181
181
|
def _handle_define_table(self, word):
|
|
182
|
-
"""
|
|
182
|
+
"""define a table struct"""
|
|
183
183
|
distance = 4
|
|
184
184
|
|
|
185
185
|
table_raw = Table(*self.stack[-distance:])
|
|
186
|
-
table = Table(
|
|
187
|
-
|
|
188
|
-
|
|
186
|
+
table = Table(
|
|
187
|
+
name=table_raw.name.split(b"\x00", 1)[0].decode(),
|
|
188
|
+
columns=[c.split(b"\x00", 1)[0].decode() for c in table_raw.columns],
|
|
189
|
+
unknown0=table_raw.unknown0,
|
|
190
|
+
unknown2=table_raw.unknown2,
|
|
191
|
+
)
|
|
189
192
|
|
|
190
193
|
self.stack = self.stack[:-distance]
|
|
191
194
|
self.tables.append(table)
|
|
192
195
|
|
|
193
196
|
def _handle_debug(self, word):
|
|
194
|
-
"""
|
|
195
|
-
debug_id = word &
|
|
197
|
+
"""pop last pushed item from stack"""
|
|
198
|
+
debug_id = word & 0xFF
|
|
196
199
|
item = self.stack[-1]
|
|
197
200
|
|
|
198
|
-
reference = int.from_bytes(item, byteorder=
|
|
201
|
+
reference = int.from_bytes(item, byteorder="little")
|
|
199
202
|
|
|
200
|
-
assert reference == len(self.stack) - 1,
|
|
201
|
-
f
|
|
203
|
+
assert reference == len(self.stack) - 1, (
|
|
204
|
+
f"assert debug {debug_id} got reference: {hex(reference)} instead of: {len(self.stack) - 1} {item}"
|
|
205
|
+
)
|
|
202
206
|
self.stack = self.stack[:-1]
|
|
203
207
|
|
|
204
208
|
def _handle_copy(self, word):
|
|
205
|
-
"""
|
|
206
|
-
distance = word &
|
|
207
|
-
if distance !=
|
|
209
|
+
"""copy item at distance from stack"""
|
|
210
|
+
distance = word & 0xFF
|
|
211
|
+
if distance != 0xFF:
|
|
208
212
|
item = self.stack[-distance - 1]
|
|
209
213
|
self.stack.append(item)
|
|
210
214
|
else:
|
|
211
215
|
# long struct - pop distance from stack
|
|
212
216
|
item = self.stack[-1]
|
|
213
|
-
reference = int.from_bytes(item, byteorder=
|
|
217
|
+
reference = int.from_bytes(item, byteorder="little") - 1
|
|
214
218
|
self.stack = self.stack[:-1]
|
|
215
219
|
self.stack.append(self.stack[reference])
|
|
216
220
|
|
|
217
221
|
def _handle_end_row(self, word):
|
|
218
|
-
"""
|
|
219
|
-
generation = word &
|
|
222
|
+
"""flush current row"""
|
|
223
|
+
generation = word & 0xFF
|
|
220
224
|
columns = self.tables[generation].columns
|
|
221
|
-
row = self.stack[-len(columns):]
|
|
222
|
-
self.stack = self.stack[
|
|
225
|
+
row = self.stack[-len(columns) :]
|
|
226
|
+
self.stack = self.stack[: -len(columns)]
|
|
223
227
|
|
|
224
|
-
Message = dataclasses.make_dataclass(
|
|
228
|
+
Message = dataclasses.make_dataclass("message", [c.replace("-", "_") for c in columns])
|
|
225
229
|
message = Message(*row)
|
|
226
|
-
message.process = 0 if message.process is None else struct.unpack(
|
|
227
|
-
message.thread = struct.unpack(
|
|
228
|
-
|
|
229
|
-
string_fields = (
|
|
230
|
-
|
|
230
|
+
message.process = 0 if message.process is None else struct.unpack("<I", message.process[0].ljust(4, b"\x00"))[0]
|
|
231
|
+
message.thread = struct.unpack("<I", message.thread[0].ljust(4, b"\x00"))[0]
|
|
232
|
+
|
|
233
|
+
string_fields = (
|
|
234
|
+
"message_type",
|
|
235
|
+
"format_string",
|
|
236
|
+
"subsystem",
|
|
237
|
+
"category",
|
|
238
|
+
"sender_image_path",
|
|
239
|
+
"event_type",
|
|
240
|
+
"name",
|
|
241
|
+
)
|
|
231
242
|
for f in string_fields:
|
|
232
243
|
if hasattr(message, f):
|
|
233
244
|
v = getattr(message, f)
|
|
234
245
|
setattr(message, f, decode_str(v) if v else v)
|
|
235
246
|
|
|
236
|
-
if hasattr(message,
|
|
247
|
+
if hasattr(message, "message"):
|
|
237
248
|
return message
|
|
238
249
|
|
|
239
250
|
def _handle_placeholder_count(self, word):
|
|
240
|
-
"""
|
|
241
|
-
count = word &
|
|
251
|
+
"""remove `count` last items from stack"""
|
|
252
|
+
count = word & 0xFF
|
|
242
253
|
if count > 0:
|
|
243
254
|
self.stack = self.stack[:-count]
|
|
244
255
|
|
|
245
256
|
def _handle_convert_mach_continuous(self, word):
|
|
246
|
-
"""
|
|
257
|
+
"""push an item and pop it. effectively do nothing"""
|
|
247
258
|
pass
|
|
248
259
|
|
|
249
260
|
def _parse(self):
|
|
@@ -2,7 +2,7 @@ from pymobiledevice3.services.remote_server import MessageAux
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
class ApplicationListing:
|
|
5
|
-
IDENTIFIER =
|
|
5
|
+
IDENTIFIER = "com.apple.instruments.server.services.device.applictionListing"
|
|
6
6
|
|
|
7
7
|
def __init__(self, dvt):
|
|
8
8
|
self._channel = dvt.make_channel(self.IDENTIFIER)
|
|
@@ -12,8 +12,7 @@ class ApplicationListing:
|
|
|
12
12
|
Get the applications list from the device.
|
|
13
13
|
:return: List of applications and their attributes.
|
|
14
14
|
"""
|
|
15
|
-
self._channel.installedApplicationsMatching_registerUpdateToken_(
|
|
16
|
-
MessageAux().append_obj({}).append_obj(''))
|
|
15
|
+
self._channel.installedApplicationsMatching_registerUpdateToken_(MessageAux().append_obj({}).append_obj(""))
|
|
17
16
|
result = self._channel.receive_plist()
|
|
18
17
|
assert isinstance(result, list)
|
|
19
18
|
return result
|
|
@@ -5,7 +5,7 @@ from pymobiledevice3.services.remote_server import MessageAux
|
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
class ConditionInducer:
|
|
8
|
-
IDENTIFIER =
|
|
8
|
+
IDENTIFIER = "com.apple.instruments.server.services.ConditionInducer"
|
|
9
9
|
|
|
10
10
|
def __init__(self, dvt):
|
|
11
11
|
self.logger = logging.getLogger(__name__)
|
|
@@ -17,15 +17,16 @@ class ConditionInducer:
|
|
|
17
17
|
|
|
18
18
|
def set(self, profile_identifier):
|
|
19
19
|
for group in self.list():
|
|
20
|
-
for profile in group.get(
|
|
21
|
-
if profile_identifier == profile.get(
|
|
22
|
-
self.logger.info(profile.get(
|
|
20
|
+
for profile in group.get("profiles"):
|
|
21
|
+
if profile_identifier == profile.get("identifier"):
|
|
22
|
+
self.logger.info(profile.get("description"))
|
|
23
23
|
self._channel.enableConditionWithIdentifier_profileIdentifier_(
|
|
24
|
-
MessageAux().append_obj(group.get(
|
|
24
|
+
MessageAux().append_obj(group.get("identifier")).append_obj(profile.get("identifier"))
|
|
25
|
+
)
|
|
25
26
|
# wait for response which may be a raised NSError
|
|
26
27
|
self._channel.receive_plist()
|
|
27
28
|
return
|
|
28
|
-
raise PyMobileDevice3Exception(
|
|
29
|
+
raise PyMobileDevice3Exception("Invalid profile identifier")
|
|
29
30
|
|
|
30
31
|
def clear(self):
|
|
31
32
|
self._channel.disableActiveCondition()
|