frida-fusion 0.1.14__tar.gz → 0.1.15__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.

Files changed (37) hide show
  1. {frida_fusion-0.1.14 → frida_fusion-0.1.15}/PKG-INFO +2 -2
  2. {frida_fusion-0.1.14 → frida_fusion-0.1.15}/README.md +1 -1
  3. {frida_fusion-0.1.14 → frida_fusion-0.1.15}/frida_fusion/__meta__.py +2 -2
  4. frida_fusion-0.1.15/frida_fusion/modules/reflection/reflection-stalker.js +293 -0
  5. frida_fusion-0.1.15/frida_fusion/modules/reflection/reflection-stalker.py +206 -0
  6. {frida_fusion-0.1.14 → frida_fusion-0.1.15}/frida_fusion.egg-info/PKG-INFO +2 -2
  7. {frida_fusion-0.1.14 → frida_fusion-0.1.15}/frida_fusion.egg-info/SOURCES.txt +2 -0
  8. {frida_fusion-0.1.14 → frida_fusion-0.1.15}/LICENSE +0 -0
  9. {frida_fusion-0.1.14 → frida_fusion-0.1.15}/frida_fusion/__init__.py +0 -0
  10. {frida_fusion-0.1.14 → frida_fusion-0.1.15}/frida_fusion/__main__.py +0 -0
  11. {frida_fusion-0.1.14 → frida_fusion-0.1.15}/frida_fusion/args.py +0 -0
  12. {frida_fusion-0.1.14 → frida_fusion-0.1.15}/frida_fusion/config.py +0 -0
  13. {frida_fusion-0.1.14 → frida_fusion-0.1.15}/frida_fusion/exceptions.py +0 -0
  14. {frida_fusion-0.1.14 → frida_fusion-0.1.15}/frida_fusion/fusion.py +0 -0
  15. {frida_fusion-0.1.14 → frida_fusion-0.1.15}/frida_fusion/libs/__init__.py +0 -0
  16. {frida_fusion-0.1.14 → frida_fusion-0.1.15}/frida_fusion/libs/color.py +0 -0
  17. {frida_fusion-0.1.14 → frida_fusion-0.1.15}/frida_fusion/libs/database.py +0 -0
  18. {frida_fusion-0.1.14 → frida_fusion-0.1.15}/frida_fusion/libs/helpers.js +0 -0
  19. {frida_fusion-0.1.14 → frida_fusion-0.1.15}/frida_fusion/libs/logger.py +0 -0
  20. {frida_fusion-0.1.14 → frida_fusion-0.1.15}/frida_fusion/libs/scriptlocation.py +0 -0
  21. {frida_fusion-0.1.14 → frida_fusion-0.1.15}/frida_fusion/module.py +0 -0
  22. {frida_fusion-0.1.14 → frida_fusion-0.1.15}/frida_fusion/modules/__init__.py +0 -0
  23. {frida_fusion-0.1.14 → frida_fusion-0.1.15}/frida_fusion/modules/android_setings/__init__.py +0 -0
  24. {frida_fusion-0.1.14 → frida_fusion-0.1.15}/frida_fusion/modules/android_setings/settings.js +0 -0
  25. {frida_fusion-0.1.14 → frida_fusion-0.1.15}/frida_fusion/modules/android_setings/settings.py +0 -0
  26. {frida_fusion-0.1.14 → frida_fusion-0.1.15}/frida_fusion/modules/crypto/__init__.py +0 -0
  27. {frida_fusion-0.1.14 → frida_fusion-0.1.15}/frida_fusion/modules/crypto/crypto.js +0 -0
  28. {frida_fusion-0.1.14 → frida_fusion-0.1.15}/frida_fusion/modules/crypto/crypto.py +0 -0
  29. {frida_fusion-0.1.14 → frida_fusion-0.1.15}/frida_fusion/modules/tls_unpinning/__init__.py +0 -0
  30. {frida_fusion-0.1.14 → frida_fusion-0.1.15}/frida_fusion/modules/tls_unpinning/frida_multiple_unpinning.py +0 -0
  31. {frida_fusion-0.1.14 → frida_fusion-0.1.15}/frida_fusion.egg-info/dependency_links.txt +0 -0
  32. {frida_fusion-0.1.14 → frida_fusion-0.1.15}/frida_fusion.egg-info/entry_points.txt +0 -0
  33. {frida_fusion-0.1.14 → frida_fusion-0.1.15}/frida_fusion.egg-info/requires.txt +0 -0
  34. {frida_fusion-0.1.14 → frida_fusion-0.1.15}/frida_fusion.egg-info/top_level.txt +0 -0
  35. {frida_fusion-0.1.14 → frida_fusion-0.1.15}/pyproject.toml +0 -0
  36. {frida_fusion-0.1.14 → frida_fusion-0.1.15}/setup.cfg +0 -0
  37. {frida_fusion-0.1.14 → frida_fusion-0.1.15}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: frida-fusion
3
- Version: 0.1.14
3
+ Version: 0.1.15
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>
@@ -105,7 +105,7 @@ void fusion_printMethods(String name);
105
105
  void fusion_waitForClass(String name, CallbackFunction onReady)
106
106
 
107
107
  # Conversions
108
- byte[] fusion_stringToBase64(String message);
108
+ String fusion_stringToBase64(String message);
109
109
  String fusion_bytesToBase64(byte[] byteArray);
110
110
  String fusion_encodeHex(byte[] byteArray);
111
111
  ```
@@ -70,7 +70,7 @@ void fusion_printMethods(String name);
70
70
  void fusion_waitForClass(String name, CallbackFunction onReady)
71
71
 
72
72
  # Conversions
73
- byte[] fusion_stringToBase64(String message);
73
+ String fusion_stringToBase64(String message);
74
74
  String fusion_bytesToBase64(byte[] byteArray);
75
75
  String fusion_encodeHex(byte[] byteArray);
76
76
  ```
@@ -1,8 +1,8 @@
1
- __version__ = '0.1.14'
1
+ __version__ = '0.1.15'
2
2
  __title__ = "Frida Fusion"
3
3
  __description__ = "📱 frida-fusion - runtime mobile exploration"
4
4
  __url__ = "https://github.com/helviojunior/frida-fusion"
5
- __build__ = 0x8a5c3b4
5
+ __build__ = 0xef43fce
6
6
  __author__ = "Helvio Junior (M4v3r1ck)"
7
7
  __author_email__ = "helvio_junior@hotmail.com"
8
8
  __license__ = "GPL-3.0"
@@ -0,0 +1,293 @@
1
+ // Script Frida: Method.invoke -> build object + enviar via fusion_sendKeyValueData
2
+ Java.perform(function () {
3
+
4
+ var jlrmethod = Java.use("java.lang.reflect.Method");
5
+ var origInvoke = jlrmethod.invoke; // referência original
6
+
7
+ function safeGetClassName(obj) {
8
+ try {
9
+ if (obj === null || obj === undefined) return null;
10
+ var cls = obj.getClass();
11
+ return cls.getName();
12
+ } catch (e) {
13
+ try { if (obj && obj.$className) return obj.$className; } catch(e2) {}
14
+ try { return Object.prototype.toString.call(obj); } catch(_) { return typeof obj; }
15
+ }
16
+ }
17
+
18
+ function buildParamInfo(param, depth) {
19
+ depth = depth || 0;
20
+ var maxDepth = 3;
21
+ var info = { type: null, class_name: null, value: null };
22
+
23
+ if (param === null || param === undefined) {
24
+ info.type = 'null';
25
+ return info;
26
+ }
27
+
28
+ var className = safeGetClassName(param);
29
+ info.class_name = className;
30
+ info.type = className;
31
+
32
+ try {
33
+ if (className && className.charAt(0) === '[') {
34
+ info.type = className;
35
+ if (className === '[B') {
36
+ try {
37
+ var buffer = Java.array('byte', param);
38
+ try { info.value = toBase64(buffer); } catch (e) {
39
+ var sb = []; for (var i=0;i<Math.min(buffer.length,256);i++) sb.push((buffer[i]&0xff).toString(16));
40
+ info.value = sb.join('');
41
+ }
42
+ } catch (errByte) { info.value = '[unreadable byte array]'; }
43
+ return info;
44
+ }
45
+ if (className.indexOf('Ljava.lang.String') !== -1) {
46
+ try {
47
+ var arrLen = param.length;
48
+ var vals = [];
49
+ for (var i=0;i<Math.min(arrLen,50);i++) { vals.push(String(param[i])); }
50
+ info.value = { length: arrLen, preview: vals };
51
+ } catch(e) { info.value = '[unreadable string array]'; }
52
+ return info;
53
+ }
54
+ if (depth >= maxDepth) { info.value = '[array - depth limit]'; return info; }
55
+ try {
56
+ var n = param.length;
57
+ var items = [];
58
+ for (var j=0; j<Math.min(n,50); j++) items.push(buildParamInfo(param[j], depth+1));
59
+ info.value = { length: n, preview: items };
60
+ } catch(e) { info.value = '[unreadable array]'; }
61
+ return info;
62
+ }
63
+ } catch(eArrDetect) {}
64
+
65
+ try {
66
+ if (className === 'java.lang.String' || (typeof param === 'string')) { info.value = String(param); return info; }
67
+ if (className && (
68
+ className.indexOf('java.lang.Number') !== -1 ||
69
+ className.indexOf('java.lang.Integer') !== -1 ||
70
+ className.indexOf('java.lang.Long') !== -1 ||
71
+ className.indexOf('java.lang.Boolean') !== -1 ||
72
+ className.indexOf('java.lang.Double') !== -1 ||
73
+ className.indexOf('java.lang.Float') !== -1 ||
74
+ className.indexOf('java.lang.Short') !== -1 ||
75
+ className.indexOf('java.lang.Character') !== -1)) {
76
+ try { info.value = param.toString(); } catch(e){ info.value = String(param); }
77
+ return info;
78
+ }
79
+ try { info.value = param.toString(); } catch (e) { info.value = '[toString failed]'; }
80
+ return info;
81
+ } catch(errGeneric) {
82
+ info.value = '[error building param]';
83
+ return info;
84
+ }
85
+ }
86
+
87
+ function buildInvokeObject(methodRef, targetObject, parameters) {
88
+ var obj = {
89
+ timestamp: (new Date()).toISOString(),
90
+ method: {
91
+ toString: String(methodRef),
92
+ name: null,
93
+ declaring_class: null,
94
+ b64: null
95
+ },
96
+ target: {
97
+ class_name: null,
98
+ toString: null
99
+ },
100
+ parameters: [],
101
+ return: {
102
+ class_name: null,
103
+ value: null
104
+ }
105
+ };
106
+
107
+ try {
108
+ if (methodRef && methodRef.getName) obj.method.name = methodRef.getName(); else obj.method.name = String(methodRef);
109
+ try {
110
+ var decl = methodRef.getDeclaringClass();
111
+ obj.method.declaring_class = decl ? decl.getName() : null;
112
+ } catch(e) { obj.method.declaring_class = null; }
113
+ } catch(_) {}
114
+
115
+ try {
116
+ var tName = "" + methodRef;
117
+ try { obj.method.b64 = fusion_stringToBase64(tName); } catch(e){ obj.method.b64 = null; }
118
+ } catch(_) { obj.method.b64 = null; }
119
+
120
+ try {
121
+ if (targetObject === null || targetObject === undefined) {
122
+ obj.target.class_name = null; obj.target.toString = null;
123
+ } else {
124
+ obj.target.class_name = safeGetClassName(targetObject);
125
+ try { obj.target.toString = targetObject.toString(); } catch(e){ obj.target.toString = '[toString failed]'; }
126
+ }
127
+ } catch(e) {}
128
+
129
+ try {
130
+ var type = Object.prototype.toString.call(parameters);
131
+ if (parameters === null || parameters === undefined) {
132
+ obj.parameters = [];
133
+ } else if (type === '[object Array]') {
134
+ var arrLen = parameters.length;
135
+ for (var i=0; i<Math.min(arrLen,200); i++) {
136
+ obj.parameters.push({ index: i, info: buildParamInfo(parameters[i], 0) });
137
+ }
138
+ if (arrLen > 200) obj.parameters_truncated = true;
139
+ } else {
140
+ try {
141
+ var maybeLen = parameters.length;
142
+ if (typeof maybeLen === 'number') {
143
+ for (var k=0; k<Math.min(maybeLen,100); k++) obj.parameters.push({ index: k, info: buildParamInfo(parameters[k],0) });
144
+ } else {
145
+ obj.parameters.push({ index: 0, info: buildParamInfo(parameters,0) });
146
+ }
147
+ } catch(e2) {
148
+ obj.parameters.push({ index: 0, info: buildParamInfo(parameters,0) });
149
+ }
150
+ }
151
+ } catch(errParams) {
152
+ obj.parameters = [{ index:0, info: { type: '[error enumerating parameters]' } }];
153
+ }
154
+
155
+ return obj;
156
+ }
157
+
158
+ // coleta backtrace da Thread Java atual e retorna [pretty, raw]
159
+ function collectBacktrace() {
160
+ var pretty = "[unavailable]";
161
+ var raw = [];
162
+ try {
163
+ var Thread = Java.use('java.lang.Thread');
164
+ var trace = Thread.currentThread().getStackTrace(); // array of StackTraceElement
165
+ var prettyLines = [];
166
+ for (var i=0; i<trace.length; i++) {
167
+ try {
168
+ var ste = trace[i];
169
+ var line = ste.toString(); // ex: com.foo.Bar.method(File.java:123)
170
+ prettyLines.push(line);
171
+ raw.push(String(ste));
172
+ } catch(eSte) { /* ignore */ }
173
+ }
174
+ pretty = prettyLines.join('\n');
175
+ } catch(e) {
176
+ try {
177
+ // fallback: usar Java.perform stack (menos informativo)
178
+ pretty = (new Error()).stack;
179
+ raw = [pretty];
180
+ } catch(e2) {}
181
+ }
182
+ return { pretty: pretty, raw: raw };
183
+ }
184
+
185
+ // sobrescreve invoke para montar objeto e enviar via fusion_sendKeyValueData
186
+ jlrmethod.invoke.implementation = function(object, parameters) {
187
+ // monta objeto
188
+ var infoObj = buildInvokeObject(this, object, parameters);
189
+
190
+ // coletar backtrace
191
+ var bt = collectBacktrace();
192
+
193
+ // chamar o método original e capturar retorno
194
+ var retvalue;
195
+ try {
196
+ retvalue = origInvoke.call(this, object, parameters);
197
+ } catch (invokeErr) {
198
+ // enviar também quando lançar (pode ser útil)
199
+ try {
200
+ fusion_sendKeyValueData("java.lang.reflect.Method!invoke!throw", [
201
+ { key: "method", value: String(infoObj.method.toString) },
202
+ { key: "declaring_class", value: String(infoObj.method.declaring_class) },
203
+ { key: "method_b64", value: String(infoObj.method.b64) },
204
+ { key: "target_class", value: String(infoObj.target.class_name) },
205
+ { key: "params_count", value: String(infoObj.parameters.length) },
206
+ { key: "params_preview", value: JSON.stringify(infoObj.parameters) },
207
+ { key: "backtrace", value: bt.pretty },
208
+ { key: "backtrace_raw", value: JSON.stringify(bt.raw) },
209
+ { key: "error", value: String(invokeErr) }
210
+ ]);
211
+ } catch(eSendErr) { fusion_sendMessage("W", "fusion_sendKeyValueData error: " + eSendErr); }
212
+
213
+ throw invokeErr; // rethrow para manter comportamento
214
+ }
215
+
216
+ // preencher retorno infoObj.return
217
+ try {
218
+ if (retvalue === null || retvalue === undefined) {
219
+ infoObj.return.class_name = null; infoObj.return.value = null;
220
+ } else {
221
+ infoObj.return.class_name = safeGetClassName(retvalue);
222
+ if (infoObj.return.class_name && infoObj.return.class_name.charAt(0) === '[') {
223
+ if (infoObj.return.class_name === '[B') {
224
+ try { infoObj.return.value = toBase64(Java.array('byte', retvalue)); } catch(e) { infoObj.return.value = '[unreadable byte array]'; }
225
+ } else {
226
+ try {
227
+ var lenR = retvalue.length, itemsR = [];
228
+ for (var ri=0; ri<Math.min(lenR,50); ri++) { itemsR.push(String(retvalue[ri])); }
229
+ infoObj.return.value = { length: lenR, preview: itemsR };
230
+ } catch(eArrR) { infoObj.return.value = '[unreadable array]'; }
231
+ }
232
+ } else {
233
+ try { infoObj.return.value = retvalue.toString(); } catch(e) { infoObj.return.value = '[toString failed]'; }
234
+ }
235
+ }
236
+ } catch(eRetFill) { infoObj.return.value = '[error reading return]'; }
237
+
238
+ // preparar payload para fusion_sendKeyValueData (array de {key, value})
239
+ var payload = [];
240
+ try {
241
+ payload.push({ key: "method", value: String(infoObj.method.toString) });
242
+ payload.push({ key: "method_name", value: String(infoObj.method.name) });
243
+ payload.push({ key: "declaring_class", value: String(infoObj.method.declaring_class) });
244
+ payload.push({ key: "method_b64", value: String(infoObj.method.b64) });
245
+ payload.push({ key: "target_class", value: String(infoObj.target.class_name) });
246
+ payload.push({ key: "target_tostring", value: String(infoObj.target.toString) });
247
+ payload.push({ key: "params_count", value: String(infoObj.parameters.length) });
248
+
249
+ // params_preview como JSON string (pode truncar se muito grande)
250
+ try {
251
+ var paramsJson = JSON.stringify(infoObj.parameters);
252
+ if (paramsJson.length > 20000) paramsJson = paramsJson.slice(0,20000) + "...(truncated)";
253
+ payload.push({ key: "params_preview", value: paramsJson });
254
+ } catch(ePJ) {
255
+ payload.push({ key: "params_preview", value: "[error serializing params]" });
256
+ }
257
+
258
+ // retorno
259
+ try {
260
+ var retSummary = (infoObj.return.class_name === null && infoObj.return.value === null) ? "null" :
261
+ ("(" + String(infoObj.return.class_name) + ") " + String(infoObj.return.value));
262
+ if (retSummary.length > 4000) retSummary = retSummary.slice(0,4000) + "...(truncated)";
263
+ payload.push({ key: "return_summary", value: retSummary });
264
+ payload.push({ key: "return_class", value: String(infoObj.return.class_name) });
265
+ } catch(eRetPush) {
266
+ payload.push({ key: "return_summary", value: "[error]" });
267
+ }
268
+
269
+ // backtrace
270
+ payload.push({ key: "backtrace", value: bt.pretty });
271
+ payload.push({ key: "backtrace_raw", value: JSON.stringify(bt.raw) });
272
+
273
+ // timestamp
274
+ payload.push({ key: "timestamp", value: infoObj.timestamp });
275
+
276
+ } catch(ePayload) {
277
+ fusion_sendMessage("W", "Erro ao preparar payload: " + ePayload);
278
+ }
279
+
280
+ // enviar pelo canal customizado
281
+ try {
282
+ fusion_sendKeyValueData("java.lang.reflect.Method!invoke!call", payload);
283
+ } catch(eSend) {
284
+ // se fusion_sendKeyValueData não existir, fallback para console + fusion_sendMessage (se existir)
285
+ try { fusion_sendMessage("E", "fusion_sendKeyValueData missing or failed"); } catch(_) {}
286
+ }
287
+
288
+ return retvalue;
289
+ };
290
+
291
+ try { fusion_sendMessage("I", "Reflection module with fusion_sendKeyValueData loaded!"); } catch(e) { fusion_sendMessage("W", "Reflection module loaded!"); }
292
+
293
+ });
@@ -0,0 +1,206 @@
1
+ import errno
2
+ import sys
3
+ import json
4
+ import os.path
5
+ from pathlib import Path
6
+ from argparse import _ArgumentGroup, Namespace
7
+ from frida_fusion.libs.logger import Logger
8
+ from frida_fusion.libs.database import Database
9
+ from frida_fusion.module import ModuleBase
10
+ from frida_fusion.libs.scriptlocation import ScriptLocation
11
+ from frida_fusion.exceptions import SilentKillError
12
+
13
+
14
+ class Reflection(ModuleBase):
15
+
16
+ _EXCLUSION_LIST = [
17
+ "android.view.View.onDraw",
18
+ "android.graphics.Picture",
19
+ "com.facebook.fbreact.specs.NativeAnimatedModuleSpec",
20
+ "com.facebook.react.uimanager.BaseViewManager.setTransform",
21
+ "com.facebook.react.uimanager.ReanimatedUIManager.updateView",
22
+ "com.facebook.fbreact.specs.NativeStatusBarManagerAndroidSpec"
23
+ ]
24
+
25
+ class StalkerDB(Database):
26
+ dbName = ""
27
+
28
+ def __init__(self, db_name: str):
29
+ super().__init__(
30
+ auto_create=True,
31
+ db_name=db_name
32
+ )
33
+ self.create_db()
34
+
35
+ def create_db(self):
36
+ super().create_db()
37
+ conn = self.connect_to_db(check=False)
38
+
39
+ # definindo um cursor
40
+ cursor = conn.cursor()
41
+
42
+ # criando a tabela (schema)
43
+ cursor.execute("""
44
+ CREATE TABLE IF NOT EXISTS [reflection_stalker] (
45
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
46
+ method TEXT NOT NULL,
47
+ method_b64 TEXT NULL,
48
+ method_name TEXT NULL,
49
+ target_class TEXT NULL,
50
+ target_tostring TEXT NULL,
51
+ params_count TEXT NULL,
52
+ params TEXT NULL,
53
+ error TEXT NULL,
54
+ return_summary TEXT NULL,
55
+ return_class TEXT NULL,
56
+ stack_trace TEXT NULL,
57
+ created_date datetime not null DEFAULT (datetime('now','localtime'))
58
+ );
59
+ """)
60
+
61
+ conn.commit()
62
+
63
+ # Must get the constraints
64
+ self.get_constraints(conn)
65
+
66
+ def __init__(self):
67
+ super().__init__('Reflection Stalker', 'Monitor reflection calls/invoke by Helvio Junior (M4v3r1ck)')
68
+ self.mod_path = str(Path(__file__).resolve().parent)
69
+ self._stalker_db = None
70
+ self._suppress_messages = False
71
+ self._ignore_list = []
72
+ self.js_file = os.path.join(self.mod_path, "reflection-stalker.js")
73
+
74
+ def start_module(self, **kwargs) -> bool:
75
+ if 'db_path' not in kwargs:
76
+ raise Exception("parameter db_path not found")
77
+
78
+ self._stalker_db = Reflection.StalkerDB(db_name=kwargs['db_path'])
79
+
80
+ def js_files(self) -> list:
81
+ return [
82
+ self.js_file
83
+ ]
84
+
85
+ def suppress_messages(self):
86
+ self._suppress_messages = True
87
+
88
+ def dynamic_script(self) -> str:
89
+ return f""
90
+
91
+
92
+ def add_params(self, flags: _ArgumentGroup):
93
+ flags.add_argument('--ignore-stalker-text',
94
+ dest='reflection_stalker_ignore',
95
+ metavar='text',
96
+ action='append',
97
+ help='Text to ignore at screen output. You can specify multiple values repeating the flag.')
98
+
99
+ def load_from_arguments(self, args: Namespace) -> bool:
100
+ self._ignore_list = []
101
+
102
+ if args.reflection_stalker_ignore is None or len(args.reflection_stalker_ignore) == 0:
103
+ return True
104
+
105
+ self._ignore_list = list(set([
106
+ txt.lower()
107
+ for t1 in args.reflection_stalker_ignore
108
+ if (txt := t1.strip()) != ''
109
+ ]))
110
+
111
+ return True
112
+
113
+ def key_value_event(self,
114
+ script_location: ScriptLocation = None,
115
+ stack_trace: str = None,
116
+ module: str = None,
117
+ received_data: dict = None
118
+ ) -> bool:
119
+
120
+
121
+ if module in ["java.lang.reflect.Method!invoke!throw",
122
+ "java.lang.reflect.Method!invoke!call"
123
+ ]:
124
+
125
+ # Exclusion list
126
+ method = received_data.get('method', '')
127
+ for em in Reflection._EXCLUSION_LIST:
128
+ if em in method:
129
+ return
130
+
131
+ params_preview = received_data.get('params_preview', '[]')
132
+ try:
133
+ params = json.dumps(json.loads(params_preview), default=Logger.json_serial)
134
+ except Exception:
135
+ params = params_preview
136
+
137
+ return_summary = received_data.get('return_summary', None)
138
+ try:
139
+ return_summary = json.dumps(json.loads(return_summary), default=Logger.json_serial)
140
+ except Exception:
141
+ pass
142
+
143
+ backtrace = received_data.get('backtrace_raw', None)
144
+ try:
145
+ if backtrace is None:
146
+ raise Exception()
147
+
148
+ if isinstance(backtrace, str):
149
+ backtrace = json.loads(backtrace)
150
+
151
+ bt = "Stack trace:\n at "
152
+ bt += '\n at '.join([
153
+ ln
154
+ for ln in backtrace
155
+ if 'dalvik.system.VMStack.getThreadStackTrace' not in ln
156
+ and 'java.lang.Thread.getStackTrace' not in ln
157
+ ])
158
+
159
+ backtrace = bt
160
+ except Exception:
161
+ backtrace = received_data.get('backtrace', stack_trace)
162
+
163
+ self._stalker_db.insert_one(
164
+ table_name='reflection_stalker',
165
+ stack_trace=backtrace,
166
+ error=received_data.get('error', ''),
167
+ method=received_data.get('method', ''),
168
+ method_b64=received_data.get('method_b64', ''),
169
+ method_name=received_data.get('method_name', ''),
170
+ target_class=received_data.get('target_class', ''),
171
+ target_tostring=received_data.get('target_tostring', ''),
172
+ params_count=received_data.get('params_count', ''),
173
+ params=params,
174
+ return_summary=return_summary,
175
+ return_class=received_data.get('return_class', '')
176
+ )
177
+
178
+ if not self._suppress_messages:
179
+ txt = json.dumps(received_data, indent=4)
180
+ for em in self._ignore_list:
181
+ if em in txt.lower():
182
+ return
183
+
184
+ Logger.print_message(
185
+ level="I",
186
+ message=f"Reflection: {received_data.get('method', '')}",
187
+ script_location=script_location
188
+ )
189
+
190
+
191
+ Logger.print_message(
192
+ level="D",
193
+ message=f"Reflection: {module}\n{txt}",
194
+ script_location=script_location
195
+ )
196
+
197
+ return True
198
+
199
+ def data_event(self,
200
+ script_location: ScriptLocation = None,
201
+ stack_trace: str = None,
202
+ received_data: str = None
203
+ ) -> bool:
204
+ return True
205
+
206
+
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: frida-fusion
3
- Version: 0.1.14
3
+ Version: 0.1.15
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>
@@ -105,7 +105,7 @@ void fusion_printMethods(String name);
105
105
  void fusion_waitForClass(String name, CallbackFunction onReady)
106
106
 
107
107
  # Conversions
108
- byte[] fusion_stringToBase64(String message);
108
+ String fusion_stringToBase64(String message);
109
109
  String fusion_bytesToBase64(byte[] byteArray);
110
110
  String fusion_encodeHex(byte[] byteArray);
111
111
  ```
@@ -29,5 +29,7 @@ frida_fusion/modules/android_setings/settings.py
29
29
  frida_fusion/modules/crypto/__init__.py
30
30
  frida_fusion/modules/crypto/crypto.js
31
31
  frida_fusion/modules/crypto/crypto.py
32
+ frida_fusion/modules/reflection/reflection-stalker.js
33
+ frida_fusion/modules/reflection/reflection-stalker.py
32
34
  frida_fusion/modules/tls_unpinning/__init__.py
33
35
  frida_fusion/modules/tls_unpinning/frida_multiple_unpinning.py
File without changes
File without changes
File without changes