From a3a14c9e01ffb575e05c2b51e2156a278871ad25 Mon Sep 17 00:00:00 2001 From: doron zarhi Date: Mon, 14 Mar 2022 10:59:16 +0200 Subject: [PATCH] client: add lief --- src/rpcclient/requirements.txt | 1 + src/rpcclient/rpcclient/client.py | 2 ++ src/rpcclient/rpcclient/darwin/client.py | 4 +++ src/rpcclient/rpcclient/darwin/consts.py | 7 +++++ src/rpcclient/rpcclient/darwin/darwin_lief.py | 31 +++++++++++++++++++ src/rpcclient/rpcclient/exceptions.py | 5 +++ src/rpcclient/rpcclient/lief.py | 28 +++++++++++++++++ 7 files changed, 78 insertions(+) create mode 100644 src/rpcclient/rpcclient/darwin/darwin_lief.py create mode 100644 src/rpcclient/rpcclient/lief.py diff --git a/src/rpcclient/requirements.txt b/src/rpcclient/requirements.txt index 5542c47d..c6e2ade1 100644 --- a/src/rpcclient/requirements.txt +++ b/src/rpcclient/requirements.txt @@ -8,3 +8,4 @@ dataclasses; python_version<"3.7" pygments objc_types_decoder pycrashreport>=0.0.8 +lief diff --git a/src/rpcclient/rpcclient/client.py b/src/rpcclient/rpcclient/client.py index 703b3a00..196c51f6 100644 --- a/src/rpcclient/rpcclient/client.py +++ b/src/rpcclient/rpcclient/client.py @@ -18,6 +18,7 @@ from rpcclient.exceptions import ArgumentError, SymbolAbsentError, SpawnError, ServerDiedError, \ InvalidServerVersionMagicError from rpcclient.fs import Fs +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, \ @@ -75,6 +76,7 @@ def __init__(self, sock, sysname: str, hostname: str, port: int = None): self.fs = Fs(self) self.processes = Processes(self) self.network = Network(self) + self.lief = Lief(self) def info(self): """ print information about current target """ diff --git a/src/rpcclient/rpcclient/darwin/client.py b/src/rpcclient/rpcclient/darwin/client.py index b8efbc6e..600a9650 100644 --- a/src/rpcclient/rpcclient/darwin/client.py +++ b/src/rpcclient/rpcclient/darwin/client.py @@ -9,6 +9,7 @@ from rpcclient.client import Client from rpcclient.darwin import objective_c_class from rpcclient.darwin.consts import kCFNumberSInt64Type, kCFNumberDoubleType, CFStringEncoding, kCFAllocatorDefault +from rpcclient.darwin.darwin_lief import DarwinLief from rpcclient.darwin.fs import DarwinFs from rpcclient.darwin.hid import Hid from rpcclient.darwin.ioregistry import IORegistry @@ -24,6 +25,7 @@ from rpcclient.darwin.time import Time from rpcclient.darwin.xpc import Xpc from rpcclient.exceptions import RpcClientException, MissingLibraryError +from rpcclient.macos.bluetooth import Bluetooth from rpcclient.structs.consts import RTLD_NOW IsaMagic = namedtuple('IsaMagic', 'mask value') @@ -71,6 +73,8 @@ def __init__(self, sock, sysname: str, hostname: str, port: int = None): self.syslog = Syslog(self) self.time = Time(self) self.hid = Hid(self) + self.lief = DarwinLief(self) + self.bluetooth = Bluetooth(self) @property def modules(self) -> typing.List[str]: diff --git a/src/rpcclient/rpcclient/darwin/consts.py b/src/rpcclient/rpcclient/darwin/consts.py index 86583890..077cce24 100644 --- a/src/rpcclient/rpcclient/darwin/consts.py +++ b/src/rpcclient/rpcclient/darwin/consts.py @@ -621,3 +621,10 @@ class NSStringEncoding(Enum): kHIDUsage_Csmr_ACFormat = 0x23C # Selector # 0x23D - 0xFFFF Reserved kHIDUsage_Csmr_Reserved = 0xFFFF + +kSecCodeMagicRequirement = 0xfade0c00 # single requirement +kSecCodeMagicRequirementSet = 0xfade0c01 # requirement set +kSecCodeMagicCodeDirectory = 0xfade0c02 # CodeDirectory +kSecCodeMagicEmbeddedSignature = 0xfade0cc0 # single-architecture embedded signature +kSecCodeMagicDetachedSignature = 0xfade0cc1 # detached multi-architecture signature +kSecCodeMagicEntitlement = 0xfade7171 # entitlement blob diff --git a/src/rpcclient/rpcclient/darwin/darwin_lief.py b/src/rpcclient/rpcclient/darwin/darwin_lief.py new file mode 100644 index 00000000..86f44ea9 --- /dev/null +++ b/src/rpcclient/rpcclient/darwin/darwin_lief.py @@ -0,0 +1,31 @@ +import plistlib +import struct +from typing import Mapping + +import lief + +from rpcclient.common import path_to_str +from rpcclient.darwin.consts import kSecCodeMagicEntitlement +from rpcclient.exceptions import NoEntitlementsError +from rpcclient.lief import Lief + + +class DarwinLief(Lief): + @path_to_str('path') + def get_entitlements(self, path: str) -> Mapping: + with self._client.fs.open(path, 'r') as f: + buf = f.readall() + parsed = lief.parse(buf) + code_signature = buf[parsed.code_signature.data_offset: + parsed.code_signature.data_offset + parsed.code_signature.data_size] + + ent_magic = struct.pack('>I', kSecCodeMagicEntitlement) + ent_magic_offset = code_signature.find(ent_magic) + + if ent_magic_offset == -1: + raise NoEntitlementsError() + + ent_buf = code_signature[ent_magic_offset + len(ent_magic) + 4:] + end_plist_magic = b'' + ent_buf = ent_buf[:ent_buf.find(end_plist_magic) + len(end_plist_magic)] + return plistlib.loads(ent_buf) diff --git a/src/rpcclient/rpcclient/exceptions.py b/src/rpcclient/rpcclient/exceptions.py index ad74c0dd..41a43cd6 100644 --- a/src/rpcclient/rpcclient/exceptions.py +++ b/src/rpcclient/rpcclient/exceptions.py @@ -66,3 +66,8 @@ class MissingLibraryError(RpcClientException): class PermissionDeniedError(RpcClientException): """ failed to access a certain something """ pass + + +class NoEntitlementsError(RpcClientException): + """ binary contains no entitlements """ + pass diff --git a/src/rpcclient/rpcclient/lief.py b/src/rpcclient/rpcclient/lief.py new file mode 100644 index 00000000..33037166 --- /dev/null +++ b/src/rpcclient/rpcclient/lief.py @@ -0,0 +1,28 @@ +from collections import namedtuple +from typing import Mapping + +import lief + +from rpcclient.common import path_to_str + +Symbol = namedtuple('Symbol', 'origin value') + + +class Lief: + """" parse and patch executable files """ + + def __init__(self, client): + self._client = client + + @path_to_str('path') + def parse(self, path: str): + with self._client.fs.open(path, 'r') as f: + return lief.parse(f.readall()) + + @path_to_str('path') + def get_symbols(self, path: str) -> Mapping[str, Symbol]: + result = {} + parsed = self.parse(path) + for s in parsed.symbols: + result[s.name] = Symbol(origin=s.origin, value=s.value) + return result