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.
Files changed (164) hide show
  1. misc/plist_sniffer.py +15 -15
  2. misc/remotexpc_sniffer.py +29 -28
  3. misc/understanding_idevice_protocol_layers.md +15 -10
  4. pymobiledevice3/__main__.py +317 -127
  5. pymobiledevice3/_version.py +22 -4
  6. pymobiledevice3/bonjour.py +358 -113
  7. pymobiledevice3/ca.py +253 -16
  8. pymobiledevice3/cli/activation.py +31 -23
  9. pymobiledevice3/cli/afc.py +49 -40
  10. pymobiledevice3/cli/amfi.py +16 -21
  11. pymobiledevice3/cli/apps.py +87 -42
  12. pymobiledevice3/cli/backup.py +160 -90
  13. pymobiledevice3/cli/bonjour.py +44 -40
  14. pymobiledevice3/cli/cli_common.py +204 -198
  15. pymobiledevice3/cli/companion_proxy.py +14 -14
  16. pymobiledevice3/cli/crash.py +105 -56
  17. pymobiledevice3/cli/developer/__init__.py +62 -0
  18. pymobiledevice3/cli/developer/accessibility/__init__.py +65 -0
  19. pymobiledevice3/cli/developer/accessibility/settings.py +43 -0
  20. pymobiledevice3/cli/developer/arbitration.py +50 -0
  21. pymobiledevice3/cli/developer/condition.py +33 -0
  22. pymobiledevice3/cli/developer/core_device.py +294 -0
  23. pymobiledevice3/cli/developer/debugserver.py +244 -0
  24. pymobiledevice3/cli/developer/dvt/__init__.py +438 -0
  25. pymobiledevice3/cli/developer/dvt/core_profile_session.py +295 -0
  26. pymobiledevice3/cli/developer/dvt/simulate_location.py +56 -0
  27. pymobiledevice3/cli/developer/dvt/sysmon/__init__.py +69 -0
  28. pymobiledevice3/cli/developer/dvt/sysmon/process.py +188 -0
  29. pymobiledevice3/cli/developer/fetch_symbols.py +108 -0
  30. pymobiledevice3/cli/developer/simulate_location.py +51 -0
  31. pymobiledevice3/cli/diagnostics/__init__.py +75 -0
  32. pymobiledevice3/cli/diagnostics/battery.py +47 -0
  33. pymobiledevice3/cli/idam.py +42 -0
  34. pymobiledevice3/cli/lockdown.py +108 -103
  35. pymobiledevice3/cli/mounter.py +158 -99
  36. pymobiledevice3/cli/notification.py +38 -26
  37. pymobiledevice3/cli/pcap.py +45 -24
  38. pymobiledevice3/cli/power_assertion.py +18 -17
  39. pymobiledevice3/cli/processes.py +17 -23
  40. pymobiledevice3/cli/profile.py +165 -109
  41. pymobiledevice3/cli/provision.py +35 -34
  42. pymobiledevice3/cli/remote.py +217 -129
  43. pymobiledevice3/cli/restore.py +159 -143
  44. pymobiledevice3/cli/springboard.py +63 -53
  45. pymobiledevice3/cli/syslog.py +193 -86
  46. pymobiledevice3/cli/usbmux.py +73 -33
  47. pymobiledevice3/cli/version.py +5 -7
  48. pymobiledevice3/cli/webinspector.py +376 -214
  49. pymobiledevice3/common.py +3 -1
  50. pymobiledevice3/exceptions.py +182 -58
  51. pymobiledevice3/irecv.py +52 -53
  52. pymobiledevice3/irecv_devices.py +1489 -464
  53. pymobiledevice3/lockdown.py +473 -275
  54. pymobiledevice3/lockdown_service_provider.py +15 -8
  55. pymobiledevice3/osu/os_utils.py +27 -9
  56. pymobiledevice3/osu/posix_util.py +34 -15
  57. pymobiledevice3/osu/win_util.py +14 -8
  58. pymobiledevice3/pair_records.py +102 -21
  59. pymobiledevice3/remote/common.py +8 -4
  60. pymobiledevice3/remote/core_device/app_service.py +94 -67
  61. pymobiledevice3/remote/core_device/core_device_service.py +17 -14
  62. pymobiledevice3/remote/core_device/device_info.py +5 -5
  63. pymobiledevice3/remote/core_device/diagnostics_service.py +19 -4
  64. pymobiledevice3/remote/core_device/file_service.py +53 -23
  65. pymobiledevice3/remote/remote_service_discovery.py +79 -45
  66. pymobiledevice3/remote/remotexpc.py +73 -44
  67. pymobiledevice3/remote/tunnel_service.py +442 -317
  68. pymobiledevice3/remote/utils.py +14 -13
  69. pymobiledevice3/remote/xpc_message.py +145 -125
  70. pymobiledevice3/resources/dsc_uuid_map.py +19 -19
  71. pymobiledevice3/resources/firmware_notifications.py +20 -16
  72. pymobiledevice3/resources/notifications.txt +144 -0
  73. pymobiledevice3/restore/asr.py +27 -27
  74. pymobiledevice3/restore/base_restore.py +110 -21
  75. pymobiledevice3/restore/consts.py +87 -66
  76. pymobiledevice3/restore/device.py +59 -12
  77. pymobiledevice3/restore/fdr.py +46 -48
  78. pymobiledevice3/restore/ftab.py +19 -19
  79. pymobiledevice3/restore/img4.py +163 -0
  80. pymobiledevice3/restore/mbn.py +587 -0
  81. pymobiledevice3/restore/recovery.py +151 -151
  82. pymobiledevice3/restore/restore.py +562 -544
  83. pymobiledevice3/restore/restore_options.py +131 -110
  84. pymobiledevice3/restore/restored_client.py +51 -31
  85. pymobiledevice3/restore/tss.py +385 -267
  86. pymobiledevice3/service_connection.py +252 -59
  87. pymobiledevice3/services/accessibilityaudit.py +202 -120
  88. pymobiledevice3/services/afc.py +962 -365
  89. pymobiledevice3/services/amfi.py +24 -30
  90. pymobiledevice3/services/companion.py +23 -19
  91. pymobiledevice3/services/crash_reports.py +71 -47
  92. pymobiledevice3/services/debugserver_applist.py +3 -3
  93. pymobiledevice3/services/device_arbitration.py +8 -8
  94. pymobiledevice3/services/device_link.py +101 -79
  95. pymobiledevice3/services/diagnostics.py +973 -967
  96. pymobiledevice3/services/dtfetchsymbols.py +8 -8
  97. pymobiledevice3/services/dvt/dvt_secure_socket_proxy.py +4 -4
  98. pymobiledevice3/services/dvt/dvt_testmanaged_proxy.py +4 -4
  99. pymobiledevice3/services/dvt/instruments/activity_trace_tap.py +85 -74
  100. pymobiledevice3/services/dvt/instruments/application_listing.py +2 -3
  101. pymobiledevice3/services/dvt/instruments/condition_inducer.py +7 -6
  102. pymobiledevice3/services/dvt/instruments/core_profile_session_tap.py +466 -384
  103. pymobiledevice3/services/dvt/instruments/device_info.py +20 -11
  104. pymobiledevice3/services/dvt/instruments/energy_monitor.py +1 -1
  105. pymobiledevice3/services/dvt/instruments/graphics.py +1 -1
  106. pymobiledevice3/services/dvt/instruments/location_simulation.py +1 -1
  107. pymobiledevice3/services/dvt/instruments/location_simulation_base.py +10 -10
  108. pymobiledevice3/services/dvt/instruments/network_monitor.py +17 -17
  109. pymobiledevice3/services/dvt/instruments/notifications.py +1 -1
  110. pymobiledevice3/services/dvt/instruments/process_control.py +35 -10
  111. pymobiledevice3/services/dvt/instruments/screenshot.py +2 -2
  112. pymobiledevice3/services/dvt/instruments/sysmontap.py +15 -15
  113. pymobiledevice3/services/dvt/testmanaged/xcuitest.py +42 -52
  114. pymobiledevice3/services/file_relay.py +10 -10
  115. pymobiledevice3/services/heartbeat.py +9 -8
  116. pymobiledevice3/services/house_arrest.py +16 -15
  117. pymobiledevice3/services/idam.py +20 -0
  118. pymobiledevice3/services/installation_proxy.py +173 -81
  119. pymobiledevice3/services/lockdown_service.py +20 -10
  120. pymobiledevice3/services/misagent.py +22 -19
  121. pymobiledevice3/services/mobile_activation.py +147 -64
  122. pymobiledevice3/services/mobile_config.py +331 -294
  123. pymobiledevice3/services/mobile_image_mounter.py +141 -113
  124. pymobiledevice3/services/mobilebackup2.py +203 -145
  125. pymobiledevice3/services/notification_proxy.py +11 -11
  126. pymobiledevice3/services/os_trace.py +134 -74
  127. pymobiledevice3/services/pcapd.py +314 -302
  128. pymobiledevice3/services/power_assertion.py +10 -9
  129. pymobiledevice3/services/preboard.py +4 -4
  130. pymobiledevice3/services/remote_fetch_symbols.py +21 -14
  131. pymobiledevice3/services/remote_server.py +176 -146
  132. pymobiledevice3/services/restore_service.py +16 -16
  133. pymobiledevice3/services/screenshot.py +15 -12
  134. pymobiledevice3/services/simulate_location.py +7 -7
  135. pymobiledevice3/services/springboard.py +15 -15
  136. pymobiledevice3/services/syslog.py +5 -5
  137. pymobiledevice3/services/web_protocol/alert.py +11 -11
  138. pymobiledevice3/services/web_protocol/automation_session.py +251 -239
  139. pymobiledevice3/services/web_protocol/cdp_screencast.py +46 -37
  140. pymobiledevice3/services/web_protocol/cdp_server.py +19 -19
  141. pymobiledevice3/services/web_protocol/cdp_target.py +411 -373
  142. pymobiledevice3/services/web_protocol/driver.py +114 -111
  143. pymobiledevice3/services/web_protocol/element.py +124 -111
  144. pymobiledevice3/services/web_protocol/inspector_session.py +106 -102
  145. pymobiledevice3/services/web_protocol/selenium_api.py +49 -49
  146. pymobiledevice3/services/web_protocol/session_protocol.py +18 -12
  147. pymobiledevice3/services/web_protocol/switch_to.py +30 -27
  148. pymobiledevice3/services/webinspector.py +189 -155
  149. pymobiledevice3/tcp_forwarder.py +87 -69
  150. pymobiledevice3/tunneld/__init__.py +0 -0
  151. pymobiledevice3/tunneld/api.py +63 -0
  152. pymobiledevice3/tunneld/server.py +603 -0
  153. pymobiledevice3/usbmux.py +198 -147
  154. pymobiledevice3/utils.py +14 -11
  155. {pymobiledevice3-4.14.6.dist-info → pymobiledevice3-7.0.6.dist-info}/METADATA +55 -28
  156. pymobiledevice3-7.0.6.dist-info/RECORD +188 -0
  157. {pymobiledevice3-4.14.6.dist-info → pymobiledevice3-7.0.6.dist-info}/WHEEL +1 -1
  158. pymobiledevice3/cli/developer.py +0 -1215
  159. pymobiledevice3/cli/diagnostics.py +0 -99
  160. pymobiledevice3/tunneld.py +0 -524
  161. pymobiledevice3-4.14.6.dist-info/RECORD +0 -168
  162. {pymobiledevice3-4.14.6.dist-info → pymobiledevice3-7.0.6.dist-info}/entry_points.txt +0 -0
  163. {pymobiledevice3-4.14.6.dist-info → pymobiledevice3-7.0.6.dist-info/licenses}/LICENSE +0 -0
  164. {pymobiledevice3-4.14.6.dist-info → pymobiledevice3-7.0.6.dist-info}/top_level.txt +0 -0
misc/plist_sniffer.py CHANGED
@@ -7,8 +7,8 @@ import click
7
7
  from scapy.packet import Packet, Raw
8
8
  from scapy.sendrecv import sniff
9
9
 
10
- BPLIST_MAGIC = b'bplist'
11
- PLIST_MAGIC = b'<plist'
10
+ BPLIST_MAGIC = b"bplist"
11
+ PLIST_MAGIC = b"<plist"
12
12
 
13
13
 
14
14
  class PcapSniffer:
@@ -20,13 +20,13 @@ class PcapSniffer:
20
20
 
21
21
  if BPLIST_MAGIC in packet:
22
22
  try:
23
- plist = plistlib.loads(packet[packet.find(BPLIST_MAGIC):])
23
+ plist = plistlib.loads(packet[packet.find(BPLIST_MAGIC) :])
24
24
  self.report(plist)
25
25
  except plistlib.InvalidFileException:
26
26
  pass
27
27
  if PLIST_MAGIC in packet:
28
28
  try:
29
- plist = plistlib.loads(packet[packet.find(PLIST_MAGIC):])
29
+ plist = plistlib.loads(packet[packet.find(PLIST_MAGIC) :])
30
30
  self.report(plist)
31
31
  except xml.parsers.expat.ExpatError:
32
32
  pass
@@ -35,37 +35,37 @@ class PcapSniffer:
35
35
  try:
36
36
  print(plist)
37
37
  if self.file is not None:
38
- self.file.write('---\n')
38
+ self.file.write("---\n")
39
39
  self.file.write(pprint.pformat(plist))
40
- self.file.write('\n---\n')
40
+ self.file.write("\n---\n")
41
41
  except ValueError:
42
- print('failed to print plist')
42
+ print("failed to print plist")
43
43
 
44
44
 
45
45
  @click.group()
46
46
  def cli():
47
- """ Parse RemoteXPC traffic """
47
+ """Parse RemoteXPC traffic"""
48
48
  pass
49
49
 
50
50
 
51
51
  @cli.command()
52
- @click.argument('pcap', type=click.Path(exists=True, file_okay=True, dir_okay=False))
53
- @click.option('-o', '--out', type=click.File('wt'))
52
+ @click.argument("pcap", type=click.Path(exists=True, file_okay=True, dir_okay=False))
53
+ @click.option("-o", "--out", type=click.File("wt"))
54
54
  def offline(pcap: str, out: IO):
55
- """ Parse plists traffic from a .pcap file """
55
+ """Parse plists traffic from a .pcap file"""
56
56
  sniffer = PcapSniffer(out)
57
57
  for p in sniff(offline=pcap):
58
58
  sniffer.process_packet(p)
59
59
 
60
60
 
61
61
  @cli.command()
62
- @click.argument('iface')
63
- @click.option('-o', '--out', type=click.File('wt'))
62
+ @click.argument("iface")
63
+ @click.option("-o", "--out", type=click.File("wt"))
64
64
  def live(iface: str, out: IO):
65
- """ Parse plists live from a given network interface """
65
+ """Parse plists live from a given network interface"""
66
66
  sniffer = PcapSniffer(out)
67
67
  sniff(iface=iface, prn=sniffer.process_packet)
68
68
 
69
69
 
70
- if __name__ == '__main__':
70
+ if __name__ == "__main__":
71
71
  cli()
misc/remotexpc_sniffer.py CHANGED
@@ -22,7 +22,7 @@ FRAME_HEADER_SIZE = 9
22
22
 
23
23
 
24
24
  def create_stream_key(src: str, sport: int, dst: str, dport: int) -> str:
25
- return f'{src}/{sport}//{dst}/{dport}'
25
+ return f"{src}/{sport}//{dst}/{dport}"
26
26
 
27
27
 
28
28
  class TCPStream:
@@ -37,7 +37,7 @@ class TCPStream:
37
37
  self.segments = {} # data segments to add later
38
38
 
39
39
  def __repr__(self) -> str:
40
- return f'Stream<{self.key}>'
40
+ return f"Stream<{self.key}>"
41
41
 
42
42
  def __len__(self) -> int:
43
43
  return len(self.data)
@@ -58,12 +58,12 @@ class TCPStream:
58
58
  return False
59
59
  else:
60
60
  # if this data is in order (has a place to be inserted)
61
- self.data[seq_offset:seq_offset + data_len] = data
61
+ self.data[seq_offset : seq_offset + data_len] = data
62
62
  # check if there are any waiting data segments to add
63
63
  for seq_offset in sorted(self.segments.keys()):
64
64
  if seq_offset <= len(self.data): # if we can add this segment to the stream
65
65
  segment_payload = self.segments[seq_offset]
66
- self.data[seq_offset:seq_offset + len(segment_payload)] = segment_payload
66
+ self.data[seq_offset : seq_offset + len(segment_payload)] = segment_payload
67
67
  self.segments.pop(seq_offset)
68
68
  else:
69
69
  break # short circuit because list is sorted
@@ -72,12 +72,12 @@ class TCPStream:
72
72
 
73
73
  class H2Stream(TCPStream):
74
74
  def pop_frames(self) -> list[Frame]:
75
- """ Pop all available H2Frames """
75
+ """Pop all available H2Frames"""
76
76
 
77
77
  # If self.data starts with the http/2 magic bytes, pop them off
78
78
  if self.data.startswith(HTTP2_MAGIC):
79
- logger.debug('HTTP/2 magic bytes')
80
- self.data = self.data[len(HTTP2_MAGIC):]
79
+ logger.debug("HTTP/2 magic bytes")
80
+ self.data = self.data[len(HTTP2_MAGIC) :]
81
81
  self.seq += len(HTTP2_MAGIC)
82
82
 
83
83
  frames = []
@@ -120,13 +120,14 @@ class RemoteXPCSniffer:
120
120
  tcp_pkt = pkt[TCP]
121
121
  stream_key = create_stream_key(net_pkt.src, tcp_pkt.sport, net_pkt.dst, tcp_pkt.dport)
122
122
  stream = self._h2_streams.setdefault(
123
- stream_key, H2Stream(net_pkt.src, tcp_pkt.sport, net_pkt.dst, tcp_pkt.dport))
123
+ stream_key, H2Stream(net_pkt.src, tcp_pkt.sport, net_pkt.dst, tcp_pkt.dport)
124
+ )
124
125
  stream_finished_assembling = stream.add(tcp_pkt)
125
126
  if stream_finished_assembling: # if we just added something in order
126
127
  self._process_stream(stream)
127
128
 
128
129
  def _handle_data_frame(self, stream: H2Stream, frame: DataFrame) -> None:
129
- previous_frame_data = self._previous_frame_data.get(stream.key, b'')
130
+ previous_frame_data = self._previous_frame_data.get(stream.key, b"")
130
131
  try:
131
132
  payload = XpcWrapper.parse(previous_frame_data + frame.data).message.payload
132
133
  if payload is None:
@@ -134,10 +135,11 @@ class RemoteXPCSniffer:
134
135
  xpc_message = decode_xpc_object(payload.obj)
135
136
  except ConstError: # if we don't know what this payload is
136
137
  logger.debug(
137
- f'New Data frame {stream.src}->{stream.dst} on HTTP/2 stream {frame.stream_id} TCP port {stream.dport}')
138
+ f"New Data frame {stream.src}->{stream.dst} on HTTP/2 stream {frame.stream_id} TCP port {stream.dport}"
139
+ )
138
140
  hexdump(frame.data[:64])
139
141
  if len(frame.data) > 64:
140
- logger.debug(f'... {len(frame.data)} bytes')
142
+ logger.debug(f"... {len(frame.data)} bytes")
141
143
  return
142
144
  except StreamError:
143
145
  self._previous_frame_data[stream.key] = previous_frame_data + frame.data
@@ -149,27 +151,26 @@ class RemoteXPCSniffer:
149
151
  if xpc_message is None:
150
152
  return
151
153
 
152
- logger.info(f'As Python Object (#{frame.stream_id}): {pformat(xpc_message)}')
154
+ logger.info(f"As Python Object (#{frame.stream_id}): {pformat(xpc_message)}")
153
155
 
154
156
  # print `pairingData` if exists, since it contains an inner struct
155
- if 'value' not in xpc_message:
157
+ if "value" not in xpc_message:
156
158
  return
157
- message = xpc_message['value']['message']
158
- if 'plain' not in message:
159
+ message = xpc_message["value"]["message"]
160
+ if "plain" not in message:
159
161
  return
160
- plain = message['plain']['_0']
161
- if 'event' not in plain:
162
+ plain = message["plain"]["_0"]
163
+ if "event" not in plain:
162
164
  return
163
- pairing_data = plain['event']['_0']['pairingData']['_0']['data']
165
+ pairing_data = plain["event"]["_0"]["pairingData"]["_0"]["data"]
164
166
  logger.info(PairingDataComponentTLVBuf.parse(pairing_data))
165
167
 
166
168
  def _handle_single_frame(self, stream: H2Stream, frame: Frame) -> None:
167
- logger.debug(f'New HTTP/2 frame: {stream.key} ({frame})')
169
+ logger.debug(f"New HTTP/2 frame: {stream.key} ({frame})")
168
170
  if isinstance(frame, HeadersFrame):
169
- logger.debug(
170
- f'{stream.src} opening stream {frame.stream_id} for communication on port {stream.dport}')
171
+ logger.debug(f"{stream.src} opening stream {frame.stream_id} for communication on port {stream.dport}")
171
172
  elif isinstance(frame, GoAwayFrame):
172
- logger.debug(f'{stream.src} closing stream {frame.stream_id} on port {stream.sport}')
173
+ logger.debug(f"{stream.src} closing stream {frame.stream_id} on port {stream.sport}")
173
174
  elif isinstance(frame, DataFrame):
174
175
  self._handle_data_frame(stream, frame)
175
176
 
@@ -180,27 +181,27 @@ class RemoteXPCSniffer:
180
181
 
181
182
  @click.group()
182
183
  def cli():
183
- """ Parse RemoteXPC traffic """
184
+ """Parse RemoteXPC traffic"""
184
185
  pass
185
186
 
186
187
 
187
188
  @cli.command()
188
- @click.argument('file', type=click.Path(exists=True, file_okay=True, dir_okay=False))
189
+ @click.argument("file", type=click.Path(exists=True, file_okay=True, dir_okay=False))
189
190
  def offline(file: str):
190
- """ Parse RemoteXPC traffic from a .pcap file """
191
+ """Parse RemoteXPC traffic from a .pcap file"""
191
192
  sniffer = RemoteXPCSniffer()
192
193
  for p in sniff(offline=file):
193
194
  sniffer.process_packet(p)
194
195
 
195
196
 
196
197
  @cli.command()
197
- @click.argument('iface')
198
+ @click.argument("iface")
198
199
  def live(iface: str):
199
- """ Parse RemoteXPC live from a given network interface """
200
+ """Parse RemoteXPC live from a given network interface"""
200
201
  sniffer = RemoteXPCSniffer()
201
202
  sniff(iface=iface, prn=sniffer.process_packet)
202
203
 
203
204
 
204
- if __name__ == '__main__':
205
+ if __name__ == "__main__":
205
206
  coloredlogs.install(level=logging.DEBUG)
206
207
  cli()
@@ -121,10 +121,10 @@ this feature over USB:
121
121
 
122
122
  ```shell
123
123
  # Turn it on
124
- pymobiledevice3 lockdown wifi-connection on
124
+ pymobiledevice3 lockdown wifi-connections on
125
125
 
126
126
  # Or off
127
- pymobiledevice3 lockdown wifi-connection off
127
+ pymobiledevice3 lockdown wifi-connections off
128
128
  ```
129
129
 
130
130
  Now the device will use the [bonjour](https://en.wikipedia.org/wiki/Bonjour_(software)) protocol in order to announce
@@ -197,7 +197,7 @@ from pymobiledevice3.lockdown import create_using_usbmux
197
197
  lockdown = create_using_usbmux()
198
198
 
199
199
  # Get a handle to the service
200
- service = lockdown.start_lockdown_service(SERIVCE_NAME)
200
+ service = lockdown.start_lockdown_service(SERVICE_NAME)
201
201
 
202
202
  # Attempt to send and receive messages from it
203
203
  service.sendall(b'hello')
@@ -287,14 +287,14 @@ pymobiledevice3 developer dvt launch com.apple.mobilesafari
287
287
 
288
288
  ## DVT
289
289
 
290
- One of the more interesting developer services, is the one exposed by `DTServiceHub`. It is using DTX protocol messages,
290
+ One of the more interesting developer services is the one exposed by `DTServiceHub`. It is using DTX protocol messages,
291
291
  but since it mainly wraps and allows access to stuff in `DVTFoundation.framework` we called it DVT in our
292
292
  implementation (probably standing for DeveloperTools).
293
293
 
294
294
  We don't delve too much into this protocol, but we'll say in general it allows us to invoke a whitelist of ObjC methods
295
295
  in different ObjC objects. The terminology used by DVT to each such ObjC object is called "channels".
296
296
 
297
- In order to access this different object use the following APIs:
297
+ To access this different object use the following APIs:
298
298
 
299
299
  ```python
300
300
  from pymobiledevice3.lockdown import create_using_usbmux
@@ -313,17 +313,22 @@ dvt_channel = Screenshot(dvt)
313
313
  open('/tmp/screen.png', 'wb').write(dvt_channel.get_screenshot())
314
314
  ```
315
315
 
316
- Looking for an unimplemented feature/channel? Feel free to play with it (and submit a PR afterwards 🙏) using the
316
+ Looking for an unimplemented feature/channel? Feel free to play with it (and submit a PR afterward 🙏) using the
317
317
  following shell:
318
318
 
319
319
  ```shell
320
320
  pymobiledevice3 developer dvt shell
321
321
  ```
322
322
 
323
+ > **NOTE:** The full list of the methods that can be invoked on a DVT channel can be found by looking at all ObjC
324
+ > classes in `DVTInstrumentsFoundation.framework` implementing the `DTXAllowedRPC` protocol.
325
+ > There is an existing [Anubis rule](https://github.com/netanelc305/anubis/blob/9da337178ebd7e9f168e9df2d82b192eba4f1b30/example_rules.yaml#L14-L17)
326
+ > I use to diff new methods against the existing ones.
327
+
323
328
  ## RemoteXPC
324
329
 
325
330
  Starting at iOS 17.0, Apple made a large refactor in the manner we all interact with the developer services. There can
326
- be multiple reasons for that decision, but in general this refactor main key points are:
331
+ be multiple reasons for that decision, but in general these refactor main key points are:
327
332
 
328
333
  - Create a single standard for interacting with the new lockdown services (XPC Messages, Apple's proprietary IPC)
329
334
  - Optimize the protocol for large file transfers (such as the dyld_shared_cache)
@@ -347,10 +352,10 @@ Since all this communication is IP-based, but without any additional exported TC
347
352
  help us here. Instead, starting at iOS 16.0, when connecting an iDevice, it exports another non-standard USB-Ethernet
348
353
  adapter (with IPv6 link-local address), placing us in a subnet with the device's `remoted`.
349
354
 
350
- As we've said this communication is non-standard, and requires either:
355
+ As we've said, this communication is non-standard and requires either:
351
356
 
352
357
  - macOS Monterey or higher
353
- - Special driver on your linux/windows machine
358
+ - Special driver on your linux/Windows machine
354
359
 
355
360
  > **Spoiler Alert:** Apple may have regretted this, since starting at iOS 17.4, they added the `CodeDeviceProxy` - a new
356
361
  > lockdown service, allowing us skip all the steps this special driver is required for.
@@ -475,7 +480,7 @@ pymobiledevice3 developer dvt launch com.apple.mobilesafari --tunnel '11223344'
475
480
  This is of course also available via a python API:
476
481
 
477
482
  ```python
478
- from pymobiledevice3.tunneld import async_get_tunneld_devices
483
+ from pymobiledevice3.tunneld.api import async_get_tunneld_devices
479
484
  from pymobiledevice3.services.os_trace import OsTraceService
480
485
 
481
486
  rsds = await async_get_tunneld_devices()