frida-fusion 0.1.3__tar.gz → 0.1.4__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.3 → frida-fusion-0.1.4}/PKG-INFO +2 -5
- {frida-fusion-0.1.3 → frida-fusion-0.1.4}/README.md +1 -4
- {frida-fusion-0.1.3 → frida-fusion-0.1.4}/frida_fusion/__meta__.py +1 -1
- frida-fusion-0.1.4/frida_fusion/libs/helpers.js +305 -0
- {frida-fusion-0.1.3 → frida-fusion-0.1.4}/frida_fusion.egg-info/PKG-INFO +2 -5
- {frida-fusion-0.1.3 → frida-fusion-0.1.4}/frida_fusion.egg-info/SOURCES.txt +1 -0
- {frida-fusion-0.1.3 → frida-fusion-0.1.4}/pyproject.toml +2 -0
- {frida-fusion-0.1.3 → frida-fusion-0.1.4}/frida_fusion/__init__.py +0 -0
- {frida-fusion-0.1.3 → frida-fusion-0.1.4}/frida_fusion/__main__.py +0 -0
- {frida-fusion-0.1.3 → frida-fusion-0.1.4}/frida_fusion/args.py +0 -0
- {frida-fusion-0.1.3 → frida-fusion-0.1.4}/frida_fusion/config.py +0 -0
- {frida-fusion-0.1.3 → frida-fusion-0.1.4}/frida_fusion/fusion.py +0 -0
- {frida-fusion-0.1.3 → frida-fusion-0.1.4}/frida_fusion/libs/__init__.py +0 -0
- {frida-fusion-0.1.3 → frida-fusion-0.1.4}/frida_fusion/libs/color.py +0 -0
- {frida-fusion-0.1.3 → frida-fusion-0.1.4}/frida_fusion/libs/database.py +0 -0
- {frida-fusion-0.1.3 → frida-fusion-0.1.4}/frida_fusion/libs/logger.py +0 -0
- {frida-fusion-0.1.3 → frida-fusion-0.1.4}/frida_fusion/module.py +0 -0
- {frida-fusion-0.1.3 → frida-fusion-0.1.4}/frida_fusion/modules/__init__.py +0 -0
- {frida-fusion-0.1.3 → frida-fusion-0.1.4}/frida_fusion/modules/crypto.js +0 -0
- {frida-fusion-0.1.3 → frida-fusion-0.1.4}/frida_fusion/modules/crypto.py +0 -0
- {frida-fusion-0.1.3 → frida-fusion-0.1.4}/frida_fusion.egg-info/dependency_links.txt +0 -0
- {frida-fusion-0.1.3 → frida-fusion-0.1.4}/frida_fusion.egg-info/entry_points.txt +0 -0
- {frida-fusion-0.1.3 → frida-fusion-0.1.4}/frida_fusion.egg-info/requires.txt +0 -0
- {frida-fusion-0.1.3 → frida-fusion-0.1.4}/frida_fusion.egg-info/top_level.txt +0 -0
- {frida-fusion-0.1.3 → frida-fusion-0.1.4}/setup.cfg +0 -0
- {frida-fusion-0.1.3 → frida-fusion-0.1.4}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: frida-fusion
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.4
|
|
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>
|
|
@@ -64,11 +64,8 @@ Modules:
|
|
|
64
64
|
|
|
65
65
|
## Install
|
|
66
66
|
|
|
67
|
-
> :information_source: We recommend using `pipx` rather than `pip` for system-wide installation.
|
|
68
|
-
|
|
69
67
|
```
|
|
70
|
-
|
|
68
|
+
pip3 install frida-fusion
|
|
71
69
|
```
|
|
72
70
|
|
|
73
|
-
> :information_source: Check whether you also need to run the `python3 -m pipx ensurepath` command.
|
|
74
71
|
|
|
@@ -34,11 +34,8 @@ Modules:
|
|
|
34
34
|
|
|
35
35
|
## Install
|
|
36
36
|
|
|
37
|
-
> :information_source: We recommend using `pipx` rather than `pip` for system-wide installation.
|
|
38
|
-
|
|
39
37
|
```
|
|
40
|
-
|
|
38
|
+
pip3 install frida-fusion
|
|
41
39
|
```
|
|
42
40
|
|
|
43
|
-
> :information_source: Check whether you also need to run the `python3 -m pipx ensurepath` command.
|
|
44
41
|
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
/* Android Scripts
|
|
2
|
+
Author: Hélvio - M4v3r1ck
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
function waitForClass(name, onReady) {
|
|
7
|
+
var intv = setInterval(function () {
|
|
8
|
+
try {
|
|
9
|
+
var C = Java.use(name);
|
|
10
|
+
clearInterval(intv);
|
|
11
|
+
onReady(C);
|
|
12
|
+
} catch (e) { /* ainda não carregou */ }
|
|
13
|
+
}, 100);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function printStackTrace(){
|
|
17
|
+
var trace = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new());
|
|
18
|
+
trace = trace.replace("java.lang.Exception\n", "Stack trace:\n");
|
|
19
|
+
sendMessage("*", trace);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function toBytes(message){
|
|
23
|
+
try{
|
|
24
|
+
const StringClass = Java.use('java.lang.String');
|
|
25
|
+
var bTxt = StringClass.$new(message).getBytes('utf-8');
|
|
26
|
+
|
|
27
|
+
return bTxt;
|
|
28
|
+
} catch (err) {
|
|
29
|
+
sendMessage("*", err)
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function toBase64(message){
|
|
34
|
+
try{
|
|
35
|
+
const StringClass = Java.use('java.lang.String');
|
|
36
|
+
const Base64Class = Java.use('android.util.Base64');
|
|
37
|
+
var bTxt = StringClass.$new(message).getBytes('utf-8');
|
|
38
|
+
var b64Msg = Base64Class.encodeToString(bTxt, 0x00000002); //Base64Class.NO_WRAP = 0x00000002
|
|
39
|
+
|
|
40
|
+
return b64Msg;
|
|
41
|
+
} catch (err) {
|
|
42
|
+
sendMessage("*", err)
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function bytesToBase64(message){
|
|
47
|
+
|
|
48
|
+
if (message === null || message === undefined) return "IA==";
|
|
49
|
+
try {
|
|
50
|
+
// 1) Confirma tipo byte[], se não tenta converter em string
|
|
51
|
+
message = Java.array('byte', message);
|
|
52
|
+
|
|
53
|
+
// 2) Tem 'length' numérico
|
|
54
|
+
const len = message.length;
|
|
55
|
+
if (typeof len !== "number") return "IA==";
|
|
56
|
+
|
|
57
|
+
// 3) (opcional) Exigir conteúdo
|
|
58
|
+
if (len === 0) return "IA==";
|
|
59
|
+
|
|
60
|
+
} catch (e) {
|
|
61
|
+
return "IA==";
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
try{
|
|
65
|
+
|
|
66
|
+
const Base64Class = Java.use('android.util.Base64');
|
|
67
|
+
var b64Msg = Base64Class.encodeToString(message, 0x00000002); //Base64Class.NO_WRAP = 0x00000002
|
|
68
|
+
|
|
69
|
+
return b64Msg;
|
|
70
|
+
} catch (err) {
|
|
71
|
+
sendMessage("*", err)
|
|
72
|
+
return "IA==";
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function getCallerInfo() {
|
|
77
|
+
try{
|
|
78
|
+
const stack = new Error().stack.split("\n");
|
|
79
|
+
|
|
80
|
+
//Skip Error and getCallerInfo from stack trace
|
|
81
|
+
for (let i = 2; i < stack.length; i++) {
|
|
82
|
+
const line = stack[i].trim();
|
|
83
|
+
|
|
84
|
+
// Extrai: functionName (file:line:col)
|
|
85
|
+
// ou apenas (file:line:col) se não tiver nome
|
|
86
|
+
const m = line.match(/at\s+(?:(\S+)\s+)?[\( ]?(\S+):(\d+)\)?$/);
|
|
87
|
+
if (m) {
|
|
88
|
+
const func = m[1] || "";
|
|
89
|
+
const file = m[2];
|
|
90
|
+
const ln = parseInt(m[3], 10);
|
|
91
|
+
|
|
92
|
+
// Ignora funções cujo nome comece com "send" (qualquer case)
|
|
93
|
+
if (/^send/i.test(func)) continue;
|
|
94
|
+
if (/^isend/i.test(func)) continue;
|
|
95
|
+
|
|
96
|
+
return { file_name: file, function_name: func, line: ln };
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
} catch (err) {
|
|
100
|
+
console.log(`Error: ${err}`)
|
|
101
|
+
}
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function iSend(payload1, payload2){
|
|
106
|
+
try{
|
|
107
|
+
const info = getCallerInfo();
|
|
108
|
+
send({
|
|
109
|
+
payload: payload1,
|
|
110
|
+
location: info
|
|
111
|
+
}, payload2);
|
|
112
|
+
} catch (err) {
|
|
113
|
+
//sendMessage("*", err)
|
|
114
|
+
console.log(`Error: ${err}`)
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function sendData(mType, jData, bData){
|
|
119
|
+
//iSend('{"type" : "'+ mType +'", "jdata" : "'+ jData +'"}', bData);
|
|
120
|
+
iSend({
|
|
121
|
+
type: mType,
|
|
122
|
+
jdata: jData
|
|
123
|
+
}, bData)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function sendKeyValueData(module, items) {
|
|
127
|
+
var st = getB64StackTrace();
|
|
128
|
+
|
|
129
|
+
var data = [];
|
|
130
|
+
|
|
131
|
+
// Force as String
|
|
132
|
+
for (let i = 0; i < items.length; i++) {
|
|
133
|
+
data = data.concat([{key: `${items[i].key}`, value:`${items[i].value}`}]);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
iSend({
|
|
137
|
+
type: "key_value_data",
|
|
138
|
+
module: module,
|
|
139
|
+
data: data,
|
|
140
|
+
stack_trace: st
|
|
141
|
+
}, null);
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
/*
|
|
145
|
+
var jData = `{"type" : "key_value_data", "module": "${module}", "data": [`;
|
|
146
|
+
for (let i = 0; i < items.length; i++) {
|
|
147
|
+
if (i > 0) {
|
|
148
|
+
jData += `, `
|
|
149
|
+
}
|
|
150
|
+
jData += `{"key": "${items[i].key}", "value": "${items[i].value}"}`
|
|
151
|
+
}
|
|
152
|
+
jData += `], "stack_trace": "${st}"}`;
|
|
153
|
+
iSend(jData, "");
|
|
154
|
+
*/
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function sendMessage(level, message){
|
|
158
|
+
try{
|
|
159
|
+
const StringClass = Java.use('java.lang.String');
|
|
160
|
+
const Base64Class = Java.use('android.util.Base64');
|
|
161
|
+
var bTxt = StringClass.$new(message).getBytes('utf-8');
|
|
162
|
+
var b64Msg = Base64Class.encodeToString(bTxt, 0x00000002); //Base64Class.NO_WRAP = 0x00000002
|
|
163
|
+
|
|
164
|
+
//send('{"type" : "message", "level" : "'+ level +'", "message" : "'+ b64Msg +'"}');
|
|
165
|
+
iSend({
|
|
166
|
+
type: "message",
|
|
167
|
+
level: level,
|
|
168
|
+
message: b64Msg
|
|
169
|
+
}, null)
|
|
170
|
+
} catch (err) {
|
|
171
|
+
sendMessage("*", err)
|
|
172
|
+
//sendMessage('-', 'secret_key_spec.$init.overload error: ' + err + '\n' + err.stack);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function sendError(error) {
|
|
177
|
+
try{
|
|
178
|
+
sendMessage("-", error + '\n' + error.stack);
|
|
179
|
+
} catch (err) {
|
|
180
|
+
sendMessage("*", err)
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function encodeHex(byteArray) {
|
|
185
|
+
|
|
186
|
+
const HexClass = Java.use('org.apache.commons.codec.binary.Hex');
|
|
187
|
+
const StringClass = Java.use('java.lang.String');
|
|
188
|
+
const hexChars = HexClass.encodeHex(byteArray);
|
|
189
|
+
//sendMessage("*", StringClass.$new(hexChars).toString());
|
|
190
|
+
//Buffer.from(bufStr, 'utf8');
|
|
191
|
+
//sendMessage("*", new Uint8Array(byteArray));
|
|
192
|
+
return StringClass.$new(hexChars).toString();
|
|
193
|
+
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function getB64StackTrace(){
|
|
197
|
+
|
|
198
|
+
try{
|
|
199
|
+
const StringClass = Java.use('java.lang.String');
|
|
200
|
+
const Base64Class = Java.use('android.util.Base64');
|
|
201
|
+
var trace = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new());
|
|
202
|
+
trace = trace.replace("java.lang.Exception\n", "Stack trace:\n");
|
|
203
|
+
var bTrace = StringClass.$new(trace).getBytes('utf-8');
|
|
204
|
+
var b64Msg = Base64Class.encodeToString(bTrace, 0x00000002); //Base64Class.NO_WRAP = 0x00000002
|
|
205
|
+
|
|
206
|
+
return b64Msg
|
|
207
|
+
|
|
208
|
+
} catch (err) {
|
|
209
|
+
sendMessage("*", err);
|
|
210
|
+
return '';
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function enumMethods(targetClass)
|
|
215
|
+
{
|
|
216
|
+
var hook = Java.use(targetClass);
|
|
217
|
+
var ownMethods = hook.class.getDeclaredMethods();
|
|
218
|
+
hook.$dispose;
|
|
219
|
+
|
|
220
|
+
return ownMethods;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function printMethods(hook)
|
|
224
|
+
{
|
|
225
|
+
var ownMethods = hook.class.getDeclaredMethods();
|
|
226
|
+
ownMethods.forEach(function(s) {
|
|
227
|
+
//sendMessage(s);
|
|
228
|
+
sendMessage('*', s);
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function intToHex(intVal)
|
|
234
|
+
{
|
|
235
|
+
return intVal.toString(16);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
Java.perform(function () {
|
|
240
|
+
const Thread = Java.use('java.lang.Thread');
|
|
241
|
+
const UEH = Java.registerClass({
|
|
242
|
+
name: 'br.com.sec4us.UehProxy',
|
|
243
|
+
implements: [Java.use('java.lang.Thread$UncaughtExceptionHandler')],
|
|
244
|
+
methods: {
|
|
245
|
+
uncaughtException: [{
|
|
246
|
+
returnType: 'void',
|
|
247
|
+
argumentTypes: ['java.lang.Thread', 'java.lang.Throwable'],
|
|
248
|
+
implementation: function (t, e) {
|
|
249
|
+
try {
|
|
250
|
+
const Throwable = Java.use('java.lang.Throwable');
|
|
251
|
+
const sw = Java.use('java.io.StringWriter').$new();
|
|
252
|
+
const pw = Java.use('java.io.PrintWriter').$new(sw);
|
|
253
|
+
Throwable.$new(e).printStackTrace(pw);
|
|
254
|
+
send({ type: 'java-uncaught', thread: t.getName(), stack: sw.toString() });
|
|
255
|
+
} catch (err) { send({ type: 'java-uncaught-error', err: err+'' }); }
|
|
256
|
+
// Opcional: impedir que o app morra? Não é garantido; normalmente o processo cai.
|
|
257
|
+
}
|
|
258
|
+
}]
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
// Define globalmente
|
|
263
|
+
Thread.setDefaultUncaughtExceptionHandler(UEH.$new());
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
function formatBacktrace(frames) {
|
|
267
|
+
return frames.map((addr, i) => {
|
|
268
|
+
const sym = DebugSymbol.fromAddress(addr);
|
|
269
|
+
const mod = Process.findModuleByAddress(addr);
|
|
270
|
+
const off = (mod && addr.sub(mod.base)) ? "0x" + addr.sub(mod.base).toString(16) : String(addr);
|
|
271
|
+
const name = (sym && sym.name) ? sym.name : "<unknown>";
|
|
272
|
+
const modname = mod ? mod.name : "<unknown>";
|
|
273
|
+
return `${i.toString().padStart(2)} ${name} (${modname}+${off})`;
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
Process.setExceptionHandler(function (details) {
|
|
278
|
+
let frames;
|
|
279
|
+
try {
|
|
280
|
+
frames = Thread.backtrace(details.context, Backtracer.ACCURATE);
|
|
281
|
+
} catch (e) {
|
|
282
|
+
frames = Thread.backtrace(details.context, Backtracer.FUZZY);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
const pretty = formatBacktrace(frames);
|
|
286
|
+
|
|
287
|
+
send({
|
|
288
|
+
type: "native-exception",
|
|
289
|
+
details: {
|
|
290
|
+
message: details.message,
|
|
291
|
+
type: details.type,
|
|
292
|
+
address: String(details.address),
|
|
293
|
+
memory: details.memory,
|
|
294
|
+
context: details.context,
|
|
295
|
+
nativeContext: String(details.nativeContext),
|
|
296
|
+
backtrace: pretty, // <— pilha simbólica
|
|
297
|
+
backtrace_raw: frames.map(String) // <— opcional: endereços puros
|
|
298
|
+
}
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
// true = tenta engolir a exceção; se quiser ver o processo cair, retorne false
|
|
302
|
+
return false;
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
sendMessage("W", "Helper functions have been successfully initialized.")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: frida-fusion
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.4
|
|
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>
|
|
@@ -64,11 +64,8 @@ Modules:
|
|
|
64
64
|
|
|
65
65
|
## Install
|
|
66
66
|
|
|
67
|
-
> :information_source: We recommend using `pipx` rather than `pip` for system-wide installation.
|
|
68
|
-
|
|
69
67
|
```
|
|
70
|
-
|
|
68
|
+
pip3 install frida-fusion
|
|
71
69
|
```
|
|
72
70
|
|
|
73
|
-
> :information_source: Check whether you also need to run the `python3 -m pipx ensurepath` command.
|
|
74
71
|
|
|
@@ -17,6 +17,7 @@ frida_fusion.egg-info/top_level.txt
|
|
|
17
17
|
frida_fusion/libs/__init__.py
|
|
18
18
|
frida_fusion/libs/color.py
|
|
19
19
|
frida_fusion/libs/database.py
|
|
20
|
+
frida_fusion/libs/helpers.js
|
|
20
21
|
frida_fusion/libs/logger.py
|
|
21
22
|
frida_fusion/modules/__init__.py
|
|
22
23
|
frida_fusion/modules/crypto.js
|
|
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
|
|
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
|
|
File without changes
|