Skip to content

Commit

Permalink
Symbol: Return raw from symbol in py failures.
Browse files Browse the repository at this point in the history
  • Loading branch information
matan1008 committed Mar 16, 2022
1 parent 69119aa commit 0b2704a
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 84 deletions.
74 changes: 61 additions & 13 deletions src/rpcclient/rpcclient/darwin/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand All @@ -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)
Expand All @@ -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]:
Expand Down Expand Up @@ -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('<d', buf.peek(8))[0]
if not self.symbols.CFNumberGetValue(symbol, kCFNumberSInt64Type, buf):
raise CfSerializationError(f'failed to deserialize int: {symbol}')
return int(buf[0])

def _decode_cfdate(self, symbol) -> 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
75 changes: 5 additions & 70 deletions src/rpcclient/rpcclient/darwin/symbol.py
Original file line number Diff line number Diff line change
@@ -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


Expand All @@ -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('<d', buf.peek(8))[0]
if not self._client.symbols.CFNumberGetValue(self, kCFNumberSInt64Type, buf):
raise CfSerializationError(f'failed to deserialize int: {self}')
return int(buf[0])

def _decode_cfdate(self) -> 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):
Expand Down
2 changes: 1 addition & 1 deletion src/rpcclient/rpcclient/ios/telephony.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

0 comments on commit 0b2704a

Please sign in to comment.