diff --git a/src/rpcclient/rpcclient/exceptions.py b/src/rpcclient/rpcclient/exceptions.py
index ca14b5ba..29774255 100644
--- a/src/rpcclient/rpcclient/exceptions.py
+++ b/src/rpcclient/rpcclient/exceptions.py
@@ -105,6 +105,11 @@ class LastElementNotFoundError(ElementNotFoundError):
pass
+class LaunchError(BadReturnValueError):
+ """ failed to launch a child process """
+ pass
+
+
class RpcFileExistsError(BadReturnValueError):
""" RPC version for FileExistsError (errno = EEXIST) """
pass
diff --git a/src/rpcclient/rpcclient/ios/client.py b/src/rpcclient/rpcclient/ios/client.py
index 92d53d71..b02b3b51 100644
--- a/src/rpcclient/rpcclient/ios/client.py
+++ b/src/rpcclient/rpcclient/ios/client.py
@@ -7,6 +7,7 @@
from rpcclient.ios.backlight import Backlight
from rpcclient.ios.lockdown import Lockdown
from rpcclient.ios.mobile_gestalt import MobileGestalt
+from rpcclient.ios.processes import IosProcesses
from rpcclient.ios.screen_capture import ScreenCapture
from rpcclient.ios.sprinboard import SpringBoard
from rpcclient.ios.telephony import Telephony
@@ -21,6 +22,7 @@ def __init__(self, sock, sysname: str, arch, create_socket_cb: typing.Callable):
self.backlight = Backlight(self)
self.reports = Reports(self, CRASH_REPORTS_DIR)
self.mobile_gestalt = MobileGestalt(self)
+ self.processes = IosProcesses(self)
self.lockdown = Lockdown(self)
self.telephony = Telephony(self)
self.screen_capture = ScreenCapture(self)
diff --git a/src/rpcclient/rpcclient/ios/processes.py b/src/rpcclient/rpcclient/ios/processes.py
new file mode 100644
index 00000000..a0fddb93
--- /dev/null
+++ b/src/rpcclient/rpcclient/ios/processes.py
@@ -0,0 +1,37 @@
+from typing import Optional
+
+from rpcclient.darwin.processes import DarwinProcesses
+from rpcclient.exceptions import LaunchError
+
+
+class IosProcesses(DarwinProcesses):
+
+ def launch(self, bundle_id: str, unlock_device: bool = True, disable_aslr: bool = False,
+ wait_for_debugger: bool = False, stdout: Optional[str] = None,
+ stderr: Optional[str] = None) -> int:
+ """ launch process using BackBoardService
+ https://github.com/swigger/debugserver-ios/blob/master/inc/BackBoardServices.framework/Headers
+ /BackBoardServices.h"""
+ debug_options = {}
+ options = {}
+ sym = self._client.symbols
+ debug_options[sym.BKSDebugOptionKeyDisableASLR[0].py()] = disable_aslr
+ debug_options[sym.BKSDebugOptionKeyWaitForDebugger[0].py()] = wait_for_debugger
+ if stdout is not None:
+ debug_options[sym.BKSDebugOptionKeyStandardOutPath[0].py()] = stdout
+ if stderr is not None:
+ debug_options[sym.BKSDebugOptionKeyStandardErrorPath[0].py()] = stderr
+
+ options[sym.BKSOpenApplicationOptionKeyUnlockDevice[0].py()] = unlock_device
+ options[sym.BKSOpenApplicationOptionKeyDebuggingOptions[0].py()] = debug_options
+
+ bkssystem_service = self._client.objc_get_class('BKSSystemService').new().objc_symbol
+ bkssystem_service.openApplication_options_clientPort_withResult_(self._client.cf(bundle_id),
+ self._client.cf(options),
+ bkssystem_service.createClientPort(),
+ self._client.get_dummy_block())
+
+ pid = bkssystem_service.pidForApplication_(self._client.cf(bundle_id)).c_int32
+ if pid == -1:
+ raise LaunchError()
+ return pid
diff --git a/src/rpcclient/tests/conftest.py b/src/rpcclient/tests/conftest.py
index 6af05580..fce8b5c9 100644
--- a/src/rpcclient/tests/conftest.py
+++ b/src/rpcclient/tests/conftest.py
@@ -6,6 +6,7 @@
from rpcclient.client_factory import create_tcp_client
from rpcclient.darwin.client import DarwinClient
from rpcclient.exceptions import BadReturnValueError
+from rpcclient.ios.client import IosClient
from rpcclient.protos.rpc_pb2 import ARCH_ARM64
@@ -41,6 +42,7 @@ def pytest_configure(config):
'''local_only: marks tests that require features the CI lacks (deselect with '-m "not local_only"')'''
)
config.addinivalue_line('markers', 'darwin: marks tests that require darwin platform to run')
+ config.addinivalue_line('markers', 'ios: marks tests that require ios platform to run')
config.addinivalue_line('markers', 'local_machine: marks tests that require local_machine to run')
config.addinivalue_line('markers', 'arm: marks tests that require arm architecture to run')
@@ -48,11 +50,13 @@ def pytest_configure(config):
def pytest_collection_modifyitems(config, items):
skip_local_only = pytest.mark.skip(reason='remove --ci option to run')
skip_not_darwin = pytest.mark.skip(reason='Darwin system is required for this test')
+ skip_not_ios = pytest.mark.skip(reason='Ios system is required for this test')
skip_not_arm = pytest.mark.skip(reason='Arm arch is required for this test')
skip_not_local_machine = pytest.mark.skip(reason='Local machine is required for this test')
with closing(create_tcp_client('127.0.0.1')) as c:
is_darwin = isinstance(c, DarwinClient)
+ is_ios = isinstance(c, IosClient)
is_arm = c.arch == ARCH_ARM64
for item in items:
@@ -62,6 +66,9 @@ def pytest_collection_modifyitems(config, items):
if 'darwin' in item.keywords and not is_darwin:
# Skip test that require Darwin on non Darwin system
item.add_marker(skip_not_darwin)
+ if 'ios' in item.keywords and not is_ios:
+ # Skip test that require ios
+ item.add_marker(skip_not_ios)
if 'arm' in item.keywords and not is_arm:
# Skip tests that require arm on non arm architecture
item.add_marker(skip_not_arm)
diff --git a/src/rpcclient/tests/test_processes.py b/src/rpcclient/tests/test_processes.py
index 64047335..ecca3a50 100644
--- a/src/rpcclient/tests/test_processes.py
+++ b/src/rpcclient/tests/test_processes.py
@@ -1,6 +1,9 @@
from pathlib import Path
+import pytest
+
from rpcclient.client_factory import DEFAULT_PORT
+from rpcclient.exceptions import LaunchError
LAUNCHD_PID = 1
LAUNCHD_PATH = '/sbin/launchd'
@@ -29,3 +32,15 @@ def test_process_object(client):
assert fds[0].fd == 0
assert fds[1].fd == 1
assert fds[2].fd == 2
+
+
+@pytest.mark.ios
+def test_launch_process(client):
+ pid = client.processes.launch('com.apple.MobileAddressBook')
+ client.processes.kill(pid)
+
+
+@pytest.mark.ios
+def test_launch_invalid_process(client):
+ with pytest.raises(LaunchError):
+ client.processes.launch('com.apple.cyber')
diff --git a/src/rpcserver/ents.plist b/src/rpcserver/ents.plist
index e3c0273e..356ef390 100644
--- a/src/rpcserver/ents.plist
+++ b/src/rpcserver/ents.plist
@@ -90,6 +90,10 @@
com.apple.backboardd.launchapplications
+ com.apple.frontboard.debugapplications
+
+ com.apple.frontboard.launchapplications
+
com.apple.private.logging.admin
com.apple.security.exception.shared-preference.read-write