From f90ee24e3bfb56ef071c9436c66277482e0bde10 Mon Sep 17 00:00:00 2001 From: Netanel Cohen <netanelc305@protonmail.com> Date: Thu, 22 Aug 2024 16:07:05 +0300 Subject: [PATCH 1/2] hilda_client: Add `hilda_root` path --- hilda/hilda_client.py | 10 +++++----- hilda/objective_c_class.py | 5 ++--- hilda/objective_c_symbol.py | 3 +-- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/hilda/hilda_client.py b/hilda/hilda_client.py index 5a03705..c343fad 100644 --- a/hilda/hilda_client.py +++ b/hilda/hilda_client.py @@ -146,6 +146,7 @@ def __init__(self, debugger: lldb.SBDebugger): self._dynamic_env_loaded = False self._symbols_loaded = False self.globals: typing.MutableMapping[str, Any] = globals() + self._hilda_root = Path(__file__).parent # the frame called within the context of the hit BP self._bp_frame = None @@ -168,7 +169,7 @@ def lsof(self) -> dict: Get dictionary of all open FDs :return: Mapping between open FDs and their paths """ - data = (Path(__file__).parent / 'objective_c' / 'lsof.m').read_text() + data = (self._hilda_root / 'objective_c' / 'lsof.m').read_text() result = json.loads(self.po(data)) # convert FDs into int return {int(k): v for k, v in result.items()} @@ -828,8 +829,7 @@ def ns(self, data: CfSerializable) -> Symbol: json_data = json.dumps({'root': data}, default=self._to_ns_json_default) except TypeError as e: raise ConvertingToNsObjectError from e - - obj_c_code = (Path(__file__).parent / 'objective_c' / 'to_ns_from_json.m').read_text() + obj_c_code = (self._hilda_root / 'objective_c' / 'to_ns_from_json.m').read_text() expression = obj_c_code.replace('__json_object_dump__', json_data.replace('"', r'\"')) try: return self.evaluate_expression(expression) @@ -842,7 +842,7 @@ def decode_cf(self, address: Union[int, str]) -> CfSerializable: :param address: NS object. :return: Python object. """ - obj_c_code = (Path(__file__).parent / 'objective_c' / 'from_ns_to_json.m').read_text() + obj_c_code = (self._hilda_root / 'objective_c' / 'from_ns_to_json.m').read_text() address = f'0x{address:x}' if isinstance(address, int) else address expression = obj_c_code.replace('__ns_object_address__', address) try: @@ -1212,7 +1212,7 @@ def _get_module_class_list(self, module_name: str): continue objc_classlist = m.FindSection('__DATA').FindSubSection('__objc_classlist') objc_classlist_addr = self.symbol(objc_classlist.GetLoadAddress(self.target)) - obj_c_code = (Path(__file__).parent / 'objective_c' / 'get_objectivec_class_by_module.m').read_text() + obj_c_code = (self._hilda_root / 'objective_c' / 'get_objectivec_class_by_module.m').read_text() obj_c_code = obj_c_code.replace('__count_objc_class', f'{objc_classlist.size // 8}').replace( '__objc_class_list', f'{objc_classlist_addr}') diff --git a/hilda/objective_c_class.py b/hilda/objective_c_class.py index b991f68..fa9ea7a 100644 --- a/hilda/objective_c_class.py +++ b/hilda/objective_c_class.py @@ -3,7 +3,6 @@ from collections import namedtuple from dataclasses import dataclass, field from functools import partial -from pathlib import Path from typing import Any from uuid import uuid4 @@ -120,7 +119,7 @@ def from_class_name(client, class_name: str): :param hilda.hilda_client.HildaClient client: Hilda client. :param class_name: Class name. """ - obj_c_code = (Path(__file__).parent / 'objective_c' / 'get_objectivec_class_description.m').read_text() + obj_c_code = (client._hilda_root / 'objective_c' / 'get_objectivec_class_description.m').read_text() obj_c_code = obj_c_code.replace('__class_address__', '0').replace('__class_name__', class_name) class_symbol = Class(client, class_data=json.loads(client.po(obj_c_code))) if class_symbol.name != class_name: @@ -143,7 +142,7 @@ def reload(self): Reload class object data. Should be used whenever the class layout changes (for example, during method swizzling) """ - obj_c_code = (Path(__file__).parent / 'objective_c' / 'get_objectivec_class_description.m').read_text() + obj_c_code = (self._client._hilda_root / 'objective_c' / 'get_objectivec_class_description.m').read_text() obj_c_code = obj_c_code.replace('__class_address__', f'{self._class_object:d}') obj_c_code = obj_c_code.replace('__class_name__', self.name) self._load_class_data(json.loads(self._client.po(obj_c_code))) diff --git a/hilda/objective_c_symbol.py b/hilda/objective_c_symbol.py index 94e38cf..2b8071b 100644 --- a/hilda/objective_c_symbol.py +++ b/hilda/objective_c_symbol.py @@ -2,7 +2,6 @@ from contextlib import suppress from dataclasses import dataclass from functools import partial -from pathlib import Path from objc_types_decoder.decode import decode as decode_type from pygments import highlight @@ -60,7 +59,7 @@ def reload(self): self.methods.clear() self.class_ = None - obj_c_code = (Path(__file__).parent / 'objective_c' / 'get_objectivec_symbol_data.m').read_text() + obj_c_code = (self._client._hilda_root / 'objective_c' / 'get_objectivec_symbol_data.m').read_text() obj_c_code = obj_c_code.replace('__symbol_address__', f'{self:d}') data = json.loads(self._client.po(obj_c_code)) From e457d688e6af21ec7d9c7157ddb6fbc090ec809a Mon Sep 17 00:00:00 2001 From: Netanel Cohen <netanelc305@protonmail.com> Date: Thu, 22 Aug 2024 16:07:49 +0300 Subject: [PATCH 2/2] hilda_client: Add `run_for` --- README.md | 2 ++ hilda/hilda_client.py | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/README.md b/README.md index 2cbfe53..ea303ae 100644 --- a/README.md +++ b/README.md @@ -132,6 +132,8 @@ Here is a gist of methods you can access from `p`: - Stop process. - `cont` - Continue process. +- `run_for` + - Run the process for given interval. - `detach` - Detach from process. Useful in order to exit gracefully so process doesn't get killed diff --git a/hilda/hilda_client.py b/hilda/hilda_client.py index c343fad..bb970bc 100644 --- a/hilda/hilda_client.py +++ b/hilda/hilda_client.py @@ -348,6 +348,16 @@ def stop(self, *args) -> None: if not self.process.Stop().Success(): self.log_critical('failed to stop process') + def run_for(self, seconds: float) -> None: + """ + Run the process for a given time + :return: + """ + self.cont() + self.logger.info(f'Running for {seconds} seconds') + time.sleep(seconds) + self.stop() + def cont(self, *args) -> None: """ Continue process. """ is_running = self.process.GetState() == lldb.eStateRunning