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