hilda 3.1.0__tar.gz → 3.2.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {hilda-3.1.0 → hilda-3.2.1}/PKG-INFO +19 -25
- {hilda-3.1.0 → hilda-3.2.1}/README.md +18 -24
- {hilda-3.1.0 → hilda-3.2.1}/hilda/_version.py +16 -3
- {hilda-3.1.0 → hilda-3.2.1}/hilda/breakpoints.py +4 -4
- {hilda-3.1.0 → hilda-3.2.1}/hilda/decorators.py +1 -0
- {hilda-3.1.0 → hilda-3.2.1}/hilda/exceptions.py +1 -6
- {hilda-3.1.0 → hilda-3.2.1}/hilda/hilda_client.py +21 -70
- {hilda-3.1.0 → hilda-3.2.1}/hilda/ipython_extensions/events.py +14 -18
- {hilda-3.1.0 → hilda-3.2.1}/hilda/objective_c_class.py +86 -29
- {hilda-3.1.0 → hilda-3.2.1}/hilda/objective_c_symbol.py +5 -16
- {hilda-3.1.0 → hilda-3.2.1}/hilda/snippets/libmalloc.py +9 -9
- {hilda-3.1.0 → hilda-3.2.1}/hilda/symbol.py +48 -12
- hilda-3.2.1/hilda/symbols.py +595 -0
- {hilda-3.1.0 → hilda-3.2.1}/hilda/watchpoints.py +5 -5
- {hilda-3.1.0 → hilda-3.2.1}/hilda.egg-info/PKG-INFO +19 -25
- {hilda-3.1.0 → hilda-3.2.1}/hilda.egg-info/SOURCES.txt +2 -3
- {hilda-3.1.0 → hilda-3.2.1}/tests/test_symbols/test_objective_c_symbol.py +1 -1
- hilda-3.2.1/tests/test_symbols/test_symbol_list.py +136 -0
- hilda-3.1.0/hilda/symbols_jar.py +0 -208
- hilda-3.1.0/tests/test_hilda_client/test_rebind_symbols.py +0 -6
- hilda-3.1.0/tests/test_symbols/test_symbols_jar.py +0 -38
- {hilda-3.1.0 → hilda-3.2.1}/.github/workflows/python-app.yml +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/.github/workflows/python-publish.yml +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/.gitignore +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/.pre-commit-config.yaml +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/LICENSE +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/gifs/.gitattributes +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/gifs/ui.png +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/gifs/xpc_print_message.gif +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/hilda/__init__.py +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/hilda/__main__.py +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/hilda/cli.py +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/hilda/common.py +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/hilda/ipython_extensions/keybindings.py +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/hilda/ipython_extensions/magics.py +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/hilda/launch_lldb.py +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/hilda/lldb_entrypoint.py +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/hilda/lldb_importer.py +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/hilda/objective_c/from_ns_to_json.m +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/hilda/objective_c/get_objectivec_class_by_module.m +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/hilda/objective_c/get_objectivec_class_description.m +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/hilda/objective_c/get_objectivec_symbol_data.m +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/hilda/objective_c/lsof.m +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/hilda/objective_c/to_ns_from_json.m +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/hilda/registers.py +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/hilda/snippets/__init__.py +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/hilda/snippets/boringssl.py +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/hilda/snippets/collections.py +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/hilda/snippets/dyld.py +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/hilda/snippets/fs_utils.py +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/hilda/snippets/mach/CFRunLoopServiceMachPort_hooks.py +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/hilda/snippets/mach/__init__.py +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/hilda/snippets/macho/__init__.py +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/hilda/snippets/macho/all_image_infos.py +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/hilda/snippets/macho/apple_version.py +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/hilda/snippets/macho/image_info.py +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/hilda/snippets/macho/macho.py +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/hilda/snippets/macho/macho_load_commands.py +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/hilda/snippets/remotepairingd.py +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/hilda/snippets/syslog.py +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/hilda/snippets/uuid.py +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/hilda/snippets/xpc.py +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/hilda/ui/colors.json +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/hilda/ui/ui_manager.py +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/hilda/ui/views.py +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/hilda.egg-info/dependency_links.txt +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/hilda.egg-info/entry_points.txt +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/hilda.egg-info/requires.txt +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/hilda.egg-info/top_level.txt +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/pyproject.toml +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/requirements.txt +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/setup.cfg +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/tests/__init__.py +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/tests/conftest.py +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/tests/test_hilda_client/test_from_ns.py +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/tests/test_hilda_client/test_hilda_client.py +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/tests/test_hilda_client/test_monitor.py +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/tests/test_hilda_client/test_ns.py +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/tests/test_hilda_client/test_registers.py +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/tests/test_snippets/test_xpc.py +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/tests/test_symbols/test_objective_c_class.py +0 -0
- {hilda-3.1.0 → hilda-3.2.1}/tests/test_symbols/test_symbol.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hilda
|
|
3
|
-
Version: 3.1
|
|
3
|
+
Version: 3.2.1
|
|
4
4
|
Summary: LLDB wrapped and empowered by iPython's features
|
|
5
5
|
Author-email: doronz88 <doron88@gmail.com>, matan <matan1008@gmail.com>, netanel cohen <netanelc305@protonmail.com>
|
|
6
6
|
Maintainer-email: doronz88 <doron88@gmail.com>, matan <matan1008@gmail.com>, netanel cohen <netanelc305@protonmail.com>
|
|
@@ -129,7 +129,7 @@ You can may start a Hilda interactive shell by invoking any of the subcommand:
|
|
|
129
129
|
- `hilda attach [-p pid] [-n process-name]`
|
|
130
130
|
- Attach to an already running process on current host (specified by either `pid` or `process-name`)
|
|
131
131
|
- `hilda remote HOSTNAME PORT`
|
|
132
|
-
- Attach to an already running process on a target host (
|
|
132
|
+
- Attach to an already running process on a target host (specified by `HOSTNAME PORT`)
|
|
133
133
|
- `hilda bare`
|
|
134
134
|
- Only start an LLDB shell and load Hilda as a plugin.
|
|
135
135
|
- Please refer to the following help page if you require help on the command available to you within the lldb shell:
|
|
@@ -145,8 +145,8 @@ You can may start a Hilda interactive shell by invoking any of the subcommand:
|
|
|
145
145
|
... and attaching to a local process:
|
|
146
146
|
|
|
147
147
|
```shell
|
|
148
|
-
process attach -n
|
|
149
|
-
process attach -p
|
|
148
|
+
process attach -n process_name
|
|
149
|
+
process attach -p process_pid
|
|
150
150
|
```
|
|
151
151
|
|
|
152
152
|
When you are ready, just execute `hilda` to move to Hilda's iPython shell.
|
|
@@ -164,7 +164,7 @@ Basic flow control:
|
|
|
164
164
|
- `step_into` - Step into current instruction
|
|
165
165
|
- `step_over` - Step over current instruction.
|
|
166
166
|
- `run_for` - Run the process for given interval
|
|
167
|
-
- `force_return` - Prematurely return from a stack frame, short-circuiting
|
|
167
|
+
- `force_return` - Prematurely return from a stack frame, short-circuiting execution of inner
|
|
168
168
|
frames and optionally yielding a specified value.
|
|
169
169
|
- `jump` - Jump to given symbol
|
|
170
170
|
- `wait_for_module` - Wait for a module to be loaded (`dlopen`) by checking if given expression is contained within its filename
|
|
@@ -176,7 +176,7 @@ Breakpoints:
|
|
|
176
176
|
- `breakpoints.show` - Show existing breakpoints
|
|
177
177
|
- `breakpoints.remove` - Remove a single breakpoint
|
|
178
178
|
- `breakpoints.clear` - Remove all breakpoints
|
|
179
|
-
- `monitor` or `breakpoints.add_monitor` - Creates a breakpoint whose callback implements the requested features (print register
|
|
179
|
+
- `monitor` or `breakpoints.add_monitor` - Creates a breakpoint whose callback implements the requested features (print register values, execute commands, mock return value, etc.)
|
|
180
180
|
|
|
181
181
|
Basic read/write:
|
|
182
182
|
|
|
@@ -212,7 +212,6 @@ Hilda symbols:
|
|
|
212
212
|
|
|
213
213
|
- `symbol` - Get symbol object for a given address
|
|
214
214
|
- `objc_symbol` - Get objc symbol wrapper for given address
|
|
215
|
-
- `rebind_symbols` - Reparse all loaded images symbols
|
|
216
215
|
- `file_symbol` - Calculate symbol address without ASLR
|
|
217
216
|
- `save` - Save loaded symbols map (for loading later using the load() command)
|
|
218
217
|
- `load` - Load an existing symbols map (previously saved by the save() command)
|
|
@@ -293,7 +292,7 @@ ui.show()
|
|
|
293
292
|
```
|
|
294
293
|
|
|
295
294
|
By default `step_into` and `step_over` will show this UI automatically.
|
|
296
|
-
You may disable this
|
|
295
|
+
You may disable this behavior by executing:
|
|
297
296
|
|
|
298
297
|
```python
|
|
299
298
|
ui.active = False
|
|
@@ -417,7 +416,7 @@ s[0] = 1
|
|
|
417
416
|
s[0] = p.symbol(0x11223344)() # calling symbols also returns symbols
|
|
418
417
|
|
|
419
418
|
# attempt to resolve symbol's name
|
|
420
|
-
print(p.symbol(0x11223344).
|
|
419
|
+
print(p.symbol(0x11223344).lldb_address)
|
|
421
420
|
|
|
422
421
|
# monitor each time a symbol is called into console and print its backtrace (`bt` option)
|
|
423
422
|
# this will create a scripted breakpoint which prints your desired data and continue
|
|
@@ -467,8 +466,8 @@ p.bp(('symbol_name', 'ModuleName'))
|
|
|
467
466
|
#### Globalized symbols
|
|
468
467
|
|
|
469
468
|
Usually you would want/need to use the symbols already mapped into the currently running process. To do so, you can
|
|
470
|
-
access them using `symbols.<symbol-name>`. The `symbols` global object is of type `
|
|
471
|
-
|
|
469
|
+
access them using `symbols.<symbol-name>`. The `symbols` global object is of type `SymbolList`, which acts like
|
|
470
|
+
`dict` for accessing all exported symbols. For example, the following will generate a call to the exported
|
|
472
471
|
`malloc` function with `20` as its only argument:
|
|
473
472
|
|
|
474
473
|
```python
|
|
@@ -491,22 +490,17 @@ x = malloc(20)
|
|
|
491
490
|
Sometimes you don't really know where to start your research. All you have is just theories of how your desired exported
|
|
492
491
|
symbol should be called (if any).
|
|
493
492
|
|
|
494
|
-
For that reason alone, we have the `rebind_symbols()`
|
|
495
|
-
command - to help you find the symbol you are looking for.
|
|
496
|
-
|
|
497
493
|
```python
|
|
498
|
-
p.rebind_symbols() # this might take some time
|
|
499
|
-
|
|
500
494
|
# find all symbols prefixed as `mem*` AND don't have `cpy`
|
|
501
495
|
# in their name
|
|
502
|
-
|
|
496
|
+
l = p.symbols.filter_startswith('mem') - p.symbols.filter_name_contains('cpy')
|
|
503
497
|
|
|
504
498
|
# filter only symbols of type "code" (removing data global for example)
|
|
505
|
-
|
|
499
|
+
l = l.filter_code_symbols()
|
|
506
500
|
|
|
507
501
|
# monitor every time each one is called, print its `x0` in HEX
|
|
508
502
|
# form and show the backtrace
|
|
509
|
-
|
|
503
|
+
l.monitor(regs={'x0': 'x'}, bt=True)
|
|
510
504
|
```
|
|
511
505
|
|
|
512
506
|
#### Objective-C Classes
|
|
@@ -538,21 +532,21 @@ print(NSDictionary.ivars)
|
|
|
538
532
|
# show the class' methods
|
|
539
533
|
print(NSDictionary.methods)
|
|
540
534
|
|
|
541
|
-
# show the class'
|
|
535
|
+
# show the class' properties
|
|
542
536
|
print(NSDictionary.properties)
|
|
543
537
|
|
|
544
538
|
# view class' selectors which are prefixed with 'init'
|
|
545
|
-
print(NSDictionary.
|
|
539
|
+
print(NSDictionary.methods.filter_startswith('init'))
|
|
546
540
|
|
|
547
|
-
# you can of course use any of `
|
|
541
|
+
# you can of course use any of `SymbolList` over them, for example:
|
|
548
542
|
# this will `po` (print object) all those selectors returned value
|
|
549
|
-
NSDictionary.
|
|
543
|
+
NSDictionary.methods.filter_startswith('init').monitor(retval='po')
|
|
550
544
|
|
|
551
545
|
# monitor each time any selector in NSDictionary is called
|
|
552
546
|
NSDictionary.monitor()
|
|
553
547
|
|
|
554
548
|
# `force_return` for some specific selector with a hard-coded value (4)
|
|
555
|
-
NSDictionary.
|
|
549
|
+
NSDictionary.methods.get('valueForKey:').address.monitor(force_return=4)
|
|
556
550
|
|
|
557
551
|
# capture the `self` object at the first hit of any selector
|
|
558
552
|
# `True` for busy-wait for object to be captured
|
|
@@ -637,7 +631,7 @@ They all use the following concept to use:
|
|
|
637
631
|
```python
|
|
638
632
|
from hilda.snippets import snippet_name
|
|
639
633
|
|
|
640
|
-
snippet_name.
|
|
634
|
+
snippet_name.do_something()
|
|
641
635
|
```
|
|
642
636
|
|
|
643
637
|
For example, XPC sniffing can be done using:
|
|
@@ -70,7 +70,7 @@ You can may start a Hilda interactive shell by invoking any of the subcommand:
|
|
|
70
70
|
- `hilda attach [-p pid] [-n process-name]`
|
|
71
71
|
- Attach to an already running process on current host (specified by either `pid` or `process-name`)
|
|
72
72
|
- `hilda remote HOSTNAME PORT`
|
|
73
|
-
- Attach to an already running process on a target host (
|
|
73
|
+
- Attach to an already running process on a target host (specified by `HOSTNAME PORT`)
|
|
74
74
|
- `hilda bare`
|
|
75
75
|
- Only start an LLDB shell and load Hilda as a plugin.
|
|
76
76
|
- Please refer to the following help page if you require help on the command available to you within the lldb shell:
|
|
@@ -86,8 +86,8 @@ You can may start a Hilda interactive shell by invoking any of the subcommand:
|
|
|
86
86
|
... and attaching to a local process:
|
|
87
87
|
|
|
88
88
|
```shell
|
|
89
|
-
process attach -n
|
|
90
|
-
process attach -p
|
|
89
|
+
process attach -n process_name
|
|
90
|
+
process attach -p process_pid
|
|
91
91
|
```
|
|
92
92
|
|
|
93
93
|
When you are ready, just execute `hilda` to move to Hilda's iPython shell.
|
|
@@ -105,7 +105,7 @@ Basic flow control:
|
|
|
105
105
|
- `step_into` - Step into current instruction
|
|
106
106
|
- `step_over` - Step over current instruction.
|
|
107
107
|
- `run_for` - Run the process for given interval
|
|
108
|
-
- `force_return` - Prematurely return from a stack frame, short-circuiting
|
|
108
|
+
- `force_return` - Prematurely return from a stack frame, short-circuiting execution of inner
|
|
109
109
|
frames and optionally yielding a specified value.
|
|
110
110
|
- `jump` - Jump to given symbol
|
|
111
111
|
- `wait_for_module` - Wait for a module to be loaded (`dlopen`) by checking if given expression is contained within its filename
|
|
@@ -117,7 +117,7 @@ Breakpoints:
|
|
|
117
117
|
- `breakpoints.show` - Show existing breakpoints
|
|
118
118
|
- `breakpoints.remove` - Remove a single breakpoint
|
|
119
119
|
- `breakpoints.clear` - Remove all breakpoints
|
|
120
|
-
- `monitor` or `breakpoints.add_monitor` - Creates a breakpoint whose callback implements the requested features (print register
|
|
120
|
+
- `monitor` or `breakpoints.add_monitor` - Creates a breakpoint whose callback implements the requested features (print register values, execute commands, mock return value, etc.)
|
|
121
121
|
|
|
122
122
|
Basic read/write:
|
|
123
123
|
|
|
@@ -153,7 +153,6 @@ Hilda symbols:
|
|
|
153
153
|
|
|
154
154
|
- `symbol` - Get symbol object for a given address
|
|
155
155
|
- `objc_symbol` - Get objc symbol wrapper for given address
|
|
156
|
-
- `rebind_symbols` - Reparse all loaded images symbols
|
|
157
156
|
- `file_symbol` - Calculate symbol address without ASLR
|
|
158
157
|
- `save` - Save loaded symbols map (for loading later using the load() command)
|
|
159
158
|
- `load` - Load an existing symbols map (previously saved by the save() command)
|
|
@@ -234,7 +233,7 @@ ui.show()
|
|
|
234
233
|
```
|
|
235
234
|
|
|
236
235
|
By default `step_into` and `step_over` will show this UI automatically.
|
|
237
|
-
You may disable this
|
|
236
|
+
You may disable this behavior by executing:
|
|
238
237
|
|
|
239
238
|
```python
|
|
240
239
|
ui.active = False
|
|
@@ -358,7 +357,7 @@ s[0] = 1
|
|
|
358
357
|
s[0] = p.symbol(0x11223344)() # calling symbols also returns symbols
|
|
359
358
|
|
|
360
359
|
# attempt to resolve symbol's name
|
|
361
|
-
print(p.symbol(0x11223344).
|
|
360
|
+
print(p.symbol(0x11223344).lldb_address)
|
|
362
361
|
|
|
363
362
|
# monitor each time a symbol is called into console and print its backtrace (`bt` option)
|
|
364
363
|
# this will create a scripted breakpoint which prints your desired data and continue
|
|
@@ -408,8 +407,8 @@ p.bp(('symbol_name', 'ModuleName'))
|
|
|
408
407
|
#### Globalized symbols
|
|
409
408
|
|
|
410
409
|
Usually you would want/need to use the symbols already mapped into the currently running process. To do so, you can
|
|
411
|
-
access them using `symbols.<symbol-name>`. The `symbols` global object is of type `
|
|
412
|
-
|
|
410
|
+
access them using `symbols.<symbol-name>`. The `symbols` global object is of type `SymbolList`, which acts like
|
|
411
|
+
`dict` for accessing all exported symbols. For example, the following will generate a call to the exported
|
|
413
412
|
`malloc` function with `20` as its only argument:
|
|
414
413
|
|
|
415
414
|
```python
|
|
@@ -432,22 +431,17 @@ x = malloc(20)
|
|
|
432
431
|
Sometimes you don't really know where to start your research. All you have is just theories of how your desired exported
|
|
433
432
|
symbol should be called (if any).
|
|
434
433
|
|
|
435
|
-
For that reason alone, we have the `rebind_symbols()`
|
|
436
|
-
command - to help you find the symbol you are looking for.
|
|
437
|
-
|
|
438
434
|
```python
|
|
439
|
-
p.rebind_symbols() # this might take some time
|
|
440
|
-
|
|
441
435
|
# find all symbols prefixed as `mem*` AND don't have `cpy`
|
|
442
436
|
# in their name
|
|
443
|
-
|
|
437
|
+
l = p.symbols.filter_startswith('mem') - p.symbols.filter_name_contains('cpy')
|
|
444
438
|
|
|
445
439
|
# filter only symbols of type "code" (removing data global for example)
|
|
446
|
-
|
|
440
|
+
l = l.filter_code_symbols()
|
|
447
441
|
|
|
448
442
|
# monitor every time each one is called, print its `x0` in HEX
|
|
449
443
|
# form and show the backtrace
|
|
450
|
-
|
|
444
|
+
l.monitor(regs={'x0': 'x'}, bt=True)
|
|
451
445
|
```
|
|
452
446
|
|
|
453
447
|
#### Objective-C Classes
|
|
@@ -479,21 +473,21 @@ print(NSDictionary.ivars)
|
|
|
479
473
|
# show the class' methods
|
|
480
474
|
print(NSDictionary.methods)
|
|
481
475
|
|
|
482
|
-
# show the class'
|
|
476
|
+
# show the class' properties
|
|
483
477
|
print(NSDictionary.properties)
|
|
484
478
|
|
|
485
479
|
# view class' selectors which are prefixed with 'init'
|
|
486
|
-
print(NSDictionary.
|
|
480
|
+
print(NSDictionary.methods.filter_startswith('init'))
|
|
487
481
|
|
|
488
|
-
# you can of course use any of `
|
|
482
|
+
# you can of course use any of `SymbolList` over them, for example:
|
|
489
483
|
# this will `po` (print object) all those selectors returned value
|
|
490
|
-
NSDictionary.
|
|
484
|
+
NSDictionary.methods.filter_startswith('init').monitor(retval='po')
|
|
491
485
|
|
|
492
486
|
# monitor each time any selector in NSDictionary is called
|
|
493
487
|
NSDictionary.monitor()
|
|
494
488
|
|
|
495
489
|
# `force_return` for some specific selector with a hard-coded value (4)
|
|
496
|
-
NSDictionary.
|
|
490
|
+
NSDictionary.methods.get('valueForKey:').address.monitor(force_return=4)
|
|
497
491
|
|
|
498
492
|
# capture the `self` object at the first hit of any selector
|
|
499
493
|
# `True` for busy-wait for object to be captured
|
|
@@ -578,7 +572,7 @@ They all use the following concept to use:
|
|
|
578
572
|
```python
|
|
579
573
|
from hilda.snippets import snippet_name
|
|
580
574
|
|
|
581
|
-
snippet_name.
|
|
575
|
+
snippet_name.do_something()
|
|
582
576
|
```
|
|
583
577
|
|
|
584
578
|
For example, XPC sniffing can be done using:
|
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
# file generated by setuptools-scm
|
|
2
2
|
# don't change, don't track in version control
|
|
3
3
|
|
|
4
|
-
__all__ = [
|
|
4
|
+
__all__ = [
|
|
5
|
+
"__version__",
|
|
6
|
+
"__version_tuple__",
|
|
7
|
+
"version",
|
|
8
|
+
"version_tuple",
|
|
9
|
+
"__commit_id__",
|
|
10
|
+
"commit_id",
|
|
11
|
+
]
|
|
5
12
|
|
|
6
13
|
TYPE_CHECKING = False
|
|
7
14
|
if TYPE_CHECKING:
|
|
@@ -9,13 +16,19 @@ if TYPE_CHECKING:
|
|
|
9
16
|
from typing import Union
|
|
10
17
|
|
|
11
18
|
VERSION_TUPLE = Tuple[Union[int, str], ...]
|
|
19
|
+
COMMIT_ID = Union[str, None]
|
|
12
20
|
else:
|
|
13
21
|
VERSION_TUPLE = object
|
|
22
|
+
COMMIT_ID = object
|
|
14
23
|
|
|
15
24
|
version: str
|
|
16
25
|
__version__: str
|
|
17
26
|
__version_tuple__: VERSION_TUPLE
|
|
18
27
|
version_tuple: VERSION_TUPLE
|
|
28
|
+
commit_id: COMMIT_ID
|
|
29
|
+
__commit_id__: COMMIT_ID
|
|
19
30
|
|
|
20
|
-
__version__ = version = '3.1
|
|
21
|
-
__version_tuple__ = version_tuple = (3,
|
|
31
|
+
__version__ = version = '3.2.1'
|
|
32
|
+
__version_tuple__ = version_tuple = (3, 2, 1)
|
|
33
|
+
|
|
34
|
+
__commit_id__ = commit_id = 'g44204a25f'
|
|
@@ -157,7 +157,7 @@ class HildaBreakpoint:
|
|
|
157
157
|
# A single breakpoint may be related to several locations (addresses)
|
|
158
158
|
locations = self.locations
|
|
159
159
|
if len(locations) == 0:
|
|
160
|
-
result +=
|
|
160
|
+
result += '\tNo locations\n'
|
|
161
161
|
for location in self.locations:
|
|
162
162
|
result += f'\tLocation {location}\n'
|
|
163
163
|
|
|
@@ -227,6 +227,7 @@ class BreakpointList:
|
|
|
227
227
|
if it does not exist.
|
|
228
228
|
|
|
229
229
|
:param id_or_name_or_bp: Breakpoint's ID or name (or the breakpoint itself)
|
|
230
|
+
:return: `HildaBreakpoint` if one exists, or `None` otherwise
|
|
230
231
|
"""
|
|
231
232
|
|
|
232
233
|
if isinstance(id_or_name_or_bp, int):
|
|
@@ -362,14 +363,13 @@ class BreakpointList:
|
|
|
362
363
|
:param frame: LLDB frame
|
|
363
364
|
:param bp_loc: LLDB breakpoint location
|
|
364
365
|
"""
|
|
365
|
-
nonlocal
|
|
366
|
+
nonlocal name
|
|
366
367
|
bp = bp_loc.GetBreakpoint()
|
|
367
368
|
symbol = hilda.symbol(hilda.frame.addr.GetLoadAddress(hilda.target))
|
|
368
369
|
thread = hilda.thread
|
|
369
|
-
printed_name = name if name is not None else str(symbol.
|
|
370
|
+
printed_name = name if name is not None else str(symbol.lldb_address)
|
|
370
371
|
|
|
371
372
|
def format_value(fmt: Union[str, Callable], value: Symbol) -> str:
|
|
372
|
-
nonlocal hilda
|
|
373
373
|
if callable(fmt):
|
|
374
374
|
return fmt(hilda, value)
|
|
375
375
|
formatters = {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
__all__ = ['HildaException', 'SymbolAbsentError', 'EvaluatingExpressionError', 'CreatingObjectiveCSymbolError',
|
|
2
2
|
'ConvertingToNsObjectError', 'ConvertingFromNSObjectError', 'DisableJetsamMemoryChecksError',
|
|
3
3
|
'GettingObjectiveCClassError', 'AccessingRegisterError', 'AccessingMemoryError',
|
|
4
|
-
'
|
|
4
|
+
'AddingLldbSymbolError', 'LLDBError', 'InvalidThreadIndexError']
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
class HildaException(Exception):
|
|
@@ -59,11 +59,6 @@ class AccessingMemoryError(HildaException):
|
|
|
59
59
|
pass
|
|
60
60
|
|
|
61
61
|
|
|
62
|
-
class BrokenLocalSymbolsJarError(HildaException):
|
|
63
|
-
""" Raise when attempt to load an invalid symbols jar pickle """
|
|
64
|
-
pass
|
|
65
|
-
|
|
66
|
-
|
|
67
62
|
class AddingLldbSymbolError(HildaException):
|
|
68
63
|
""" Raise when failing to convert a LLDB symbol to Hilda's symbol. """
|
|
69
64
|
pass
|
|
@@ -10,7 +10,7 @@ import sys
|
|
|
10
10
|
import time
|
|
11
11
|
import typing
|
|
12
12
|
from collections import namedtuple
|
|
13
|
-
from contextlib import contextmanager
|
|
13
|
+
from contextlib import contextmanager
|
|
14
14
|
from dataclasses import dataclass, field
|
|
15
15
|
from datetime import datetime, timezone
|
|
16
16
|
from functools import cached_property, wraps
|
|
@@ -30,17 +30,16 @@ from traitlets.config import Config
|
|
|
30
30
|
from hilda import objective_c_class
|
|
31
31
|
from hilda.breakpoints import BreakpointList, HildaBreakpoint, WhereType
|
|
32
32
|
from hilda.common import CfSerializable, selection_prompt
|
|
33
|
-
from hilda.exceptions import AccessingMemoryError, AccessingRegisterError,
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
SymbolAbsentError
|
|
33
|
+
from hilda.exceptions import AccessingMemoryError, AccessingRegisterError, ConvertingFromNSObjectError, \
|
|
34
|
+
ConvertingToNsObjectError, CreatingObjectiveCSymbolError, DisableJetsamMemoryChecksError, \
|
|
35
|
+
EvaluatingExpressionError, HildaException, InvalidThreadIndexError, SymbolAbsentError
|
|
37
36
|
from hilda.ipython_extensions.keybindings import get_keybindings
|
|
38
37
|
from hilda.lldb_importer import lldb
|
|
39
38
|
from hilda.objective_c_symbol import ObjectiveCSymbol
|
|
40
39
|
from hilda.registers import Registers
|
|
41
40
|
from hilda.snippets.mach import CFRunLoopServiceMachPort_hooks
|
|
42
41
|
from hilda.symbol import Symbol
|
|
43
|
-
from hilda.
|
|
42
|
+
from hilda.symbols import SymbolList
|
|
44
43
|
from hilda.ui.ui_manager import UiManager
|
|
45
44
|
from hilda.watchpoints import WatchpointList
|
|
46
45
|
|
|
@@ -127,7 +126,7 @@ class HildaClient:
|
|
|
127
126
|
self.debugger = debugger
|
|
128
127
|
self.target = debugger.GetSelectedTarget()
|
|
129
128
|
self.process = self.target.GetProcess()
|
|
130
|
-
self.symbols =
|
|
129
|
+
self.symbols = SymbolList(self)
|
|
131
130
|
self.breakpoints = BreakpointList(self)
|
|
132
131
|
self.watchpoints = WatchpointList(self)
|
|
133
132
|
self.captured_objects = {}
|
|
@@ -201,7 +200,7 @@ class HildaClient:
|
|
|
201
200
|
:param address:
|
|
202
201
|
:return: Hilda's symbol object
|
|
203
202
|
"""
|
|
204
|
-
return
|
|
203
|
+
return self.symbols.add(address)
|
|
205
204
|
|
|
206
205
|
def objc_symbol(self, address: int) -> ObjectiveCSymbol:
|
|
207
206
|
"""
|
|
@@ -214,18 +213,18 @@ class HildaClient:
|
|
|
214
213
|
except HildaException as e:
|
|
215
214
|
raise CreatingObjectiveCSymbolError from e
|
|
216
215
|
|
|
217
|
-
def inject(self, filename: str) ->
|
|
216
|
+
def inject(self, filename: str) -> SymbolList:
|
|
218
217
|
"""
|
|
219
218
|
Inject a single library into currently running process.
|
|
220
219
|
|
|
221
220
|
:param filename: library to inject (dylib)
|
|
222
|
-
:return:
|
|
221
|
+
:return: SymbolList
|
|
223
222
|
"""
|
|
224
223
|
module = self.target.FindModule(lldb.SBFileSpec(os.path.basename(filename), False))
|
|
225
224
|
if module.file.basename is not None:
|
|
226
225
|
self.log_warning(f'file {filename} has already been loaded')
|
|
227
226
|
|
|
228
|
-
injected =
|
|
227
|
+
injected = SymbolList(self)
|
|
229
228
|
handle = self.symbols.dlopen(filename, 10) # RTLD_GLOBAL|RTLD_NOW
|
|
230
229
|
|
|
231
230
|
if handle == 0:
|
|
@@ -247,34 +246,9 @@ class HildaClient:
|
|
|
247
246
|
# ignore unnamed symbols and those which are not: data, code or objc classes
|
|
248
247
|
continue
|
|
249
248
|
|
|
250
|
-
injected
|
|
249
|
+
injected.add(self.symbol(load_addr), name)
|
|
251
250
|
return injected
|
|
252
251
|
|
|
253
|
-
def rebind_symbols(self, image_range=None, filename_expr=''):
|
|
254
|
-
"""
|
|
255
|
-
Reparse all loaded images symbols
|
|
256
|
-
:param image_range: index range for images to load in the form of [start, end]
|
|
257
|
-
:param filename_expr: filter only images containing given expression
|
|
258
|
-
"""
|
|
259
|
-
self.log_debug('mapping symbols')
|
|
260
|
-
self._symbols_loaded = False
|
|
261
|
-
|
|
262
|
-
for i, module in enumerate(tqdm(self.target.modules)):
|
|
263
|
-
filename = module.file.basename
|
|
264
|
-
|
|
265
|
-
if filename_expr not in filename:
|
|
266
|
-
continue
|
|
267
|
-
|
|
268
|
-
if image_range is not None and (i < image_range[0] or i > image_range[1]):
|
|
269
|
-
continue
|
|
270
|
-
|
|
271
|
-
for symbol in module:
|
|
272
|
-
with suppress(AddingLldbSymbolError):
|
|
273
|
-
self.add_lldb_symbol(symbol)
|
|
274
|
-
|
|
275
|
-
globals()['symbols'] = self.symbols
|
|
276
|
-
self._symbols_loaded = True
|
|
277
|
-
|
|
278
252
|
@stop_is_needed
|
|
279
253
|
def poke(self, address, buf: bytes):
|
|
280
254
|
"""
|
|
@@ -594,7 +568,7 @@ class HildaClient:
|
|
|
594
568
|
""" jump to given symbol """
|
|
595
569
|
self.lldb_handle_command(f'j *{symbol}')
|
|
596
570
|
|
|
597
|
-
def lldb_handle_command(self, cmd: str) ->
|
|
571
|
+
def lldb_handle_command(self, cmd: str, capture_output: bool = False) -> Optional[str]:
|
|
598
572
|
"""
|
|
599
573
|
Execute an LLDB command
|
|
600
574
|
|
|
@@ -602,8 +576,15 @@ class HildaClient:
|
|
|
602
576
|
lldb_handle_command('register read')
|
|
603
577
|
|
|
604
578
|
:param cmd: LLDB command
|
|
579
|
+
:param capture_output: True if capturing the command output
|
|
580
|
+
:return: The output if capture was requested, None if not or the command failed
|
|
605
581
|
"""
|
|
606
|
-
|
|
582
|
+
if capture_output:
|
|
583
|
+
result = lldb.SBCommandReturnObject()
|
|
584
|
+
self.debugger.GetCommandInterpreter().HandleCommand(cmd, result)
|
|
585
|
+
return result.GetOutput() if result.Succeeded() else None
|
|
586
|
+
else:
|
|
587
|
+
self.debugger.HandleCommand(cmd)
|
|
607
588
|
|
|
608
589
|
def objc_get_class(self, name: str, module_name: Optional[str] = None) -> objective_c_class.Class:
|
|
609
590
|
"""
|
|
@@ -828,36 +809,6 @@ class HildaClient:
|
|
|
828
809
|
""" Log at info level """
|
|
829
810
|
self.logger.info(message)
|
|
830
811
|
|
|
831
|
-
def add_lldb_symbol(self, symbol: lldb.SBSymbol) -> Symbol:
|
|
832
|
-
"""
|
|
833
|
-
Convert an LLDB symbol into Hilda's symbol object and insert into `symbols` global
|
|
834
|
-
:param symbol: LLDB symbol
|
|
835
|
-
:return: converted symbol
|
|
836
|
-
:raise AddingLldbSymbolError: Hilda failed to convert the LLDB symbol.
|
|
837
|
-
"""
|
|
838
|
-
load_addr = symbol.addr.GetLoadAddress(self.target)
|
|
839
|
-
if load_addr == 0xffffffffffffffff:
|
|
840
|
-
# skip those not having a real address
|
|
841
|
-
raise AddingLldbSymbolError()
|
|
842
|
-
|
|
843
|
-
name = symbol.name
|
|
844
|
-
type_ = symbol.GetType()
|
|
845
|
-
|
|
846
|
-
if name in ('<redacted>',) or (type_ not in (lldb.eSymbolTypeCode,
|
|
847
|
-
lldb.eSymbolTypeRuntime,
|
|
848
|
-
lldb.eSymbolTypeData,
|
|
849
|
-
lldb.eSymbolTypeObjCMetaClass)):
|
|
850
|
-
# ignore unnamed symbols and those which are not in a really used type
|
|
851
|
-
raise AddingLldbSymbolError()
|
|
852
|
-
|
|
853
|
-
value = self.symbol(load_addr)
|
|
854
|
-
|
|
855
|
-
# add it into symbols global
|
|
856
|
-
self.symbols[name] = value
|
|
857
|
-
self.symbols[f'{name}{{{value.filename}}}'] = value
|
|
858
|
-
|
|
859
|
-
return value
|
|
860
|
-
|
|
861
812
|
def wait_for_module(self, expression: str) -> None:
|
|
862
813
|
""" Wait for a module to be loaded using `dlopen` by matching given expression """
|
|
863
814
|
self.log_info(f'Waiting for module name containing "{expression}" to be loaded')
|
|
@@ -901,7 +852,7 @@ class HildaClient:
|
|
|
901
852
|
|
|
902
853
|
# Configure and start IPython shell
|
|
903
854
|
ipython_config = Config()
|
|
904
|
-
ipython_config.IPCompleter.use_jedi =
|
|
855
|
+
ipython_config.IPCompleter.use_jedi = False
|
|
905
856
|
ipython_config.BaseIPythonApplication.profile = 'hilda'
|
|
906
857
|
ipython_config.InteractiveShellApp.extensions = ['hilda.ipython_extensions.magics',
|
|
907
858
|
'hilda.ipython_extensions.events',
|
|
@@ -3,10 +3,9 @@ import builtins
|
|
|
3
3
|
|
|
4
4
|
from IPython.terminal.interactiveshell import TerminalInteractiveShell
|
|
5
5
|
|
|
6
|
-
from hilda.exceptions import EvaluatingExpressionError
|
|
6
|
+
from hilda.exceptions import EvaluatingExpressionError
|
|
7
7
|
from hilda.hilda_client import HildaClient
|
|
8
8
|
from hilda.lldb_importer import lldb
|
|
9
|
-
from hilda.symbols_jar import SymbolsJar
|
|
10
9
|
|
|
11
10
|
|
|
12
11
|
class HIEvents:
|
|
@@ -30,22 +29,19 @@ class HIEvents:
|
|
|
30
29
|
# That are undefined
|
|
31
30
|
continue
|
|
32
31
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
except EvaluatingExpressionError:
|
|
47
|
-
self.hilda_client.log_warning(
|
|
48
|
-
f'Process is running. Pause execution in order to resolve "{node.id}"')
|
|
32
|
+
symbol = self.hilda_client.symbols.get(node.id)
|
|
33
|
+
if symbol is None:
|
|
34
|
+
continue
|
|
35
|
+
|
|
36
|
+
try:
|
|
37
|
+
self.hilda_client._add_global(
|
|
38
|
+
node.id,
|
|
39
|
+
symbol if symbol.type_ != lldb.eSymbolTypeObjCMetaClass else self.hilda_client.objc_get_class(
|
|
40
|
+
node.id)
|
|
41
|
+
)
|
|
42
|
+
except EvaluatingExpressionError:
|
|
43
|
+
self.hilda_client.log_warning(
|
|
44
|
+
f'Process is running. Pause execution in order to resolve "{node.id}"')
|
|
49
45
|
|
|
50
46
|
|
|
51
47
|
def load_ipython_extension(ip: TerminalInteractiveShell):
|