From 0b2704ab9336a324ad334f05e1f2385e91db42f2 Mon Sep 17 00:00:00 2001 From: matan Date: Wed, 16 Mar 2022 16:09:40 +0200 Subject: [PATCH] Symbol: Return raw from symbol in py failures. --- src/rpcclient/rpcclient/darwin/client.py | 74 +++++++++++++++++++---- src/rpcclient/rpcclient/darwin/symbol.py | 75 ++---------------------- src/rpcclient/rpcclient/ios/telephony.py | 2 +- 3 files changed, 67 insertions(+), 84 deletions(-) diff --git a/src/rpcclient/rpcclient/darwin/client.py b/src/rpcclient/rpcclient/darwin/client.py index 26fcc369..5e555faf 100644 --- a/src/rpcclient/rpcclient/darwin/client.py +++ b/src/rpcclient/rpcclient/darwin/client.py @@ -25,7 +25,7 @@ from rpcclient.darwin.syslog import Syslog from rpcclient.darwin.time import Time from rpcclient.darwin.xpc import Xpc -from rpcclient.exceptions import RpcClientException, MissingLibraryError +from rpcclient.exceptions import RpcClientException, MissingLibraryError, CfSerializationError from rpcclient.structs.consts import RTLD_NOW IsaMagic = namedtuple('IsaMagic', 'mask value') @@ -48,18 +48,6 @@ def __init__(self, sock, sysname: str, hostname: str, port: int = None): if 0 == self.dlopen("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation", RTLD_NOW): raise MissingLibraryError('failed to load CoreFoundation') - self._cf_types = { - self.symbols.CFNullGetTypeID(): 'null', - self.symbols.CFDateGetTypeID(): 'date', - self.symbols.CFDataGetTypeID(): 'data', - self.symbols.CFStringGetTypeID(): 'str', - self.symbols.CFArrayGetTypeID(): 'array', - self.symbols.CFBooleanGetTypeID(): 'bool', - self.symbols.CFNumberGetTypeID(): 'number', - self.symbols.CFSetGetTypeID(): 'set', - self.symbols.CFDictionaryGetTypeID(): 'dict', - } - if self.uname.machine != 'x86_64': self.inode64 = True self.fs = DarwinFs(self) @@ -75,6 +63,16 @@ def __init__(self, sock, sysname: str, hostname: str, port: int = None): self.hid = Hid(self) self.lief = DarwinLief(self) self.bluetooth = Bluetooth(self) + self.type_decoders = { + self.symbols.CFNullGetTypeID(): self._decode_cfnull, + self.symbols.CFStringGetTypeID(): self._decode_cfstr, + self.symbols.CFBooleanGetTypeID(): self._decode_cfbool, + self.symbols.CFNumberGetTypeID(): self._decode_cfnumber, + self.symbols.CFDateGetTypeID(): self._decode_cfdate, + self.symbols.CFDataGetTypeID(): self._decode_cfdata, + self.symbols.CFArrayGetTypeID(): self._decode_cfarray, + self.symbols.CFDictionaryGetTypeID(): self._decode_cfdict, + } @property def modules(self) -> typing.List[str]: @@ -233,3 +231,53 @@ def is_objc_type(symbol: DarwinSymbol) -> bool: return True return False + + def _decode_cfnull(self, symbol) -> None: + return None + + def _decode_cfstr(self, symbol) -> str: + ptr = self.symbols.CFStringGetCStringPtr(symbol, CFStringEncoding.kCFStringEncodingMacRoman) + if ptr: + return ptr.peek_str('mac_roman') + + with self.safe_malloc(4096) as buf: + if not self.symbols.CFStringGetCString(symbol, buf, 4096, CFStringEncoding.kCFStringEncodingMacRoman): + raise CfSerializationError('CFStringGetCString failed') + return buf.peek_str('mac_roman') + + def _decode_cfbool(self, symbol) -> bool: + return bool(self.symbols.CFBooleanGetValue(symbol)) + + def _decode_cfnumber(self, symbol) -> int: + with self.safe_malloc(200) as buf: + if self.symbols.CFNumberIsFloatType(symbol): + if not self.symbols.CFNumberGetValue(symbol, kCFNumberDoubleType, buf): + raise CfSerializationError(f'failed to deserialize float: {symbol}') + return struct.unpack(' datetime.datetime: + return datetime.datetime.strptime(symbol.cfdesc, '%Y-%m-%d %H:%M:%S %z') + + def _decode_cfdata(self, symbol) -> bytes: + count = self.symbols.CFDataGetLength(symbol) + return self.symbols.CFDataGetBytePtr(symbol).peek(count) + + def _decode_cfarray(self, symbol) -> typing.List: + result = [] + count = self.symbols.CFArrayGetCount(symbol) + for i in range(count): + result.append(self.symbols.CFArrayGetValueAtIndex(symbol, i).py) + return result + + def _decode_cfdict(self, symbol) -> typing.Mapping: + result = {} + count = self.symbols.CFArrayGetCount(symbol) + with self.safe_malloc(8 * count) as keys: + with self.safe_malloc(8 * count) as values: + self.symbols.CFDictionaryGetKeysAndValues(symbol, keys, values) + for i in range(count): + result[keys[i].py] = values[i].py + return result diff --git a/src/rpcclient/rpcclient/darwin/symbol.py b/src/rpcclient/rpcclient/darwin/symbol.py index 78c28caf..06d9dd94 100644 --- a/src/rpcclient/rpcclient/darwin/symbol.py +++ b/src/rpcclient/rpcclient/darwin/symbol.py @@ -1,9 +1,4 @@ -import datetime -import struct -from typing import List, Mapping - -from rpcclient.darwin.consts import kCFNumberSInt64Type, kCFNumberDoubleType, CFStringEncoding -from rpcclient.exceptions import CfSerializationError, UnrecognizedSelectorError +from rpcclient.exceptions import UnrecognizedSelectorError from rpcclient.symbol import Symbol @@ -26,77 +21,17 @@ def cfdesc(self): return None return self._client.symbols.CFCopyDescription(self).py - def _decode_cfnull(self) -> None: - return None - - def _decode_cfstr(self) -> str: - ptr = self._client.symbols.CFStringGetCStringPtr(self, CFStringEncoding.kCFStringEncodingMacRoman) - if ptr: - return ptr.peek_str('mac_roman') - - with self._client.safe_malloc(4096) as buf: - if not self._client.symbols.CFStringGetCString(self, buf, 4096, CFStringEncoding.kCFStringEncodingMacRoman): - raise CfSerializationError('CFStringGetCString failed') - return buf.peek_str('mac_roman') - - def _decode_cfbool(self) -> bool: - return bool(self._client.symbols.CFBooleanGetValue(self)) - - def _decode_cfnumber(self) -> int: - with self._client.safe_malloc(200) as buf: - if self._client.symbols.CFNumberIsFloatType(self): - if not self._client.symbols.CFNumberGetValue(self, kCFNumberDoubleType, buf): - raise CfSerializationError(f'failed to deserialize float: {self}') - return struct.unpack(' datetime.datetime: - return datetime.datetime.strptime(self.cfdesc, '%Y-%m-%d %H:%M:%S %z') - - def _decode_cfdata(self) -> bytes: - count = self._client.symbols.CFDataGetLength(self) - return self._client.symbols.CFDataGetBytePtr(self).peek(count) - - def _decode_cfarray(self) -> List: - result = [] - count = self._client.symbols.CFArrayGetCount(self) - for i in range(count): - result.append(self._client.symbols.CFArrayGetValueAtIndex(self, i).py) - return result - - def _decode_cfdict(self) -> Mapping: - result = {} - count = self._client.symbols.CFArrayGetCount(self) - with self._client.safe_malloc(8 * count) as keys: - with self._client.safe_malloc(8 * count) as values: - self._client.symbols.CFDictionaryGetKeysAndValues(self, keys, values) - for i in range(count): - result[keys[i].py] = values[i].py - return result - @property def py(self): """ get a python object from a core foundation one """ if self == 0: return None - t = self._client._cf_types[self._client.symbols.CFGetTypeID(self)] - type_decoders = { - 'null': self._decode_cfnull, - 'str': self._decode_cfstr, - 'bool': self._decode_cfbool, - 'number': self._decode_cfnumber, - 'date': self._decode_cfdate, - 'data': self._decode_cfdata, - 'array': self._decode_cfarray, - 'dict': self._decode_cfdict, - } - if t not in type_decoders: - raise NotImplementedError(f'type: {t}') + cf_type = self._client.symbols.CFGetTypeID(self) + if cf_type not in self._client.type_decoders: + return self - return type_decoders[t]() + return self._client.type_decoders[cf_type](self) @property def objc_symbol(self): diff --git a/src/rpcclient/rpcclient/ios/telephony.py b/src/rpcclient/rpcclient/ios/telephony.py index 57d880ab..2b29381a 100644 --- a/src/rpcclient/rpcclient/ios/telephony.py +++ b/src/rpcclient/rpcclient/ios/telephony.py @@ -52,7 +52,7 @@ def current_call(self) -> Call: """ calls = self.cx_call_observer.objc_call('calls') for call_id in range(calls.objc_call('count')): - call = calls.objc_call('objectAtIndex:', call_id) + call = calls.py[call_id] if call.objc_call('hasEnded'): continue return Call(self._client, self.cx_call_controller, call)