frida-fusion 0.1.4__tar.gz → 0.1.6__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.
Potentially problematic release.
This version of frida-fusion might be problematic. Click here for more details.
- frida_fusion-0.1.6/LICENSE +25 -0
- {frida-fusion-0.1.4 → frida_fusion-0.1.6}/PKG-INFO +65 -3
- {frida-fusion-0.1.4 → frida_fusion-0.1.6}/README.md +57 -0
- {frida-fusion-0.1.4 → frida_fusion-0.1.6}/frida_fusion/__meta__.py +2 -2
- {frida-fusion-0.1.4 → frida_fusion-0.1.6}/frida_fusion/config.py +21 -9
- {frida-fusion-0.1.4 → frida_fusion-0.1.6}/frida_fusion/fusion.py +24 -8
- frida_fusion-0.1.6/frida_fusion/module.py +272 -0
- frida_fusion-0.1.6/frida_fusion/modules/crypto/__init__.py +0 -0
- {frida-fusion-0.1.4/frida_fusion/modules → frida_fusion-0.1.6/frida_fusion/modules/crypto}/crypto.py +9 -6
- frida_fusion-0.1.6/frida_fusion/modules/tls_unpinning/__init__.py +0 -0
- frida_fusion-0.1.6/frida_fusion/modules/tls_unpinning/frida_multiple_unpinning.py +66 -0
- {frida-fusion-0.1.4 → frida_fusion-0.1.6}/frida_fusion.egg-info/PKG-INFO +65 -3
- {frida-fusion-0.1.4 → frida_fusion-0.1.6}/frida_fusion.egg-info/SOURCES.txt +6 -2
- {frida-fusion-0.1.4 → frida_fusion-0.1.6}/pyproject.toml +2 -3
- frida-fusion-0.1.4/frida_fusion/module.py +0 -116
- {frida-fusion-0.1.4 → frida_fusion-0.1.6}/frida_fusion/__init__.py +0 -0
- {frida-fusion-0.1.4 → frida_fusion-0.1.6}/frida_fusion/__main__.py +0 -0
- {frida-fusion-0.1.4 → frida_fusion-0.1.6}/frida_fusion/args.py +0 -0
- {frida-fusion-0.1.4 → frida_fusion-0.1.6}/frida_fusion/libs/__init__.py +0 -0
- {frida-fusion-0.1.4 → frida_fusion-0.1.6}/frida_fusion/libs/color.py +0 -0
- {frida-fusion-0.1.4 → frida_fusion-0.1.6}/frida_fusion/libs/database.py +0 -0
- {frida-fusion-0.1.4 → frida_fusion-0.1.6}/frida_fusion/libs/helpers.js +0 -0
- {frida-fusion-0.1.4 → frida_fusion-0.1.6}/frida_fusion/libs/logger.py +0 -0
- {frida-fusion-0.1.4 → frida_fusion-0.1.6}/frida_fusion/modules/__init__.py +0 -0
- {frida-fusion-0.1.4/frida_fusion/modules → frida_fusion-0.1.6/frida_fusion/modules/crypto}/crypto.js +0 -0
- {frida-fusion-0.1.4 → frida_fusion-0.1.6}/frida_fusion.egg-info/dependency_links.txt +0 -0
- {frida-fusion-0.1.4 → frida_fusion-0.1.6}/frida_fusion.egg-info/entry_points.txt +0 -0
- {frida-fusion-0.1.4 → frida_fusion-0.1.6}/frida_fusion.egg-info/requires.txt +0 -0
- {frida-fusion-0.1.4 → frida_fusion-0.1.6}/frida_fusion.egg-info/top_level.txt +0 -0
- {frida-fusion-0.1.4 → frida_fusion-0.1.6}/setup.cfg +0 -0
- {frida-fusion-0.1.4 → frida_fusion-0.1.6}/setup.py +0 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
BSD 2-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2022, Helvio Junior
|
|
4
|
+
All rights reserved.
|
|
5
|
+
|
|
6
|
+
Redistribution and use in source and binary forms, with or without
|
|
7
|
+
modification, are permitted provided that the following conditions are met:
|
|
8
|
+
|
|
9
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
10
|
+
list of conditions and the following disclaimer.
|
|
11
|
+
|
|
12
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
13
|
+
this list of conditions and the following disclaimer in the documentation
|
|
14
|
+
and/or other materials provided with the distribution.
|
|
15
|
+
|
|
16
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
17
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
18
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
19
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
20
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
21
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
22
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
23
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
24
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
25
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: frida-fusion
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.6
|
|
4
4
|
Summary: Hook your mobile tests with Frida
|
|
5
5
|
Author-email: "Helvio Junior (M4v3r1ck)" <helvio_junior@hotmail.com>
|
|
6
6
|
Maintainer-email: "Helvio Junior (M4v3r1ck)" <helvio_junior@hotmail.com>
|
|
@@ -12,7 +12,6 @@ Keywords: Frida Fusion,Frida,Frida Scripts,development,red team
|
|
|
12
12
|
Classifier: Development Status :: 4 - Beta
|
|
13
13
|
Classifier: Environment :: Console
|
|
14
14
|
Classifier: Intended Audience :: System Administrators
|
|
15
|
-
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
|
|
16
15
|
Classifier: Natural Language :: English
|
|
17
16
|
Classifier: Operating System :: OS Independent
|
|
18
17
|
Classifier: Programming Language :: Python
|
|
@@ -27,6 +26,12 @@ Classifier: Topic :: Security
|
|
|
27
26
|
Classifier: Topic :: Utilities
|
|
28
27
|
Requires-Python: <4,>=3.9
|
|
29
28
|
Description-Content-Type: text/markdown
|
|
29
|
+
License-File: LICENSE
|
|
30
|
+
Requires-Dist: colorama
|
|
31
|
+
Requires-Dist: requests>=2.23.0
|
|
32
|
+
Requires-Dist: frida>=15.1.17
|
|
33
|
+
Requires-Dist: frida-tools>=10.8.0
|
|
34
|
+
Dynamic: license-file
|
|
30
35
|
|
|
31
36
|
# Frida Fusion
|
|
32
37
|
|
|
@@ -68,4 +73,61 @@ Modules:
|
|
|
68
73
|
pip3 install frida-fusion
|
|
69
74
|
```
|
|
70
75
|
|
|
76
|
+
## Module engine
|
|
71
77
|
|
|
78
|
+
You can check available modules with `frida-fusion --list-modules` command.
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
frida-fusion --list-modules
|
|
82
|
+
|
|
83
|
+
[ FRIDA ]—o—( FUSION )—o—[ MOBILE TESTS ] // v0.1.4
|
|
84
|
+
> hook your mobile tests with Frida
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
Available modules
|
|
88
|
+
Module Name : Description
|
|
89
|
+
Crypto : Hook cryptography/hashing functions
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### External modules
|
|
93
|
+
|
|
94
|
+
You can develop or download community modules and load into frida-fusion.
|
|
95
|
+
|
|
96
|
+
To pass to the Frida Fusion the external module path you can use the environment variable `FUSION_MODULES` with the full path of modules
|
|
97
|
+
|
|
98
|
+
At linux:
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
export FUSION_MODULES=/tmp/modules
|
|
102
|
+
|
|
103
|
+
# List all modules
|
|
104
|
+
frida-fusion --list-modules
|
|
105
|
+
|
|
106
|
+
# Using available module
|
|
107
|
+
frida-fusion -f [app_id] -U --script-path . -m [module_name]
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
At windows:
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
$env:FUSION_MODULES = "C:\extra_mods"
|
|
114
|
+
|
|
115
|
+
# List all modules
|
|
116
|
+
frida-fusion --list-modules
|
|
117
|
+
|
|
118
|
+
# Using available module
|
|
119
|
+
frida-fusion -f [app_id] -U --script-path . -m [module_name]
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Community modules
|
|
123
|
+
|
|
124
|
+
You can also use one of community developed modules
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
cd /tmp/
|
|
128
|
+
git clone https://github.com/helviojunior/frida-fusion-community-modules
|
|
129
|
+
export FUSION_MODULES=/tmp/frida-fusion-community-modules
|
|
130
|
+
|
|
131
|
+
# List all modules
|
|
132
|
+
frida-fusion --list-modules
|
|
133
|
+
```
|
|
@@ -38,4 +38,61 @@ Modules:
|
|
|
38
38
|
pip3 install frida-fusion
|
|
39
39
|
```
|
|
40
40
|
|
|
41
|
+
## Module engine
|
|
41
42
|
|
|
43
|
+
You can check available modules with `frida-fusion --list-modules` command.
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
frida-fusion --list-modules
|
|
47
|
+
|
|
48
|
+
[ FRIDA ]—o—( FUSION )—o—[ MOBILE TESTS ] // v0.1.4
|
|
49
|
+
> hook your mobile tests with Frida
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
Available modules
|
|
53
|
+
Module Name : Description
|
|
54
|
+
Crypto : Hook cryptography/hashing functions
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### External modules
|
|
58
|
+
|
|
59
|
+
You can develop or download community modules and load into frida-fusion.
|
|
60
|
+
|
|
61
|
+
To pass to the Frida Fusion the external module path you can use the environment variable `FUSION_MODULES` with the full path of modules
|
|
62
|
+
|
|
63
|
+
At linux:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
export FUSION_MODULES=/tmp/modules
|
|
67
|
+
|
|
68
|
+
# List all modules
|
|
69
|
+
frida-fusion --list-modules
|
|
70
|
+
|
|
71
|
+
# Using available module
|
|
72
|
+
frida-fusion -f [app_id] -U --script-path . -m [module_name]
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
At windows:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
$env:FUSION_MODULES = "C:\extra_mods"
|
|
79
|
+
|
|
80
|
+
# List all modules
|
|
81
|
+
frida-fusion --list-modules
|
|
82
|
+
|
|
83
|
+
# Using available module
|
|
84
|
+
frida-fusion -f [app_id] -U --script-path . -m [module_name]
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Community modules
|
|
88
|
+
|
|
89
|
+
You can also use one of community developed modules
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
cd /tmp/
|
|
93
|
+
git clone https://github.com/helviojunior/frida-fusion-community-modules
|
|
94
|
+
export FUSION_MODULES=/tmp/frida-fusion-community-modules
|
|
95
|
+
|
|
96
|
+
# List all modules
|
|
97
|
+
frida-fusion --list-modules
|
|
98
|
+
```
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
__version__ = '0.1.
|
|
1
|
+
__version__ = '0.1.6'
|
|
2
2
|
__title__ = "Frida Fusion"
|
|
3
3
|
__description__ = "📱 frida-fusion - runtime mobile exploration"
|
|
4
4
|
__url__ = "https://github.com/helviojunior/frida-fusion"
|
|
5
|
-
__build__ =
|
|
5
|
+
__build__ = 0x9f83cd2
|
|
6
6
|
__author__ = "Helvio Junior (M4v3r1ck)"
|
|
7
7
|
__author_email__ = "helvio_junior@hotmail.com"
|
|
8
8
|
__license__ = "GPL-3.0"
|
|
@@ -6,7 +6,7 @@ import sys
|
|
|
6
6
|
import signal
|
|
7
7
|
from pathlib import Path
|
|
8
8
|
|
|
9
|
-
from .module import Module
|
|
9
|
+
from .module import Module, ModuleManager, InternalModule, ExternalModule
|
|
10
10
|
from .libs.color import Color
|
|
11
11
|
from .libs.logger import Logger
|
|
12
12
|
from .__meta__ import __version__
|
|
@@ -71,15 +71,27 @@ class Configuration(object):
|
|
|
71
71
|
#show_help = any(['-h' == word for word in sys.argv])
|
|
72
72
|
|
|
73
73
|
if list_modules:
|
|
74
|
-
mods =
|
|
74
|
+
mods = ModuleManager.list_modules()
|
|
75
|
+
|
|
76
|
+
if len(mods) == 0:
|
|
77
|
+
Color.pl('{!} {R}error: no modules found{R}{W}\r\n')
|
|
78
|
+
sys.exit(1)
|
|
79
|
+
|
|
75
80
|
max_name = max(iter([
|
|
76
81
|
len(m.name) + 3
|
|
77
82
|
for _, m in mods.items()
|
|
78
83
|
] + [15]))
|
|
79
|
-
Color.pl(f"Available modules")
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
84
|
+
Color.pl(f"Available internal modules")
|
|
85
|
+
for m in [m for _, m in mods.items() if isinstance(m, InternalModule)]:
|
|
86
|
+
Color.pl(f" {m.safe_name().ljust(max_name)} : {m.description}")
|
|
87
|
+
|
|
88
|
+
Color.pl(f"\nAvailable external modules")
|
|
89
|
+
ext_mods = [m for _, m in mods.items() if isinstance(m, ExternalModule)]
|
|
90
|
+
if len(ext_mods) == 0:
|
|
91
|
+
Color.pl((" No external modules available. You can set {G}FUSION_MODULES{W} environment variable "
|
|
92
|
+
"to set an external modules Path"))
|
|
93
|
+
for m in ext_mods:
|
|
94
|
+
Color.pl(f" {m.safe_name().ljust(max_name)} : {m.description}")
|
|
83
95
|
|
|
84
96
|
print("")
|
|
85
97
|
sys.exit(0)
|
|
@@ -167,19 +179,19 @@ class Configuration(object):
|
|
|
167
179
|
Logger.pl(' {C}min debug level:{O} %s{W}' % str(args.debug_level).upper())
|
|
168
180
|
|
|
169
181
|
if args.enabled_modules is not None and isinstance(args.enabled_modules, list):
|
|
170
|
-
mods =
|
|
182
|
+
mods = ModuleManager.list_modules()
|
|
171
183
|
for mod in args.enabled_modules:
|
|
172
184
|
fm = next(iter([
|
|
173
185
|
m
|
|
174
186
|
for _, m in mods.items()
|
|
175
|
-
if m.
|
|
187
|
+
if m.safe_name() == mod.lower()
|
|
176
188
|
]), None)
|
|
177
189
|
if fm is None:
|
|
178
190
|
Color.pl(
|
|
179
191
|
'{!} {R}error: module {O}%s{R} not found{W}\r\n' % mod)
|
|
180
192
|
sys.exit(1)
|
|
181
193
|
|
|
182
|
-
name = fm.
|
|
194
|
+
name = fm.safe_name()
|
|
183
195
|
if name not in Configuration.enabled_modules.keys():
|
|
184
196
|
Configuration.enabled_modules[name] = fm
|
|
185
197
|
|
|
@@ -216,7 +216,7 @@ class Fusion(object):
|
|
|
216
216
|
self.session = self.device.attach(self.pid)
|
|
217
217
|
self.session.on("detached", self.on_detached)
|
|
218
218
|
|
|
219
|
-
Logger.pl("{+}
|
|
219
|
+
Logger.pl("{+} Starting frida scripts")
|
|
220
220
|
self.load_all_scripts()
|
|
221
221
|
self.device.resume(self.pid)
|
|
222
222
|
|
|
@@ -227,7 +227,7 @@ class Fusion(object):
|
|
|
227
227
|
self.session = self.device.attach(self.pid)
|
|
228
228
|
self.session.on("detached", self.on_detached)
|
|
229
229
|
|
|
230
|
-
Logger.pl("{+}
|
|
230
|
+
Logger.pl("{+} Starting frida scripts")
|
|
231
231
|
self.load_all_scripts()
|
|
232
232
|
self.device.resume(self.pid)
|
|
233
233
|
|
|
@@ -242,7 +242,7 @@ class Fusion(object):
|
|
|
242
242
|
self.session = self.device.attach(self.pid)
|
|
243
243
|
self.session.on("detached", self.on_detached)
|
|
244
244
|
|
|
245
|
-
Logger.pl("{+}
|
|
245
|
+
Logger.pl("{+} Starting frida scripts")
|
|
246
246
|
self.load_all_scripts()
|
|
247
247
|
|
|
248
248
|
def make_handler(self, script_name):
|
|
@@ -261,6 +261,19 @@ class Fusion(object):
|
|
|
261
261
|
jData = jData.get("payload", {})
|
|
262
262
|
script_location = self.translate_location(location)
|
|
263
263
|
|
|
264
|
+
if isinstance(jData, str):
|
|
265
|
+
msg = jData
|
|
266
|
+
try:
|
|
267
|
+
msg = base64.b64encode(jData.encode("UTF-8"))
|
|
268
|
+
except Exception:
|
|
269
|
+
pass
|
|
270
|
+
|
|
271
|
+
jData = {
|
|
272
|
+
"type": "message",
|
|
273
|
+
"level": "I",
|
|
274
|
+
"message": msg
|
|
275
|
+
}
|
|
276
|
+
|
|
264
277
|
if script_location.file_name == "<unknown>":
|
|
265
278
|
script_location.file_name = script_name
|
|
266
279
|
|
|
@@ -631,16 +644,19 @@ class Fusion(object):
|
|
|
631
644
|
Configuration.initialize()
|
|
632
645
|
|
|
633
646
|
try:
|
|
647
|
+
print(f" 🛠️ Starting Frida Fusion instrumentation")
|
|
648
|
+
timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
|
649
|
+
Logger.pl('{+} {C}Start time {O}%s{W}' % timestamp)
|
|
650
|
+
|
|
634
651
|
self._modules = [
|
|
635
652
|
m.create_instance()
|
|
636
653
|
for _, m in Configuration.enabled_modules.items()
|
|
637
654
|
]
|
|
638
|
-
for m in self._modules:
|
|
639
|
-
m.start_db(db_path=Configuration.db_path)
|
|
640
655
|
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
656
|
+
if len(self._modules) > 0:
|
|
657
|
+
Logger.pl("{+} Starting selected modules")
|
|
658
|
+
for m in self._modules:
|
|
659
|
+
m.start_module(db_path=Configuration.db_path)
|
|
644
660
|
|
|
645
661
|
self.get_device()
|
|
646
662
|
if self.device is not None:
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
import re
|
|
4
|
+
import frida
|
|
5
|
+
import pkgutil
|
|
6
|
+
import importlib
|
|
7
|
+
import requests
|
|
8
|
+
import importlib.util
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
from typing import TYPE_CHECKING
|
|
12
|
+
|
|
13
|
+
from .__meta__ import __version__
|
|
14
|
+
from .libs.logger import Logger
|
|
15
|
+
|
|
16
|
+
if TYPE_CHECKING:
|
|
17
|
+
from .fusion import Fusion # só no type checker
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class ModuleLoaderError(Exception):
|
|
21
|
+
pass
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class ModuleBase(object):
|
|
25
|
+
|
|
26
|
+
name = ''
|
|
27
|
+
description = ''
|
|
28
|
+
mod_path = ''
|
|
29
|
+
|
|
30
|
+
def __init__(self, name, description):
|
|
31
|
+
self.name = name
|
|
32
|
+
self.description = description
|
|
33
|
+
self.mod_path = str(Path(__file__).resolve().parent)
|
|
34
|
+
pass
|
|
35
|
+
|
|
36
|
+
def safe_name(self):
|
|
37
|
+
return ModuleBase.get_safe_name(self.name)
|
|
38
|
+
|
|
39
|
+
def start_module(self, **kwargs) -> bool:
|
|
40
|
+
raise Exception('Method "start_module" is not yet implemented.')
|
|
41
|
+
|
|
42
|
+
def js_files(self) -> list:
|
|
43
|
+
return []
|
|
44
|
+
|
|
45
|
+
def key_value_event(self,
|
|
46
|
+
script_location: "Fusion.ScriptLocation" = None,
|
|
47
|
+
stack_trace: str = None,
|
|
48
|
+
module: str = None,
|
|
49
|
+
received_data: dict = None
|
|
50
|
+
) -> bool:
|
|
51
|
+
raise Exception('Method "key_value_event" is not yet implemented.')
|
|
52
|
+
|
|
53
|
+
def data_event(self,
|
|
54
|
+
script_location: "Fusion.ScriptLocation" = None,
|
|
55
|
+
stack_trace: str = None,
|
|
56
|
+
received_data: str = None
|
|
57
|
+
) -> bool:
|
|
58
|
+
raise Exception('Method "data_event" is not yet implemented.')
|
|
59
|
+
|
|
60
|
+
@staticmethod
|
|
61
|
+
def get_safe_name(name):
|
|
62
|
+
name = name.replace(" ", "_").lower()
|
|
63
|
+
return re.sub(r'[^a-zA-Z0-9_.-]+', '', name)
|
|
64
|
+
|
|
65
|
+
@classmethod
|
|
66
|
+
def _get_codeshare(cls, uri: str) -> dict:
|
|
67
|
+
|
|
68
|
+
if uri is None or len(uri) <= 10:
|
|
69
|
+
raise Exception("Invalid codeshare uri. Uri must be only user/project_name.")
|
|
70
|
+
|
|
71
|
+
uri = uri.strip(" /@.")
|
|
72
|
+
|
|
73
|
+
headers = {
|
|
74
|
+
"Accept": "application/vnd.github+json",
|
|
75
|
+
"User-Agent": f"Frida-fusion v{__version__}, Frida v{frida.__version__}"
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
try:
|
|
79
|
+
resp = requests.get(f"https://codeshare.frida.re/api/project/{uri}", headers=headers, timeout=30)
|
|
80
|
+
resp.raise_for_status()
|
|
81
|
+
data = resp.json()
|
|
82
|
+
if data is None:
|
|
83
|
+
raise Exception("data is empty")
|
|
84
|
+
|
|
85
|
+
if data.get('source', None) is None or data.get('source', '').strip(" \r\n") == "":
|
|
86
|
+
raise Exception("source code is empty")
|
|
87
|
+
|
|
88
|
+
return data
|
|
89
|
+
|
|
90
|
+
except Exception as e:
|
|
91
|
+
raise ModuleLoaderError("Error getting codeshare data") from e
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class Module(object):
|
|
95
|
+
modules = {}
|
|
96
|
+
|
|
97
|
+
def __init__(self, name, description, module, qualname, class_name):
|
|
98
|
+
self.name = name
|
|
99
|
+
self.description = description
|
|
100
|
+
self.module = module
|
|
101
|
+
self.qualname = qualname
|
|
102
|
+
self._class = class_name
|
|
103
|
+
pass
|
|
104
|
+
|
|
105
|
+
def safe_name(self):
|
|
106
|
+
return ModuleBase.get_safe_name(self.name)
|
|
107
|
+
|
|
108
|
+
def create_instance(self):
|
|
109
|
+
return self._class()
|
|
110
|
+
|
|
111
|
+
@classmethod
|
|
112
|
+
def get_base_module(cls) -> str:
|
|
113
|
+
file = Path(__file__).stem
|
|
114
|
+
|
|
115
|
+
parent_module = f'.{cls.__module__}.'.replace(f'.{file}.', '').strip(' .')
|
|
116
|
+
|
|
117
|
+
return '.'.join((parent_module, 'modules'))
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
class InternalModule(Module):
|
|
121
|
+
pass
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
class ExternalModule(Module):
|
|
125
|
+
pass
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
class ModuleManager:
|
|
129
|
+
@classmethod
|
|
130
|
+
def _safe_import_from_path(cls, path: Path, loaded_files: set):
|
|
131
|
+
"""
|
|
132
|
+
Importa um .py arbitrário usando um nome único e registra o arquivo
|
|
133
|
+
para não ser importado duas vezes.
|
|
134
|
+
"""
|
|
135
|
+
real = path.resolve()
|
|
136
|
+
|
|
137
|
+
try:
|
|
138
|
+
if real in loaded_files:
|
|
139
|
+
return
|
|
140
|
+
|
|
141
|
+
# nome único, estável, baseado no caminho
|
|
142
|
+
pseudo_name = (
|
|
143
|
+
"fusion_ext_"
|
|
144
|
+
+ "_".join(real.parts).replace(":", "_").replace("\\", "_").replace("/", "_")
|
|
145
|
+
.replace(".", "_")
|
|
146
|
+
)
|
|
147
|
+
spec = importlib.util.spec_from_file_location(pseudo_name, real)
|
|
148
|
+
if spec and spec.loader:
|
|
149
|
+
mod = importlib.util.module_from_spec(spec)
|
|
150
|
+
sys.modules[pseudo_name] = mod
|
|
151
|
+
spec.loader.exec_module(mod)
|
|
152
|
+
loaded_files.add(real)
|
|
153
|
+
except Exception as ie:
|
|
154
|
+
Logger.pl('\n{!} {R}Error loading external module: {G}%s{R}\n {O} %s{W}' % (str(ie), str(real)))
|
|
155
|
+
pass
|
|
156
|
+
|
|
157
|
+
@classmethod
|
|
158
|
+
def _import_via_pkgutil(cls, roots: list[Path], loaded_files: set):
|
|
159
|
+
"""
|
|
160
|
+
Varre roots com pkgutil.walk_packages. Isso encontra
|
|
161
|
+
- módulos .py no nível do root
|
|
162
|
+
- pacotes (pastas com __init__.py) e seus submódulos
|
|
163
|
+
NÃO entra em subpastas sem __init__.py (por isso depois complementamos).
|
|
164
|
+
"""
|
|
165
|
+
str_roots = [str(p) for p in roots]
|
|
166
|
+
for loader, modname, is_pkg in pkgutil.walk_packages(str_roots):
|
|
167
|
+
try:
|
|
168
|
+
mod = importlib.import_module(modname)
|
|
169
|
+
mfile = getattr(mod, "__file__", None)
|
|
170
|
+
if mfile:
|
|
171
|
+
loaded_files.add(Path(mfile).resolve())
|
|
172
|
+
except Exception as ie:
|
|
173
|
+
Logger.pl(
|
|
174
|
+
'\n{!} {R}Error loading internal module: {G}%s{R}\n {O} %s{W}' % (
|
|
175
|
+
str(ie), str(loader.path)))
|
|
176
|
+
pass
|
|
177
|
+
|
|
178
|
+
@classmethod
|
|
179
|
+
def _load_any_py_recursively(cls, root: Path, loaded_files: set):
|
|
180
|
+
"""
|
|
181
|
+
Carrega *todo* arquivo .py sob root (rglob), incluindo subpastas sem __init__.py,
|
|
182
|
+
sem duplicar o que já foi importado.
|
|
183
|
+
"""
|
|
184
|
+
for py in root.rglob("*.py"):
|
|
185
|
+
# exclui caches e similares
|
|
186
|
+
if any(part in {"__pycache__"} for part in py.parts):
|
|
187
|
+
continue
|
|
188
|
+
cls._safe_import_from_path(py, loaded_files)
|
|
189
|
+
|
|
190
|
+
@classmethod
|
|
191
|
+
def list_modules(cls) -> dict:
|
|
192
|
+
try:
|
|
193
|
+
base_module = Module.get_base_module()
|
|
194
|
+
modules: dict[str, Module] = {}
|
|
195
|
+
|
|
196
|
+
# --- 1) Varredura padrão do seu pacote interno: <este_arquivo>/modules ---
|
|
197
|
+
base_path = Path(__file__).resolve().parent / "modules"
|
|
198
|
+
internal_mod_roots = [p for p in base_path.iterdir() if p.is_dir()]
|
|
199
|
+
|
|
200
|
+
internal_mods = []
|
|
201
|
+
|
|
202
|
+
# Vamos usar pkgutil para o pacote interno (mantém o comportamento)
|
|
203
|
+
loaded_files: set[Path] = set()
|
|
204
|
+
mods = [str(p) for p in internal_mod_roots]
|
|
205
|
+
for loader, modname, is_pkg in pkgutil.walk_packages(mods):
|
|
206
|
+
if not is_pkg:
|
|
207
|
+
# Reconstrói o caminho relativo para montar o import dentro do pacote base
|
|
208
|
+
mod_path = Path(getattr(loader, "path", ""))
|
|
209
|
+
try:
|
|
210
|
+
rel = mod_path.resolve().relative_to(base_path.resolve())
|
|
211
|
+
dotted = "." + ".".join(rel.parts) if rel.parts else ""
|
|
212
|
+
except Exception:
|
|
213
|
+
dotted = ""
|
|
214
|
+
importlib.import_module(f"{base_module}{dotted}.{modname}")
|
|
215
|
+
internal_mods.append(f"{base_module}{dotted}.{modname}")
|
|
216
|
+
|
|
217
|
+
# --- 2) Varredura de caminhos externos via FUSION_MODULES ---
|
|
218
|
+
env_value = os.environ.get("FUSION_MODULES", "").strip()
|
|
219
|
+
if env_value:
|
|
220
|
+
extra_roots = [Path(p).expanduser() for p in env_value.split(os.pathsep) if p.strip()]
|
|
221
|
+
existing_roots = [p for p in extra_roots if p.exists() and p.is_dir()]
|
|
222
|
+
|
|
223
|
+
# Para que pkgutil encontre módulos top-level nesses roots
|
|
224
|
+
# (sem precisar de nomes de pacote), colocamos cada root no sys.path
|
|
225
|
+
# durante a varredura. Usamos um conjunto para restaurar depois se preferir.
|
|
226
|
+
original_sys_path = list(sys.path)
|
|
227
|
+
try:
|
|
228
|
+
for root in existing_roots:
|
|
229
|
+
if str(root) not in sys.path:
|
|
230
|
+
sys.path.insert(0, str(root))
|
|
231
|
+
|
|
232
|
+
# 2a) Encontrar módulos top-level e pacotes (com __init__.py)
|
|
233
|
+
cls._import_via_pkgutil(existing_roots, loaded_files)
|
|
234
|
+
|
|
235
|
+
# 2b) Complementar: carregar QUALQUER .py (inclusive subpastas sem __init__.py)
|
|
236
|
+
for root in existing_roots:
|
|
237
|
+
cls._load_any_py_recursively(root, loaded_files)
|
|
238
|
+
finally:
|
|
239
|
+
# opcional: restaurar sys.path (seguro para evitar vazamentos)
|
|
240
|
+
sys.path[:] = original_sys_path
|
|
241
|
+
|
|
242
|
+
# --- 3) Instanciar subclasses de ModuleBase e montar o registry ---
|
|
243
|
+
for i_class in ModuleBase.__subclasses__():
|
|
244
|
+
t = i_class()
|
|
245
|
+
key = t.safe_name()
|
|
246
|
+
if key in modules:
|
|
247
|
+
raise ModuleLoaderError(
|
|
248
|
+
f"Duplicated Module name: {i_class.__module__}.{i_class.__qualname__}"
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
if str(i_class.__module__) in internal_mods:
|
|
252
|
+
modules[key] = InternalModule(
|
|
253
|
+
name=t.name,
|
|
254
|
+
description=t.description,
|
|
255
|
+
module=str(i_class.__module__),
|
|
256
|
+
qualname=str(i_class.__qualname__),
|
|
257
|
+
class_name=i_class,
|
|
258
|
+
)
|
|
259
|
+
else:
|
|
260
|
+
modules[key] = ExternalModule(
|
|
261
|
+
name=t.name,
|
|
262
|
+
description=t.description,
|
|
263
|
+
module=str(i_class.__module__),
|
|
264
|
+
qualname=str(i_class.__qualname__),
|
|
265
|
+
class_name=i_class,
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
return modules
|
|
269
|
+
|
|
270
|
+
except Exception as e:
|
|
271
|
+
# Envolve a exceção original para manter contexto
|
|
272
|
+
raise ModuleLoaderError("Error listing modules") from e
|
|
File without changes
|
{frida-fusion-0.1.4/frida_fusion/modules → frida_fusion-0.1.6/frida_fusion/modules/crypto}/crypto.py
RENAMED
|
@@ -3,13 +3,13 @@ from pathlib import Path
|
|
|
3
3
|
import base64
|
|
4
4
|
import string
|
|
5
5
|
|
|
6
|
-
from
|
|
7
|
-
from
|
|
8
|
-
from
|
|
6
|
+
from frida_fusion.libs.logger import Logger
|
|
7
|
+
from frida_fusion.libs.database import Database
|
|
8
|
+
from frida_fusion.module import ModuleBase
|
|
9
9
|
|
|
10
10
|
from typing import TYPE_CHECKING
|
|
11
11
|
if TYPE_CHECKING:
|
|
12
|
-
from
|
|
12
|
+
from frida_fusion.fusion import Fusion # só no type checker
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
class Crypto(ModuleBase):
|
|
@@ -274,8 +274,11 @@ class Crypto(ModuleBase):
|
|
|
274
274
|
self._crypto_db = None
|
|
275
275
|
self.mod_path = str(Path(__file__).resolve().parent)
|
|
276
276
|
|
|
277
|
-
def
|
|
278
|
-
|
|
277
|
+
def start_module(self, **kwargs) -> bool:
|
|
278
|
+
if 'db_path' not in kwargs:
|
|
279
|
+
raise Exception("parameter db_path not found")
|
|
280
|
+
|
|
281
|
+
self._crypto_db = Crypto.CryptoDB(db_name=kwargs['db_path'])
|
|
279
282
|
return True
|
|
280
283
|
|
|
281
284
|
def js_files(self) -> list:
|
|
File without changes
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import errno
|
|
2
|
+
import os.path
|
|
3
|
+
import tempfile
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from frida_fusion.libs.logger import Logger
|
|
6
|
+
from frida_fusion.module import ModuleBase
|
|
7
|
+
|
|
8
|
+
from typing import TYPE_CHECKING
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from frida_fusion.fusion import Fusion # só no type checker
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class TlsUnpinning(ModuleBase):
|
|
15
|
+
|
|
16
|
+
def __init__(self):
|
|
17
|
+
super().__init__('Multiple unpinning', 'Use frida_multiple_unpinning by Maurizio Siddu (@akabe1)')
|
|
18
|
+
self.mod_path = str(Path(__file__).resolve().parent)
|
|
19
|
+
self.js_file = os.path.join(self.mod_path, "frida_multiple_unpinning.js")
|
|
20
|
+
|
|
21
|
+
def start_module(self, **kwargs) -> bool:
|
|
22
|
+
if not os.path.isfile(self.js_file):
|
|
23
|
+
Logger.pl("{+} Downloading CodeShare script from @akabe1/frida-multiple-unpinning")
|
|
24
|
+
data = self._get_codeshare("@akabe1/frida-multiple-unpinning/")
|
|
25
|
+
if data.get('source', None) is None or data.get('source', '').strip(" \r\n") == "":
|
|
26
|
+
raise Exception("source code is empty")
|
|
27
|
+
|
|
28
|
+
try:
|
|
29
|
+
with open(self.js_file, "w", encoding='utf-8') as f:
|
|
30
|
+
f.write(data.get('source', ''))
|
|
31
|
+
except IOError as x:
|
|
32
|
+
if x.errno == errno.EACCES:
|
|
33
|
+
Logger.pl('{!} {R}error: could not open output file to write {O}permission denied{R}{W}\r\n')
|
|
34
|
+
elif x.errno == errno.EISDIR:
|
|
35
|
+
Logger.pl('{!} {R}error: could not open output file to write {O}it is an directory{R}{W}\r\n')
|
|
36
|
+
else:
|
|
37
|
+
Logger.pl('{!} {R}error: could not open output file to write{W}\r\n')
|
|
38
|
+
|
|
39
|
+
# Try to save locally
|
|
40
|
+
self.js_file = str(Path("frida_multiple_unpinning.js").resolve().absolute())
|
|
41
|
+
with open(self.js_file, "w", encoding='utf-8') as f:
|
|
42
|
+
f.write(data.get('source', ''))
|
|
43
|
+
|
|
44
|
+
return True
|
|
45
|
+
|
|
46
|
+
def js_files(self) -> list:
|
|
47
|
+
return [
|
|
48
|
+
self.js_file
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
def key_value_event(self,
|
|
52
|
+
script_location: "Fusion.ScriptLocation" = None,
|
|
53
|
+
stack_trace: str = None,
|
|
54
|
+
module: str = None,
|
|
55
|
+
received_data: dict = None
|
|
56
|
+
) -> bool:
|
|
57
|
+
return True
|
|
58
|
+
|
|
59
|
+
def data_event(self,
|
|
60
|
+
script_location: "Fusion.ScriptLocation" = None,
|
|
61
|
+
stack_trace: str = None,
|
|
62
|
+
received_data: str = None
|
|
63
|
+
) -> bool:
|
|
64
|
+
return True
|
|
65
|
+
|
|
66
|
+
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: frida-fusion
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.6
|
|
4
4
|
Summary: Hook your mobile tests with Frida
|
|
5
5
|
Author-email: "Helvio Junior (M4v3r1ck)" <helvio_junior@hotmail.com>
|
|
6
6
|
Maintainer-email: "Helvio Junior (M4v3r1ck)" <helvio_junior@hotmail.com>
|
|
@@ -12,7 +12,6 @@ Keywords: Frida Fusion,Frida,Frida Scripts,development,red team
|
|
|
12
12
|
Classifier: Development Status :: 4 - Beta
|
|
13
13
|
Classifier: Environment :: Console
|
|
14
14
|
Classifier: Intended Audience :: System Administrators
|
|
15
|
-
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
|
|
16
15
|
Classifier: Natural Language :: English
|
|
17
16
|
Classifier: Operating System :: OS Independent
|
|
18
17
|
Classifier: Programming Language :: Python
|
|
@@ -27,6 +26,12 @@ Classifier: Topic :: Security
|
|
|
27
26
|
Classifier: Topic :: Utilities
|
|
28
27
|
Requires-Python: <4,>=3.9
|
|
29
28
|
Description-Content-Type: text/markdown
|
|
29
|
+
License-File: LICENSE
|
|
30
|
+
Requires-Dist: colorama
|
|
31
|
+
Requires-Dist: requests>=2.23.0
|
|
32
|
+
Requires-Dist: frida>=15.1.17
|
|
33
|
+
Requires-Dist: frida-tools>=10.8.0
|
|
34
|
+
Dynamic: license-file
|
|
30
35
|
|
|
31
36
|
# Frida Fusion
|
|
32
37
|
|
|
@@ -68,4 +73,61 @@ Modules:
|
|
|
68
73
|
pip3 install frida-fusion
|
|
69
74
|
```
|
|
70
75
|
|
|
76
|
+
## Module engine
|
|
71
77
|
|
|
78
|
+
You can check available modules with `frida-fusion --list-modules` command.
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
frida-fusion --list-modules
|
|
82
|
+
|
|
83
|
+
[ FRIDA ]—o—( FUSION )—o—[ MOBILE TESTS ] // v0.1.4
|
|
84
|
+
> hook your mobile tests with Frida
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
Available modules
|
|
88
|
+
Module Name : Description
|
|
89
|
+
Crypto : Hook cryptography/hashing functions
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### External modules
|
|
93
|
+
|
|
94
|
+
You can develop or download community modules and load into frida-fusion.
|
|
95
|
+
|
|
96
|
+
To pass to the Frida Fusion the external module path you can use the environment variable `FUSION_MODULES` with the full path of modules
|
|
97
|
+
|
|
98
|
+
At linux:
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
export FUSION_MODULES=/tmp/modules
|
|
102
|
+
|
|
103
|
+
# List all modules
|
|
104
|
+
frida-fusion --list-modules
|
|
105
|
+
|
|
106
|
+
# Using available module
|
|
107
|
+
frida-fusion -f [app_id] -U --script-path . -m [module_name]
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
At windows:
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
$env:FUSION_MODULES = "C:\extra_mods"
|
|
114
|
+
|
|
115
|
+
# List all modules
|
|
116
|
+
frida-fusion --list-modules
|
|
117
|
+
|
|
118
|
+
# Using available module
|
|
119
|
+
frida-fusion -f [app_id] -U --script-path . -m [module_name]
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Community modules
|
|
123
|
+
|
|
124
|
+
You can also use one of community developed modules
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
cd /tmp/
|
|
128
|
+
git clone https://github.com/helviojunior/frida-fusion-community-modules
|
|
129
|
+
export FUSION_MODULES=/tmp/frida-fusion-community-modules
|
|
130
|
+
|
|
131
|
+
# List all modules
|
|
132
|
+
frida-fusion --list-modules
|
|
133
|
+
```
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
LICENSE
|
|
1
2
|
README.md
|
|
2
3
|
pyproject.toml
|
|
3
4
|
setup.py
|
|
@@ -20,5 +21,8 @@ frida_fusion/libs/database.py
|
|
|
20
21
|
frida_fusion/libs/helpers.js
|
|
21
22
|
frida_fusion/libs/logger.py
|
|
22
23
|
frida_fusion/modules/__init__.py
|
|
23
|
-
frida_fusion/modules/crypto.
|
|
24
|
-
frida_fusion/modules/crypto.
|
|
24
|
+
frida_fusion/modules/crypto/__init__.py
|
|
25
|
+
frida_fusion/modules/crypto/crypto.js
|
|
26
|
+
frida_fusion/modules/crypto/crypto.py
|
|
27
|
+
frida_fusion/modules/tls_unpinning/__init__.py
|
|
28
|
+
frida_fusion/modules/tls_unpinning/frida_multiple_unpinning.py
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
[build-system]
|
|
2
|
-
requires = ["setuptools"
|
|
2
|
+
requires = ["setuptools>=80.0.0"]
|
|
3
3
|
build-backend = "setuptools.build_meta"
|
|
4
4
|
|
|
5
5
|
[project]
|
|
@@ -8,13 +8,12 @@ name = "frida-fusion"
|
|
|
8
8
|
description = "Hook your mobile tests with Frida"
|
|
9
9
|
readme = {file = "README.md", content-type = "text/markdown"}
|
|
10
10
|
requires-python = ">=3.9,<4"
|
|
11
|
-
license =
|
|
11
|
+
license-files = ["LICEN[CS]E*"]
|
|
12
12
|
keywords = ["Frida Fusion", "Frida", "Frida Scripts", "development", "red team"]
|
|
13
13
|
classifiers = [
|
|
14
14
|
"Development Status :: 4 - Beta",
|
|
15
15
|
"Environment :: Console",
|
|
16
16
|
"Intended Audience :: System Administrators",
|
|
17
|
-
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
|
|
18
17
|
"Natural Language :: English",
|
|
19
18
|
"Operating System :: OS Independent",
|
|
20
19
|
"Programming Language :: Python",
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
import pkgutil
|
|
3
|
-
import importlib
|
|
4
|
-
from pathlib import Path
|
|
5
|
-
|
|
6
|
-
from .libs.database import Database
|
|
7
|
-
from typing import TYPE_CHECKING
|
|
8
|
-
if TYPE_CHECKING:
|
|
9
|
-
from .fusion import Fusion # só no type checker
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class ModuleBase(object):
|
|
13
|
-
|
|
14
|
-
name = ''
|
|
15
|
-
description = ''
|
|
16
|
-
mod_path = ''
|
|
17
|
-
|
|
18
|
-
def __init__(self, name, description):
|
|
19
|
-
self.name = name
|
|
20
|
-
self.description = description
|
|
21
|
-
self.mod_path = str(Path(__file__).resolve().parent)
|
|
22
|
-
pass
|
|
23
|
-
|
|
24
|
-
def start_db(self, db_path: str) -> bool:
|
|
25
|
-
raise Exception('Method "start_db" is not yet implemented.')
|
|
26
|
-
|
|
27
|
-
def js_files(self) -> list:
|
|
28
|
-
return []
|
|
29
|
-
|
|
30
|
-
def key_value_event(self,
|
|
31
|
-
script_location: "Fusion.ScriptLocation" = None,
|
|
32
|
-
stack_trace: str = None,
|
|
33
|
-
module: str = None,
|
|
34
|
-
received_data: dict = None
|
|
35
|
-
) -> bool:
|
|
36
|
-
raise Exception('Method "key_value_event" is not yet implemented.')
|
|
37
|
-
|
|
38
|
-
def data_event(self,
|
|
39
|
-
script_location: "Fusion.ScriptLocation" = None,
|
|
40
|
-
stack_trace: str = None,
|
|
41
|
-
received_data: str = None
|
|
42
|
-
) -> bool:
|
|
43
|
-
raise Exception('Method "data_event" is not yet implemented.')
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
class Module(object):
|
|
47
|
-
modules = {}
|
|
48
|
-
|
|
49
|
-
def __init__(self, name, description, module, qualname, class_name):
|
|
50
|
-
self.name = name
|
|
51
|
-
self.description = description
|
|
52
|
-
self.module = module
|
|
53
|
-
self.qualname = qualname
|
|
54
|
-
self._class = class_name
|
|
55
|
-
pass
|
|
56
|
-
|
|
57
|
-
def create_instance(self):
|
|
58
|
-
return self._class()
|
|
59
|
-
|
|
60
|
-
@classmethod
|
|
61
|
-
def get_instance(cls, name: str):
|
|
62
|
-
if len(Module.modules) == 0:
|
|
63
|
-
Module.modules = Module.list_modules()
|
|
64
|
-
|
|
65
|
-
selected_modules = [
|
|
66
|
-
mod for mod in Module.modules
|
|
67
|
-
if mod == name
|
|
68
|
-
]
|
|
69
|
-
|
|
70
|
-
mod = None
|
|
71
|
-
if len(selected_modules) == 1:
|
|
72
|
-
mod = Module.modules[selected_modules[0]].create_instance()
|
|
73
|
-
|
|
74
|
-
return mod
|
|
75
|
-
|
|
76
|
-
@classmethod
|
|
77
|
-
def get_base_module(cls) -> str:
|
|
78
|
-
file = Path(__file__).stem
|
|
79
|
-
|
|
80
|
-
parent_module = f'.{cls.__module__}.'.replace(f'.{file}.', '').strip(' .')
|
|
81
|
-
|
|
82
|
-
return '.'.join((parent_module, 'modules'))
|
|
83
|
-
|
|
84
|
-
@classmethod
|
|
85
|
-
def list_modules(cls) -> dict:
|
|
86
|
-
try:
|
|
87
|
-
|
|
88
|
-
base_module = Module.get_base_module()
|
|
89
|
-
|
|
90
|
-
modules = {}
|
|
91
|
-
|
|
92
|
-
base_path = os.path.join(
|
|
93
|
-
Path(__file__).resolve().parent, 'modules'
|
|
94
|
-
)
|
|
95
|
-
|
|
96
|
-
for loader, modname, ispkg in pkgutil.walk_packages([base_path]):
|
|
97
|
-
if not ispkg:
|
|
98
|
-
importlib.import_module(f'{base_module}.{modname}')
|
|
99
|
-
|
|
100
|
-
for iclass in ModuleBase.__subclasses__():
|
|
101
|
-
t = iclass()
|
|
102
|
-
if t.name in modules:
|
|
103
|
-
raise Exception(f'Duplicated Module name: {iclass.__module__}.{iclass.__qualname__}')
|
|
104
|
-
|
|
105
|
-
modules[t.name.lower()] = Module(
|
|
106
|
-
name=t.name,
|
|
107
|
-
description=t.description,
|
|
108
|
-
module=str(iclass.__module__),
|
|
109
|
-
qualname=str(iclass.__qualname__),
|
|
110
|
-
class_name=iclass
|
|
111
|
-
)
|
|
112
|
-
|
|
113
|
-
return modules
|
|
114
|
-
|
|
115
|
-
except Exception as e:
|
|
116
|
-
raise Exception('Error listing command modules', e)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{frida-fusion-0.1.4/frida_fusion/modules → frida_fusion-0.1.6/frida_fusion/modules/crypto}/crypto.js
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|