Compare commits
121 Commits
style-refa
...
master
Author | SHA1 | Date | |
---|---|---|---|
33ee88c0e8 | |||
|
88fbef19f5 | ||
|
afe0e9dd9f | ||
|
c0d4f48b28 | ||
|
9baa12b04f | ||
|
03a26f73ca | ||
|
e88989f182 | ||
|
e627f950c1 | ||
|
f7e291649a | ||
|
01867e4796 | ||
|
6b5e839335 | ||
|
ea8b909747 | ||
|
653ce0b613 | ||
|
e5468a4f6a | ||
|
716e8236c5 | ||
|
f533235530 | ||
|
6fe08f607c | ||
|
0102391670 | ||
|
780ee12c9f | ||
|
31584e46ef | ||
|
50ae9a92d6 | ||
|
a6eaabc7fb | ||
|
7257797be2 | ||
|
d115483d32 | ||
|
c106d2aa81 | ||
|
d87440906c | ||
|
0804545271 | ||
|
b3e40c2b57 | ||
|
64b54be7da | ||
|
88d288a327 | ||
|
95e06f5c7b | ||
|
306fc5eb85 | ||
|
36a223dbc0 | ||
|
9f6e7f9504 | ||
|
6b4702ac86 | ||
|
b077347938 | ||
|
0e473c1e95 | ||
|
b9a5789d5c | ||
|
249202f9ab | ||
|
d2c52a1dbd | ||
|
dbef1c1a78 | ||
|
26b85c3e4a | ||
|
e151ca90fb | ||
|
0fc76eafb3 | ||
|
d29c03d36a | ||
|
48d0499ae6 | ||
|
e7104f2205 | ||
|
d847c76187 | ||
|
b6ecd41421 | ||
|
cc9e3d9fb7 | ||
|
a850707367 | ||
|
2ea7288186 | ||
|
a6f994deae | ||
|
677037b450 | ||
|
3cff0e9346 | ||
|
5b7c2d794d | ||
|
eaaffe7014 | ||
|
e25e3aaa8d | ||
|
743dfe086e | ||
|
29fbbdd281 | ||
|
fe0021a176 | ||
|
ec018a5171 | ||
|
94e0fd3b07 | ||
|
4f18af7edd | ||
|
b984306ea3 | ||
|
d8583ccf28 | ||
|
ff6fbe14c7 | ||
|
c61a477a7c | ||
|
9c2b7e8f7f | ||
|
d9da5e5c99 | ||
|
d00d54e1dc | ||
|
08200a5d73 | ||
|
25bdd40c69 | ||
|
fbe4908f23 | ||
|
0eb81236c6 | ||
|
c009b66efa | ||
|
bbe7ab5be3 | ||
|
29643058cc | ||
|
2067de23a4 | ||
|
2a210509c6 | ||
|
357a9e3e1c | ||
|
8aeb1d9c90 | ||
|
39d3f75251 | ||
|
4f8595d90a | ||
|
52a7557c72 | ||
|
372a7bacc8 | ||
|
0dd0f51bf2 | ||
|
2b87e7e6bc | ||
|
11fce7c847 | ||
|
f0c0a8c898 | ||
|
5d120c0834 | ||
|
08a4df5b51 | ||
|
1e92708ee1 | ||
|
df2f75f3be | ||
|
d6db57ae2f | ||
|
8658889847 | ||
|
7208fc7793 | ||
|
be8fdd13f5 | ||
|
3fb941dced | ||
|
3e67a68b54 | ||
|
7e3bde9518 | ||
|
85d02960d3 | ||
|
53ba7ccf93 | ||
|
e917f166bd | ||
|
889f6030c4 | ||
|
7fe8eedcd1 | ||
|
9bbc7c1344 | ||
|
c1687cd3b3 | ||
|
87a46b133e | ||
|
47d2fdd08b | ||
|
3302d093ee | ||
|
b6b63e2dd4 | ||
|
3aadf1c18c | ||
|
00dfdf717d | ||
|
906b713fc9 | ||
|
e0e93e2a57 | ||
|
be8c289bbe | ||
|
bd9cacda50 | ||
|
5aa3bc3933 | ||
|
952c0f8ea8 | ||
|
6fd5ea6984 |
1
gif/README.md
Normal file
1
gif/README.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
.
|
BIN
gif/intercept_open_chrome_android.gif
Normal file
BIN
gif/intercept_open_chrome_android.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.6 MiB |
148
scripts/FridaCodeGenerator.py
Normal file
148
scripts/FridaCodeGenerator.py
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
#?shortcut=Mod1+Shift+Z
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from com.pnfsoftware.jeb.client.api import IScript
|
||||||
|
from com.pnfsoftware.jeb.core import RuntimeProjectUtil
|
||||||
|
from com.pnfsoftware.jeb.core.units.code.android import IDexUnit
|
||||||
|
from subprocess import Popen, PIPE
|
||||||
|
|
||||||
|
|
||||||
|
def arg_format(i):
|
||||||
|
return 'arg_%d' % i
|
||||||
|
|
||||||
|
|
||||||
|
def generate_body_code(types, retval, method_name, orig_method_name, class_name):
|
||||||
|
body_code = "\n\tconsole.log('[{}#{}] ' + JSON.strigify({{\n\t".format(
|
||||||
|
FridaCodeGenerator.to_canonical_name(class_name), method_name)
|
||||||
|
for i, typ in enumerate(types):
|
||||||
|
body_code += '\t{}: {}, // {}\n\t'.format('a%d' % i, arg_format(i), typ)
|
||||||
|
|
||||||
|
if retval != 'void':
|
||||||
|
body_code = '\n\tvar retval = this.{}.apply(this, arguments);{}\tretv: retval\n\t}});'.format(
|
||||||
|
orig_method_name, body_code)
|
||||||
|
else:
|
||||||
|
body_code += '}});\n\tthis.{}.apply(this, arguments);'.format(method_name)
|
||||||
|
|
||||||
|
return body_code + '\n'
|
||||||
|
|
||||||
|
|
||||||
|
class JavaMethod(object):
|
||||||
|
def __init__(self):
|
||||||
|
self.class_name = None
|
||||||
|
self.class_orig_name = None
|
||||||
|
self.name = None
|
||||||
|
self.orig_name = None
|
||||||
|
self.arg = []
|
||||||
|
self.retType = None
|
||||||
|
|
||||||
|
def get_parameters(self):
|
||||||
|
return self.arg
|
||||||
|
|
||||||
|
def get_return_type(self):
|
||||||
|
return self.retType
|
||||||
|
|
||||||
|
def get_name(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
def get_orig_name(self):
|
||||||
|
return self.orig_name
|
||||||
|
|
||||||
|
def get_class_orig_name(self):
|
||||||
|
return self.class_orig_name
|
||||||
|
|
||||||
|
def get_class_name(self):
|
||||||
|
return self.class_name
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return 'JavaMethod[name: %s, orig_name: %s, args: %s, return type: %s]' % (
|
||||||
|
self.name, self.orig_name, self.arg, self.retType)
|
||||||
|
|
||||||
|
|
||||||
|
class FridaCodeGenerator(IScript):
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def to_canonical_name(mname):
|
||||||
|
mname = mname.replace('/', '.')
|
||||||
|
return {
|
||||||
|
'C': 'char',
|
||||||
|
'I': 'int',
|
||||||
|
'B': 'byte',
|
||||||
|
'Z': 'boolean',
|
||||||
|
'F': 'float',
|
||||||
|
'D': 'double',
|
||||||
|
'S': 'short',
|
||||||
|
'J': 'long',
|
||||||
|
'V': 'void',
|
||||||
|
'L': mname[1:-1],
|
||||||
|
'[': mname
|
||||||
|
}[mname[0]]
|
||||||
|
|
||||||
|
def run(self, ctx):
|
||||||
|
project = ctx.getEnginesContext().getProjects()[0] # Get current project(IRuntimeProject)
|
||||||
|
self.dexunit = RuntimeProjectUtil.findUnitsByType(project, IDexUnit, False)[0] # Get dex context, needs >=V2.2.1
|
||||||
|
try:
|
||||||
|
self.current_unit = ctx.getFocusedView().getActiveFragment().getUnit() # Get current Source Tab in Focus
|
||||||
|
java_class = self.current_unit.getClassElement().getName()
|
||||||
|
current_addr = ctx.getFocusedView().getActiveFragment().getActiveAddress()
|
||||||
|
m = FridaCodeGenerator.get_decompiled_method(self.dexunit, current_addr, java_class)
|
||||||
|
method_name = m.get_name()
|
||||||
|
class_name = FridaCodeGenerator.to_canonical_name(m.get_class_orig_name())
|
||||||
|
return_type = FridaCodeGenerator.to_canonical_name(str(m.get_return_type()))
|
||||||
|
if method_name == '<clinit>':
|
||||||
|
raise Exception('Class initializer')
|
||||||
|
args_code = ', '.join([arg_format(i) for i in range(len(m.get_parameters()))])
|
||||||
|
|
||||||
|
if method_name == '<init>': method_name = '$init'
|
||||||
|
|
||||||
|
types = [FridaCodeGenerator.to_canonical_name(param) for param in m.get_parameters()]
|
||||||
|
# TODO get original type class names
|
||||||
|
type_code = ', '.join(["'{0}'".format(t) for t in types])
|
||||||
|
body_code = generate_body_code(types, return_type, method_name, m.get_orig_name(), m.get_class_name())
|
||||||
|
hook = "Java.use('{class_name}').{method}.overload({sig}).implementation = function({args}) {{{body}}}".format(
|
||||||
|
class_name=class_name,
|
||||||
|
method=m.get_orig_name() if method_name != '$init' else method_name,
|
||||||
|
sig=type_code,
|
||||||
|
args=args_code,
|
||||||
|
body=body_code
|
||||||
|
)
|
||||||
|
print(hook)
|
||||||
|
# copy to system's clipboard
|
||||||
|
Popen(['xclip', '-sel', 'c', '-i'], stdin=PIPE).communicate(input=(hook.encode()))
|
||||||
|
except Exception as e:
|
||||||
|
print(e)
|
||||||
|
ctx.displayMessageBox(None, 'Place the cursor in the function you want to generate the Frida code', None, None)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_decompiled_method(dex, addr, class_orig_name):
|
||||||
|
method_info = JavaMethod()
|
||||||
|
method_info.orig_name = dex.getMethod(addr).getName(False)
|
||||||
|
msig = addr.split('+')[0]
|
||||||
|
infos = str(msig).split('->')
|
||||||
|
if len(infos) == 2:
|
||||||
|
method_info.class_name = infos[0]
|
||||||
|
method_info.class_orig_name = class_orig_name
|
||||||
|
if len(infos[1].split('(')) == 2:
|
||||||
|
method_info.name = infos[1].split('(')[0]
|
||||||
|
if len(infos[1].split(')')) == 2:
|
||||||
|
method_info.retType = infos[1].split(')')[1]
|
||||||
|
if len(infos[1].split('(')) == 2 and len(infos[1].split(')')) == 2:
|
||||||
|
args = infos[1].split('(')[-1].split(')')[0]
|
||||||
|
while args:
|
||||||
|
if args[0] in ['C', 'I', 'B', 'Z', 'F', 'D', 'S', 'J', 'V']:
|
||||||
|
method_info.arg.append(str(args[0]))
|
||||||
|
args = args[1:]
|
||||||
|
elif args[0] == '[':
|
||||||
|
if args[1] == 'L':
|
||||||
|
offset = args.find(';')
|
||||||
|
method_info.arg.append(str(args[0:offset + 1]))
|
||||||
|
args = args[offset + 1:]
|
||||||
|
else:
|
||||||
|
method_info.arg.append(str(args[0:2]))
|
||||||
|
args = args[2:]
|
||||||
|
elif args[0] == 'L':
|
||||||
|
offset = args.find(";")
|
||||||
|
method_info.arg.append(str(args[0:offset + 1]))
|
||||||
|
args = args[offset + 1:]
|
||||||
|
print(method_info)
|
||||||
|
return method_info
|
28
scripts/WIP_android_ipc.js
Normal file
28
scripts/WIP_android_ipc.js
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
var ContextWrapper = Java.use("android.content.ContextWrapper");
|
||||||
|
|
||||||
|
ContextWrapper.sendBroadcast.overload("android.content.Intent").implementation = function(intent) {
|
||||||
|
send(JSON.stringify({
|
||||||
|
_intent: intent.toString(),
|
||||||
|
extras: intent.getExtras() ? intent.getExtras().toString() : 'null',
|
||||||
|
flags: intent.getFlags().toString()
|
||||||
|
}));
|
||||||
|
return this.sendBroadcast.overload("android.content.Intent").apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
ContextWrapper.sendBroadcast.overload("android.content.Intent", "java.lang.String").implementation = function(intent, receiverPermission) {
|
||||||
|
send(JSON.stringify({
|
||||||
|
|
||||||
|
});
|
||||||
|
return this.sendBroadcast.overload("android.content.Intent", "java.lang.String").apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ContextWrapper.sendStickyBroadcast.overload("android.content.Intent").implementation = function(intent) {
|
||||||
|
|
||||||
|
return this.sendStickyBroadcast.overload("android.content.Intent").apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
ContextWrapper.startActivity.overload("android.content.Intent").implementation = function(intent) {
|
||||||
|
|
||||||
|
return this.startActivity.overload("android.content.Intent").apply(this, arguments);
|
||||||
|
}
|
134
scripts/WIP_dump_dynamically_created_files.js
Normal file
134
scripts/WIP_dump_dynamically_created_files.js
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
// Work in progress
|
||||||
|
// TBD how to show diff.. use git or just git style
|
||||||
|
const fs = require('fs');
|
||||||
|
const frida = require('frida');
|
||||||
|
|
||||||
|
const APP_ID = process.argv[2];
|
||||||
|
|
||||||
|
const source = `
|
||||||
|
Java.perform(function() {
|
||||||
|
|
||||||
|
var openedfile = "";
|
||||||
|
var data = {
|
||||||
|
"file": "",
|
||||||
|
"content": []
|
||||||
|
};
|
||||||
|
var isOpen = false;
|
||||||
|
var index = 0;
|
||||||
|
|
||||||
|
var fos = Java.use('java.io.FileOutputStream');
|
||||||
|
|
||||||
|
var fos_construct_2 = fos.$init.overload('java.lang.String');
|
||||||
|
var fos_construct_3 = fos.$init.overload('java.io.File');
|
||||||
|
var fos_construct_4 = fos.$init.overload('java.lang.String', 'boolean');
|
||||||
|
var fos_construct_5 = fos.$init.overload('java.io.File', 'boolean');
|
||||||
|
|
||||||
|
var fos_write_1 = fos.write.overload('[B', 'int', 'int');
|
||||||
|
|
||||||
|
var fos_close = fos.close;
|
||||||
|
|
||||||
|
function dump(data) {
|
||||||
|
console.log("Got " + data["content"].length + " bytes!");
|
||||||
|
var tmp_name = openedfile.split("/");
|
||||||
|
tmp_name = tmp_name[tmp_name.length - 1];
|
||||||
|
data["file"] = tmp_name;
|
||||||
|
send(data);
|
||||||
|
data["content"] = [];
|
||||||
|
index = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fos_construct_2.implementation = function(file) {
|
||||||
|
var filename = file;
|
||||||
|
if (openedfile != filename) {
|
||||||
|
openedfile = filename;
|
||||||
|
console.log("File opened for write " + filename);
|
||||||
|
isOpen = true;
|
||||||
|
}
|
||||||
|
return fos_construct_2.call(this, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
fos_construct_3.implementation = function(file) {
|
||||||
|
var filename = file.getAbsolutePath();
|
||||||
|
if (openedfile != filename) {
|
||||||
|
openedfile = filename;
|
||||||
|
console.log("File opened for write " + filename);
|
||||||
|
isOpen = true;
|
||||||
|
}
|
||||||
|
return fos_construct_3.call(this, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
fos_construct_4.implementation = function(file, true_false) {
|
||||||
|
var filename = file;
|
||||||
|
if (openedfile != filename) {
|
||||||
|
openedfile = filename;
|
||||||
|
console.log("File opened for write " + filename);
|
||||||
|
isOpen = true;
|
||||||
|
}
|
||||||
|
return fos_construct_4.call(this, file, true_false);
|
||||||
|
}
|
||||||
|
|
||||||
|
fos_construct_5.implementation = function(file, true_false) {
|
||||||
|
var filename = file.getAbsolutePath();
|
||||||
|
if (openedfile != filename) {
|
||||||
|
openedfile = filename;
|
||||||
|
console.log("File opened for write " + filename);
|
||||||
|
isOpen = true;
|
||||||
|
}
|
||||||
|
return fos_construct_5.call(this, file, true_false);
|
||||||
|
}
|
||||||
|
|
||||||
|
fos_write_1.implementation = function(arr, offset, length) {
|
||||||
|
var i = 0;
|
||||||
|
for (i = offset; i < length; i = i + 1) {
|
||||||
|
data["content"][index] = arr[i];
|
||||||
|
index = index + 1;
|
||||||
|
}
|
||||||
|
return fos_write_1.call(this, arr, offset, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
fos_close.implementation = function() {
|
||||||
|
dump(data);
|
||||||
|
return fos_close.call(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
`;
|
||||||
|
|
||||||
|
function stop() { // cleanup, TODO add session.detach ?
|
||||||
|
if (script !== null) {
|
||||||
|
script.unload().then(() => {
|
||||||
|
script = null;
|
||||||
|
console.log('[!] Script unloaded');
|
||||||
|
}).catch(console.error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function Main() {
|
||||||
|
|
||||||
|
let device = await frida.getUsbDevice();
|
||||||
|
let pid = await device.spawn([APP_ID]);
|
||||||
|
let session = await device.attach(pid);
|
||||||
|
let script = await session.createScript(source);
|
||||||
|
|
||||||
|
script.message.connect(msg => {
|
||||||
|
if (msg['type'] === 'send') {
|
||||||
|
let payload = msg['payload'];
|
||||||
|
if (typeof payload === 'object') {
|
||||||
|
console.log('[D]', payload['file'], '\n\n', payload['content']);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.error('[!]', msg, '\n', msg['stack']);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
await script.load();
|
||||||
|
await device.resume(pid);
|
||||||
|
|
||||||
|
process.stdin.resume(); // keep process running
|
||||||
|
process.on('SIGTERM', stop);
|
||||||
|
process.on('SIGINT', stop);
|
||||||
|
console.log('...');
|
||||||
|
}
|
||||||
|
|
||||||
|
Main().catch(console.error);
|
57
scripts/WIP_ios_app_info.js
Normal file
57
scripts/WIP_ios_app_info.js
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
function dictFromNSDictionary(nsDict) {
|
||||||
|
var jsDict = {};
|
||||||
|
var keys = nsDict.allKeys();
|
||||||
|
var count = keys.count();
|
||||||
|
for (var i = 0; i < count; i++) {
|
||||||
|
var key = keys.objectAtIndex_(i);
|
||||||
|
var value = nsDict.objectForKey_(key);
|
||||||
|
jsDict[key.toString()] = value.toString();
|
||||||
|
}
|
||||||
|
return jsDict;
|
||||||
|
}
|
||||||
|
|
||||||
|
function arrayFromNSArray(nsArray) {
|
||||||
|
var jsArray = [];
|
||||||
|
var count = nsArray.count();
|
||||||
|
for (var i = 0; i < count; i++) {
|
||||||
|
jsArray[i] = nsArray.objectAtIndex_(i).toString();
|
||||||
|
}
|
||||||
|
return jsArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
function infoDictionary() {
|
||||||
|
if (ObjC.available && "NSBundle" in ObjC.classes) {
|
||||||
|
var info = ObjC.classes.NSBundle.mainBundle().infoDictionary();
|
||||||
|
return dictFromNSDictionary(info);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function infoLookup(key) {
|
||||||
|
if (ObjC.available && "NSBundle" in ObjC.classes) {
|
||||||
|
var info = ObjC.classes.NSBundle.mainBundle().infoDictionary();
|
||||||
|
var value = info.objectForKey_(key);
|
||||||
|
if (value === null) {
|
||||||
|
return value;
|
||||||
|
} else if (value.class().toString() === "__NSCFArray") {
|
||||||
|
return arrayFromNSArray(value);
|
||||||
|
} else if (value.class().toString() === "__NSCFDictionary") {
|
||||||
|
return dictFromNSDictionary(value);
|
||||||
|
} else {
|
||||||
|
return value.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.warn(JSON.stringify({
|
||||||
|
name: infoLookup("CFBundleName"),
|
||||||
|
bundleId: ObjC.classes.NSBundle.mainBundle().bundleIdentifier().toString(),
|
||||||
|
version: infoLookup("CFBundleVersion"),
|
||||||
|
path: {
|
||||||
|
bundle: ObjC.classes.NSBundle.mainBundle().bundlePath().toString(),
|
||||||
|
data: ObjC.classes.NSProcessInfo.processInfo().environment().objectForKey_("HOME").toString(),
|
||||||
|
binary: ObjC.classes.NSBundle.mainBundle().executablePath().toString()
|
||||||
|
},
|
||||||
|
info: infoDictionary()
|
||||||
|
}, null, 2))
|
21
scripts/WIP_unpack_64.js
Normal file
21
scripts/WIP_unpack_64.js
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
var art_DexFile_OpenMemory = Module.findExportByName('libart.so','_ZN3art7DexFile10OpenMemoryEPKhmRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPKNS_10OatDexFileEPS9_'); // art::DexFile::OpenMemory > 64bit version
|
||||||
|
console.log(art_DexFile_OpenMemory);
|
||||||
|
Interceptor.attach(art_DexFile_OpenMemory, {
|
||||||
|
onEnter: function (_args) {
|
||||||
|
var begin = this.context.x0;
|
||||||
|
this.o = {};
|
||||||
|
this.o.begin = begin;
|
||||||
|
this.o.magic = Memory.readUtf8String(begin);
|
||||||
|
var address = parseInt(begin, 16) + 0x20;
|
||||||
|
var dexSize = Memory.readInt(ptr(address));
|
||||||
|
this.o.dexSize = dexSize;
|
||||||
|
var file = new File('/sdcard/unpack/' + dexSize + '.dex', 'wb');
|
||||||
|
file.write(Memory.readByteArray(begin, dexSize));
|
||||||
|
file.flush();
|
||||||
|
file.close();
|
||||||
|
},
|
||||||
|
onLeave: function (retval) {
|
||||||
|
this.o.retval = retval;
|
||||||
|
console.log(JSON.stringify(this.o, null, 2));
|
||||||
|
}
|
||||||
|
});
|
4
scripts/android_proxy.js
Normal file
4
scripts/android_proxy.js
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
// open proxy (not working)
|
||||||
|
Java.perform(function() {
|
||||||
|
Java.use('android.net.Proxy').setHttpProxySystemProperty(Java.use('android.net.ProxyInfo').buildDirectProxy('1.0.0.1', 8081));
|
||||||
|
});
|
29
scripts/enable_remote_debugging.js
Normal file
29
scripts/enable_remote_debugging.js
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
Enable remote debugging of Android WebViews at Runtime using Frida
|
||||||
|
run "adb shell dumpsys window windows | grep -E 'mCurrentFocus|mFocusedApp'" to get the current activity
|
||||||
|
*/
|
||||||
|
Java.perform(function() {
|
||||||
|
Java.deoptimizeEverything();
|
||||||
|
var injected = false;
|
||||||
|
Java.choose('com.app.SomeActivity', {
|
||||||
|
'onMatch': function(o) {
|
||||||
|
var Runnable = Java.use('java.lang.Runnable');
|
||||||
|
var MyRunnable = Java.registerClass({
|
||||||
|
name: 'com.example.MyRunnable',
|
||||||
|
implements: [Runnable],
|
||||||
|
methods: {
|
||||||
|
'run': function() {
|
||||||
|
Java.use('android.webkit.WebView').setWebContentsDebuggingEnabled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var runnable = MyRunnable.$new();
|
||||||
|
o.runOnUiThread(runnable);
|
||||||
|
console.log('\nWebview debug enabled......');
|
||||||
|
|
||||||
|
},
|
||||||
|
'onComplete': function() {
|
||||||
|
console.log('completed');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
17
scripts/extact_ipa.sh
Normal file
17
scripts/extact_ipa.sh
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Extracting IPA from Jailbroken +Frida device
|
||||||
|
# The IPA will be @ /tmp/ios_ssh/iphonessh/python-client/frida-ios-dump/AppName.ipa
|
||||||
|
mkdir /tmp/ios_ssh
|
||||||
|
cd "$_"
|
||||||
|
sudo apt-get install libgcrypt20-doc gnutls-doc gnutls-bin usbmuxd libimobiledevice*
|
||||||
|
git clone https://github.com/rcg4u/iphonessh
|
||||||
|
cd iphonessh/python-client/
|
||||||
|
chmod +x *
|
||||||
|
python2.7 tcprelay.py -t 22:2222 &
|
||||||
|
TCP_RELAY_PID=$!
|
||||||
|
git clone https://github.com/AloneMonkey/frida-ios-dump.git
|
||||||
|
cd frida-ios-dump
|
||||||
|
git checkout origin/3.x
|
||||||
|
sudo -H pip3 install -r requirements.txt --upgrade
|
||||||
|
sudo python3.6 dump.py $1 # com.app.bundle.id
|
||||||
|
kill $TCP_RELAY_PID
|
8
scripts/ios_ssl_unpin.js
Normal file
8
scripts/ios_ssl_unpin.js
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
var SecTrustEvaluate_prt = Module.findExportByName("Security", "SecTrustEvaluate");
|
||||||
|
var SecTrustEvaluate = new NativeFunction(SecTrustEvaluate_prt, "int", ["pointer", "pointer"]);
|
||||||
|
Interceptor.replace(SecTrustEvaluate_prt, new NativeCallback(function(trust, result) {
|
||||||
|
console.log("[*] SecTrustEvaluate(...) hit!");
|
||||||
|
SecTrustEvaluate(trust, result); // call original method
|
||||||
|
Memory.writeU8(result, 1);
|
||||||
|
return 0;
|
||||||
|
}, "int", ["pointer", "pointer"]));
|
109
scripts/okhttp3.Interceptor.js
Normal file
109
scripts/okhttp3.Interceptor.js
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
function hook_okhttp3(classLoader) {
|
||||||
|
Java.perform(function () {
|
||||||
|
var ByteString = classLoader.use("com.android.okhttp.okio.ByteString");
|
||||||
|
var Buffer = classLoader.use("com.android.okhttp.okio.Buffer");
|
||||||
|
var Interceptor = classLoader.use("okhttp3.Interceptor");
|
||||||
|
var MyInterceptor = Java.registerClass({
|
||||||
|
name: "okhttp3.MyInterceptor",
|
||||||
|
implements: [Interceptor],
|
||||||
|
methods: {
|
||||||
|
intercept: function (chain) {
|
||||||
|
var request = chain.request();
|
||||||
|
try {
|
||||||
|
console.log("MyInterceptor.intercept onEnter:", request, "\nrequest headers:\n", request.headers());
|
||||||
|
var requestBody = request.body();
|
||||||
|
var contentLength = requestBody ? requestBody.contentLength() : 0;
|
||||||
|
if (contentLength > 0) {
|
||||||
|
var BufferObj = Buffer.$new();
|
||||||
|
requestBody.writeTo(BufferObj);
|
||||||
|
try {
|
||||||
|
console.log("\nrequest body String:\n", BufferObj.readString(), "\n");
|
||||||
|
} catch (error) {
|
||||||
|
try {
|
||||||
|
console.log("\nrequest body ByteString:\n", ByteString.of(BufferObj.readByteArray()).hex(), "\n");
|
||||||
|
} catch (error) {
|
||||||
|
console.log("error 1:", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log("error 2:", error);
|
||||||
|
}
|
||||||
|
var response = chain.proceed(request);
|
||||||
|
try {
|
||||||
|
console.log("MyInterceptor.intercept onLeave:", response, "\nresponse headers:\n", response.headers());
|
||||||
|
var responseBody = response.body();
|
||||||
|
var contentLength = responseBody ? responseBody.contentLength() : 0;
|
||||||
|
if (contentLength > 0) {
|
||||||
|
console.log("\nresponsecontentLength:", contentLength, "responseBody:", responseBody, "\n");
|
||||||
|
|
||||||
|
var ContentType = response.headers().get("Content-Type");
|
||||||
|
console.log("ContentType:", ContentType);
|
||||||
|
if (ContentType.indexOf("video") == -1) {
|
||||||
|
if (ContentType.indexOf("application") == 0) {
|
||||||
|
var source = responseBody.source();
|
||||||
|
if (ContentType.indexOf("application/zip") != 0) {
|
||||||
|
try {
|
||||||
|
console.log("\nresponse.body StringClass\n", source.readUtf8(), "\n");
|
||||||
|
} catch (error) {
|
||||||
|
try {
|
||||||
|
console.log("\nresponse.body ByteString\n", source.readByteString().hex(), "\n");
|
||||||
|
} catch (error) {
|
||||||
|
console.log("error 4:", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.log("error 3:", error);
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var ArrayList = classLoader.use("java.util.ArrayList");
|
||||||
|
var OkHttpClient = classLoader.use("okhttp3.OkHttpClient");
|
||||||
|
console.log(OkHttpClient);
|
||||||
|
OkHttpClient.$init.overload('okhttp3.OkHttpClient$Builder').implementation = function (Builder) {
|
||||||
|
console.log("OkHttpClient.$init:", this, Java.cast(Builder.interceptors(), ArrayList));
|
||||||
|
this.$init(Builder);
|
||||||
|
};
|
||||||
|
|
||||||
|
var MyInterceptorObj = MyInterceptor.$new();
|
||||||
|
var Builder = classLoader.use("okhttp3.OkHttpClient$Builder");
|
||||||
|
console.log(Builder);
|
||||||
|
Builder.build.implementation = function () {
|
||||||
|
this.interceptors().clear();
|
||||||
|
//var MyInterceptorObj = MyInterceptor.$new();
|
||||||
|
this.interceptors().add(MyInterceptorObj);
|
||||||
|
var result = this.build();
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
Builder.addInterceptor.implementation = function (interceptor) {
|
||||||
|
this.interceptors().clear();
|
||||||
|
//var MyInterceptorObj = MyInterceptor.$new();
|
||||||
|
this.interceptors().add(MyInterceptorObj);
|
||||||
|
return this;
|
||||||
|
//return this.addInterceptor(interceptor);
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log("hook_okhttp3...");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Java.perform(function() {
|
||||||
|
var application = Java.use("android.app.Application");
|
||||||
|
application.attach.overload('android.content.Context').implementation = function(context) {
|
||||||
|
var result = this.attach(context); // 先执行原来的attach方法
|
||||||
|
var classloader = context.getClassLoader(); // 获取classloader
|
||||||
|
Java.classFactory.loader = classloader;
|
||||||
|
hook_okhttp3(Java.classFactory);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
43
scripts/stalker.js
Normal file
43
scripts/stalker.js
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
Interceptor.attach(ObjC.classes.MyClass['- myMethod:param1'].implementation, {
|
||||||
|
onEnter: function (args) {
|
||||||
|
console.warn(JSON.stringify({
|
||||||
|
fname: args[1].readCString(),
|
||||||
|
text: new ObjC.Object(args[2]).toString(),
|
||||||
|
backtrace: Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).map(m => m.moduleName+'!'+m.name),
|
||||||
|
ctx: this.context
|
||||||
|
}, null, 2));
|
||||||
|
var tid = Process.getCurrentThreadId();
|
||||||
|
this.tid = tid;
|
||||||
|
Stalker.follow(tid, {
|
||||||
|
events: {
|
||||||
|
call: true
|
||||||
|
},
|
||||||
|
/*
|
||||||
|
onCallSummary: function (summary) {
|
||||||
|
Object.keys(summary).forEach(s => {
|
||||||
|
var sym = DebugSymbol.fromAddress(ptr(s));
|
||||||
|
if (sym.moduleName == 'Viber')
|
||||||
|
console.log(summary[s], sym.name);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
transform: function (iterator) {
|
||||||
|
var instruction;
|
||||||
|
while ((instruction = iterator.next()) !== null) {
|
||||||
|
iterator.keep();
|
||||||
|
if (instruction.mnemonic.startsWith('bl')) {
|
||||||
|
try {
|
||||||
|
console.log('#' + tid + ':' + DebugSymbol.fromAddress(ptr(instruction.operands[0].value)));
|
||||||
|
} catch (e) {
|
||||||
|
// ignoring branch&link to register
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onLeave: function (retval) {
|
||||||
|
Stalker.unfollow(this.tid);
|
||||||
|
Stalker.garbageCollect();
|
||||||
|
}
|
||||||
|
})
|
Loading…
Reference in New Issue
Block a user