Skip to content

Commit

Permalink
protocol: add arm64 registers x0-x7,d0-d7 in return values
Browse files Browse the repository at this point in the history
  • Loading branch information
doronz88 committed Mar 24, 2022
1 parent 70acad5 commit 78d7352
Show file tree
Hide file tree
Showing 9 changed files with 201 additions and 84 deletions.
56 changes: 37 additions & 19 deletions src/rpcclient/rpcclient/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from socket import socket

import IPython
from construct import Int64sl, Float64l, Float32l
from construct import Int64sl, Float64l, Float32l, Float16l
from traitlets.config import Config

from rpcclient.darwin.structs import pid_t, exitcode_t
Expand All @@ -21,8 +21,9 @@
from rpcclient.lief import Lief
from rpcclient.network import Network
from rpcclient.processes import Processes
from rpcclient.protocol import protocol_message_t, cmd_type_t, exec_chunk_t, exec_chunk_type_t, UNAME_VERSION_LEN, \
reply_protocol_message_t, dummy_block_t, SERVER_MAGIC_VERSION, argument_type_t
from rpcclient.protocol import protocol_message_t, cmd_type_t, exec_chunk_t, exec_chunk_type_t, \
reply_protocol_message_t, dummy_block_t, SERVER_MAGIC_VERSION, argument_type_t, call_response_t, arch_t, \
protocol_handshake_t, call_response_t_size
from rpcclient.symbol import Symbol
from rpcclient.symbols_jar import SymbolsJar
from rpcclient.sysctl import Sysctl
Expand Down Expand Up @@ -61,7 +62,8 @@ class Client:
DEFAULT_ARGV = ['/bin/sh']
DEFAULT_ENVP = []

def __init__(self, sock, sysname: str, hostname: str, port: int = None):
def __init__(self, sock, sysname: str, arch: arch_t, hostname: str, port: int = None):
self._arch = arch
self._hostname = hostname
self._port = port
self._sock = sock
Expand Down Expand Up @@ -99,6 +101,11 @@ def uname(self):
""" get the utsname struct from remote """
raise NotImplementedError()

@property
def arch(self):
""" get remote arch """
return self._arch

def dlopen(self, filename: str, mode: int) -> Symbol:
""" call dlopen() at remote and return its handle. see the man page for more details. """
message = protocol_message_t.build({
Expand Down Expand Up @@ -131,7 +138,8 @@ def dlsym(self, lib: int, symbol_name: str):
err = Int64sl.parse(self._recvall(Int64sl.sizeof()))
return err

def call(self, address: int, argv: typing.List[int] = None, return_float64=False, return_float32=False) -> Symbol:
def call(self, address: int, argv: typing.List[int] = None, return_float64=False, return_float32=False,
return_float16=False, return_raw=False) -> Symbol:
""" call a remote function and retrieve its return value as Symbol object """
fixed_argv = []
free_list = []
Expand Down Expand Up @@ -171,22 +179,33 @@ def call(self, address: int, argv: typing.List[int] = None, return_float64=False
'data': {'address': address, 'argv': fixed_argv},
})
self._sock.sendall(message)
integer_err = Int64sl.parse(self._recvall(Int64sl.sizeof()))

double_buf = self._recvall(Float64l.sizeof())
float32_err = Float32l.parse(double_buf)
float64_err = Float64l.parse(double_buf)
response = call_response_t.parse(self._recvall(call_response_t_size))

for f in free_list:
self.symbols.free(f)

if return_float32:
return float32_err
if self.arch == arch_t.ARCH_ARM64:
double_buf = Float64l.build(response.return_values.arm_registers.d[0])
float16_err = Float16l.parse(double_buf)
float32_err = Float32l.parse(double_buf)
float64_err = response.return_values.arm_registers.d[0]

if return_float16:
return float16_err

if return_float32:
return float32_err

if return_float64:
return float64_err

if return_raw:
return response.return_values.arm_registers

if return_float64:
return float64_err
return self.symbol(response.return_values.arm_registers.x[0])

return self.symbol(integer_err)
return self.symbol(response.return_values.return_value)

def peek(self, address: int, size: int) -> bytes:
""" peek data at given address """
Expand Down Expand Up @@ -399,12 +418,11 @@ def reconnect(self):
self.close()
self._sock = socket()
self._sock.connect((self._hostname, self._port))
magic = self._recvall(len(SERVER_MAGIC_VERSION))

if magic != SERVER_MAGIC_VERSION:
raise InvalidServerVersionMagicError(f'got an invalid server magic: {magic.hex()}')
handshake = protocol_handshake_t.parse(self._recvall(protocol_handshake_t.sizeof()))

self._recvall(UNAME_VERSION_LEN)
if handshake.magic != SERVER_MAGIC_VERSION:
raise InvalidServerVersionMagicError()

def _execute(self, argv: typing.List[str], envp: typing.List[str], background=False) -> int:
message = protocol_message_t.build({
Expand Down Expand Up @@ -485,6 +503,6 @@ def _execution_loop(self, stdin: io_or_str = sys.stdin, stdout=sys.stdout):
def __repr__(self):
buf = f'<{self.__class__.__name__} '
buf += f'PID:{self.symbols.getpid():d} UID:{self.symbols.getuid():d} GID:{self.symbols.getgid():d} ' \
f'SYSNAME:{self._sysname}'
f'SYSNAME:{self._sysname} ARCH:{self.arch}'
buf += '>'
return buf
27 changes: 15 additions & 12 deletions src/rpcclient/rpcclient/client_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@

from rpcclient.client import Client
from rpcclient.darwin.client import DarwinClient
from rpcclient.exceptions import FailedToConnectError, InvalidServerVersionMagicError
from rpcclient.ios.client import IosClient
from rpcclient.linux.client import LinuxClient
from rpcclient.exceptions import FailedToConnectError, InvalidServerVersionMagicError
from rpcclient.macos.client import MacosClient
from rpcclient.protocol import UNAME_VERSION_LEN, DEFAULT_PORT, SERVER_MAGIC_VERSION
from rpcclient.protocol import DEFAULT_PORT, SERVER_MAGIC_VERSION, protocol_handshake_t


def recvall(sock, size: int) -> bytes:
Expand All @@ -29,21 +29,24 @@ def create_client(hostname: str, port: int = DEFAULT_PORT):
# wrap in our own exception
raise FailedToConnectError() from e

magic = recvall(sock, len(SERVER_MAGIC_VERSION))
if magic != SERVER_MAGIC_VERSION:
raise InvalidServerVersionMagicError(f'got an invalid server magic: {magic.hex()}')
handshake = protocol_handshake_t.parse(recvall(sock, protocol_handshake_t.sizeof()))

if handshake.magic != SERVER_MAGIC_VERSION:
raise InvalidServerVersionMagicError()

sysname = handshake.sysname.lower()
arch = handshake.arch

sysname = recvall(sock, UNAME_VERSION_LEN).split(b'\x00', 1)[0].decode().lower()
logging.info(f'connection uname.sysname: {sysname}')
logging.info(f'connection uname.sysname: {handshake.sysname}')

if sysname == 'darwin':
client = DarwinClient(sock, sysname, hostname, port)
client = DarwinClient(sock, sysname, arch, hostname, port)

if client.uname.machine.startswith('iPhone'):
return IosClient(sock, sysname, hostname, port)
return IosClient(sock, sysname, arch, hostname, port)
else:
return MacosClient(sock, sysname, hostname, port)
return MacosClient(sock, sysname, arch, hostname, port)
elif sysname == 'linux':
return LinuxClient(sock, sysname, hostname, port)
return LinuxClient(sock, sysname, arch, hostname, port)

return Client(sock, sysname, hostname, port)
return Client(sock, sysname, arch, hostname, port)
6 changes: 3 additions & 3 deletions src/rpcclient/rpcclient/darwin/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
from rpcclient.darwin.time import Time
from rpcclient.darwin.xpc import Xpc
from rpcclient.exceptions import RpcClientException, MissingLibraryError, CfSerializationError
from rpcclient.protocol import arch_t
from rpcclient.structs.consts import RTLD_NOW

IsaMagic = namedtuple('IsaMagic', 'mask value')
Expand All @@ -41,9 +42,8 @@


class DarwinClient(Client):

def __init__(self, sock, sysname: str, hostname: str, port: int = None):
super().__init__(sock, sysname, hostname, port)
def __init__(self, sock, sysname: str, arch: arch_t, hostname: str, port: int = None):
super().__init__(sock, sysname, arch, hostname, port)
self._dlsym_global_handle = -2 # RTLD_GLOBAL

if 0 == self.dlopen("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation", RTLD_NOW):
Expand Down
4 changes: 2 additions & 2 deletions src/rpcclient/rpcclient/darwin/symbol.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@


class DarwinSymbol(Symbol):
def objc_call(self, selector, *params):
def objc_call(self, selector, *params, **kwargs):
""" call an objc method on a given object """
sel = self._client.symbols.sel_getUid(selector)
if not self._client.symbols.objc_msgSend(self, self._client.symbols.sel_getUid("respondsToSelector:"), sel):
raise UnrecognizedSelectorError(f"unrecognized selector '{selector}' sent to class")

return self._client.symbols.objc_msgSend(self, sel, *params)
return self._client.symbols.objc_msgSend(self, sel, *params, **kwargs)

@property
def cfdesc(self):
Expand Down
5 changes: 3 additions & 2 deletions src/rpcclient/rpcclient/ios/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@
from rpcclient.ios.lockdown import Lockdown
from rpcclient.ios.mobile_gestalt import MobileGestalt
from rpcclient.ios.telephony import Telephony
from rpcclient.protocol import arch_t

CRASH_REPORTS_DIR = 'Library/Logs/CrashReporter'


class IosClient(DarwinClient):
def __init__(self, sock, sysname: str, hostname: str, port: int = None):
super().__init__(sock, sysname, hostname, port)
def __init__(self, sock, sysname: str, arch: arch_t, hostname: str, port: int = None):
super().__init__(sock, sysname, arch, hostname, port)
self.backlight = Backlight(self)
self.reports = Reports(self, CRASH_REPORTS_DIR)
self.mobile_gestalt = MobileGestalt(self)
Expand Down
5 changes: 3 additions & 2 deletions src/rpcclient/rpcclient/linux/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
from rpcclient.client import Client
from rpcclient.linux.fs import LinuxFs
from rpcclient.linux.structs import utsname
from rpcclient.protocol import arch_t


class LinuxClient(Client):
def __init__(self, sock, uname_version: str, hostname: str, port: int = None):
super().__init__(sock, uname_version, hostname, port)
def __init__(self, sock, sysname: str, arch: arch_t, hostname: str, port: int = None):
super().__init__(sock, sysname, arch, hostname, port)
self.fs = LinuxFs(self)

@cached_property
Expand Down
5 changes: 3 additions & 2 deletions src/rpcclient/rpcclient/macos/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@

from rpcclient.darwin.client import DarwinClient
from rpcclient.darwin.reports import Reports
from rpcclient.protocol import arch_t

CRASH_REPORTS_DIR = 'Library/Logs/DiagnosticReports'


class MacosClient(DarwinClient):

def __init__(self, sock, sysname: str, hostname: str, port: int = None):
super().__init__(sock, sysname, hostname, port)
def __init__(self, sock, sysname: str, arch: arch_t, hostname: str, port: int = None):
super().__init__(sock, sysname, arch, hostname, port)
self.reports = Reports(self, CRASH_REPORTS_DIR)

@property
Expand Down
32 changes: 29 additions & 3 deletions src/rpcclient/rpcclient/protocol.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from construct import Struct, Int32ul, PrefixedArray, Const, Enum, this, PascalString, Switch, PaddedString, Bytes, \
Int64ul, Int8ul, IfThenElse, Float64l
Int64ul, Int8ul, IfThenElse, Float64l, Array, Union

cmd_type_t = Enum(Int32ul,
CMD_EXEC=0,
Expand All @@ -15,11 +15,23 @@
CMD_CLOSE=10,
CMD_REPLY_POKE=11,
)

arch_t = Enum(Int32ul,
ARCH_UNKNOWN=0,
ARCH_ARM64=1,
)


DEFAULT_PORT = 5910
SERVER_MAGIC_VERSION = Int32ul.build(0x88888800)
SERVER_MAGIC_VERSION = 0x88888801
MAGIC = 0x12345678
MAX_PATH_LEN = 1024
UNAME_VERSION_LEN = 256

protocol_handshake_t = Struct(
'magic' / Int32ul,
'arch' / arch_t,
'sysname' / PaddedString(256, 'utf8'),
)

cmd_exec_t = Struct(
'background' / Int8ul,
Expand Down Expand Up @@ -95,4 +107,18 @@
'size' / Int32ul,
)

return_registers_arm_t = Struct(
'x' / Array(8, Int64ul),
'd' / Array(8, Float64l),
)

call_response_t_size = 128

call_response_t = Struct(
'return_values' / Union(None,
'arm_registers' / return_registers_arm_t,
'return_value' / Int64ul,
),
)

dummy_block_t = Int64ul
Loading

0 comments on commit 78d7352

Please sign in to comment.