Pure python3 implementation for working with iDevices (iPhone, etc...).
See NEWS.
pymobiledevice3
is a pure python3 implementation for working with iDevices (iPhone, etc...). This means this tool is
both architecture and platform generic and is supported and tested on:
Main features include:
notify_post()
api)top
like)You can install from PyPi:
python3 -m pip install -U pymobiledevice3
Or install the latest version directly from sources:
git clone [email protected]:doronz88/pymobiledevice3.git
cd pymobiledevice3
python3 -m pip install -U -e .
You can also install auto-completion for all available sub-commands by adding the following into your ~/.zshrc
:
# python-click<8.0
eval "$(_PYMOBILEDEVICE3_COMPLETE=source_zsh pymobiledevice3)"
# python-click>=8.0
eval "$(_PYMOBILEDEVICE3_COMPLETE=zsh_source pymobiledevice3)"
Currently, openssl is explicitly required if using on older iOS version (<13).
On macOS:
brew install openssl
On Linux:
sudo apt install openssl
The CLI subcommands are divided roughly by the protocol layer used for interacting in the device. For example, all
features derived from the DeveloperDiskImage will be accessible from the developer
subcommand. This also means that every feature which isn't there won't require it.
This is the main CLI usage:
Usage: python -m pymobiledevice3 [OPTIONS] COMMAND [ARGS]...
Options:
-h, --help Show this message and exit.
Commands:
activation activation options
afc FileSystem utils
amfi amfi options
apps application options
backup2 backup utils
bonjour bonjour options
companion companion options
crash crash report options
developer developer options.
diagnostics diagnostics options
lockdown lockdown options
mounter mounter options
notification notification options
pcap sniff device traffic
power-assertion Create a power assertion (wraps...
processes processes cli
profile profile options
provision privision options
remote remote options
restore restore options
springboard springboard options
syslog syslog options
usbmux usbmuxd options
webinspector webinspector options
version get installed package version
NOTE: Currently, this is only officially supported on macOS & Windows (up to iOS 17.3.1), but fully supported on all platforms starting at iOS 17.4 using the new lockdown tunnel. For windows interaction with iOS 17.0-17.3.1, you'll need to install the additional WeTest drivers using:
pymobiledevice3 remote install-wetest-drivers
inside an administrator terminal
Starting at iOS 17.0, Apple introduced the new CoreDevice framework to work with iOS devices. This framework relies on the RemoteXPC protocol. In order to communicate with the developer services you'll be required to first create trusted tunnel in one of the two forms:
Launch a tunnel-server named tunneld
to automatically detect devices and establish connections
# if the device supports remote pairing, such as corellium instances or AppleTVs,
# you'll need to first pair them
# normal iOS devices don't require this step
python3 -m pymobiledevice3 remote pair
# on windows, use a privileged shell
sudo python3 -m pymobiledevice3 remote tunneld
Create tunnel manually using start-tunnel
Execute the following:
# if the device supports remote pairing, such as corellium instances or AppleTVs,
# you'll need to first pair them
# normal iOS devices don't require this step
python3 -m pymobiledevice3 remote pair
# NOTE: on windows, use a privileged shell for the following commands
# starting at iOS 17.4 you can use the much faster lockdown tunnel
sudo python3 -m pymobiledevice3 lockdown start-tunnel
# if you need this connection type to be also available over wifi, you can enable it
python3 -m pymobiledevice3 lockdown wifi-connections on
# on older iOS version use the following instead
# you may pass `-t wifi` to force a WiFi tunnel
sudo python3 -m pymobiledevice3 remote start-tunnel
You will be printed with the following output providing you with the required connection details:
Interface: utun6
RSD Address: fd7b:e5b:6f53::1
RSD Port: 64337
Use the follow connection option:
--rsd fd7b:e5b:6f53::1 64337
Ths command must be run with high privileges since it creates a new TUN/TAP device which is a high privilege operation.
Now, (almost) all of pymobiledevice3 accept an additional --rsd
/--tunnel
option for connecting to the service over
the tunnel. The --tunnel
option specifically, is always attempted implicitly upon an InvalidServiceError
error to
simplify the work with developer services. You can now try to execute any of them as follows:
# Accessing the DVT services
# The --tunnel option may accept either an empty string, or a UDID for a specific device
python3 -m pymobiledevice3 developer dvt ls / --tunnel ''
# Or simply without the `--tunnel` option, assuming the tunneld is running
python3 -m pymobiledevice3 developer dvt ls /
# Or we could use the manual tunnel details
python3 -m pymobiledevice3 developer dvt ls / --rsd fd7b:e5b:6f53::1 64337
# And we can also access or the other "normal" lockdown services
python3 -m pymobiledevice3 syslog live --tunnel ''
You could also import the modules and use the API yourself.
To communicate the device you'll need an instance of LockdownClient
, from which you can pair with the device and
request to establish a connection to all its exposed services.
To do so, use the following snippet:
from pymobiledevice3.lockdown import create_using_usbmux, get_mobdev2_lockdowns
# Connecting via usbmuxd (you can also specify a specific UDID to connect to)
# Please note usbmuxd allows connecting to devices both on USB or on WiFi
lockdown = create_using_usbmux()
# you can also query network lockdown instances using the following:
async for ip, lockdown in get_mobdev2_lockdowns():
print(ip, lockdown)
Now you can connect to which service you'd like. We already implemented many of the services,
you can use import and use in the form of: from pymobiledevice3.service.<SERVICE-NAME> import <SERVICE-CLASS>
.
For example, consider the following piece of code to print all syslog lines:
from pymobiledevice3.lockdown import create_using_usbmux
from pymobiledevice3.services.syslog import SyslogService
# Connecting via usbmuxd
lockdown = create_using_usbmux()
for line in SyslogService(service_provider=lockdown).watch():
# just print all syslog lines as is
print(line)
If you need more examples of different cool stuff you can do with the different services, just look at what all the CLI commands are already doing.
However, iOS 17.0 introduced a new type of connection called RSD (RemoteServiceDiscovery), used to establish a connection with the different Developer-Mode services over a trusted tunnel. To do so, you'll first need to create a trusted tunnel.
Afterward, use the following APIs:
from pymobiledevice3.remote.remote_service_discovery import RemoteServiceDiscoveryService
from pymobiledevice3.tunneld import get_tunneld_devices
from pymobiledevice3.services.syslog import SyslogService
# Get a list of all established tunnels in the `rsds` object
# You can treat them as any other LockdownClient
rsds = get_tunneld_devices()
# For example, you could use them to connect to any service as seen in prior example
for line in SyslogService(service_provider=rsds[0]).watch():
# just print all syslog lines as is
print(line)
# Or you could connect manually to a specific tunnel created by `start-tunnel`
host = 'fded:c26b:3d2f::1'
port = 65177
async with RemoteServiceDiscoveryService((host, port)) as rsd:
# you can now use this connection as any other LockdownClient connection
pass
# Alternatively, you can use this API not in a context-manager
rsd = RemoteServiceDiscoveryService((host, port))
await rsd.connect()
await rsd.close()
A recorded example for using a variety of features can be viewed at: https://terminalizer.com/view/18920b405193
There is A LOT you may do on the device using pymobiledevice3
. This is just a TL;DR of some common operations:
pymobiledevice3 usbmux list
pymobiledevice3 bonjour browse
pymobiledevice3 syslog live
pymobiledevice3 syslog live -m SpringBoard
pymobiledevice3 diagnostics restart
pymobiledevice3 crash pull /path/to/crashes
pymobiledevice3 afc shell
pymobiledevice3 apps list
pymobiledevice3 apps query BUNDLE_ID1 BUNDLE_ID2
pymobiledevice3 usbmux forward HOST_PORT DEVICE_PORT
pymobiledevice3 backup2 backup --full DIRECTORY
pymobiledevice3 backup2 restore DIRECTORY
pymobiledevice3 webinspector js_shell
pymobiledevice3 webinspector opened-tabs
pymobiledevice3 webinspector js_shell --automation
pymobiledevice3 webinspector launch URL
pymobiledevice3 webinspector shell
--rsd
option):
pymobiledevice3 mounter auto-mount
lat long
location:
pymobiledevice3 developer simulate-location set lat long
pymobiledevice3 developer dvt simulate-location set --rsd HOST PORT -- lat long
pymobiledevice3 developer dvt simulate-location play route.gpx
pymobiledevice3 developer dvt simulate-location play route.gpx 500
pymobiledevice3 developer dvt simulate-location clear
pymobiledevice3 developer dvt screenshot /path/to/screen.png
pymobiledevice3 developer dvt sysmon process single
pymobiledevice3 developer dvt oslog
pymobiledevice3 developer dvt kill PID
pymobiledevice3 developer dvt ls PATH
pymobiledevice3 developer dvt launch com.apple.mobilesafari
strace
-like output:
pymobiledevice3 developer dvt core-profile-session parse-live
pykdebugparser
, fs_usage
and so on...
pymobiledevice3 developer dvt core-profile-session save FILENAME
pymobiledevice3 developer dvt device-information
pymobiledevice3 developer dvt energy PID1 PID2 ...
To understand the bits and bytes of the communication with lockdownd you are advised to take a look at this article:
This is the list of all the services from lockdownd
which we reversed and implemented API wrappers for. A click on
each will lead to each one's implementation, where you can learn more about.
com.apple.mobile.heartbeat
lockdownd
service.lockdownd
com.apple.mobileactivationd
com.apple.afc
/var/mobile/Media
com.apple.crashreportcopymobile
/var/mobile/Library/Logs/CrashReports
com.apple.pcapd
com.apple.syslog_relay
com.apple.os_trace_relay
relay.com.apple.os_trace_relay
com.apple.mobile.diagnostics_relay
com.apple.mobile.notification_proxy
& com.apple.mobile.insecure_notification_proxy
notify_post()
& notify_register_dispatch()
com.apple.crashreportmover
crash_mover
to move all crash reports into crash directorycom.apple.mobile.MCInstall
com.apple.misagent
com.apple.companion_proxy
com.apple.mobilebackup2
com.apple.mobile.assertion_agent
com.apple.springboardservices
com.apple.mobile.mobile_image_mounter
com.apple.mobile.house_arrest
com.apple.mobile.installation_proxy
com.apple.instruments.remoteserver
com.apple.instruments.remoteserver.DVTSecureSocketProxy
com.apple.mobile.screenshotr
com.apple.accessibility.axAuditDaemon.remoteserver
com.apple.dt.simulatelocation
com.apple.dt.fetchsymbols
dyld
and dyld shared cache files (DeveloperDiskImage)com.apple.webinspector
com.apple.amfi.lockdown
This is the list of services we haven't dedicated time in implementing. If you feel the need to use one of them or any other that is not listed in here, feel free to create us an issue request .
com.apple.idamd
com.apple.atc
com.apple.atc2
com.apple.ait.aitd
com.apple.mobile.file_relay
(Deprecated)
com.apple.mobilesync
com.apple.purpletestr
(Deprecated)com.apple.PurpleReverseProxy.Conn
com.apple.PurpleReverseProxy.Ctrl
com.apple.dt.remotepairingdeviced.lockdown
com.apple.commcenter.mobile-helper-cbupdateservice
com.apple.carkit.service
com.apple.bluetooth.BTPacketLogger
com.apple.streaming_zip_conduit
Every such subcommand may wrap several relay requests underneath. If you wish to try and play with some the relays yourself, you can run:
pymobiledevice3 lockdown service <service-name>
This will start an IPython shell where you already have the connection established using the client
variable and you
can send & receive messages.
# This shell allows you to communicate directly with every service layer behind the lockdownd daemon.
# For example, you can do the following:
client.send_plist({"Command": "DoSomething"})
# and view the reply
print(client.recv_plist())
# or just send raw message
client.sendall(b"hello")
# and view the result
print(client.recvall(20))
If you want to play with DTServiceHub
which lies behind the developer
options, you can also use:
pymobiledevice3 developer shell
To also get an IPython shell, which lets you call ObjC methods from the exported objects in the instruments' namespace like so:
# This shell allows you to send messages to the DVTSecureSocketProxy and receive answers easily.
# Generally speaking, each channel represents a group of actions.
# Calling actions is done using a selector and auxiliary (parameters).
# Receiving answers is done by getting a return value and seldom auxiliary (private / extra parameters).
# To see the available channels, type the following:
developer.supported_identifiers
# In order to send messages, you need to create a channel:
channel = developer.make_channel('com.apple.instruments.server.services.deviceinfo')
# After creating the channel you can call allowed selectors:
channel.runningProcesses()
# If an answer is expected, you can receive it using the receive method:
processes = channel.receive_plist()
# Sometimes the selector requires parameters, You can add them using MessageAux. For example lets kill a process:
channel = developer.make_channel('com.apple.instruments.server.services.processcontrol')
args = MessageAux().append_obj(80) # This will kill pid 80
channel.killPid_(args, expects_reply=False) # Killing a process doesn't require an answer.
# In some rare cases, you might want to receive the auxiliary and the selector return value.
# For that cases you can use the recv_plist method.
return_value, auxiliary = developer.recv_plist()
See CONTRIBUTING.
Please see misc