Skip to content

Commit e8c641b

Browse files
committed
when running friTap as a module you can now work with your own message handler
1 parent dd6f105 commit e8c641b

File tree

4 files changed

+175
-52
lines changed

4 files changed

+175
-52
lines changed

INTEGRATION.md

Lines changed: 149 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ The following example demonstrates how to use `friTap` to hook into an applicati
1111
### **Code Example**
1212

1313
```python
14+
#!/usr/bin/env python3
15+
# -*- coding: utf-8 -*-
16+
1417
from friTap import SSL_Logger
1518
import sys
1619

@@ -26,7 +29,7 @@ try:
2629
app_package,
2730
verbose=True, # Enable verbose output
2831
mobile=True, # Indicate that the target app is running on a mobile device
29-
keylog="keylogtest3.log", # Path to save SSL key log
32+
keylog="keylogtest.log", # Path to save SSL key log
3033
debug_output=True # Enable debug output
3134
)
3235

@@ -68,17 +71,160 @@ except KeyboardInterrupt:
6871
| `payload_modification` | `bool` | `False` | Enable payload modification during traffic capture. |
6972
| `enable_default_fd` | `bool` | `False` | Enable default file descriptor handling. |
7073
| `patterns` | `list` | `None` | List of patterns to match during traffic capture. |
71-
| `custom_hook_script` | `str` | `None` | Path to a custom Frida hook script to be executed during the session. |
74+
| `custom_hook_script` | `str` | `None` | Path to a custom Frida hook script to be executed during the session. These hooks are installed prior to the installation of friTap hooks. |
7275

7376
---
7477

78+
## Advanced Usage: Integrating friTap with Custom Handler
79+
80+
If you'd like to integrate friTap into your project but prefer to manage Frida yourself, friTap offers advanced flexibility. With this approach, you can either:
81+
82+
- Retrieve the friTap script Path: Use `ssl_log.get_fritap_frida_script_path()` to obtain the path to the friTap Frida script. You can then manually load the script into your target process.
83+
- Use the Advanced API: Utilize the `start_fritap_session_instrumentation(own_message_handler, process)` API to integrate friTap while managing Frida yourself.
84+
- `on_message_handler`: Your custom handler function to process messages between the script and your Python code.
85+
- `process`: The Frida process object you manage, which can be created by spawning or attaching to the target application.
86+
87+
This API gives you full control over when the friTap script is loaded into the target process. It returns the script object, allowing you to load the script at your preferred time. Below is an example of how to use this API:
88+
89+
```python
90+
#!/usr/bin/env python3
91+
# -*- coding: utf-8 -*-
92+
93+
from friTap import SSL_Logger
94+
import sys
95+
import frida
96+
97+
#global variable
98+
script = None
99+
100+
# Custom message handler function
101+
def myAwesomeHandler(message, data):
102+
global script
103+
104+
# Pass options to friTap hooks (mandotory)
105+
if message['payload'] == 'experimental':
106+
script.post({'type':'experimental', 'payload': False})
107+
return
108+
109+
if message['payload'] == 'defaultFD':
110+
script.post({'type':'defaultFD', 'payload': False})
111+
return
112+
113+
if message['payload'] == 'pattern_hooking':
114+
script.post({'type':'pattern_hooking', 'payload': False})
115+
return
116+
117+
if message['payload'] == 'offset_hooking':
118+
script.post({'type':'offset_hooking', 'payload': False})
119+
return
120+
121+
if message['payload'] == 'anti':
122+
script.post({'type':'antiroot', 'payload': False})
123+
return
124+
125+
126+
print(f"Message from Frida: {message}")
127+
if data:
128+
print(f"Data: {data}")
129+
130+
131+
132+
def getFridaProcess(target_app):
133+
device = frida.get_usb_device()
134+
process = device.attach(int(target_app) if target_app.isnumeric() else target_app)
135+
return process, device
136+
137+
138+
139+
try:
140+
print("Starting friTap logging...")
141+
print("Press Ctrl+C to stop logging.")
142+
143+
# Specify the target app package
144+
app_package = "YouTube"
145+
146+
# Create or attach a Frida process (replace with your implementation)
147+
process, device = getFridaProcess(app_package) # Your code for creating or attaching to a Frida process.
148+
149+
# Initialize SSL_Logger with optional arguments
150+
ssl_log = SSL_Logger(
151+
app_package,
152+
verbose=True, # Enable detailed output
153+
keylog="keylogtest.log" # Path to save the SSL key log
154+
)
155+
156+
# Hook friTap into the target process without immediately loading the script
157+
script = ssl_log.start_fritap_session_instrumentation(myAwesomeHandler, process)
158+
159+
# Manually load the friTap script into the target process
160+
script.load()
161+
162+
# Wait for the user to interrupt
163+
sys.stdin.read()
164+
165+
except KeyboardInterrupt:
166+
# Detach the process when interrupted
167+
process.detach()
168+
print("friTap logging stopped.")
169+
170+
```
171+
172+
Key Notes about this approach:
173+
174+
- Script Loading: The `start_fritap_session_instrumentation` API provides the script object but does not automatically load it. This gives you full control over when the friTap hooks are injected.
175+
- Custom Message Handler: Your on_message_handler function allows you to handle Frida messages and data flexibly. When managing the handler yourself, it is mandatory to ensure that certain internal friTap variables are correctly communicated with the Frida script. Failing to do so will halt the installation of the friTap hooks, as they depend on values from the Python environment to determine how certain hooks should be applied.
176+
- Full Control: This approach is ideal for advanced use cases where you want precise management of Frida processes and script lifecycle.
177+
178+
### Understanding Frida Messages in friTap
179+
180+
In friTap, the `on_fritap_message(self, job, message, data)` handler processes messages sent from the Frida script. These messages contain important information about the operation of friTap. The key fields in the message are:
181+
182+
- **`payload`**: This field contains a structured dictionary with a `contentType` key that determines the type of the message. The specific `contentType` dictates how the remaining fields in the `payload` are interpreted. The structure looks like this `'payload': {'contentType': '<content type>', '<content key>': <content value>}`
183+
- **`data`**: This field contains the decrypted TLS payload when the `contentType` is `datalog`. In other cases, the `data` field is typically unused and the focus remains on the `payload` field.
184+
185+
Here are the different `contentType` values and their meanings:
186+
187+
| **Content Type** | **Description** | **Access Key** |
188+
|-----------------------|----------------------------------------------------------------------------------------------------------|---------------------|
189+
| `datalog` | Contains decrypted TLS payload data and associated socket information. Useful for analyzing TLS traffic. | `datalog` |
190+
| `console_dev` | Debug output intended for development and troubleshooting, such as scanning logs or fallback patterns. | `console_dev` |
191+
| `console_error` | Error messages encountered during the operation of friTap. | `console_error` |
192+
| `console` | Standard output messages visible to the user when running friTap. | `console` |
193+
| `keylog` | Extracted TLS key material from the target application. | `keylog` |
194+
195+
**Key Details**:
196+
197+
1. **Decrypted TLS Data**:
198+
- When `contentType` is `datalog`, the `data` field contains the decrypted TLS payload (if available), along with associated socket information.
199+
200+
2. **Development Logs**:
201+
- `console_dev` messages provide insights into debug operations, which are helpful during development or when fixing bugs.
202+
203+
3. **Error Handling**:
204+
- Error messages (`console_error`) help identify problems within friTap’s execution.
205+
206+
4. **User Output**:
207+
- `console` messages are meant for the user and reflect key operational statuses.
208+
209+
5. **TLS Key Extraction**:
210+
- `keylog` messages provide extracted key material for analyzing the cryptographic state of the target application.
211+
212+
By using the `contentType` as the key, you can access specific fields in the `payload` to analyze the messages accordingly.
213+
214+
215+
216+
By using this API, you can seamlessly integrate friTap while maintaining complete control over Frida's operation in your application.
217+
75218
## Advanced Usage: Using friTap as a Job in AndroidFridaManager
76219

77220
friTap can also be used as a job within the `AndroidFridaManager` framework. This allows you to manage friTap sessions as part of a larger job workflow.
78221

79222
### **Code Example**
80223

81224
```python
225+
#!/usr/bin/env python3
226+
# -*- coding: utf-8 -*-
227+
82228
from friTap import SSL_Logger
83229
from AndroidFridaManager import JobManager
84230
import sys
@@ -97,7 +243,7 @@ try:
97243
ssl_log = SSL_Logger(
98244
app_package,
99245
verbose=True, # Enable verbose output
100-
keylog="keylogtest3.log", # Path to save SSL key log
246+
keylog="keylogjobtest.log", # Path to save SSL key log
101247
debug_output=True # Enable debug output
102248
)
103249

friTap/about.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22
# -*- coding: utf-8 -*-
33

44
__author__ = "Daniel Baier, Francois Egner, Max Ufer"
5-
__version__ = "1.2.4.0"
5+
__version__ = "1.2.4.3"
66
debug = False # are we running in debug mode?

friTap/ssl_logger.py

Lines changed: 24 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ def on_fritap_message(self,job, message, data):
139139
Args:
140140
message: A dictionary containing the message "type" and other fields
141141
dependent on message type.
142-
data: The string of captured decrypted data.
142+
data: The string of captured decrypted data or the caputured decryption keys
143143
"""
144144

145145

@@ -272,7 +272,7 @@ def on_spawn_added(self, spawn):
272272
self.device.resume(spawn.pid)
273273

274274

275-
def instrument(self, process):
275+
def instrument(self, process, own_message_handler):
276276
runtime="qjs"
277277
debug_port = 1337
278278
if self.debug:
@@ -311,7 +311,12 @@ def instrument(self, process):
311311

312312
if self.debug and frida.__version__ >= "16":
313313
self.script.enable_debugger(debug_port)
314-
self.script.on("message", self.internal_callback_wrapper())
314+
315+
if own_message_handler != None:
316+
self.script.on("message", self._provide_custom_hooking_handler(own_message_handler))
317+
return self.script
318+
else:
319+
self.script.on("message", self._internal_callback_wrapper())
315320
self.script.load()
316321

317322

@@ -370,8 +375,13 @@ def load_patterns(self):
370375
print(f"[-] Pattern file {self.patterns} does not exist.")
371376

372377

378+
def start_fritap_session_instrumentation(self, own_message_handler, process):
379+
self.process = process
380+
script = self.instrument(self.process, own_message_handler)
381+
return script
382+
373383

374-
def start_fritap_session(self):
384+
def start_fritap_session(self, own_message_handler=None):
375385

376386
if self.mobile:
377387
self.device = frida.get_usb_device()
@@ -380,34 +390,13 @@ def start_fritap_session(self):
380390
else:
381391
self.device = frida.get_local_device()
382392

383-
"""
384-
if self.offsets is not None:
385-
if os.path.exists(self.offsets):
386-
offset_file = open(self.offsets, "r")
387-
self.offsets_data = offset_file.read()
388-
offset_file.close()
389-
else:
390-
try:
391-
json.load(self.offsets)
392-
self.offsets_data = self.offsets
393-
except ValueError as e:
394-
print(f"Log error, defaulting to auto-detection: {e}")
395-
396-
if self.patterns is not None:
397-
self.load_patterns()
398-
"""
399-
400-
401393
self.device.on("child_added", self.on_child_added)
402394
if self.enable_spawn_gating:
403395
self.device.enable_spawn_gating()
404396
self.device.on("spawn_added", self.on_spawn_added)
405397
if self.spawn:
406398
print("spawning "+ self.target_app)
407399

408-
#if self.pcap_name:
409-
# self.pcap_obj = PCAP(self.pcap_name,SSL_READ,SSL_WRITE,self.full_capture, self.mobile,self.debug)
410-
411400
if self.mobile or self.host:
412401
pid = self.device.spawn(self.target_app)
413402
else:
@@ -420,29 +409,10 @@ def start_fritap_session(self):
420409
time.sleep(1) # without it Java.perform silently fails
421410
self.process = self.device.attach(pid)
422411
else:
423-
#if self.pcap_name:
424-
# self.pcap_obj = PCAP(self.pcap_name,SSL_READ,SSL_WRITE,self.full_capture, self.mobile,self.debug)
425412
self.process = self.device.attach(int(self.target_app) if self.target_app.isnumeric() else self.target_app)
426413

427-
"""
428-
if self.live:
429-
if self.pcap_name:
430-
print("[*] YOU ARE TRYING TO WRITE A PCAP AND HAVING A LIVE VIEW\nTHIS IS NOT SUPPORTED!\nWHEN YOU DO A LIVE VIEW YOU CAN SAFE YOUR CAPUTRE WITH WIRESHARK.")
431-
fifo_file = self.temp_fifo()
432-
print(f'[*] friTap live view on Wireshark')
433-
print(f'[*] Created named pipe for Wireshark live view to {fifo_file}')
434-
print(
435-
f'[*] Now open this named pipe with Wireshark in another terminal: sudo wireshark -k -i {fifo_file}')
436-
print(f'[*] friTap will continue after the named pipe is ready....\n')
437-
self.pcap_obj = PCAP(fifo_file,SSL_READ,SSL_WRITE,self.full_capture, self.mobile,self.debug)
438-
439-
440-
if self.keylog:
441-
self.keylog_file = open(self.keylog, "w")
442-
"""
443-
444414

445-
self.instrument(self.process)
415+
script = self.instrument(self.process, own_message_handler)
446416

447417

448418

@@ -458,15 +428,22 @@ def start_fritap_session(self):
458428
if self.spawn:
459429
self.device.resume(pid)
460430

461-
return self.process
431+
return self.process, script
462432

463433

464434
def finish_fritap(self):
465435
if self.script:
466436
self.script.unload()
467437

468438

469-
def internal_callback_wrapper(self):
439+
def _provide_custom_hooking_handler(self, handler):
440+
def wrapped_handler(message, data):
441+
handler(message, data)
442+
443+
return wrapped_handler
444+
445+
446+
def _internal_callback_wrapper(self):
470447
def wrapped_handler(message, data):
471448
self.on_fritap_message(None, message, data)
472449

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "friTap",
3-
"version": "1.2.4.0",
3+
"version": "1.2.4.3",
44
"description": "Frida agent for logging SSL traffic as plaintext and extracting SSL keys",
55
"private": true,
66
"main": "agent/ssl_log.ts",

0 commit comments

Comments
 (0)