hilda 3.1.0__tar.gz → 3.2.0__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.0}/PKG-INFO +19 -25
- {hilda-3.1.0 → hilda-3.2.0}/README.md +18 -24
- {hilda-3.1.0 → hilda-3.2.0}/hilda/_version.py +2 -2
- {hilda-3.1.0 → hilda-3.2.0}/hilda/breakpoints.py +2 -1
- {hilda-3.1.0 → hilda-3.2.0}/hilda/exceptions.py +1 -6
- {hilda-3.1.0 → hilda-3.2.0}/hilda/hilda_client.py +17 -65
- {hilda-3.1.0 → hilda-3.2.0}/hilda/ipython_extensions/events.py +13 -17
- {hilda-3.1.0 → hilda-3.2.0}/hilda/objective_c_class.py +86 -29
- {hilda-3.1.0 → hilda-3.2.0}/hilda/objective_c_symbol.py +5 -16
- {hilda-3.1.0 → hilda-3.2.0}/hilda/symbol.py +47 -12
- hilda-3.2.0/hilda/symbols.py +579 -0
- {hilda-3.1.0 → hilda-3.2.0}/hilda/watchpoints.py +5 -5
- {hilda-3.1.0 → hilda-3.2.0}/hilda.egg-info/PKG-INFO +19 -25
- {hilda-3.1.0 → hilda-3.2.0}/hilda.egg-info/SOURCES.txt +2 -3
- {hilda-3.1.0 → hilda-3.2.0}/tests/test_symbols/test_objective_c_symbol.py +1 -1
- hilda-3.2.0/tests/test_symbols/test_symbol_list.py +142 -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.0}/.github/workflows/python-app.yml +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/.github/workflows/python-publish.yml +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/.gitignore +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/.pre-commit-config.yaml +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/LICENSE +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/gifs/.gitattributes +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/gifs/ui.png +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/gifs/xpc_print_message.gif +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/hilda/__init__.py +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/hilda/__main__.py +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/hilda/cli.py +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/hilda/common.py +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/hilda/decorators.py +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/hilda/ipython_extensions/keybindings.py +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/hilda/ipython_extensions/magics.py +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/hilda/launch_lldb.py +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/hilda/lldb_entrypoint.py +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/hilda/lldb_importer.py +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/hilda/objective_c/from_ns_to_json.m +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/hilda/objective_c/get_objectivec_class_by_module.m +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/hilda/objective_c/get_objectivec_class_description.m +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/hilda/objective_c/get_objectivec_symbol_data.m +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/hilda/objective_c/lsof.m +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/hilda/objective_c/to_ns_from_json.m +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/hilda/registers.py +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/hilda/snippets/__init__.py +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/hilda/snippets/boringssl.py +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/hilda/snippets/collections.py +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/hilda/snippets/dyld.py +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/hilda/snippets/fs_utils.py +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/hilda/snippets/libmalloc.py +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/hilda/snippets/mach/CFRunLoopServiceMachPort_hooks.py +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/hilda/snippets/mach/__init__.py +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/hilda/snippets/macho/__init__.py +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/hilda/snippets/macho/all_image_infos.py +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/hilda/snippets/macho/apple_version.py +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/hilda/snippets/macho/image_info.py +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/hilda/snippets/macho/macho.py +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/hilda/snippets/macho/macho_load_commands.py +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/hilda/snippets/remotepairingd.py +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/hilda/snippets/syslog.py +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/hilda/snippets/uuid.py +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/hilda/snippets/xpc.py +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/hilda/ui/colors.json +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/hilda/ui/ui_manager.py +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/hilda/ui/views.py +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/hilda.egg-info/dependency_links.txt +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/hilda.egg-info/entry_points.txt +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/hilda.egg-info/requires.txt +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/hilda.egg-info/top_level.txt +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/pyproject.toml +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/requirements.txt +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/setup.cfg +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/tests/__init__.py +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/tests/conftest.py +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/tests/test_hilda_client/test_from_ns.py +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/tests/test_hilda_client/test_hilda_client.py +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/tests/test_hilda_client/test_monitor.py +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/tests/test_hilda_client/test_ns.py +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/tests/test_hilda_client/test_registers.py +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/tests/test_snippets/test_xpc.py +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/tests/test_symbols/test_objective_c_class.py +0 -0
- {hilda-3.1.0 → hilda-3.2.0}/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.
|
|
3
|
+
Version: 3.2.0
|
|
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:
|
|
@@ -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):
|
|
@@ -366,7 +367,7 @@ class BreakpointList:
|
|
|
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
373
|
nonlocal hilda
|
|
@@ -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
|
|
@@ -40,7 +40,7 @@ from hilda.objective_c_symbol import ObjectiveCSymbol
|
|
|
40
40
|
from hilda.registers import Registers
|
|
41
41
|
from hilda.snippets.mach import CFRunLoopServiceMachPort_hooks
|
|
42
42
|
from hilda.symbol import Symbol
|
|
43
|
-
from hilda.
|
|
43
|
+
from hilda.symbols import SymbolList
|
|
44
44
|
from hilda.ui.ui_manager import UiManager
|
|
45
45
|
from hilda.watchpoints import WatchpointList
|
|
46
46
|
|
|
@@ -127,7 +127,7 @@ class HildaClient:
|
|
|
127
127
|
self.debugger = debugger
|
|
128
128
|
self.target = debugger.GetSelectedTarget()
|
|
129
129
|
self.process = self.target.GetProcess()
|
|
130
|
-
self.symbols =
|
|
130
|
+
self.symbols = SymbolList(self)
|
|
131
131
|
self.breakpoints = BreakpointList(self)
|
|
132
132
|
self.watchpoints = WatchpointList(self)
|
|
133
133
|
self.captured_objects = {}
|
|
@@ -201,7 +201,7 @@ class HildaClient:
|
|
|
201
201
|
:param address:
|
|
202
202
|
:return: Hilda's symbol object
|
|
203
203
|
"""
|
|
204
|
-
return
|
|
204
|
+
return self.symbols.add(address)
|
|
205
205
|
|
|
206
206
|
def objc_symbol(self, address: int) -> ObjectiveCSymbol:
|
|
207
207
|
"""
|
|
@@ -214,18 +214,18 @@ class HildaClient:
|
|
|
214
214
|
except HildaException as e:
|
|
215
215
|
raise CreatingObjectiveCSymbolError from e
|
|
216
216
|
|
|
217
|
-
def inject(self, filename: str) ->
|
|
217
|
+
def inject(self, filename: str) -> SymbolList:
|
|
218
218
|
"""
|
|
219
219
|
Inject a single library into currently running process.
|
|
220
220
|
|
|
221
221
|
:param filename: library to inject (dylib)
|
|
222
|
-
:return:
|
|
222
|
+
:return: SymbolList
|
|
223
223
|
"""
|
|
224
224
|
module = self.target.FindModule(lldb.SBFileSpec(os.path.basename(filename), False))
|
|
225
225
|
if module.file.basename is not None:
|
|
226
226
|
self.log_warning(f'file {filename} has already been loaded')
|
|
227
227
|
|
|
228
|
-
injected =
|
|
228
|
+
injected = SymbolList(self)
|
|
229
229
|
handle = self.symbols.dlopen(filename, 10) # RTLD_GLOBAL|RTLD_NOW
|
|
230
230
|
|
|
231
231
|
if handle == 0:
|
|
@@ -247,34 +247,9 @@ class HildaClient:
|
|
|
247
247
|
# ignore unnamed symbols and those which are not: data, code or objc classes
|
|
248
248
|
continue
|
|
249
249
|
|
|
250
|
-
injected
|
|
250
|
+
injected.add(self.symbol(load_addr), name)
|
|
251
251
|
return injected
|
|
252
252
|
|
|
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
253
|
@stop_is_needed
|
|
279
254
|
def poke(self, address, buf: bytes):
|
|
280
255
|
"""
|
|
@@ -594,7 +569,7 @@ class HildaClient:
|
|
|
594
569
|
""" jump to given symbol """
|
|
595
570
|
self.lldb_handle_command(f'j *{symbol}')
|
|
596
571
|
|
|
597
|
-
def lldb_handle_command(self, cmd: str) ->
|
|
572
|
+
def lldb_handle_command(self, cmd: str, capture_output: bool = False) -> Optional[str]:
|
|
598
573
|
"""
|
|
599
574
|
Execute an LLDB command
|
|
600
575
|
|
|
@@ -602,8 +577,15 @@ class HildaClient:
|
|
|
602
577
|
lldb_handle_command('register read')
|
|
603
578
|
|
|
604
579
|
:param cmd: LLDB command
|
|
580
|
+
:param capture_output: True if capturing the command output
|
|
581
|
+
:return: The output if capture was requested, None if not or the command failed
|
|
605
582
|
"""
|
|
606
|
-
|
|
583
|
+
if capture_output:
|
|
584
|
+
result = lldb.SBCommandReturnObject()
|
|
585
|
+
self.debugger.GetCommandInterpreter().HandleCommand(cmd, result)
|
|
586
|
+
return result.GetOutput() if result.Succeeded() else None
|
|
587
|
+
else:
|
|
588
|
+
self.debugger.HandleCommand(cmd)
|
|
607
589
|
|
|
608
590
|
def objc_get_class(self, name: str, module_name: Optional[str] = None) -> objective_c_class.Class:
|
|
609
591
|
"""
|
|
@@ -828,36 +810,6 @@ class HildaClient:
|
|
|
828
810
|
""" Log at info level """
|
|
829
811
|
self.logger.info(message)
|
|
830
812
|
|
|
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
813
|
def wait_for_module(self, expression: str) -> None:
|
|
862
814
|
""" Wait for a module to be loaded using `dlopen` by matching given expression """
|
|
863
815
|
self.log_info(f'Waiting for module name containing "{expression}" to be loaded')
|
|
@@ -901,7 +853,7 @@ class HildaClient:
|
|
|
901
853
|
|
|
902
854
|
# Configure and start IPython shell
|
|
903
855
|
ipython_config = Config()
|
|
904
|
-
ipython_config.IPCompleter.use_jedi =
|
|
856
|
+
ipython_config.IPCompleter.use_jedi = False
|
|
905
857
|
ipython_config.BaseIPythonApplication.profile = 'hilda'
|
|
906
858
|
ipython_config.InteractiveShellApp.extensions = ['hilda.ipython_extensions.magics',
|
|
907
859
|
'hilda.ipython_extensions.events',
|
|
@@ -6,7 +6,6 @@ from IPython.terminal.interactiveshell import TerminalInteractiveShell
|
|
|
6
6
|
from hilda.exceptions import EvaluatingExpressionError, SymbolAbsentError
|
|
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):
|