hilda 0.1.2__tar.gz → 0.3.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-0.3.0/LICENSE +20 -0
- {hilda-0.1.2/hilda.egg-info → hilda-0.3.0}/PKG-INFO +113 -12
- hilda-0.1.2/PKG-INFO → hilda-0.3.0/README.md +81 -22
- {hilda-0.1.2 → hilda-0.3.0}/hilda/hilda_client.py +55 -35
- {hilda-0.1.2 → hilda-0.3.0}/hilda/launch_lldb.py +20 -0
- {hilda-0.1.2 → hilda-0.3.0}/hilda/lldb_entrypoint.py +3 -1
- {hilda-0.1.2 → hilda-0.3.0}/hilda/objective_c_class.py +3 -2
- {hilda-0.1.2 → hilda-0.3.0}/hilda/objective_c_symbol.py +3 -3
- hilda-0.3.0/hilda/snippets/boringssl.py +26 -0
- {hilda-0.1.2 → hilda-0.3.0}/hilda/snippets/dyld.py +1 -2
- hilda-0.3.0/hilda/snippets/mach/CFRunLoopServiceMachPort_hooks.py +92 -0
- {hilda-0.1.2 → hilda-0.3.0}/hilda/snippets/macho/all_image_infos.py +2 -2
- {hilda-0.1.2 → hilda-0.3.0}/hilda/snippets/macho/apple_version.py +1 -1
- {hilda-0.1.2 → hilda-0.3.0}/hilda/snippets/macho/image_info.py +1 -1
- {hilda-0.1.2 → hilda-0.3.0}/hilda/snippets/macho/macho.py +2 -1
- {hilda-0.1.2 → hilda-0.3.0}/hilda/snippets/macho/macho_load_commands.py +2 -3
- {hilda-0.1.2 → hilda-0.3.0}/hilda/snippets/remotepairingd.py +12 -18
- {hilda-0.1.2 → hilda-0.3.0}/hilda/snippets/uuid.py +1 -1
- {hilda-0.1.2 → hilda-0.3.0}/hilda/snippets/xpc.py +9 -0
- {hilda-0.1.2 → hilda-0.3.0}/hilda/symbol.py +9 -5
- {hilda-0.1.2 → hilda-0.3.0}/hilda/symbols_jar.py +1 -1
- hilda-0.3.0/hilda/ui/colors.json +13 -0
- hilda-0.3.0/hilda/ui/ui_manager.py +74 -0
- hilda-0.3.0/hilda/ui/views.py +217 -0
- hilda-0.1.2/README.md → hilda-0.3.0/hilda.egg-info/PKG-INFO +123 -7
- {hilda-0.1.2 → hilda-0.3.0}/hilda.egg-info/SOURCES.txt +7 -7
- {hilda-0.1.2 → hilda-0.3.0}/hilda.egg-info/requires.txt +0 -1
- hilda-0.3.0/hilda.egg-info/top_level.txt +3 -0
- hilda-0.3.0/pyproject.toml +51 -0
- hilda-0.3.0/requirements.txt +10 -0
- hilda-0.3.0/setup.cfg +4 -0
- hilda-0.1.2/hilda/snippets/mach/CFRunLoopServiceMachPort_hooks.py +0 -43
- hilda-0.1.2/hilda.egg-info/top_level.txt +0 -2
- hilda-0.1.2/setup.cfg +0 -48
- hilda-0.1.2/setup.py +0 -3
- hilda-0.1.2/tests/__init__.py +0 -0
- hilda-0.1.2/tests/__main__.py +0 -4
- hilda-0.1.2/tests/conftest.py +0 -21
- hilda-0.1.2/tests/hilda_tests.py +0 -20
- hilda-0.1.2/tests/lldb_entrypoint.py +0 -33
- {hilda-0.1.2 → hilda-0.3.0}/hilda/__init__.py +0 -0
- {hilda-0.1.2 → hilda-0.3.0}/hilda/__main__.py +0 -0
- {hilda-0.1.2 → hilda-0.3.0}/hilda/command.py +0 -0
- {hilda-0.1.2 → hilda-0.3.0}/hilda/exceptions.py +0 -0
- {hilda-0.1.2 → hilda-0.3.0}/hilda/from_ns_to_json.m +0 -0
- {hilda-0.1.2 → hilda-0.3.0}/hilda/get_objectivec_class_description.m +0 -0
- {hilda-0.1.2 → hilda-0.3.0}/hilda/get_objectivec_symbol_data.m +0 -0
- {hilda-0.1.2 → hilda-0.3.0}/hilda/hilda_ascii_art.html +0 -0
- {hilda-0.1.2 → hilda-0.3.0}/hilda/lsof.m +0 -0
- {hilda-0.1.2 → hilda-0.3.0}/hilda/registers.py +0 -0
- {hilda-0.1.2 → hilda-0.3.0}/hilda/snippets/__init__.py +0 -0
- {hilda-0.1.2 → hilda-0.3.0}/hilda/snippets/collections.py +0 -0
- {hilda-0.1.2 → hilda-0.3.0}/hilda/snippets/fs_utils.py +0 -0
- {hilda-0.1.2 → hilda-0.3.0}/hilda/snippets/mach/__init__.py +0 -0
- {hilda-0.1.2 → hilda-0.3.0}/hilda/snippets/macho/__init__.py +0 -0
- {hilda-0.1.2 → hilda-0.3.0}/hilda/snippets/syslog.py +0 -0
- {hilda-0.1.2 → hilda-0.3.0}/hilda/to_ns_from_json.m +0 -0
- {hilda-0.1.2 → hilda-0.3.0}/hilda.egg-info/dependency_links.txt +0 -0
- {hilda-0.1.2 → hilda-0.3.0}/hilda.egg-info/entry_points.txt +0 -0
hilda-0.3.0/LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright (c) 2012-2023 Doron Zarhi and Metan Perelman
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
|
+
a copy of this software and associated documentation files (the
|
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
9
|
+
the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be
|
|
12
|
+
included in all copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -1,17 +1,44 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: hilda
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: LLDB wrapped and empowered by iPython's features
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
Author-email: doronz88 <doron88@gmail.com>, matan <matan1008@gmail.com>, netanel <matan1008@gmail.com>
|
|
6
|
+
Maintainer-email: doronz88 <doron88@gmail.com>, matan <matan1008@gmail.com>
|
|
7
|
+
License: Copyright (c) 2012-2023 Doron Zarhi and Metan Perelman
|
|
8
|
+
|
|
9
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
10
|
+
a copy of this software and associated documentation files (the
|
|
11
|
+
"Software"), to deal in the Software without restriction, including
|
|
12
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
13
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
14
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
15
|
+
the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be
|
|
18
|
+
included in all copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
21
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
22
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
23
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
24
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
25
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
26
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
27
|
+
Project-URL: Homepage, https://github.com/doronz88/hilda
|
|
28
|
+
Project-URL: Bug Reports, https://github.com/doronz88/hilda/issues
|
|
29
|
+
Keywords: python,debugger,lldb,ipython,ios,debug
|
|
30
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
31
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
32
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
33
|
Classifier: Programming Language :: Python :: 3.8
|
|
10
34
|
Classifier: Programming Language :: Python :: 3.9
|
|
11
35
|
Classifier: Programming Language :: Python :: 3.10
|
|
12
36
|
Classifier: Programming Language :: Python :: 3.11
|
|
37
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
38
|
+
Requires-Python: >=3.8
|
|
13
39
|
Description-Content-Type: text/markdown
|
|
14
40
|
Provides-Extra: test
|
|
41
|
+
License-File: LICENSE
|
|
15
42
|
|
|
16
43
|
- [Description](#description)
|
|
17
44
|
- [Example](#example)
|
|
@@ -80,6 +107,16 @@ xcrun python3 -m pip install --user -U hilda
|
|
|
80
107
|
|
|
81
108
|
## Starting a Hilda shell
|
|
82
109
|
|
|
110
|
+
### Attach mode
|
|
111
|
+
|
|
112
|
+
Use the attach sub-command in order to start an LLDB shell attached to given process.
|
|
113
|
+
|
|
114
|
+
```shell
|
|
115
|
+
hilda attach [-p pid] [-n process-name]
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
After attaching, simply execute `hilda` command to enter the hilda shell.
|
|
119
|
+
|
|
83
120
|
### Bare mode
|
|
84
121
|
|
|
85
122
|
Use "Bare mode" to get a "bare-bones" lldb shell, whereas hilda plugin is already loaded and ready to start. This mode
|
|
@@ -117,13 +154,17 @@ This mode will auto-connect to the remote device and attach to your target proce
|
|
|
117
154
|
remote jailbroken iOS device.
|
|
118
155
|
|
|
119
156
|
Please note the following:
|
|
120
|
-
|
|
121
|
-
|
|
157
|
+
|
|
158
|
+
* script assumes the connected device already **has a running ssh server**, which doesn't require a password (you can
|
|
159
|
+
use
|
|
160
|
+
`ssh-copy-id` to achieve this).
|
|
122
161
|
|
|
123
162
|
From this point the flow diverges into 2 flows:
|
|
124
163
|
|
|
125
164
|
### The connected device is connected to the network via `internet sharing` with your computer
|
|
165
|
+
|
|
126
166
|
Run the following command:
|
|
167
|
+
|
|
127
168
|
```shell
|
|
128
169
|
hilda remote PROCESS_NAME SSH_PORT
|
|
129
170
|
```
|
|
@@ -131,11 +172,12 @@ hilda remote PROCESS_NAME SSH_PORT
|
|
|
131
172
|
### The connected device is connected via Wi-Fi
|
|
132
173
|
|
|
133
174
|
For this to work, you will need to make sure of the following:
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
175
|
+
|
|
176
|
+
* Find your cellphone IP address (Settings -> Wi-Fi -> network info -> IP Address).
|
|
177
|
+
* Once you found it, run the following command:
|
|
178
|
+
```shell
|
|
179
|
+
hilda remote PROCESS_NAME SSH_PORT --hostname <DEVICE_IP_ADDRESS>
|
|
180
|
+
```
|
|
139
181
|
|
|
140
182
|
## Commands
|
|
141
183
|
|
|
@@ -260,6 +302,65 @@ capabilities:
|
|
|
260
302
|
stop?
|
|
261
303
|
```
|
|
262
304
|
|
|
305
|
+
## UI Configuration
|
|
306
|
+
|
|
307
|
+
Hilda contains minimal UI for examining the target state.
|
|
308
|
+
The UI is divided into views:
|
|
309
|
+
|
|
310
|
+
- Registers
|
|
311
|
+
- Disassembly
|
|
312
|
+
- Stack
|
|
313
|
+
- Backtrace
|
|
314
|
+
|
|
315
|
+

|
|
316
|
+
|
|
317
|
+
This UI can be displayed at any time be executing:
|
|
318
|
+
|
|
319
|
+
```python
|
|
320
|
+
ui.show()
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
By default `step_into` and `step_over` will show this UI automatically.
|
|
324
|
+
You may disable this behaviour by executing:
|
|
325
|
+
|
|
326
|
+
```python
|
|
327
|
+
ui.active = False
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
Attentively, if you want to display UI after hitting a breakpoint, you can register `ui.show` as callback:
|
|
331
|
+
|
|
332
|
+
```python
|
|
333
|
+
symbol(0x7ff7b97c21b0).bp(ui.show)
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
Try playing with the UI settings by yourself:
|
|
337
|
+
|
|
338
|
+
```python
|
|
339
|
+
# Disable stack view
|
|
340
|
+
ui.views.stack.active = False
|
|
341
|
+
|
|
342
|
+
# View words from the stack
|
|
343
|
+
ui.views.stack.depth = 10
|
|
344
|
+
|
|
345
|
+
# View last 10 frames
|
|
346
|
+
ui.views.backtrace.depth = 10
|
|
347
|
+
|
|
348
|
+
# Disassemble 5 instructions
|
|
349
|
+
ui.views.disassembly.instruction_count = 5
|
|
350
|
+
|
|
351
|
+
# Change disassembly syntax to AT&T
|
|
352
|
+
ui.views.disassembly.flavor = 'att'
|
|
353
|
+
|
|
354
|
+
# View floating point registers
|
|
355
|
+
ui.views.registers.rtype = 'float'
|
|
356
|
+
|
|
357
|
+
# Change addresses print color
|
|
358
|
+
ui.colors.address = 'red'
|
|
359
|
+
|
|
360
|
+
# Change titles color
|
|
361
|
+
ui.color.title = 'green'
|
|
362
|
+
```
|
|
363
|
+
|
|
263
364
|
## Symbol objects
|
|
264
365
|
|
|
265
366
|
In Hilda, almost everything is wrapped using the `Symbol` Object. Symbol is just a nicer way for referring to addresses
|
|
@@ -1,18 +1,3 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: hilda
|
|
3
|
-
Version: 0.1.2
|
|
4
|
-
Summary: LLDB wrapped and empowered by iPython's features
|
|
5
|
-
Home-page: https://github.com/doronz88/hilda
|
|
6
|
-
Author: DoronZ
|
|
7
|
-
Project-URL: hilda, https://github.com/doronz88/hilda
|
|
8
|
-
Classifier: Programming Language :: Python :: 3.7
|
|
9
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
10
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
11
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
12
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
-
Description-Content-Type: text/markdown
|
|
14
|
-
Provides-Extra: test
|
|
15
|
-
|
|
16
1
|
- [Description](#description)
|
|
17
2
|
- [Example](#example)
|
|
18
3
|
- [Installation](#installation)
|
|
@@ -80,6 +65,16 @@ xcrun python3 -m pip install --user -U hilda
|
|
|
80
65
|
|
|
81
66
|
## Starting a Hilda shell
|
|
82
67
|
|
|
68
|
+
### Attach mode
|
|
69
|
+
|
|
70
|
+
Use the attach sub-command in order to start an LLDB shell attached to given process.
|
|
71
|
+
|
|
72
|
+
```shell
|
|
73
|
+
hilda attach [-p pid] [-n process-name]
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
After attaching, simply execute `hilda` command to enter the hilda shell.
|
|
77
|
+
|
|
83
78
|
### Bare mode
|
|
84
79
|
|
|
85
80
|
Use "Bare mode" to get a "bare-bones" lldb shell, whereas hilda plugin is already loaded and ready to start. This mode
|
|
@@ -117,13 +112,17 @@ This mode will auto-connect to the remote device and attach to your target proce
|
|
|
117
112
|
remote jailbroken iOS device.
|
|
118
113
|
|
|
119
114
|
Please note the following:
|
|
120
|
-
|
|
121
|
-
|
|
115
|
+
|
|
116
|
+
* script assumes the connected device already **has a running ssh server**, which doesn't require a password (you can
|
|
117
|
+
use
|
|
118
|
+
`ssh-copy-id` to achieve this).
|
|
122
119
|
|
|
123
120
|
From this point the flow diverges into 2 flows:
|
|
124
121
|
|
|
125
122
|
### The connected device is connected to the network via `internet sharing` with your computer
|
|
123
|
+
|
|
126
124
|
Run the following command:
|
|
125
|
+
|
|
127
126
|
```shell
|
|
128
127
|
hilda remote PROCESS_NAME SSH_PORT
|
|
129
128
|
```
|
|
@@ -131,11 +130,12 @@ hilda remote PROCESS_NAME SSH_PORT
|
|
|
131
130
|
### The connected device is connected via Wi-Fi
|
|
132
131
|
|
|
133
132
|
For this to work, you will need to make sure of the following:
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
133
|
+
|
|
134
|
+
* Find your cellphone IP address (Settings -> Wi-Fi -> network info -> IP Address).
|
|
135
|
+
* Once you found it, run the following command:
|
|
136
|
+
```shell
|
|
137
|
+
hilda remote PROCESS_NAME SSH_PORT --hostname <DEVICE_IP_ADDRESS>
|
|
138
|
+
```
|
|
139
139
|
|
|
140
140
|
## Commands
|
|
141
141
|
|
|
@@ -260,6 +260,65 @@ capabilities:
|
|
|
260
260
|
stop?
|
|
261
261
|
```
|
|
262
262
|
|
|
263
|
+
## UI Configuration
|
|
264
|
+
|
|
265
|
+
Hilda contains minimal UI for examining the target state.
|
|
266
|
+
The UI is divided into views:
|
|
267
|
+
|
|
268
|
+
- Registers
|
|
269
|
+
- Disassembly
|
|
270
|
+
- Stack
|
|
271
|
+
- Backtrace
|
|
272
|
+
|
|
273
|
+

|
|
274
|
+
|
|
275
|
+
This UI can be displayed at any time be executing:
|
|
276
|
+
|
|
277
|
+
```python
|
|
278
|
+
ui.show()
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
By default `step_into` and `step_over` will show this UI automatically.
|
|
282
|
+
You may disable this behaviour by executing:
|
|
283
|
+
|
|
284
|
+
```python
|
|
285
|
+
ui.active = False
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
Attentively, if you want to display UI after hitting a breakpoint, you can register `ui.show` as callback:
|
|
289
|
+
|
|
290
|
+
```python
|
|
291
|
+
symbol(0x7ff7b97c21b0).bp(ui.show)
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
Try playing with the UI settings by yourself:
|
|
295
|
+
|
|
296
|
+
```python
|
|
297
|
+
# Disable stack view
|
|
298
|
+
ui.views.stack.active = False
|
|
299
|
+
|
|
300
|
+
# View words from the stack
|
|
301
|
+
ui.views.stack.depth = 10
|
|
302
|
+
|
|
303
|
+
# View last 10 frames
|
|
304
|
+
ui.views.backtrace.depth = 10
|
|
305
|
+
|
|
306
|
+
# Disassemble 5 instructions
|
|
307
|
+
ui.views.disassembly.instruction_count = 5
|
|
308
|
+
|
|
309
|
+
# Change disassembly syntax to AT&T
|
|
310
|
+
ui.views.disassembly.flavor = 'att'
|
|
311
|
+
|
|
312
|
+
# View floating point registers
|
|
313
|
+
ui.views.registers.rtype = 'float'
|
|
314
|
+
|
|
315
|
+
# Change addresses print color
|
|
316
|
+
ui.colors.address = 'red'
|
|
317
|
+
|
|
318
|
+
# Change titles color
|
|
319
|
+
ui.color.title = 'green'
|
|
320
|
+
```
|
|
321
|
+
|
|
263
322
|
## Symbol objects
|
|
264
323
|
|
|
265
324
|
In Hilda, almost everything is wrapped using the `Symbol` Object. Symbol is just a nicer way for referring to addresses
|
|
@@ -9,19 +9,21 @@ import os
|
|
|
9
9
|
import pickle
|
|
10
10
|
import textwrap
|
|
11
11
|
import time
|
|
12
|
+
import typing
|
|
12
13
|
from collections import namedtuple
|
|
13
14
|
from contextlib import contextmanager, suppress
|
|
14
15
|
from datetime import datetime, timezone
|
|
15
|
-
from functools import partial
|
|
16
|
+
from functools import cached_property, partial
|
|
16
17
|
from pathlib import Path
|
|
17
|
-
from typing import Union
|
|
18
|
+
from typing import List, Optional, Union
|
|
18
19
|
|
|
19
|
-
import IPython
|
|
20
20
|
import docstring_parser
|
|
21
21
|
import hexdump
|
|
22
|
+
import IPython
|
|
22
23
|
import lldb
|
|
23
24
|
from humanfriendly import prompts
|
|
24
25
|
from humanfriendly.terminal.html import html_to_ansi
|
|
26
|
+
from keystone import KS_ARCH_ARM64, KS_ARCH_X86, KS_MODE_64, KS_MODE_LITTLE_ENDIAN, Ks
|
|
25
27
|
from pygments import highlight
|
|
26
28
|
from pygments.formatters import TerminalTrueColorFormatter
|
|
27
29
|
from pygments.lexers import XmlLexer
|
|
@@ -29,14 +31,17 @@ from tqdm import tqdm
|
|
|
29
31
|
from traitlets.config import Config
|
|
30
32
|
|
|
31
33
|
from hilda import objective_c_class
|
|
32
|
-
from hilda.command import
|
|
33
|
-
from hilda.exceptions import
|
|
34
|
+
from hilda.command import CommandsMeta, command
|
|
35
|
+
from hilda.exceptions import AccessingMemoryError, AccessingRegisterError, AddingLldbSymbolError, \
|
|
36
|
+
BrokenLocalSymbolsJarError, ConvertingFromNSObjectError, ConvertingToNsObjectError, CreatingObjectiveCSymbolError, \
|
|
37
|
+
DisableJetsamMemoryChecksError, EvaluatingExpressionError, HildaException, SymbolAbsentError
|
|
38
|
+
from hilda.launch_lldb import disable_logs # noqa: F401
|
|
34
39
|
from hilda.objective_c_symbol import ObjectiveCSymbol
|
|
35
40
|
from hilda.registers import Registers
|
|
36
41
|
from hilda.snippets.mach import CFRunLoopServiceMachPort_hooks
|
|
37
42
|
from hilda.symbol import Symbol
|
|
38
43
|
from hilda.symbols_jar import SymbolsJar
|
|
39
|
-
from hilda.
|
|
44
|
+
from hilda.ui.ui_manager import UiManager
|
|
40
45
|
|
|
41
46
|
IsaMagic = namedtuple('IsaMagic', 'mask value')
|
|
42
47
|
ISA_MAGICS = [
|
|
@@ -77,7 +82,8 @@ class HildaClient(metaclass=CommandsMeta):
|
|
|
77
82
|
self.breakpoints = {}
|
|
78
83
|
self.captured_objects = {}
|
|
79
84
|
self.registers = Registers(self)
|
|
80
|
-
|
|
85
|
+
self.arch = self.target.GetTriple().split('-')[0]
|
|
86
|
+
self.ui_manager = UiManager(self)
|
|
81
87
|
# should unwind the stack on errors. change this to False in order to debug self-made calls
|
|
82
88
|
# within hilda
|
|
83
89
|
self._evaluation_unwind_on_error = True
|
|
@@ -117,16 +123,22 @@ class HildaClient(metaclass=CommandsMeta):
|
|
|
117
123
|
return {int(k): v for k, v in result.items()}
|
|
118
124
|
|
|
119
125
|
@command()
|
|
120
|
-
def bt(self):
|
|
126
|
+
def bt(self, should_print=True, depth: Optional[int] = None) -> List:
|
|
121
127
|
""" Print an improved backtrace. """
|
|
128
|
+
backtrace = []
|
|
122
129
|
for i, frame in enumerate(self.thread.frames):
|
|
130
|
+
if i == depth:
|
|
131
|
+
break
|
|
123
132
|
row = ''
|
|
124
133
|
row += html_to_ansi(f'<span style="color: cyan">0x{frame.addr.GetFileAddress():x}</span> ')
|
|
125
134
|
row += str(frame)
|
|
126
135
|
if i == 0:
|
|
127
136
|
# first line
|
|
128
137
|
row += ' 👈'
|
|
129
|
-
|
|
138
|
+
backtrace.append([f'0x{frame.addr.file_addr:016x}', frame])
|
|
139
|
+
if should_print:
|
|
140
|
+
print(row)
|
|
141
|
+
return backtrace
|
|
130
142
|
|
|
131
143
|
@command()
|
|
132
144
|
def disable_jetsam_memory_checks(self):
|
|
@@ -238,6 +250,16 @@ class HildaClient(metaclass=CommandsMeta):
|
|
|
238
250
|
|
|
239
251
|
return retval
|
|
240
252
|
|
|
253
|
+
@command()
|
|
254
|
+
def poke_text(self, address: int, code: str) -> int:
|
|
255
|
+
"""
|
|
256
|
+
Write instructions to address.
|
|
257
|
+
:param address:
|
|
258
|
+
:param code:
|
|
259
|
+
"""
|
|
260
|
+
bytecode, count = self._ks.asm(code, as_bytes=True)
|
|
261
|
+
return self.poke(address, bytecode)
|
|
262
|
+
|
|
241
263
|
@command()
|
|
242
264
|
def peek(self, address, size: int) -> bytes:
|
|
243
265
|
"""
|
|
@@ -258,28 +280,13 @@ class HildaClient(metaclass=CommandsMeta):
|
|
|
258
280
|
return retval
|
|
259
281
|
|
|
260
282
|
@command()
|
|
261
|
-
def peek_str(self, address
|
|
283
|
+
def peek_str(self, address: Symbol) -> str:
|
|
262
284
|
"""
|
|
263
285
|
Peek a buffer till null termination
|
|
264
286
|
:param address:
|
|
265
|
-
:param encoding: character encoding. if None, bytes is returned
|
|
266
287
|
:return:
|
|
267
288
|
"""
|
|
268
|
-
|
|
269
|
-
# always prefer using native strlen
|
|
270
|
-
buf = self.peek(address, self.symbols.strlen(address))
|
|
271
|
-
else:
|
|
272
|
-
buf = self.peek(address, 1)
|
|
273
|
-
while buf[-1] != 0:
|
|
274
|
-
buf += self.peek(address + len(buf), 1)
|
|
275
|
-
|
|
276
|
-
# remove null terminator
|
|
277
|
-
buf = buf[:-1]
|
|
278
|
-
|
|
279
|
-
if encoding is not None:
|
|
280
|
-
buf = str(buf, encoding)
|
|
281
|
-
|
|
282
|
-
return buf
|
|
289
|
+
return address.po('char *')[1:-1] # strip the ""
|
|
283
290
|
|
|
284
291
|
@command()
|
|
285
292
|
def stop(self):
|
|
@@ -322,15 +329,16 @@ class HildaClient(metaclass=CommandsMeta):
|
|
|
322
329
|
self.log_critical('failed to detach')
|
|
323
330
|
|
|
324
331
|
@command()
|
|
325
|
-
def disass(self, address, buf, should_print=True) -> lldb.SBInstructionList:
|
|
332
|
+
def disass(self, address, buf, flavor='intel', should_print=True) -> lldb.SBInstructionList:
|
|
326
333
|
"""
|
|
327
334
|
Print disassembly from a given address
|
|
335
|
+
:param flavor:
|
|
328
336
|
:param address:
|
|
329
337
|
:param buf:
|
|
330
338
|
:param should_print:
|
|
331
339
|
:return:
|
|
332
340
|
"""
|
|
333
|
-
inst = self.target.
|
|
341
|
+
inst = self.target.GetInstructionsWithFlavor(lldb.SBAddress(address, self.target), flavor, buf)
|
|
334
342
|
if should_print:
|
|
335
343
|
print(inst)
|
|
336
344
|
return inst
|
|
@@ -515,12 +523,16 @@ class HildaClient(metaclass=CommandsMeta):
|
|
|
515
523
|
""" Step into current instruction. """
|
|
516
524
|
with self.sync_mode():
|
|
517
525
|
self.thread.StepInto()
|
|
526
|
+
if self.ui_manager.active:
|
|
527
|
+
self.ui_manager.show()
|
|
518
528
|
|
|
519
529
|
@command()
|
|
520
530
|
def step_over(self):
|
|
521
531
|
""" Step over current instruction. """
|
|
522
532
|
with self.sync_mode():
|
|
523
533
|
self.thread.StepOver()
|
|
534
|
+
if self.ui_manager.active:
|
|
535
|
+
self.ui_manager.show()
|
|
524
536
|
|
|
525
537
|
@command()
|
|
526
538
|
def remove_all_hilda_breakpoints(self, remove_forced=False):
|
|
@@ -608,7 +620,7 @@ class HildaClient(metaclass=CommandsMeta):
|
|
|
608
620
|
|
|
609
621
|
def bp_callback_router(self, frame, bp_loc, *_):
|
|
610
622
|
"""
|
|
611
|
-
Route the breakpoint callback the
|
|
623
|
+
Route the breakpoint callback the specific breakpoint callback.
|
|
612
624
|
:param lldb.SBFrame frame: LLDB Frame object.
|
|
613
625
|
:param lldb.SBBreakpointLocation bp_loc: LLDB Breakpoint location object.
|
|
614
626
|
"""
|
|
@@ -902,13 +914,13 @@ class HildaClient(metaclass=CommandsMeta):
|
|
|
902
914
|
|
|
903
915
|
if is_running:
|
|
904
916
|
self.stop()
|
|
905
|
-
time.sleep(
|
|
917
|
+
time.sleep(interval)
|
|
906
918
|
|
|
907
919
|
try:
|
|
908
920
|
yield
|
|
909
921
|
finally:
|
|
910
922
|
if is_running:
|
|
911
|
-
time.sleep(
|
|
923
|
+
time.sleep(interval)
|
|
912
924
|
self.cont()
|
|
913
925
|
|
|
914
926
|
@contextmanager
|
|
@@ -1009,7 +1021,7 @@ class HildaClient(metaclass=CommandsMeta):
|
|
|
1009
1021
|
|
|
1010
1022
|
return value
|
|
1011
1023
|
|
|
1012
|
-
def interactive(self):
|
|
1024
|
+
def interactive(self, additional_namespace: typing.Mapping = None):
|
|
1013
1025
|
""" Start an interactive Hilda shell """
|
|
1014
1026
|
if not self._dynamic_env_loaded:
|
|
1015
1027
|
self.init_dynamic_environment()
|
|
@@ -1025,6 +1037,8 @@ class HildaClient(metaclass=CommandsMeta):
|
|
|
1025
1037
|
]
|
|
1026
1038
|
namespace = globals()
|
|
1027
1039
|
namespace.update(locals())
|
|
1040
|
+
if additional_namespace is not None:
|
|
1041
|
+
namespace.update(additional_namespace)
|
|
1028
1042
|
|
|
1029
1043
|
IPython.start_ipython(config=c, user_ns=namespace)
|
|
1030
1044
|
|
|
@@ -1116,12 +1130,11 @@ class HildaClient(metaclass=CommandsMeta):
|
|
|
1116
1130
|
raise NotImplementedError('cannot serialize argument')
|
|
1117
1131
|
return args_conv
|
|
1118
1132
|
|
|
1119
|
-
|
|
1120
|
-
def _generate_call_expression(address, params):
|
|
1133
|
+
def _generate_call_expression(self, address, params):
|
|
1121
1134
|
args_type = ','.join(['intptr_t'] * len(params))
|
|
1122
1135
|
args_conv = ','.join(params)
|
|
1123
1136
|
|
|
1124
|
-
if self.
|
|
1137
|
+
if self.arch == 'arm64e':
|
|
1125
1138
|
address = f'ptrauth_sign_unauthenticated((void *){address}, ptrauth_key_asia, 0)'
|
|
1126
1139
|
|
|
1127
1140
|
return f'((intptr_t(*)({args_type}))({address}))({args_conv})'
|
|
@@ -1178,3 +1191,10 @@ class HildaClient(metaclass=CommandsMeta):
|
|
|
1178
1191
|
return formatters[fmt](value)
|
|
1179
1192
|
else:
|
|
1180
1193
|
return f'{value:x} (unsupported format)'
|
|
1194
|
+
|
|
1195
|
+
@cached_property
|
|
1196
|
+
def _ks(self) -> Ks:
|
|
1197
|
+
platforms = {'arm64': Ks(KS_ARCH_ARM64, KS_MODE_LITTLE_ENDIAN),
|
|
1198
|
+
'arm64e': Ks(KS_ARCH_ARM64, KS_MODE_LITTLE_ENDIAN),
|
|
1199
|
+
'x86_64h': Ks(KS_ARCH_X86, KS_MODE_64)}
|
|
1200
|
+
return platforms.get(self.arch)
|
|
@@ -67,6 +67,26 @@ def bare():
|
|
|
67
67
|
execute(f'lldb --one-line "{commands}"')
|
|
68
68
|
|
|
69
69
|
|
|
70
|
+
@cli.command('attach')
|
|
71
|
+
@click.option('-n', '--name', help='process name to attach')
|
|
72
|
+
@click.option('-p', '--pid', type=click.INT, help='pid to attach')
|
|
73
|
+
def attach(name: str, pid: int):
|
|
74
|
+
""" Attach to given process and start an lldb shell """
|
|
75
|
+
# connect local LLDB client
|
|
76
|
+
commands = []
|
|
77
|
+
if name is not None:
|
|
78
|
+
commands.append(f'process attach -n {name}')
|
|
79
|
+
elif pid is not None:
|
|
80
|
+
commands.append(f'process attach -p {pid}')
|
|
81
|
+
else:
|
|
82
|
+
print('missing either process name or pid for attaching')
|
|
83
|
+
return
|
|
84
|
+
|
|
85
|
+
commands.append(f'command script import {os.path.join(Path(__file__).resolve().parent, "lldb_entrypoint.py")}')
|
|
86
|
+
commands = '\n'.join(commands)
|
|
87
|
+
execute(f'lldb --one-line "{commands}"')
|
|
88
|
+
|
|
89
|
+
|
|
70
90
|
if __name__ == '__main__':
|
|
71
91
|
disable_logs()
|
|
72
92
|
cli()
|
|
@@ -15,7 +15,9 @@ lldb.hilda_client = None
|
|
|
15
15
|
def hilda(debugger, command, result, internal_dict):
|
|
16
16
|
if lldb.hilda_client is None:
|
|
17
17
|
lldb.hilda_client = HildaClient(debugger)
|
|
18
|
-
|
|
18
|
+
|
|
19
|
+
additional_namespace = {'ui': lldb.hilda_client.ui_manager}
|
|
20
|
+
lldb.hilda_client.interactive(additional_namespace=additional_namespace)
|
|
19
21
|
|
|
20
22
|
|
|
21
23
|
def __lldb_init_module(debugger, internal_dict):
|
|
@@ -7,13 +7,14 @@ from functools import partial
|
|
|
7
7
|
from pathlib import Path
|
|
8
8
|
from uuid import uuid4
|
|
9
9
|
|
|
10
|
+
from objc_types_decoder.decode import decode as decode_type
|
|
11
|
+
from objc_types_decoder.decode import decode_with_tail
|
|
10
12
|
from pygments import highlight
|
|
11
13
|
from pygments.formatters import TerminalTrueColorFormatter
|
|
12
14
|
from pygments.lexers import ObjectiveCLexer
|
|
13
|
-
from objc_types_decoder.decode import decode as decode_type, decode_with_tail
|
|
14
15
|
|
|
15
|
-
from hilda.symbols_jar import SymbolsJar
|
|
16
16
|
from hilda.exceptions import GettingObjectiveCClassError
|
|
17
|
+
from hilda.symbols_jar import SymbolsJar
|
|
17
18
|
|
|
18
19
|
Ivar = namedtuple('Ivar', 'name type_ offset')
|
|
19
20
|
Property = namedtuple('Property', 'name attributes')
|
|
@@ -5,15 +5,15 @@ from dataclasses import dataclass
|
|
|
5
5
|
from functools import partial
|
|
6
6
|
from pathlib import Path
|
|
7
7
|
|
|
8
|
+
from objc_types_decoder.decode import decode as decode_type
|
|
8
9
|
from pygments import highlight
|
|
9
10
|
from pygments.formatters import TerminalTrueColorFormatter
|
|
10
11
|
from pygments.lexers import ObjectiveCLexer
|
|
11
|
-
from objc_types_decoder.decode import decode as decode_type
|
|
12
12
|
|
|
13
13
|
from hilda.exceptions import HildaException
|
|
14
|
-
from hilda.objective_c_class import Class,
|
|
15
|
-
from hilda.symbols_jar import SymbolsJar
|
|
14
|
+
from hilda.objective_c_class import Class, Method, Property, convert_encoded_property_attributes
|
|
16
15
|
from hilda.symbol import Symbol
|
|
16
|
+
from hilda.symbols_jar import SymbolsJar
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
class SettingIvarError(HildaException):
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import lldb
|
|
2
|
+
|
|
3
|
+
_FILENAME = '/tmp/hilda-keylog.txt'
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def _ssl_log_secret_bp(hilda, *args):
|
|
7
|
+
label = hilda.registers.x1.peek_str()
|
|
8
|
+
secret = hilda.registers.x2.peek(hilda.registers.x3).hex()
|
|
9
|
+
random = (hilda.registers.x0[6] + 48).peek(32).hex()
|
|
10
|
+
print(f'ssl_log_secret\n'
|
|
11
|
+
f' label: {label}\n'
|
|
12
|
+
f' secret: {secret}\n'
|
|
13
|
+
f' random: {random}\n'
|
|
14
|
+
f'---\n')
|
|
15
|
+
with open(_FILENAME, 'a') as f:
|
|
16
|
+
f.write(f'{label} {random} {secret}\n')
|
|
17
|
+
hilda.cont()
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def start_keylog(filename: str = None) -> None:
|
|
21
|
+
global _FILENAME
|
|
22
|
+
|
|
23
|
+
if filename is not None:
|
|
24
|
+
_FILENAME = filename
|
|
25
|
+
hilda_client = lldb.hilda_client
|
|
26
|
+
hilda_client.symbols._ZN4bssl14ssl_log_secretEPK6ssl_stPKcNS_4SpanIKhEE.bp(_ssl_log_secret_bp)
|