adding re env setup
This commit is contained in:
parent
a7650ae99b
commit
7a00e8fc58
54
README.md
54
README.md
@ -1,3 +1,55 @@
|
||||
# relab
|
||||
Lab for reverse engineering APKs
|
||||
|
||||
RE env for inspecting APKs
|
||||
|
||||
### RE environment for dynamic and static analysis of APKs
|
||||
|
||||
Includes:
|
||||
|
||||
1. mitmproxy
|
||||
2. Frida
|
||||
3. Genymotion
|
||||
4. Jadx
|
||||
5. apktool
|
||||
|
||||
_**Note:** Setup scripts built and tested on Ubuntu 20_
|
||||
|
||||
#### Prereqs:
|
||||
|
||||
1. Python3: `sudo apt install python3`
|
||||
2. pip3: `sudo apt install python3-pip`
|
||||
3. dev-tools: `apt install build-essential`)
|
||||
|
||||
|
||||
#### Install Dynamic Analysis Tools
|
||||
|
||||
1. Run install script for mitmproxy and genymotion emulator: `./install_all.sh`
|
||||
2. Create and start Android emulated device in Genymotion OR attach physical rooted test Android device over USB.
|
||||
3. Make sure test device is accessible over adb with root access: `adb shell` -> `su`
|
||||
4. Run script to copy mitmproxy cert to be system cert on device: `cd setup_scripts; ./make_root_ca.sh`
|
||||
5. Install frida: `cd frida; ./install_frida.sh`
|
||||
6. Get frida-server binary then push to test Android device: `./get_frida_server.sh`
|
||||
7. Start frida-server on Android: `adb shell` -> `su` -> `/data/local/tmp/frida-server &`
|
||||
8. Verify frida is attaching to device over adb: `frida-ps -U`
|
||||
|
||||
|
||||
_**Note:**_ May need to mount Android filesystem as writable after step 3: `adb shell; su; mount -o rw,remount /system`
|
||||
|
||||
#### Capturing Live HTTPS from app
|
||||
|
||||
1. Start mitmproxy on desktop: `cd mitmprox; ./mitmweb`
|
||||
2. Make sure test Android is connected to proxy: `Settings` -> `Network` -> `Wi-Fi` -> `Click then hold down connected network` -> `Modify network` -> `(click) Advanced options drop down` -> `Set Proxy to "Manual"` -> `hostname = IP of desktop` -> `proxy port = 8080`
|
||||
3. View decrypted traffic panel in `mitmweb` browser on desktop at: `localhost:8081
|
||||
4. Visit any site in browser on Android to verify decryption is working
|
||||
|
||||
|
||||
|
||||
#### Use Frida to bypass SSL pinning and capture files accessed
|
||||
|
||||
1. Make sure frida server is started on Android and verify connection: `frida-ps -U`
|
||||
2. Find name of app package to target with frida: `adb shell pm list packages`
|
||||
3. Bypass SSL for targeted app: `frida -l frida_scripts/multiple_unpinning.js -U -f <package_id> --no-pause`
|
||||
4. Trace files being opened by app on device: `frida-trace -U -i open -f <package_id>`
|
||||
|
||||
|
||||
_**Note:** Most Android apps do not need SSL pinning bypass for mitmproxy to work_
|
||||
|
38
frida/__handlers__/libc.so/open.js
Normal file
38
frida/__handlers__/libc.so/open.js
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Auto-generated by Frida. Please modify to match the signature of open.
|
||||
* This stub is currently auto-generated from manpages when available.
|
||||
*
|
||||
* For full API reference, see: https://frida.re/docs/javascript-api/
|
||||
*/
|
||||
|
||||
{
|
||||
/**
|
||||
* Called synchronously when about to call open.
|
||||
*
|
||||
* @this {object} - Object allowing you to store state for use in onLeave.
|
||||
* @param {function} log - Call this function with a string to be presented to the user.
|
||||
* @param {array} args - Function arguments represented as an array of NativePointer objects.
|
||||
* For example use args[0].readUtf8String() if the first argument is a pointer to a C string encoded as UTF-8.
|
||||
* It is also possible to modify arguments by assigning a NativePointer object to an element of this array.
|
||||
* @param {object} state - Object allowing you to keep state across function calls.
|
||||
* Only one JavaScript function will execute at a time, so do not worry about race-conditions.
|
||||
* However, do not use this to store function arguments across onEnter/onLeave, but instead
|
||||
* use "this" which is an object for keeping state local to an invocation.
|
||||
*/
|
||||
onEnter(log, args, state) {
|
||||
log(`open(pathname="${args[0].readUtf8String()}", flags=${args[1]})`);
|
||||
},
|
||||
|
||||
/**
|
||||
* Called synchronously when about to return from open.
|
||||
*
|
||||
* See onEnter for details.
|
||||
*
|
||||
* @this {object} - Object allowing you to access state stored in onEnter.
|
||||
* @param {function} log - Call this function with a string to be presented to the user.
|
||||
* @param {NativePointer} retval - Return value represented as a NativePointer object.
|
||||
* @param {object} state - Object allowing you to keep state across function calls.
|
||||
*/
|
||||
onLeave(log, retval, state) {
|
||||
}
|
||||
}
|
38
frida/__handlers__/libc.so/send.js
Normal file
38
frida/__handlers__/libc.so/send.js
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Auto-generated by Frida. Please modify to match the signature of send.
|
||||
* This stub is currently auto-generated from manpages when available.
|
||||
*
|
||||
* For full API reference, see: https://frida.re/docs/javascript-api/
|
||||
*/
|
||||
|
||||
{
|
||||
/**
|
||||
* Called synchronously when about to call send.
|
||||
*
|
||||
* @this {object} - Object allowing you to store state for use in onLeave.
|
||||
* @param {function} log - Call this function with a string to be presented to the user.
|
||||
* @param {array} args - Function arguments represented as an array of NativePointer objects.
|
||||
* For example use args[0].readUtf8String() if the first argument is a pointer to a C string encoded as UTF-8.
|
||||
* It is also possible to modify arguments by assigning a NativePointer object to an element of this array.
|
||||
* @param {object} state - Object allowing you to keep state across function calls.
|
||||
* Only one JavaScript function will execute at a time, so do not worry about race-conditions.
|
||||
* However, do not use this to store function arguments across onEnter/onLeave, but instead
|
||||
* use "this" which is an object for keeping state local to an invocation.
|
||||
*/
|
||||
onEnter(log, args, state) {
|
||||
log(`send(sockfd=${args[0]}, buf=${args[1]}, len=${args[2]}, flags=${args[3]})`);
|
||||
},
|
||||
|
||||
/**
|
||||
* Called synchronously when about to return from send.
|
||||
*
|
||||
* See onEnter for details.
|
||||
*
|
||||
* @this {object} - Object allowing you to access state stored in onEnter.
|
||||
* @param {function} log - Call this function with a string to be presented to the user.
|
||||
* @param {NativePointer} retval - Return value represented as a NativePointer object.
|
||||
* @param {object} state - Object allowing you to keep state across function calls.
|
||||
*/
|
||||
onLeave(log, retval, state) {
|
||||
}
|
||||
}
|
38
frida/__handlers__/libc.so/sendfile.js
Normal file
38
frida/__handlers__/libc.so/sendfile.js
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Auto-generated by Frida. Please modify to match the signature of sendfile.
|
||||
* This stub is currently auto-generated from manpages when available.
|
||||
*
|
||||
* For full API reference, see: https://frida.re/docs/javascript-api/
|
||||
*/
|
||||
|
||||
{
|
||||
/**
|
||||
* Called synchronously when about to call sendfile.
|
||||
*
|
||||
* @this {object} - Object allowing you to store state for use in onLeave.
|
||||
* @param {function} log - Call this function with a string to be presented to the user.
|
||||
* @param {array} args - Function arguments represented as an array of NativePointer objects.
|
||||
* For example use args[0].readUtf8String() if the first argument is a pointer to a C string encoded as UTF-8.
|
||||
* It is also possible to modify arguments by assigning a NativePointer object to an element of this array.
|
||||
* @param {object} state - Object allowing you to keep state across function calls.
|
||||
* Only one JavaScript function will execute at a time, so do not worry about race-conditions.
|
||||
* However, do not use this to store function arguments across onEnter/onLeave, but instead
|
||||
* use "this" which is an object for keeping state local to an invocation.
|
||||
*/
|
||||
onEnter(log, args, state) {
|
||||
log(`sendfile(out_fd=${args[0]}, in_fd=${args[1]}, offset=${args[2]}, count=${args[3]})`);
|
||||
},
|
||||
|
||||
/**
|
||||
* Called synchronously when about to return from sendfile.
|
||||
*
|
||||
* See onEnter for details.
|
||||
*
|
||||
* @this {object} - Object allowing you to access state stored in onEnter.
|
||||
* @param {function} log - Call this function with a string to be presented to the user.
|
||||
* @param {NativePointer} retval - Return value represented as a NativePointer object.
|
||||
* @param {object} state - Object allowing you to keep state across function calls.
|
||||
*/
|
||||
onLeave(log, retval, state) {
|
||||
}
|
||||
}
|
38
frida/__handlers__/libc.so/sendmmsg.js
Normal file
38
frida/__handlers__/libc.so/sendmmsg.js
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Auto-generated by Frida. Please modify to match the signature of sendmmsg.
|
||||
* This stub is currently auto-generated from manpages when available.
|
||||
*
|
||||
* For full API reference, see: https://frida.re/docs/javascript-api/
|
||||
*/
|
||||
|
||||
{
|
||||
/**
|
||||
* Called synchronously when about to call sendmmsg.
|
||||
*
|
||||
* @this {object} - Object allowing you to store state for use in onLeave.
|
||||
* @param {function} log - Call this function with a string to be presented to the user.
|
||||
* @param {array} args - Function arguments represented as an array of NativePointer objects.
|
||||
* For example use args[0].readUtf8String() if the first argument is a pointer to a C string encoded as UTF-8.
|
||||
* It is also possible to modify arguments by assigning a NativePointer object to an element of this array.
|
||||
* @param {object} state - Object allowing you to keep state across function calls.
|
||||
* Only one JavaScript function will execute at a time, so do not worry about race-conditions.
|
||||
* However, do not use this to store function arguments across onEnter/onLeave, but instead
|
||||
* use "this" which is an object for keeping state local to an invocation.
|
||||
*/
|
||||
onEnter(log, args, state) {
|
||||
log(`sendmmsg(sockfd=${args[0]}, msgvec=${args[1]}, vlen=${args[2]}, flags=${args[3]})`);
|
||||
},
|
||||
|
||||
/**
|
||||
* Called synchronously when about to return from sendmmsg.
|
||||
*
|
||||
* See onEnter for details.
|
||||
*
|
||||
* @this {object} - Object allowing you to access state stored in onEnter.
|
||||
* @param {function} log - Call this function with a string to be presented to the user.
|
||||
* @param {NativePointer} retval - Return value represented as a NativePointer object.
|
||||
* @param {object} state - Object allowing you to keep state across function calls.
|
||||
*/
|
||||
onLeave(log, retval, state) {
|
||||
}
|
||||
}
|
38
frida/__handlers__/libc.so/sendmsg.js
Normal file
38
frida/__handlers__/libc.so/sendmsg.js
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Auto-generated by Frida. Please modify to match the signature of sendmsg.
|
||||
* This stub is currently auto-generated from manpages when available.
|
||||
*
|
||||
* For full API reference, see: https://frida.re/docs/javascript-api/
|
||||
*/
|
||||
|
||||
{
|
||||
/**
|
||||
* Called synchronously when about to call sendmsg.
|
||||
*
|
||||
* @this {object} - Object allowing you to store state for use in onLeave.
|
||||
* @param {function} log - Call this function with a string to be presented to the user.
|
||||
* @param {array} args - Function arguments represented as an array of NativePointer objects.
|
||||
* For example use args[0].readUtf8String() if the first argument is a pointer to a C string encoded as UTF-8.
|
||||
* It is also possible to modify arguments by assigning a NativePointer object to an element of this array.
|
||||
* @param {object} state - Object allowing you to keep state across function calls.
|
||||
* Only one JavaScript function will execute at a time, so do not worry about race-conditions.
|
||||
* However, do not use this to store function arguments across onEnter/onLeave, but instead
|
||||
* use "this" which is an object for keeping state local to an invocation.
|
||||
*/
|
||||
onEnter(log, args, state) {
|
||||
log(`sendmsg(sockfd=${args[0]}, msg=${args[1]}, flags=${args[2]})`);
|
||||
},
|
||||
|
||||
/**
|
||||
* Called synchronously when about to return from sendmsg.
|
||||
*
|
||||
* See onEnter for details.
|
||||
*
|
||||
* @this {object} - Object allowing you to access state stored in onEnter.
|
||||
* @param {function} log - Call this function with a string to be presented to the user.
|
||||
* @param {NativePointer} retval - Return value represented as a NativePointer object.
|
||||
* @param {object} state - Object allowing you to keep state across function calls.
|
||||
*/
|
||||
onLeave(log, retval, state) {
|
||||
}
|
||||
}
|
38
frida/__handlers__/libc.so/sendto.js
Normal file
38
frida/__handlers__/libc.so/sendto.js
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Auto-generated by Frida. Please modify to match the signature of sendto.
|
||||
* This stub is currently auto-generated from manpages when available.
|
||||
*
|
||||
* For full API reference, see: https://frida.re/docs/javascript-api/
|
||||
*/
|
||||
|
||||
{
|
||||
/**
|
||||
* Called synchronously when about to call sendto.
|
||||
*
|
||||
* @this {object} - Object allowing you to store state for use in onLeave.
|
||||
* @param {function} log - Call this function with a string to be presented to the user.
|
||||
* @param {array} args - Function arguments represented as an array of NativePointer objects.
|
||||
* For example use args[0].readUtf8String() if the first argument is a pointer to a C string encoded as UTF-8.
|
||||
* It is also possible to modify arguments by assigning a NativePointer object to an element of this array.
|
||||
* @param {object} state - Object allowing you to keep state across function calls.
|
||||
* Only one JavaScript function will execute at a time, so do not worry about race-conditions.
|
||||
* However, do not use this to store function arguments across onEnter/onLeave, but instead
|
||||
* use "this" which is an object for keeping state local to an invocation.
|
||||
*/
|
||||
onEnter(log, args, state) {
|
||||
log(`sendto(sockfd=${args[0]}, buf=${args[1]}, len=${args[2]}, flags=${args[3]}, dest_addr=${args[4]}, addrlen=${args[5]})`);
|
||||
},
|
||||
|
||||
/**
|
||||
* Called synchronously when about to return from sendto.
|
||||
*
|
||||
* See onEnter for details.
|
||||
*
|
||||
* @this {object} - Object allowing you to access state stored in onEnter.
|
||||
* @param {function} log - Call this function with a string to be presented to the user.
|
||||
* @param {NativePointer} retval - Return value represented as a NativePointer object.
|
||||
* @param {object} state - Object allowing you to keep state across function calls.
|
||||
*/
|
||||
onLeave(log, retval, state) {
|
||||
}
|
||||
}
|
11
frida/col_pin_pass.sh
Executable file
11
frida/col_pin_pass.sh
Executable file
@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
|
||||
|
||||
printf "\n\nBypassing ssl pin in Claro colombia"
|
||||
|
||||
|
||||
frida -l frida_scripts/multiple_unpinning -U -f com.clarocolombia.miclaro --no-pause
|
||||
|
||||
|
||||
|
28
frida/frida_scripts/classers.js
Normal file
28
frida/frida_scripts/classers.js
Normal file
@ -0,0 +1,28 @@
|
||||
Java.perform(() => {
|
||||
|
||||
var obj = Java.enumerateMethods('*com.twitter*!*') // com.example.demotest is application package name
|
||||
console.log("obj length: " + obj.length);
|
||||
///var methods= JSON.stringify(groups, null," ")
|
||||
///console.log(methods)
|
||||
|
||||
///var common =JSON.stringify(obj[0].classes[0],null," ")
|
||||
///console.log("\x1b[32m","class-name "+" "+JSON.parse(common).name,"\n"+"\x1b[35m","Methods name"+" "+JSON.parse(common).methods)
|
||||
///console.log("\x1b[32m", common);
|
||||
var i =0;
|
||||
//console.log(obj.length)
|
||||
for (i=0;i<obj.length;i++){
|
||||
console.log("obj" +"::"+i)
|
||||
var common =JSON.stringify(obj[i].classes[i],null," ")
|
||||
console.log("\x1b[32m","class-name "+" "+JSON.parse(common).name)
|
||||
var x;
|
||||
for (x=0;x<JSON.parse(common).methods.length;x++)
|
||||
{
|
||||
//console.log("methods"+ "::>"+x)
|
||||
//console.log("df")
|
||||
console.log("\x1b[34m",JSON.parse(common).methods[x])
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
});
|
5
frida/frida_scripts/enumerate_methods.js
Normal file
5
frida/frida_scripts/enumerate_methods.js
Normal file
@ -0,0 +1,5 @@
|
||||
console.log("Enumerating methods of MainActivity");
|
||||
Java.perform(function() {
|
||||
const groups = Java.enumerateMethods('*com.movistarmx*!*');
|
||||
console.log(JSON.stringify(groups, null, 2));
|
||||
});
|
455
frida/frida_scripts/file_access.js
Normal file
455
frida/frida_scripts/file_access.js
Normal file
@ -0,0 +1,455 @@
|
||||
/**
|
||||
It should be launch earlier in order to be aware of a maximun
|
||||
quantity of file descriptors.
|
||||
|
||||
|
||||
@author @FrenchYeti
|
||||
*/
|
||||
Java.perform(function() {
|
||||
|
||||
// ============= Config
|
||||
var CONFIG = {
|
||||
// if TRUE enable data dump
|
||||
printEnable: true,
|
||||
// if TRUE enable libc.so open/read/write hook
|
||||
printLibc: false,
|
||||
// if TRUE print the stack trace for each hook
|
||||
printStackTrace: false,
|
||||
// to filter the file path whose data want to be dumped in ASCII
|
||||
dump_ascii_If_Path_contains: [".log", ".xml", ".prop"],
|
||||
// to filter the file path whose data want to be NOT dumped in hexdump (useful for big chunk and excessive reads)
|
||||
dump_hex_If_Path_NOT_contains: [".png", "/proc/self/task", "/system/lib", "base.apk", "cacert"],
|
||||
// to filter the file path whose data want to be NOT dumped fron libc read/write (useful for big chunk and excessive reads)
|
||||
dump_raw_If_Path_NOT_contains: [".png", "/proc/self/task", "/system/lib", "base.apk", "cacert"]
|
||||
}
|
||||
|
||||
// ============= Keep a trace of file descriptor, path, and so
|
||||
var TraceFD = {};
|
||||
var TraceFS = {};
|
||||
var TraceFile = {};
|
||||
var TraceSysFD = {};
|
||||
|
||||
|
||||
// ============= Get classes
|
||||
var CLS = {
|
||||
File: Java.use("java.io.File"),
|
||||
FileInputStream: Java.use("java.io.FileInputStream"),
|
||||
FileOutputStream: Java.use("java.io.FileOutputStream"),
|
||||
String: Java.use("java.lang.String"),
|
||||
FileChannel: Java.use("java.nio.channels.FileChannel"),
|
||||
FileDescriptor: Java.use("java.io.FileDescriptor"),
|
||||
Thread: Java.use("java.lang.Thread"),
|
||||
StackTraceElement: Java.use("java.lang.StackTraceElement"),
|
||||
AndroidDbSQLite: Java.use("android.database.sqlite.SQLiteDatabase")
|
||||
};
|
||||
var File = {
|
||||
new: [
|
||||
CLS.File.$init.overload("java.io.File", "java.lang.String"),
|
||||
CLS.File.$init.overload("java.lang.String"),
|
||||
CLS.File.$init.overload("java.lang.String", "java.lang.String"),
|
||||
CLS.File.$init.overload("java.net.URI"),
|
||||
]
|
||||
};
|
||||
var FileInputStream = {
|
||||
new: [
|
||||
CLS.FileInputStream.$init.overload("java.io.File"),
|
||||
CLS.FileInputStream.$init.overload("java.io.FileDescriptor"),
|
||||
CLS.FileInputStream.$init.overload("java.lang.String"),
|
||||
],
|
||||
read: [
|
||||
CLS.FileInputStream.read.overload(),
|
||||
CLS.FileInputStream.read.overload("[B"),
|
||||
CLS.FileInputStream.read.overload("[B", "int", "int"),
|
||||
],
|
||||
};
|
||||
var FileOuputStream = {
|
||||
new: [
|
||||
CLS.FileOutputStream.$init.overload("java.io.File"),
|
||||
CLS.FileOutputStream.$init.overload("java.io.File", "boolean"),
|
||||
CLS.FileOutputStream.$init.overload("java.io.FileDescriptor"),
|
||||
CLS.FileOutputStream.$init.overload("java.lang.String"),
|
||||
CLS.FileOutputStream.$init.overload("java.lang.String", "boolean")
|
||||
],
|
||||
write: [
|
||||
CLS.FileOutputStream.write.overload("[B"),
|
||||
CLS.FileOutputStream.write.overload("int"),
|
||||
CLS.FileOutputStream.write.overload("[B", "int", "int"),
|
||||
],
|
||||
};
|
||||
|
||||
|
||||
|
||||
// ============= Hook implementation
|
||||
|
||||
File.new[1].implementation = function(a0) {
|
||||
prettyLog("[Java::File.new.1] New file : " + a0);
|
||||
|
||||
var ret = File.new[1].call(this, a0);
|
||||
var f = Java.cast(this, CLS.File);
|
||||
TraceFile["f" + this.hashCode()] = a0;
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
File.new[2].implementation = function(a0, a1) {
|
||||
prettyLog("[Java::File.read.2] New file : " + a0 + "/" + a1);
|
||||
|
||||
var ret = File.new[2].call(this, a0, a1);;
|
||||
var f = Java.cast(this, CLS.File);
|
||||
TraceFile["f" + this.hashCode()] = a0 + "/" + a1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
FileInputStream.new[0].implementation = function(a0) {
|
||||
var file = Java.cast(a0, CLS.File);
|
||||
var fname = TraceFile["f" + file.hashCode()];
|
||||
|
||||
if (fname == null) {
|
||||
var p = file.getAbsolutePath();
|
||||
if (p !== null)
|
||||
fname = TraceFile["f" + file.hashCode()] = p;
|
||||
}
|
||||
if (fname == null)
|
||||
fname = "[unknow]"
|
||||
|
||||
prettyLog("[Java::FileInputStream.new.0] New input stream from file (" + fname + "): ");
|
||||
|
||||
var fis = FileInputStream.new[0].call(this, a0)
|
||||
var f = Java.cast(this, CLS.FileInputStream);
|
||||
|
||||
TraceFS["fd" + this.hashCode()] = fname;
|
||||
|
||||
var fd = Java.cast(this.getFD(), CLS.FileDescriptor);
|
||||
|
||||
TraceFD["fd" + fd.hashCode()] = fname;
|
||||
|
||||
return fis;
|
||||
}
|
||||
|
||||
|
||||
|
||||
FileInputStream.read[1].implementation = function(a0) {
|
||||
var fname = TraceFS["fd" + this.hashCode()];
|
||||
var fd = null;
|
||||
if (fname == null) {
|
||||
fd = Java.cast(this.getFD(), CLS.FileDescriptor);
|
||||
fname = TraceFD["fd" + fd.hashCode()]
|
||||
}
|
||||
if (fname == null)
|
||||
fname = "[unknow]";
|
||||
|
||||
var b = Java.array('byte', a0);
|
||||
|
||||
prettyLog("[Java::FileInputStream.read.1] Read from file,offset (" + fname + "," + a0 + "):\n" +
|
||||
prettyPrint(fname, b));
|
||||
|
||||
return FileInputStream.read[1].call(this, a0);
|
||||
}
|
||||
FileInputStream.read[2].implementation = function(a0, a1, a2) {
|
||||
var fname = TraceFS["fd" + this.hashCode()];
|
||||
var fd = null;
|
||||
if (fname == null) {
|
||||
fd = Java.cast(this.getFD(), CLS.FileDescriptor);
|
||||
fname = TraceFD["fd" + fd.hashCode()]
|
||||
}
|
||||
if (fname == null)
|
||||
fname = "[unknow]";
|
||||
|
||||
var b = Java.array('byte', a0);
|
||||
|
||||
prettyLog("[Java::FileInputStream.read.2] Read from file,offset,len (" + fname + "," + a1 + "," + a2 + ")\n" +
|
||||
prettyPrint(fname, b));
|
||||
|
||||
return FileInputStream.read[2].call(this, a0, a1, a2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// =============== File Output Stream ============
|
||||
|
||||
|
||||
|
||||
FileOuputStream.new[0].implementation = function(a0) {
|
||||
var file = Java.cast(a0, CLS.File);
|
||||
var fname = TraceFile["f" + file.hashCode()];
|
||||
|
||||
if (fname == null)
|
||||
fname = "[unknow]<File:" + file.hashCode() + ">";
|
||||
|
||||
|
||||
prettyLog("[Java::FileOuputStream.new.0] New output stream to file (" + fname + "): ");
|
||||
|
||||
var fis = FileOuputStream.new[0].call(this, a0);
|
||||
|
||||
TraceFS["fd" + this.hashCode()] = fname;
|
||||
|
||||
var fd = Java.cast(this.getFD(), CLS.FileDescriptor);
|
||||
TraceFD["fd" + fd.hashCode()] = fname;
|
||||
|
||||
return fis;
|
||||
}
|
||||
|
||||
FileOuputStream.new[1].implementation = function(a0) {
|
||||
var file = Java.cast(a0, CLS.File);
|
||||
var fname = TraceFile["f" + file.hashCode()];
|
||||
|
||||
if (fname == null)
|
||||
fname = "[unknow]";
|
||||
|
||||
|
||||
prettyLog("[Java::FileOuputStream.new.1] New output stream to file (" + fname + "): \n");
|
||||
|
||||
var fis = FileOuputStream.new[1].call(this, a0);
|
||||
|
||||
TraceFS["fd" + this.hashCode()] = fname;
|
||||
|
||||
var fd = Java.cast(this.getFD(), CLS.FileDescriptor);
|
||||
|
||||
TraceFD["fd" + fd.hashCode()] = fname;
|
||||
|
||||
return fis;
|
||||
}
|
||||
|
||||
FileOuputStream.new[2].implementation = function(a0) {
|
||||
var fd = Java.cast(a0, CLS.FileDescriptor);
|
||||
var fname = TraceFD["fd" + fd.hashCode()];
|
||||
|
||||
if (fname == null)
|
||||
fname = "[unknow]";
|
||||
|
||||
|
||||
prettyLog("[Java::FileOuputStream.new.2] New output stream to FileDescriptor (" + fname + "): \n");
|
||||
var fis = FileOuputStream.new[1].call(this, a0)
|
||||
|
||||
TraceFS["fd" + this.hashCode()] = fname;
|
||||
|
||||
return fis;
|
||||
}
|
||||
FileOuputStream.new[3].implementation = function(a0) {
|
||||
prettyLog("[Java::FileOuputStream.new.3] New output stream to file (str=" + a0 + "): \n");
|
||||
|
||||
var fis = FileOuputStream.new[1].call(this, a0)
|
||||
|
||||
TraceFS["fd" + this.hashCode()] = a0;
|
||||
var fd = Java.cast(this.getFD(), CLS.FileDescriptor);
|
||||
TraceFD["fd" + fd.hashCode()] = a0;
|
||||
|
||||
return fis;
|
||||
}
|
||||
FileOuputStream.new[4].implementation = function(a0) {
|
||||
prettyLog("[Java::FileOuputStream.new.4] New output stream to file (str=" + a0 + ",bool): \n");
|
||||
|
||||
var fis = FileOuputStream.new[1].call(this, a0)
|
||||
TraceFS["fd" + this.hashCode()] = a0;
|
||||
var fd = Java.cast(this.getFD(), CLS.FileDescriptor);
|
||||
TraceFD["fd" + fd.hashCode()] = a0;
|
||||
|
||||
return fis;
|
||||
}
|
||||
|
||||
|
||||
|
||||
FileOuputStream.write[0].implementation = function(a0) {
|
||||
var fname = TraceFS["fd" + this.hashCode()];
|
||||
var fd = null;
|
||||
|
||||
if (fname == null) {
|
||||
fd = Java.cast(this.getFD(), CLS.FileDescriptor);
|
||||
fname = TraceFD["fd" + fd.hashCode()]
|
||||
}
|
||||
if (fname == null)
|
||||
fname = "[unknow]";
|
||||
|
||||
prettyLog("[Java::FileOuputStream.write.0] Write byte array (" + fname + "):\n" +
|
||||
prettyPrint(fname, a0));
|
||||
|
||||
return FileOuputStream.write[0].call(this, a0);
|
||||
}
|
||||
FileOuputStream.write[1].implementation = function(a0) {
|
||||
|
||||
var fname = TraceFS["fd" + this.hashCode()];
|
||||
var fd = null;
|
||||
if (fname == null) {
|
||||
fd = Java.cast(this.getFD(), CLS.FileDescriptor);
|
||||
fname = TraceFD["fd" + fd.hashCode()]
|
||||
}
|
||||
if (fname == null)
|
||||
fname = "[unknow]";
|
||||
|
||||
prettyLog("[Java::FileOuputStream.write.1] Write int (" + fname + "): " + a0);
|
||||
|
||||
|
||||
return FileOuputStream.write[1].call(this, a0);
|
||||
}
|
||||
FileOuputStream.write[2].implementation = function(a0, a1, a2) {
|
||||
|
||||
var fname = TraceFS["fd" + this.hashCode()];
|
||||
var fd = null;
|
||||
if (fname == null) {
|
||||
fd = Java.cast(this.getFD(), CLS.FileDescriptor);
|
||||
fname = TraceFD["fd" + fd.hashCode()]
|
||||
if (fname == null)
|
||||
fname = "[unknow], fd=" + this.hashCode();
|
||||
}
|
||||
|
||||
prettyLog("[Java::FileOuputStream.write.2] Write " + a2 + " bytes from " + a1 + " (" + fname + "):\n" +
|
||||
prettyPrint(fname, a0));
|
||||
|
||||
return FileOuputStream.write[2].call(this, a0, a1, a2);
|
||||
}
|
||||
|
||||
// native hooks
|
||||
Interceptor.attach(
|
||||
Module.findExportByName("libc.so", "read"), {
|
||||
// fd, buff, len
|
||||
onEnter: function(args) {
|
||||
if (CONFIG.printLibc === true) {
|
||||
var bfr = args[1],
|
||||
sz = args[2].toInt32();
|
||||
var path = (TraceSysFD["fd-" + args[0].toInt32()] != null) ? TraceSysFD["fd-" + args[0].toInt32()] : "[unknow path]";
|
||||
|
||||
prettyLog("[Libc::read] Read FD (" + path + "," + bfr + "," + sz + ")\n" +
|
||||
rawPrint(path, Memory.readByteArray(bfr, sz)));
|
||||
}
|
||||
},
|
||||
onLeave: function(ret) {
|
||||
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
Interceptor.attach(
|
||||
Module.findExportByName("libc.so", "open"), {
|
||||
// path, flags, mode
|
||||
onEnter: function(args) {
|
||||
this.path = Memory.readCString(args[0]);
|
||||
},
|
||||
onLeave: function(ret) {
|
||||
TraceSysFD["fd-" + ret.toInt32()] = this.path;
|
||||
if (CONFIG.printLibc === true)
|
||||
prettyLog("[Libc::open] Open file '" + this.path + "' (fd: " + ret.toInt32() + ")");
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
Interceptor.attach(
|
||||
Module.findExportByName("libc.so", "write"), {
|
||||
// fd, buff, count
|
||||
onEnter: function(args) {
|
||||
if (CONFIG.printLibc === true) {
|
||||
var bfr = args[1],
|
||||
sz = args[2].toInt32();
|
||||
var path = (TraceSysFD["fd-" + args[0].toInt32()] != null) ? TraceSysFD["fd-" + args[0].toInt32()] : "[unknow path]";
|
||||
|
||||
prettyLog("[Libc::write] Write FD (" + path + "," + bfr + "," + sz + ")\n" +
|
||||
rawPrint(path, Memory.readByteArray(bfr, sz)));
|
||||
}
|
||||
},
|
||||
onLeave: function(ret) {
|
||||
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
|
||||
// helper functions
|
||||
function prettyLog(str) {
|
||||
console.log("---------------------------\n" + str);
|
||||
if (CONFIG.printStackTrace === true) {
|
||||
printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
function prettyPrint(path, buffer) {
|
||||
if (CONFIG.printEnable === false) return "";
|
||||
|
||||
if (contains(path, CONFIG.dump_ascii_If_Path_contains)) {
|
||||
return b2s(buffer);
|
||||
} else if (!contains(path, CONFIG.dump_hex_If_Path_NOT_contains)) {
|
||||
return hexdump(b2s(buffer));
|
||||
}
|
||||
return "[dump skipped by config]";
|
||||
}
|
||||
|
||||
function rawPrint(path, buffer) {
|
||||
if (CONFIG.printEnable === false) return "";
|
||||
|
||||
if (!contains(path, CONFIG.dump_raw_If_Path_NOT_contains)) {
|
||||
return hexdump(buffer);
|
||||
}
|
||||
return "[dump skipped by config]";
|
||||
}
|
||||
|
||||
function contains(path, patterns) {
|
||||
for (var i = 0; i < patterns.length; i++)
|
||||
if (path.indexOf(patterns[i]) > -1) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
function printStackTrace() {
|
||||
var th = Java.cast(CLS.Thread.currentThread(), CLS.Thread);
|
||||
var stack = th.getStackTrace(),
|
||||
e = null;
|
||||
|
||||
for (var i = 0; i < stack.length; i++) {
|
||||
console.log("\t" + stack[i].getClassName() + "." + stack[i].getMethodName() + "(" + stack[i].getFileName() + ")");
|
||||
}
|
||||
}
|
||||
|
||||
function isZero(block) {
|
||||
var m = /^[0\s]+$/.exec(block);
|
||||
return m != null && m.length > 0 && (m[0] == block);
|
||||
}
|
||||
|
||||
function hexdump(buffer, blockSize) {
|
||||
blockSize = blockSize || 16;
|
||||
var lines = [];
|
||||
var hex = "0123456789ABCDEF";
|
||||
var prevZero = false,
|
||||
ctrZero = 0;
|
||||
for (var b = 0; b < buffer.length; b += blockSize) {
|
||||
var block = buffer.slice(b, Math.min(b + blockSize, buffer.length));
|
||||
var addr = ("0000" + b.toString(16)).slice(-4);
|
||||
var codes = block.split('').map(function(ch) {
|
||||
var code = ch.charCodeAt(0);
|
||||
return " " + hex[(0xF0 & code) >> 4] + hex[0x0F & code];
|
||||
}).join("");
|
||||
codes += " ".repeat(blockSize - block.length);
|
||||
var chars = block.replace(/[\\x00-\\x1F\\x20\n]/g, '.');
|
||||
chars += " ".repeat(blockSize - block.length);
|
||||
if (isZero(codes)) {
|
||||
ctrZero += blockSize;
|
||||
prevZero = true;
|
||||
} else {
|
||||
if (prevZero) {
|
||||
lines.push("\t [" + ctrZero + "] bytes of zeroes");
|
||||
}
|
||||
lines.push(addr + " " + codes + " " + chars);
|
||||
prevZero = false;
|
||||
ctrZero = 0;
|
||||
}
|
||||
}
|
||||
if (prevZero) {
|
||||
lines.push("\t [" + ctrZero + "] bytes of zeroes");
|
||||
}
|
||||
return lines.join("\\n");
|
||||
}
|
||||
|
||||
function b2s(array) {
|
||||
var result = "";
|
||||
for (var i = 0; i < array.length; i++) {
|
||||
result += String.fromCharCode(modulus(array[i], 256));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function modulus(x, n) {
|
||||
return ((x % n) + n) % n;
|
||||
}
|
||||
|
||||
});
|
||||
|
66
frida/frida_scripts/frida_certpin_pass.js
Normal file
66
frida/frida_scripts/frida_certpin_pass.js
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
Android SSL Re-pinning frida script v0.2 030417-pier
|
||||
|
||||
$ adb push burpca-cert-der.crt /data/local/tmp/cert-der.crt
|
||||
$ frida -U -f it.app.mobile -l frida-android-repinning.js --no-pause
|
||||
|
||||
https://techblog.mediaservice.net/2017/07/universal-android-ssl-pinning-bypass-with-frida/
|
||||
|
||||
UPDATE 20191605: Fixed undeclared var. Thanks to @oleavr and @ehsanpc9999 !
|
||||
*/
|
||||
|
||||
setTimeout(function(){
|
||||
Java.perform(function (){
|
||||
console.log("");
|
||||
console.log("[.] Cert Pinning Bypass/Re-Pinning");
|
||||
|
||||
var CertificateFactory = Java.use("java.security.cert.CertificateFactory");
|
||||
var FileInputStream = Java.use("java.io.FileInputStream");
|
||||
var BufferedInputStream = Java.use("java.io.BufferedInputStream");
|
||||
var X509Certificate = Java.use("java.security.cert.X509Certificate");
|
||||
var KeyStore = Java.use("java.security.KeyStore");
|
||||
var TrustManagerFactory = Java.use("javax.net.ssl.TrustManagerFactory");
|
||||
var SSLContext = Java.use("javax.net.ssl.SSLContext");
|
||||
|
||||
// Load CAs from an InputStream
|
||||
console.log("[+] Loading our CA...")
|
||||
var cf = CertificateFactory.getInstance("X.509");
|
||||
|
||||
try {
|
||||
var fileInputStream = FileInputStream.$new("/data/local/tmp/cert-der.crt");
|
||||
}
|
||||
catch(err) {
|
||||
console.log("[o] " + err);
|
||||
}
|
||||
|
||||
var bufferedInputStream = BufferedInputStream.$new(fileInputStream);
|
||||
var ca = cf.generateCertificate(bufferedInputStream);
|
||||
bufferedInputStream.close();
|
||||
|
||||
var certInfo = Java.cast(ca, X509Certificate);
|
||||
console.log("[o] Our CA Info: " + certInfo.getSubjectDN());
|
||||
|
||||
// Create a KeyStore containing our trusted CAs
|
||||
console.log("[+] Creating a KeyStore for our CA...");
|
||||
var keyStoreType = KeyStore.getDefaultType();
|
||||
var keyStore = KeyStore.getInstance(keyStoreType);
|
||||
keyStore.load(null, null);
|
||||
keyStore.setCertificateEntry("ca", ca);
|
||||
|
||||
// Create a TrustManager that trusts the CAs in our KeyStore
|
||||
console.log("[+] Creating a TrustManager that trusts the CA in our KeyStore...");
|
||||
var tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
|
||||
var tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
|
||||
tmf.init(keyStore);
|
||||
console.log("[+] Our TrustManager is ready...");
|
||||
|
||||
console.log("[+] Hijacking SSLContext methods now...")
|
||||
console.log("[-] Waiting for the app to invoke SSLContext.init()...")
|
||||
|
||||
SSLContext.init.overload("[Ljavax.net.ssl.KeyManager;", "[Ljavax.net.ssl.TrustManager;", "java.security.SecureRandom").implementation = function(a,b,c) {
|
||||
console.log("[o] App invoked javax.net.ssl.SSLContext.init...");
|
||||
SSLContext.init.overload("[Ljavax.net.ssl.KeyManager;", "[Ljavax.net.ssl.TrustManager;", "java.security.SecureRandom").call(this, a, tmf.getTrustManagers(), c);
|
||||
console.log("[+] SSLContext initialized with our custom TrustManager!");
|
||||
}
|
||||
});
|
||||
},0);
|
251
frida/frida_scripts/hook-finder.js
Normal file
251
frida/frida_scripts/hook-finder.js
Normal file
@ -0,0 +1,251 @@
|
||||
// Script to gather the shared library from disk and also
|
||||
// from memory utilizing Frida. After reading the file from
|
||||
// disk, it will then compare some sections of the file in
|
||||
// order to hunt and identify potentially modified and hooked
|
||||
// functions.
|
||||
//
|
||||
// Re-written over the ages for usage while
|
||||
// unpacking Android applications by
|
||||
// Tim 'diff' Strazzere, <tim -at- corellium.com> <diff -at- protonmail.com>
|
||||
// Based off older code and concepts from lich4/lichao890427
|
||||
//
|
||||
// Corresponding blog https://corellium.com/blog/android-frida-finding-hooks
|
||||
|
||||
// Helper function for creating a native function for usage
|
||||
function getNativeFunction(name, ret, args) {
|
||||
var mod = Module.findExportByName(null, name);
|
||||
if (mod === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var func = new NativeFunction(mod, ret, args);
|
||||
if (typeof func === 'undefined') {
|
||||
return null;
|
||||
}
|
||||
|
||||
return func;
|
||||
}
|
||||
|
||||
var open_ptr = getNativeFunction('open', 'int', ['pointer', 'int', 'int']);
|
||||
var read_ptr = getNativeFunction('read', 'int', ['int', 'pointer', 'int']);
|
||||
var close_ptr = getNativeFunction('close', 'int', ['int']);
|
||||
var lseek_ptr = getNativeFunction('lseek', 'int', ['int', 'int', 'int']);
|
||||
|
||||
function getElfData(module) {
|
||||
console.log('Processing ', module.path);
|
||||
if (module.sections) {
|
||||
return true;
|
||||
}
|
||||
|
||||
var fd = open_ptr(Memory.allocUtf8String(module.path), 0 /* O_RDONLY */, 0);
|
||||
if (fd == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get elf header
|
||||
var header = Memory.alloc(64);
|
||||
lseek_ptr(fd, 0, 0 /* SEEK_SET */);
|
||||
read_ptr(fd, header, 64);
|
||||
|
||||
// Allow for both 32bit and 64bit binaries
|
||||
var is32 = Memory.readU8(header.add(4)) === 1;
|
||||
module.is32 = is32;
|
||||
|
||||
// Parse section headers
|
||||
var sectionHeaderOffset = is32 ? Memory.readU32(header.add(32)) : Memory.readU64(header.add(40)).toNumber(); // For some reason this is read as a string
|
||||
var sectionHeaderSize = is32 ? Memory.readU16(header.add(46)) : Memory.readU16(header.add(58));
|
||||
var sectionHeaderCount = is32 ? Memory.readU16(header.add(48)) : Memory.readU16(header.add(60));
|
||||
var sectionHeaderStringTableIndex = is32 ? Memory.readU16(header.add(50)) : Memory.readU16(header.add(62));
|
||||
|
||||
var sectionHeaders = Memory.alloc(sectionHeaderSize * sectionHeaderCount);
|
||||
|
||||
lseek_ptr(fd, sectionHeaderOffset, 0 /* SEEK_SET */);
|
||||
read_ptr(fd, sectionHeaders, sectionHeaderSize * sectionHeaderCount);
|
||||
|
||||
var stringTableOffset = is32 ? Memory.readU32(sectionHeaders.add(sectionHeaderSize * sectionHeaderStringTableIndex + 16)) : Memory.readU64(sectionHeaders.add(sectionHeaderSize * sectionHeaderStringTableIndex + 24)).toNumber();
|
||||
var stringTableSize = is32 ? Memory.readU32(sectionHeaders.add(sectionHeaderSize * sectionHeaderStringTableIndex + 20)) : Memory.readU64(sectionHeaders.add(sectionHeaderSize * sectionHeaderStringTableIndex + 32)).toNumber();
|
||||
|
||||
var stringTable = Memory.alloc(stringTableSize);
|
||||
lseek_ptr(fd, stringTableOffset, 0 /* SEEK_SET */);
|
||||
read_ptr(fd, stringTable, stringTableSize);
|
||||
var sections = [];
|
||||
|
||||
var dynsym = undefined;
|
||||
var dynstr = undefined;
|
||||
var relplt = undefined;
|
||||
var reldyn = undefined;
|
||||
|
||||
for (var i = 0; i < sectionHeaderCount; i++) {
|
||||
var sectionName = Memory.readUtf8String(stringTable.add(Memory.readU32(sectionHeaders.add(i * sectionHeaderSize))));
|
||||
var sectionAddress = is32 ? Memory.readU32(sectionHeaders.add(i * sectionHeaderSize + 12)) : Memory.readU64(sectionHeaders.add(i * sectionHeaderSize + 16)).toNumber();
|
||||
var sectionOffset = is32 ? Memory.readU32(sectionHeaders.add(i * sectionHeaderSize + 16)) : Memory.readU64(sectionHeaders.add(i * sectionHeaderSize + 24)).toNumber();
|
||||
var sectionSize = is32 ? Memory.readU32(sectionHeaders.add(i * sectionHeaderSize + 20)) : Memory.readU64(sectionHeaders.add(i * sectionHeaderSize + 32)).toNumber();
|
||||
|
||||
if (['.text', '.rodata', '.got', '.got.plt'].includes(sectionName)) {
|
||||
var section = {};
|
||||
section.name = sectionName;
|
||||
section.memoryOffset = sectionAddress;
|
||||
section.fileOffset = sectionOffset;
|
||||
section.size = sectionSize;
|
||||
if (sectionSize > 0) {
|
||||
section.data = Memory.alloc(sectionSize);
|
||||
lseek_ptr(fd, sectionOffset, 0 /* SEEK_SET */);
|
||||
read_ptr(fd, section.data, sectionSize);
|
||||
} else {
|
||||
section.data = undefined;
|
||||
}
|
||||
sections.push(section);
|
||||
} else if (['.dynsym', '.dynstr', '.rel.dyn', '.rel.plt'].includes(sectionName)) {
|
||||
var section = {};
|
||||
section.name = sectionName;
|
||||
section.memoryOffset = sectionAddress;
|
||||
section.fileOffset = sectionOffset;
|
||||
section.size = sectionSize;
|
||||
if (sectionSize > 0) {
|
||||
section.data = Memory.alloc(sectionSize);
|
||||
lseek_ptr(fd, sectionOffset, 0 /* SEEK_SET */);
|
||||
read_ptr(fd, section.data, sectionSize);
|
||||
} else {
|
||||
console.log('No data section for', section.name);
|
||||
section.data = undefined;
|
||||
}
|
||||
|
||||
if (section.name === '.dynsym') {
|
||||
dynsym = section;
|
||||
}
|
||||
if (section.name === '.dynstr') {
|
||||
dynstr = section;
|
||||
}
|
||||
if (section.name === '.rel.dyn') {
|
||||
reldyn = section;
|
||||
}
|
||||
if (section.name === '.rel.plt') {
|
||||
relplt = section;
|
||||
}
|
||||
sections.push(section);
|
||||
}
|
||||
}
|
||||
|
||||
if (!!dynsym && !!dynstr) {
|
||||
var symbols = [];
|
||||
var stringTable = module.base.add(dynstr.memoryOffset);
|
||||
var structSize = is32 ? 16 : 24;
|
||||
for (var i = 0; i < dynsym.size / structSize; i++) {
|
||||
var symbolOffset = Memory.readU32(module.base.add(dynsym.memoryOffset).add(structSize * i));
|
||||
symbols.push(Memory.readUtf8String(stringTable.add(symbolOffset)));
|
||||
}
|
||||
|
||||
module.symbols = symbols;
|
||||
}
|
||||
|
||||
var relmap = new Map();
|
||||
if (!!reldyn) {
|
||||
for (var i = 0; i < reldyn.size / 8; i++) {
|
||||
if ((Memory.readU32(module.base.add(reldyn.memoryOffset).add(i * 8)) != 0) &&
|
||||
(Memory.readU32(module.base.add(reldyn.memoryOffset).add(i * 8).add(4)) >> 8 != 0)) {
|
||||
relmap[Memory.readU32(module.base.add(reldyn.memoryOffset).add(i * 8))] = Memory.readU32(module.base.add(reldyn.memoryOffset).add(i * 8).add(4)) >> 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!!relplt) {
|
||||
for (var i = 0; i < relplt.size / 8; i++) {
|
||||
if ((Memory.readU32(module.base.add(relplt.memoryOffset).add(i * 8)) != 0) &&
|
||||
(Memory.readU32(module.base.add(relplt.memoryOffset).add(i * 8).add(4)) >> 8 != 0)) {
|
||||
relmap[Memory.readU32(module.base.add(relplt.memoryOffset).add(i * 8))] = Memory.readU32(module.base.add(relplt.memoryOffset).add(i * 8).add(4)) >> 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
module.relmap = relmap;
|
||||
|
||||
module.sections = sections;
|
||||
return true;
|
||||
}
|
||||
|
||||
function findHooks(module) {
|
||||
if (module.sections === undefined) {
|
||||
if (!getElfData(module)) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
module.sections.forEach((section) => {
|
||||
if (section.size === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// It's important to cast the ArrayBuffer returned by `readByteArray` cannot be referenced incrementally
|
||||
var file = new Uint8Array(Memory.readByteArray(section.data, section.size));
|
||||
var memory = new Uint8Array(Memory.readByteArray(module.base.add(section.memoryOffset), section.size));
|
||||
for (var i = 0; i < section.size;) {
|
||||
if (['.rodata', '.text'].includes(section.name)) {
|
||||
if (file[i] != memory[i]) {
|
||||
console.log('*** Potential variance found at ', DebugSymbol.fromAddress(module.base.add(section.memoryOffset).add(i)));
|
||||
i += 4;
|
||||
}
|
||||
i++
|
||||
} else if (['.got'].includes(section.name)) {
|
||||
break;
|
||||
// It shouldn't be as the got table isn't initialized until execution
|
||||
if (file[i] != memory[i]) {
|
||||
// todo compare the symbol to string against what it resolves too
|
||||
}
|
||||
i += module.is32 ? 4 : 8;
|
||||
} else {
|
||||
// Unscanned sections, to be added as needed
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Quick and simple way to get the package name, assumes that the script
|
||||
// was injected into an APK otherwise it won't work.
|
||||
function getPackageName() {
|
||||
var fd = open_ptr(Memory.allocUtf8String('/proc/self/cmdline'), 0 /* O_RDONLY */, 0);
|
||||
if (fd == -1) {
|
||||
return 'null';
|
||||
}
|
||||
|
||||
var buffer = Memory.alloc(32);
|
||||
read_ptr(fd, buffer, 32);
|
||||
close_ptr(fd);
|
||||
|
||||
return Memory.readUtf8String(buffer);
|
||||
}
|
||||
|
||||
// Adjust this as needed, often I don't need to scan anything outside of the
|
||||
// included shared libraries and a few which are almost always in an apex folder.
|
||||
// This logic will need to be changed if you're using a pre-apex version of Android
|
||||
// to ensure it picked up the proper libraries for hunting
|
||||
//
|
||||
// While it doesn't hurt to scan everything, it's almost never needed and will just slow
|
||||
// down the process at a linear scale.
|
||||
//
|
||||
// If you already know what you're hunting for, feel free to just return or look for
|
||||
// libart, libdvm, etc, etc
|
||||
function getRelevantModules() {
|
||||
var modules = [];
|
||||
var packagename = getPackageName();
|
||||
|
||||
Process.enumerateModules().forEach((module) => {
|
||||
if (module.path.includes(packagename)) {
|
||||
modules.push(module);
|
||||
console.log('Adding ', module.path);
|
||||
} else if (module.path.includes('/apex')) {
|
||||
modules.push(module);
|
||||
console.log('Adding ', module.path);
|
||||
} else {
|
||||
console.log('Skipping ', module.path);
|
||||
}
|
||||
})
|
||||
|
||||
return modules;
|
||||
}
|
||||
|
||||
var modules = getRelevantModules();
|
||||
|
||||
modules.forEach((module) => {
|
||||
getElfData(module);
|
||||
findHooks(module);
|
||||
});
|
148
frida/frida_scripts/http-connection.js
Normal file
148
frida/frida_scripts/http-connection.js
Normal file
@ -0,0 +1,148 @@
|
||||
setImmediate(function() {
|
||||
Java.perform(function() {
|
||||
|
||||
var url = Java.use("java.net.URL");
|
||||
|
||||
url.$init.overload('java.lang.String').implementation = function (var0) {
|
||||
console.log("[*] Created new URL with value: " + var0 +"\n");
|
||||
return this.$init(var0);
|
||||
};
|
||||
|
||||
url.openConnection.overload().implementation = function () {
|
||||
console.log("[*] Created new URL connection\n");
|
||||
return this.openConnection();
|
||||
};
|
||||
|
||||
url.openConnection.overload('java.net.Proxy').implementation = function (var0) {
|
||||
console.log("[*] Created new URL connection with proxy value: " + var0 +"\n");
|
||||
return this.openConnection(var0);
|
||||
};
|
||||
|
||||
|
||||
var URLConnection = Java.use("java.net.URLConnection");
|
||||
|
||||
URLConnection.connect.implementation = function () {
|
||||
console.log("[*] Connect called.\n");
|
||||
this.connect();
|
||||
};
|
||||
|
||||
URLConnection.getContent.overload().implementation = function () {
|
||||
var content = this.getContent();
|
||||
console.log("[*] Get content called. Content: " + content + "\n");
|
||||
return content;
|
||||
};
|
||||
|
||||
URLConnection.getContentType.implementation = function () {
|
||||
var contentType = this.getContentType();
|
||||
console.log("[*] Get content type called. Content type: " + contentType + "\n");
|
||||
return contentType;
|
||||
};
|
||||
|
||||
URLConnection.getContentLength.implementation = function () {
|
||||
var contentLength = this.getContentLength();
|
||||
console.log("[*] Get content length called. Content length: " + contentLength + "\n");
|
||||
return contentLength;
|
||||
};
|
||||
|
||||
URLConnection.getContentLengthLong.implementation = function () {
|
||||
var contentLengthLong = this.getContentLengthLong();
|
||||
console.log("[*] Get content length long called. Content length long: " + contentLengthLong + "\n");
|
||||
return contentLengthLong;
|
||||
};
|
||||
|
||||
URLConnection.getContentEncoding.implementation = function () {
|
||||
var contentEncoding = this.getContentEncoding();
|
||||
console.log("[*] Get content encoding called. Content encoding: " + contentEncoding + "\n");
|
||||
return contentEncoding;
|
||||
};
|
||||
|
||||
URLConnection.getDate.implementation = function () {
|
||||
var contentDate = this.getDate();
|
||||
console.log("[*] Get date called. Date: " + contentDate + "\n");
|
||||
return contentDate;
|
||||
};
|
||||
|
||||
URLConnection.getExpiration.implementation = function () {
|
||||
var contentExpiration = this.getExpiration();
|
||||
console.log("[*] Get expiration called. Expiration: " + contentExpiration + "\n");
|
||||
return contentExpiration;
|
||||
};
|
||||
|
||||
URLConnection.getLastModified.implementation = function () {
|
||||
var lastModified = this.getLastModified();
|
||||
console.log("[*] Get last modified called. Value: " + lastModified + "\n");
|
||||
return lastModified;
|
||||
};
|
||||
|
||||
URLConnection.getInputStream.implementation = function () {
|
||||
console.log("[*] Get input stream called.\n");
|
||||
return this.getInputStream;
|
||||
};
|
||||
|
||||
URLConnection.setDoOutput.overload('boolean').implementation = function (var0) {
|
||||
console.log("[*] URLConnection.setDoOutput called with value: " + var0 + ".\n");
|
||||
this.setDoOutput(var0);
|
||||
};
|
||||
|
||||
URLConnection.setDoInput.overload('boolean').implementation = function (var0) {
|
||||
console.log("[*] URLConnection.setDoInput called with value: " + var0 + ".\n");
|
||||
this.setDoInput(var0);
|
||||
};
|
||||
|
||||
var httpURLConnection = Java.use("com.android.okhttp.internal.huc.HttpURLConnectionImpl");
|
||||
|
||||
httpURLConnection.setRequestMethod.overload('java.lang.String').implementation = function (var0) {
|
||||
console.log("[*] Set request method called: " + var0 + "\n");
|
||||
this.setRequestMethod(var0);
|
||||
};
|
||||
|
||||
httpURLConnection.setRequestMethod.overload('java.lang.String').implementation = function (var0) {
|
||||
console.log("[*] Set request method called: " + var0 + "\n");
|
||||
this.setRequestMethod(var0);
|
||||
};
|
||||
|
||||
httpURLConnection.connect.implementation = function () {
|
||||
console.log("[*] Connect called.\n");
|
||||
this.connect();
|
||||
};
|
||||
|
||||
httpURLConnection.disconnect.implementation = function () {
|
||||
console.log("[*] Disconnect called.\n");
|
||||
this.disconnect();
|
||||
};
|
||||
|
||||
httpURLConnection.getResponseCode.implementation = function () {
|
||||
var responseCode = this.getResponseCode();
|
||||
console.log("[*] Get response code called: " + responseCode + "\n");
|
||||
return responseCode;
|
||||
};
|
||||
|
||||
var httpsURLConnection = Java.use("com.android.okhttp.internal.huc.HttpsURLConnectionImpl");
|
||||
|
||||
httpsURLConnection.setRequestMethod.overload('java.lang.String').implementation = function (var0) {
|
||||
console.log("[*] Set request method called: " + var0 + "\n");
|
||||
this.setRequestMethod(var0);
|
||||
};
|
||||
|
||||
httpsURLConnection.connect.implementation = function () {
|
||||
console.log("[*] Connect called.\n");
|
||||
this.connect();
|
||||
};
|
||||
|
||||
httpsURLConnection.disconnect.implementation = function () {
|
||||
console.log("[*] Disconnect called.\n");
|
||||
this.disconnect();
|
||||
};
|
||||
|
||||
httpsURLConnection.getResponseCode.implementation = function () {
|
||||
var responseCode = this.getResponseCode();
|
||||
console.log("[*] Get response code called: " + responseCode + "\n");
|
||||
return responseCode;
|
||||
};
|
||||
|
||||
httpsURLConnection.setRequestProperty.overload('java.lang.String', 'java.lang.String').implementation = function (var0, var1) {
|
||||
console.log("[*] URLConnection.setRequestProperty called with key: " + var0 + " and value: " + var1 + ".\n");
|
||||
this.setRequestProperty(var0, var1);
|
||||
};
|
||||
});
|
||||
});
|
731
frida/frida_scripts/multiple_unpinning.js
Normal file
731
frida/frida_scripts/multiple_unpinning.js
Normal file
@ -0,0 +1,731 @@
|
||||
/* Android ssl certificate pinning bypass script for various methods
|
||||
by Maurizio Siddu
|
||||
|
||||
Run with:
|
||||
frida -U -f [APP_ID] -l frida_multiple_unpinning.js --no-pause
|
||||
*/
|
||||
|
||||
setTimeout(function() {
|
||||
Java.perform(function() {
|
||||
console.log('');
|
||||
console.log('======');
|
||||
console.log('[#] Android Bypass for various Certificate Pinning methods [#]');
|
||||
console.log('======');
|
||||
|
||||
|
||||
var X509TrustManager = Java.use('javax.net.ssl.X509TrustManager');
|
||||
var SSLContext = Java.use('javax.net.ssl.SSLContext');
|
||||
|
||||
// TrustManager (Android < 7) //
|
||||
////////////////////////////////
|
||||
var TrustManager = Java.registerClass({
|
||||
// Implement a custom TrustManager
|
||||
name: 'dev.asd.test.TrustManager',
|
||||
implements: [X509TrustManager],
|
||||
methods: {
|
||||
checkClientTrusted: function(chain, authType) {},
|
||||
checkServerTrusted: function(chain, authType) {},
|
||||
getAcceptedIssuers: function() {return []; }
|
||||
}
|
||||
});
|
||||
// Prepare the TrustManager array to pass to SSLContext.init()
|
||||
var TrustManagers = [TrustManager.$new()];
|
||||
// Get a handle on the init() on the SSLContext class
|
||||
var SSLContext_init = SSLContext.init.overload(
|
||||
'[Ljavax.net.ssl.KeyManager;', '[Ljavax.net.ssl.TrustManager;', 'java.security.SecureRandom');
|
||||
try {
|
||||
// Override the init method, specifying the custom TrustManager
|
||||
SSLContext_init.implementation = function(keyManager, trustManager, secureRandom) {
|
||||
console.log('[+] Bypassing Trustmanager (Android < 7) pinner');
|
||||
SSLContext_init.call(this, keyManager, TrustManagers, secureRandom);
|
||||
};
|
||||
} catch (err) {
|
||||
console.log('[-] TrustManager (Android < 7) pinner not found');
|
||||
//console.log(err);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// OkHTTPv3 (quadruple bypass) //
|
||||
/////////////////////////////////
|
||||
try {
|
||||
// Bypass OkHTTPv3 {1}
|
||||
var okhttp3_Activity_1 = Java.use('okhttp3.CertificatePinner');
|
||||
okhttp3_Activity_1.check.overload('java.lang.String', 'java.util.List').implementation = function(a, b) {
|
||||
console.log('[+] Bypassing OkHTTPv3 {1}: ' + a);
|
||||
return;
|
||||
};
|
||||
} catch (err) {
|
||||
console.log('[-] OkHTTPv3 {1} pinner not found');
|
||||
//console.log(err);
|
||||
}
|
||||
try {
|
||||
// Bypass OkHTTPv3 {2}
|
||||
// This method of CertificatePinner.check is deprecated but could be found in some old Android apps
|
||||
var okhttp3_Activity_2 = Java.use('okhttp3.CertificatePinner');
|
||||
okhttp3_Activity_2.check.overload('java.lang.String', 'java.security.cert.Certificate').implementation = function(a, b) {
|
||||
console.log('[+] Bypassing OkHTTPv3 {2}: ' + a);
|
||||
return;
|
||||
};
|
||||
} catch (err) {
|
||||
console.log('[-] OkHTTPv3 {2} pinner not found');
|
||||
//console.log(err);
|
||||
}
|
||||
try {
|
||||
// Bypass OkHTTPv3 {3}
|
||||
var okhttp3_Activity_3 = Java.use('okhttp3.CertificatePinner');
|
||||
okhttp3_Activity_3.check.overload('java.lang.String', '[Ljava.security.cert.Certificate;').implementation = function(a, b) {
|
||||
console.log('[+] Bypassing OkHTTPv3 {3}: ' + a);
|
||||
return;
|
||||
};
|
||||
} catch(err) {
|
||||
console.log('[-] OkHTTPv3 {3} pinner not found');
|
||||
//console.log(err);
|
||||
}
|
||||
try {
|
||||
// Bypass OkHTTPv3 {4}
|
||||
var okhttp3_Activity_4 = Java.use('okhttp3.CertificatePinner');
|
||||
//okhttp3_Activity_4['check$okhttp'].implementation = function(a, b) {
|
||||
okhttp3_Activity_4.check$okhttp.overload('java.lang.String', 'kotlin.jvm.functions.Function0').implementation = function(a, b) {
|
||||
console.log('[+] Bypassing OkHTTPv3 {4}: ' + a);
|
||||
return;
|
||||
};
|
||||
} catch(err) {
|
||||
console.log('[-] OkHTTPv3 {4} pinner not found');
|
||||
//console.log(err);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Trustkit (triple bypass) //
|
||||
//////////////////////////////
|
||||
try {
|
||||
// Bypass Trustkit {1}
|
||||
var trustkit_Activity_1 = Java.use('com.datatheorem.android.trustkit.pinning.OkHostnameVerifier');
|
||||
trustkit_Activity_1.verify.overload('java.lang.String', 'javax.net.ssl.SSLSession').implementation = function(a, b) {
|
||||
console.log('[+] Bypassing Trustkit {1}: ' + a);
|
||||
return true;
|
||||
};
|
||||
} catch (err) {
|
||||
console.log('[-] Trustkit {1} pinner not found');
|
||||
//console.log(err);
|
||||
}
|
||||
try {
|
||||
// Bypass Trustkit {2}
|
||||
var trustkit_Activity_2 = Java.use('com.datatheorem.android.trustkit.pinning.OkHostnameVerifier');
|
||||
trustkit_Activity_2.verify.overload('java.lang.String', 'java.security.cert.X509Certificate').implementation = function(a, b) {
|
||||
console.log('[+] Bypassing Trustkit {2}: ' + a);
|
||||
return true;
|
||||
};
|
||||
} catch (err) {
|
||||
console.log('[-] Trustkit {2} pinner not found');
|
||||
//console.log(err);
|
||||
}
|
||||
try {
|
||||
// Bypass Trustkit {3}
|
||||
var trustkit_PinningTrustManager = Java.use('com.datatheorem.android.trustkit.pinning.PinningTrustManager');
|
||||
trustkit_PinningTrustManager.checkServerTrusted.overload('[Ljava.security.cert.X509Certificate;', 'java.lang.String').implementation = function(chain, authType) {
|
||||
console.log('[+] Bypassing Trustkit {3}');
|
||||
//return;
|
||||
};
|
||||
} catch (err) {
|
||||
console.log('[-] Trustkit {3} pinner not found');
|
||||
//console.log(err);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// TrustManagerImpl (Android > 7) //
|
||||
////////////////////////////////////
|
||||
try {
|
||||
// Bypass TrustManagerImpl (Android > 7) {1}
|
||||
var array_list = Java.use("java.util.ArrayList");
|
||||
var TrustManagerImpl_Activity_1 = Java.use('com.android.org.conscrypt.TrustManagerImpl');
|
||||
TrustManagerImpl_Activity_1.checkTrustedRecursive.implementation = function(certs, ocspData, tlsSctData, host, clientAuth, untrustedChain, trustAnchorChain, used) {
|
||||
console.log('[+] Bypassing TrustManagerImpl (Android > 7) checkTrustedRecursive check: '+ host);
|
||||
return array_list.$new();
|
||||
};
|
||||
} catch (err) {
|
||||
console.log('[-] TrustManagerImpl (Android > 7) checkTrustedRecursive check not found');
|
||||
//console.log(err);
|
||||
}
|
||||
try {
|
||||
// Bypass TrustManagerImpl (Android > 7) {2} (probably no more necessary)
|
||||
var TrustManagerImpl_Activity_2 = Java.use('com.android.org.conscrypt.TrustManagerImpl');
|
||||
TrustManagerImpl_Activity_2.verifyChain.implementation = function(untrustedChain, trustAnchorChain, host, clientAuth, ocspData, tlsSctData) {
|
||||
console.log('[+] Bypassing TrustManagerImpl (Android > 7) verifyChain check: ' + host);
|
||||
return untrustedChain;
|
||||
};
|
||||
} catch (err) {
|
||||
console.log('[-] TrustManagerImpl (Android > 7) verifyChain check not found');
|
||||
//console.log(err);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Appcelerator Titanium PinningTrustManager //
|
||||
///////////////////////////////////////////////
|
||||
try {
|
||||
var appcelerator_PinningTrustManager = Java.use('appcelerator.https.PinningTrustManager');
|
||||
appcelerator_PinningTrustManager.checkServerTrusted.implementation = function(chain, authType) {
|
||||
console.log('[+] Bypassing Appcelerator PinningTrustManager');
|
||||
return;
|
||||
};
|
||||
} catch (err) {
|
||||
console.log('[-] Appcelerator PinningTrustManager pinner not found');
|
||||
//console.log(err);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Fabric PinningTrustManager //
|
||||
////////////////////////////////
|
||||
try {
|
||||
var fabric_PinningTrustManager = Java.use('io.fabric.sdk.android.services.network.PinningTrustManager');
|
||||
fabric_PinningTrustManager.checkServerTrusted.implementation = function(chain, authType) {
|
||||
console.log('[+] Bypassing Fabric PinningTrustManager');
|
||||
return;
|
||||
};
|
||||
} catch (err) {
|
||||
console.log('[-] Fabric PinningTrustManager pinner not found');
|
||||
//console.log(err);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// OpenSSLSocketImpl Conscrypt (double bypass) //
|
||||
/////////////////////////////////////////////////
|
||||
try {
|
||||
var OpenSSLSocketImpl = Java.use('com.android.org.conscrypt.OpenSSLSocketImpl');
|
||||
OpenSSLSocketImpl.verifyCertificateChain.implementation = function(certRefs, JavaObject, authMethod) {
|
||||
console.log('[+] Bypassing OpenSSLSocketImpl Conscrypt {1}');
|
||||
};
|
||||
} catch (err) {
|
||||
console.log('[-] OpenSSLSocketImpl Conscrypt {1} pinner not found');
|
||||
//console.log(err);
|
||||
}
|
||||
try {
|
||||
var OpenSSLSocketImpl = Java.use('com.android.org.conscrypt.OpenSSLSocketImpl');
|
||||
OpenSSLSocketImpl.verifyCertificateChain.implementation = function(certChain, authMethod) {
|
||||
console.log('[+] Bypassing OpenSSLSocketImpl Conscrypt {2}');
|
||||
};
|
||||
} catch (err) {
|
||||
console.log('[-] OpenSSLSocketImpl Conscrypt {2} pinner not found');
|
||||
//console.log(err);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// OpenSSLEngineSocketImpl Conscrypt //
|
||||
///////////////////////////////////////
|
||||
try {
|
||||
var OpenSSLEngineSocketImpl_Activity = Java.use('com.android.org.conscrypt.OpenSSLEngineSocketImpl');
|
||||
OpenSSLEngineSocketImpl_Activity.verifyCertificateChain.overload('[Ljava.lang.Long;', 'java.lang.String').implementation = function(a, b) {
|
||||
console.log('[+] Bypassing OpenSSLEngineSocketImpl Conscrypt: ' + b);
|
||||
};
|
||||
} catch (err) {
|
||||
console.log('[-] OpenSSLEngineSocketImpl Conscrypt pinner not found');
|
||||
//console.log(err);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// OpenSSLSocketImpl Apache Harmony //
|
||||
//////////////////////////////////////
|
||||
try {
|
||||
var OpenSSLSocketImpl_Harmony = Java.use('org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl');
|
||||
OpenSSLSocketImpl_Harmony.verifyCertificateChain.implementation = function(asn1DerEncodedCertificateChain, authMethod) {
|
||||
console.log('[+] Bypassing OpenSSLSocketImpl Apache Harmony');
|
||||
};
|
||||
} catch (err) {
|
||||
console.log('[-] OpenSSLSocketImpl Apache Harmony pinner not found');
|
||||
//console.log(err);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// PhoneGap sslCertificateChecker //
|
||||
////////////////////////////////////
|
||||
try {
|
||||
var phonegap_Activity = Java.use('nl.xservices.plugins.sslCertificateChecker');
|
||||
phonegap_Activity.execute.overload('java.lang.String', 'org.json.JSONArray', 'org.apache.cordova.CallbackContext').implementation = function(a, b, c) {
|
||||
console.log('[+] Bypassing PhoneGap sslCertificateChecker: ' + a);
|
||||
return true;
|
||||
};
|
||||
} catch (err) {
|
||||
console.log('[-] PhoneGap sslCertificateChecker pinner not found');
|
||||
//console.log(err);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// IBM MobileFirst pinTrustedCertificatePublicKey (double bypass) //
|
||||
////////////////////////////////////////////////////////////////////
|
||||
try {
|
||||
// Bypass IBM MobileFirst {1}
|
||||
var WLClient_Activity_1 = Java.use('com.worklight.wlclient.api.WLClient');
|
||||
WLClient_Activity_1.getInstance().pinTrustedCertificatePublicKey.overload('java.lang.String').implementation = function(cert) {
|
||||
console.log('[+] Bypassing IBM MobileFirst pinTrustedCertificatePublicKey {1}: ' + cert);
|
||||
return;
|
||||
};
|
||||
} catch (err) {
|
||||
console.log('[-] IBM MobileFirst pinTrustedCertificatePublicKey {1} pinner not found');
|
||||
//console.log(err);
|
||||
}
|
||||
try {
|
||||
// Bypass IBM MobileFirst {2}
|
||||
var WLClient_Activity_2 = Java.use('com.worklight.wlclient.api.WLClient');
|
||||
WLClient_Activity_2.getInstance().pinTrustedCertificatePublicKey.overload('[Ljava.lang.String;').implementation = function(cert) {
|
||||
console.log('[+] Bypassing IBM MobileFirst pinTrustedCertificatePublicKey {2}: ' + cert);
|
||||
return;
|
||||
};
|
||||
} catch (err) {
|
||||
console.log('[-] IBM MobileFirst pinTrustedCertificatePublicKey {2} pinner not found');
|
||||
//console.log(err);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// IBM WorkLight (ancestor of MobileFirst) HostNameVerifierWithCertificatePinning (quadruple bypass) //
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
try {
|
||||
// Bypass IBM WorkLight {1}
|
||||
var worklight_Activity_1 = Java.use('com.worklight.wlclient.certificatepinning.HostNameVerifierWithCertificatePinning');
|
||||
worklight_Activity_1.verify.overload('java.lang.String', 'javax.net.ssl.SSLSocket').implementation = function(a, b) {
|
||||
console.log('[+] Bypassing IBM WorkLight HostNameVerifierWithCertificatePinning {1}: ' + a);
|
||||
return;
|
||||
};
|
||||
} catch (err) {
|
||||
console.log('[-] IBM WorkLight HostNameVerifierWithCertificatePinning {1} pinner not found');
|
||||
//console.log(err);
|
||||
}
|
||||
try {
|
||||
// Bypass IBM WorkLight {2}
|
||||
var worklight_Activity_2 = Java.use('com.worklight.wlclient.certificatepinning.HostNameVerifierWithCertificatePinning');
|
||||
worklight_Activity_2.verify.overload('java.lang.String', 'java.security.cert.X509Certificate').implementation = function(a, b) {
|
||||
console.log('[+] Bypassing IBM WorkLight HostNameVerifierWithCertificatePinning {2}: ' + a);
|
||||
return;
|
||||
};
|
||||
} catch (err) {
|
||||
console.log('[-] IBM WorkLight HostNameVerifierWithCertificatePinning {2} pinner not found');
|
||||
//console.log(err);
|
||||
}
|
||||
try {
|
||||
// Bypass IBM WorkLight {3}
|
||||
var worklight_Activity_3 = Java.use('com.worklight.wlclient.certificatepinning.HostNameVerifierWithCertificatePinning');
|
||||
worklight_Activity_3.verify.overload('java.lang.String', '[Ljava.lang.String;', '[Ljava.lang.String;').implementation = function(a, b) {
|
||||
console.log('[+] Bypassing IBM WorkLight HostNameVerifierWithCertificatePinning {3}: ' + a);
|
||||
return;
|
||||
};
|
||||
} catch (err) {
|
||||
console.log('[-] IBM WorkLight HostNameVerifierWithCertificatePinning {3} pinner not found');
|
||||
//console.log(err);
|
||||
}
|
||||
try {
|
||||
// Bypass IBM WorkLight {4}
|
||||
var worklight_Activity_4 = Java.use('com.worklight.wlclient.certificatepinning.HostNameVerifierWithCertificatePinning');
|
||||
worklight_Activity_4.verify.overload('java.lang.String', 'javax.net.ssl.SSLSession').implementation = function(a, b) {
|
||||
console.log('[+] Bypassing IBM WorkLight HostNameVerifierWithCertificatePinning {4}: ' + a);
|
||||
return true;
|
||||
};
|
||||
} catch (err) {
|
||||
console.log('[-] IBM WorkLight HostNameVerifierWithCertificatePinning {4} pinner not found');
|
||||
//console.log(err);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Conscrypt CertPinManager //
|
||||
//////////////////////////////
|
||||
try {
|
||||
var conscrypt_CertPinManager_Activity = Java.use('com.android.org.conscrypt.CertPinManager');
|
||||
conscrypt_CertPinManager_Activity.checkChainPinning.overload('java.lang.String', 'java.util.List').implementation = function(a, b) {
|
||||
console.log('[+] Bypassing Conscrypt CertPinManager: ' + a);
|
||||
//return;
|
||||
return true;
|
||||
};
|
||||
} catch (err) {
|
||||
console.log('[-] Conscrypt CertPinManager pinner not found');
|
||||
//console.log(err);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Conscrypt CertPinManager (Legacy) //
|
||||
///////////////////////////////////////
|
||||
try {
|
||||
var legacy_conscrypt_CertPinManager_Activity = Java.use('com.android.org.conscrypt.CertPinManager');
|
||||
legacy_conscrypt_CertPinManager_Activity.isChainValid.overload('java.lang.String', 'java.util.List').implementation = function(a, b) {
|
||||
console.log('[+] Bypassing Conscrypt CertPinManager (Legacy): ' + a);
|
||||
return true;
|
||||
};
|
||||
} catch (err) {
|
||||
console.log('[-] Conscrypt CertPinManager (Legacy) pinner not found');
|
||||
//console.log(err);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// CWAC-Netsecurity (unofficial back-port pinner for Android<4.2) CertPinManager //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
try {
|
||||
var cwac_CertPinManager_Activity = Java.use('com.commonsware.cwac.netsecurity.conscrypt.CertPinManager');
|
||||
cwac_CertPinManager_Activity.isChainValid.overload('java.lang.String', 'java.util.List').implementation = function(a, b) {
|
||||
console.log('[+] Bypassing CWAC-Netsecurity CertPinManager: ' + a);
|
||||
return true;
|
||||
};
|
||||
} catch (err) {
|
||||
console.log('[-] CWAC-Netsecurity CertPinManager pinner not found');
|
||||
//console.log(err);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Worklight Androidgap WLCertificatePinningPlugin //
|
||||
/////////////////////////////////////////////////////
|
||||
try {
|
||||
var androidgap_WLCertificatePinningPlugin_Activity = Java.use('com.worklight.androidgap.plugin.WLCertificatePinningPlugin');
|
||||
androidgap_WLCertificatePinningPlugin_Activity.execute.overload('java.lang.String', 'org.json.JSONArray', 'org.apache.cordova.CallbackContext').implementation = function(a, b, c) {
|
||||
console.log('[+] Bypassing Worklight Androidgap WLCertificatePinningPlugin: ' + a);
|
||||
return true;
|
||||
};
|
||||
} catch (err) {
|
||||
console.log('[-] Worklight Androidgap WLCertificatePinningPlugin pinner not found');
|
||||
//console.log(err);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Netty FingerprintTrustManagerFactory //
|
||||
//////////////////////////////////////////
|
||||
try {
|
||||
var netty_FingerprintTrustManagerFactory = Java.use('io.netty.handler.ssl.util.FingerprintTrustManagerFactory');
|
||||
//NOTE: sometimes this below implementation could be useful
|
||||
//var netty_FingerprintTrustManagerFactory = Java.use('org.jboss.netty.handler.ssl.util.FingerprintTrustManagerFactory');
|
||||
netty_FingerprintTrustManagerFactory.checkTrusted.implementation = function(type, chain) {
|
||||
console.log('[+] Bypassing Netty FingerprintTrustManagerFactory');
|
||||
};
|
||||
} catch (err) {
|
||||
console.log('[-] Netty FingerprintTrustManagerFactory pinner not found');
|
||||
//console.log(err);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Squareup CertificatePinner [OkHTTP<v3] (double bypass) //
|
||||
////////////////////////////////////////////////////////////
|
||||
try {
|
||||
// Bypass Squareup CertificatePinner {1}
|
||||
var Squareup_CertificatePinner_Activity_1 = Java.use('com.squareup.okhttp.CertificatePinner');
|
||||
Squareup_CertificatePinner_Activity_1.check.overload('java.lang.String', 'java.security.cert.Certificate').implementation = function(a, b) {
|
||||
console.log('[+] Bypassing Squareup CertificatePinner {1}: ' + a);
|
||||
return;
|
||||
};
|
||||
} catch (err) {
|
||||
console.log('[-] Squareup CertificatePinner {1} pinner not found');
|
||||
//console.log(err);
|
||||
}
|
||||
try {
|
||||
// Bypass Squareup CertificatePinner {2}
|
||||
var Squareup_CertificatePinner_Activity_2 = Java.use('com.squareup.okhttp.CertificatePinner');
|
||||
Squareup_CertificatePinner_Activity_2.check.overload('java.lang.String', 'java.util.List').implementation = function(a, b) {
|
||||
console.log('[+] Bypassing Squareup CertificatePinner {2}: ' + a);
|
||||
return;
|
||||
};
|
||||
} catch (err) {
|
||||
console.log('[-] Squareup CertificatePinner {2} pinner not found');
|
||||
//console.log(err);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Squareup OkHostnameVerifier [OkHTTP v3] (double bypass) //
|
||||
/////////////////////////////////////////////////////////////
|
||||
try {
|
||||
// Bypass Squareup OkHostnameVerifier {1}
|
||||
var Squareup_OkHostnameVerifier_Activity_1 = Java.use('com.squareup.okhttp.internal.tls.OkHostnameVerifier');
|
||||
Squareup_OkHostnameVerifier_Activity_1.verify.overload('java.lang.String', 'java.security.cert.X509Certificate').implementation = function(a, b) {
|
||||
console.log('[+] Bypassing Squareup OkHostnameVerifier {1}: ' + a);
|
||||
return true;
|
||||
};
|
||||
} catch (err) {
|
||||
console.log('[-] Squareup OkHostnameVerifier check not found');
|
||||
//console.log(err);
|
||||
}
|
||||
try {
|
||||
// Bypass Squareup OkHostnameVerifier {2}
|
||||
var Squareup_OkHostnameVerifier_Activity_2 = Java.use('com.squareup.okhttp.internal.tls.OkHostnameVerifier');
|
||||
Squareup_OkHostnameVerifier_Activity_2.verify.overload('java.lang.String', 'javax.net.ssl.SSLSession').implementation = function(a, b) {
|
||||
console.log('[+] Bypassing Squareup OkHostnameVerifier {2}: ' + a);
|
||||
return true;
|
||||
};
|
||||
} catch (err) {
|
||||
console.log('[-] Squareup OkHostnameVerifier check not found');
|
||||
//console.log(err);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Android WebViewClient (quadruple bypass) //
|
||||
//////////////////////////////////////////////
|
||||
try {
|
||||
// Bypass WebViewClient {1} (deprecated from Android 6)
|
||||
var AndroidWebViewClient_Activity_1 = Java.use('android.webkit.WebViewClient');
|
||||
AndroidWebViewClient_Activity_1.onReceivedSslError.overload('android.webkit.WebView', 'android.webkit.SslErrorHandler', 'android.net.http.SslError').implementation = function(obj1, obj2, obj3) {
|
||||
console.log('[+] Bypassing Android WebViewClient check {1}');
|
||||
};
|
||||
} catch (err) {
|
||||
console.log('[-] Android WebViewClient {1} check not found');
|
||||
//console.log(err)
|
||||
}
|
||||
try {
|
||||
// Bypass WebViewClient {2}
|
||||
var AndroidWebViewClient_Activity_2 = Java.use('android.webkit.WebViewClient');
|
||||
AndroidWebViewClient_Activity_2.onReceivedSslError.overload('android.webkit.WebView', 'android.webkit.WebResourceRequest', 'android.webkit.WebResourceError').implementation = function(obj1, obj2, obj3) {
|
||||
console.log('[+] Bypassing Android WebViewClient check {2}');
|
||||
};
|
||||
} catch (err) {
|
||||
console.log('[-] Android WebViewClient {2} check not found');
|
||||
//console.log(err)
|
||||
}
|
||||
try {
|
||||
// Bypass WebViewClient {3}
|
||||
var AndroidWebViewClient_Activity_3 = Java.use('android.webkit.WebViewClient');
|
||||
AndroidWebViewClient_Activity_3.onReceivedError.overload('android.webkit.WebView', 'int', 'java.lang.String', 'java.lang.String').implementation = function(obj1, obj2, obj3, obj4) {
|
||||
console.log('[+] Bypassing Android WebViewClient check {3}');
|
||||
};
|
||||
} catch (err) {
|
||||
console.log('[-] Android WebViewClient {3} check not found');
|
||||
//console.log(err)
|
||||
}
|
||||
try {
|
||||
// Bypass WebViewClient {4}
|
||||
var AndroidWebViewClient_Activity_4 = Java.use('android.webkit.WebViewClient');
|
||||
AndroidWebViewClient_Activity_4.onReceivedError.overload('android.webkit.WebView', 'android.webkit.WebResourceRequest', 'android.webkit.WebResourceError').implementation = function(obj1, obj2, obj3) {
|
||||
console.log('[+] Bypassing Android WebViewClient check {4}');
|
||||
};
|
||||
} catch (err) {
|
||||
console.log('[-] Android WebViewClient {4} check not found');
|
||||
//console.log(err)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Apache Cordova WebViewClient //
|
||||
//////////////////////////////////
|
||||
try {
|
||||
var CordovaWebViewClient_Activity = Java.use('org.apache.cordova.CordovaWebViewClient');
|
||||
CordovaWebViewClient_Activity.onReceivedSslError.overload('android.webkit.WebView', 'android.webkit.SslErrorHandler', 'android.net.http.SslError').implementation = function(obj1, obj2, obj3) {
|
||||
console.log('[+] Bypassing Apache Cordova WebViewClient check');
|
||||
obj3.proceed();
|
||||
};
|
||||
} catch (err) {
|
||||
console.log('[-] Apache Cordova WebViewClient check not found');
|
||||
//console.log(err);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Boye AbstractVerifier //
|
||||
///////////////////////////
|
||||
try {
|
||||
var boye_AbstractVerifier = Java.use('ch.boye.httpclientandroidlib.conn.ssl.AbstractVerifier');
|
||||
boye_AbstractVerifier.verify.implementation = function(host, ssl) {
|
||||
console.log('[+] Bypassing Boye AbstractVerifier check: ' + host);
|
||||
};
|
||||
} catch (err) {
|
||||
console.log('[-] Boye AbstractVerifier check not found');
|
||||
//console.log(err);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Apache AbstractVerifier //
|
||||
/////////////////////////////
|
||||
try {
|
||||
var apache_AbstractVerifier = Java.use('org.apache.http.conn.ssl.AbstractVerifier');
|
||||
apache_AbstractVerifier.verify.implementation = function(a, b, c, d) {
|
||||
console.log('[+] Bypassing Apache AbstractVerifier check: ' + a);
|
||||
return;
|
||||
};
|
||||
} catch (err) {
|
||||
console.log('[-] Apache AbstractVerifier check not found');
|
||||
//console.log(err);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Chromium Cronet //
|
||||
/////////////////////
|
||||
try {
|
||||
var CronetEngineBuilderImpl_Activity = Java.use("org.chromium.net.impl.CronetEngineBuilderImpl");
|
||||
// Setting argument to TRUE (default is TRUE) to disable Public Key pinning for local trust anchors
|
||||
CronetEngine_Activity.enablePublicKeyPinningBypassForLocalTrustAnchors.overload('boolean').implementation = function(a) {
|
||||
console.log("[+] Disabling Public Key pinning for local trust anchors in Chromium Cronet");
|
||||
var cronet_obj_1 = CronetEngine_Activity.enablePublicKeyPinningBypassForLocalTrustAnchors.call(this, true);
|
||||
return cronet_obj_1;
|
||||
};
|
||||
// Bypassing Chromium Cronet pinner
|
||||
CronetEngine_Activity.addPublicKeyPins.overload('java.lang.String', 'java.util.Set', 'boolean', 'java.util.Date').implementation = function(hostName, pinsSha256, includeSubdomains, expirationDate) {
|
||||
console.log("[+] Bypassing Chromium Cronet pinner: " + hostName);
|
||||
var cronet_obj_2 = CronetEngine_Activity.addPublicKeyPins.call(this, hostName, pinsSha256, includeSubdomains, expirationDate);
|
||||
return cronet_obj_2;
|
||||
};
|
||||
} catch (err) {
|
||||
console.log('[-] Chromium Cronet pinner not found')
|
||||
//console.log(err);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Flutter Pinning packages http_certificate_pinning and ssl_pinning_plugin (double bypass) //
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
try {
|
||||
// Bypass HttpCertificatePinning.check {1}
|
||||
var HttpCertificatePinning_Activity = Java.use('diefferson.http_certificate_pinning.HttpCertificatePinning');
|
||||
HttpCertificatePinning_Activity.checkConnexion.overload("java.lang.String", "java.util.List", "java.util.Map", "int", "java.lang.String").implementation = function (a, b, c ,d, e) {
|
||||
console.log('[+] Bypassing Flutter HttpCertificatePinning : ' + a);
|
||||
return true;
|
||||
};
|
||||
} catch (err) {
|
||||
console.log('[-] Flutter HttpCertificatePinning pinner not found');
|
||||
//console.log(err);
|
||||
}
|
||||
try {
|
||||
// Bypass SslPinningPlugin.check {2}
|
||||
var SslPinningPlugin_Activity = Java.use('com.macif.plugin.sslpinningplugin.SslPinningPlugin');
|
||||
SslPinningPlugin_Activity.checkConnexion.overload("java.lang.String", "java.util.List", "java.util.Map", "int", "java.lang.String").implementation = function (a, b, c ,d, e) {
|
||||
console.log('[+] Bypassing Flutter SslPinningPlugin: ' + a);
|
||||
return true;
|
||||
};
|
||||
} catch (err) {
|
||||
console.log('[-] Flutter SslPinningPlugin pinner not found');
|
||||
//console.log(err);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Dynamic SSLPeerUnverifiedException Patcher //
|
||||
// An useful technique to bypass SSLPeerUnverifiedException failures raising //
|
||||
// when the Android app uses some uncommon SSL Pinning methods or an heavily //
|
||||
// code obfuscation. Inspired by an idea of: https://github.com/httptoolkit //
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
function rudimentaryFix(typeName) {
|
||||
// This is a improvable rudimentary fix, if not works you can patch it manually
|
||||
if (typeName === undefined){
|
||||
return;
|
||||
} else if (typeName === 'boolean') {
|
||||
return true;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
try {
|
||||
var UnverifiedCertError = Java.use('javax.net.ssl.SSLPeerUnverifiedException');
|
||||
UnverifiedCertError.$init.implementation = function (str) {
|
||||
console.log('\x1b[36m[!] Unexpected SSLPeerUnverifiedException occurred, trying to patch it dynamically...\x1b[0m');
|
||||
try {
|
||||
var stackTrace = Java.use('java.lang.Thread').currentThread().getStackTrace();
|
||||
var exceptionStackIndex = stackTrace.findIndex(stack =>
|
||||
stack.getClassName() === "javax.net.ssl.SSLPeerUnverifiedException"
|
||||
);
|
||||
// Retrieve the method raising the SSLPeerUnverifiedException
|
||||
var callingFunctionStack = stackTrace[exceptionStackIndex + 1];
|
||||
var className = callingFunctionStack.getClassName();
|
||||
var methodName = callingFunctionStack.getMethodName();
|
||||
var callingClass = Java.use(className);
|
||||
var callingMethod = callingClass[methodName];
|
||||
console.log('\x1b[36m[!] Attempting to bypass uncommon SSL Pinning method on: '+className+'.'+methodName+'\x1b[0m');
|
||||
// Skip it when already patched by Frida
|
||||
if (callingMethod.implementation) {
|
||||
return;
|
||||
}
|
||||
// Trying to patch the uncommon SSL Pinning method via implementation
|
||||
var returnTypeName = callingMethod.returnType.type;
|
||||
callingMethod.implementation = function() {
|
||||
rudimentaryFix(returnTypeName);
|
||||
};
|
||||
} catch (e) {
|
||||
// Dynamic patching via implementation does not works, then trying via function overloading
|
||||
//console.log('[!] The uncommon SSL Pinning method has more than one overload);
|
||||
if (String(e).includes(".overload")) {
|
||||
var splittedList = String(e).split(".overload");
|
||||
for (let i=2; i<splittedList.length; i++) {
|
||||
var extractedOverload = splittedList[i].trim().split("(")[1].slice(0,-1).replaceAll("'","");
|
||||
// Check if extractedOverload has multiple arguments
|
||||
if (extractedOverload.includes(",")) {
|
||||
// Go here if overloaded method has multiple arguments (NOTE: max 6 args are covered here)
|
||||
var argList = extractedOverload.split(", ");
|
||||
console.log('\x1b[36m[!] Attempting overload of '+className+'.'+methodName+' with arguments: '+extractedOverload+'\x1b[0m');
|
||||
if (argList.length == 2) {
|
||||
callingMethod.overload(argList[0], argList[1]).implementation = function(a,b) {
|
||||
rudimentaryFix(returnTypeName);
|
||||
}
|
||||
} else if (argNum == 3) {
|
||||
callingMethod.overload(argList[0], argList[1], argList[2]).implementation = function(a,b,c) {
|
||||
rudimentaryFix(returnTypeName);
|
||||
}
|
||||
} else if (argNum == 4) {
|
||||
callingMethod.overload(argList[0], argList[1], argList[2], argList[3]).implementation = function(a,b,c,d) {
|
||||
rudimentaryFix(returnTypeName);
|
||||
}
|
||||
} else if (argNum == 5) {
|
||||
callingMethod.overload(argList[0], argList[1], argList[2], argList[3], argList[4]).implementation = function(a,b,c,d,e) {
|
||||
rudimentaryFix(returnTypeName);
|
||||
}
|
||||
} else if (argNum == 6) {
|
||||
callingMethod.overload(argList[0], argList[1], argList[2], argList[3], argList[4], argList[5]).implementation = function(a,b,c,d,e,f) {
|
||||
rudimentaryFix(returnTypeName);
|
||||
}
|
||||
}
|
||||
// Go here if overloaded method has a single argument
|
||||
} else {
|
||||
callingMethod.overload(extractedOverload).implementation = function(a) {
|
||||
rudimentaryFix(returnTypeName);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.log('\x1b[36m[-] Failed to dynamically patch SSLPeerUnverifiedException '+e+'\x1b[0m');
|
||||
}
|
||||
}
|
||||
//console.log('\x1b[36m[+] SSLPeerUnverifiedException hooked\x1b[0m');
|
||||
return this.$init(str);
|
||||
};
|
||||
} catch (err) {
|
||||
//console.log('\x1b[36m[-] SSLPeerUnverifiedException not found\x1b[0m');
|
||||
//console.log('\x1b[36m'+err+'\x1b[0m');
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
||||
}, 0);
|
||||
|
1
frida/frida_scripts/other-enumerate.js
Normal file
1
frida/frida_scripts/other-enumerate.js
Normal file
@ -0,0 +1 @@
|
||||
Java.perform(function(){Java.enumerateLoadedClasses({"onMatch":function(className){ console.log(className) },"onComplete":function(){}})})
|
523
frida/frida_scripts/pass2.js
Normal file
523
frida/frida_scripts/pass2.js
Normal file
@ -0,0 +1,523 @@
|
||||
/*
|
||||
* This script combines, fixes & extends a long list of other scripts, most notably including:
|
||||
*
|
||||
* - https://codeshare.frida.re/@akabe1/frida-multiple-unpinning/
|
||||
* - https://codeshare.frida.re/@avltree9798/universal-android-ssl-pinning-bypass/
|
||||
* - https://pastebin.com/TVJD63uM
|
||||
*/
|
||||
|
||||
setTimeout(function () {
|
||||
Java.perform(function () {
|
||||
console.log("---");
|
||||
console.log("Unpinning Android app...");
|
||||
|
||||
/// -- Generic hook to protect against SSLPeerUnverifiedException -- ///
|
||||
|
||||
// In some cases, with unusual cert pinning approaches, or heavy obfuscation, we can't
|
||||
// match the real method & package names. This is a problem! Fortunately, we can still
|
||||
// always match built-in types, so here we spot all failures that use the built-in cert
|
||||
// error type (notably this includes OkHttp), and after the first failure, we dynamically
|
||||
// generate & inject a patch to completely disable the method that threw the error.
|
||||
try {
|
||||
const UnverifiedCertError = Java.use('javax.net.ssl.SSLPeerUnverifiedException');
|
||||
UnverifiedCertError.$init.implementation = function (str) {
|
||||
console.log(' --> Unexpected SSL verification failure, adding dynamic patch...');
|
||||
|
||||
try {
|
||||
const stackTrace = Java.use('java.lang.Thread').currentThread().getStackTrace();
|
||||
const exceptionStackIndex = stackTrace.findIndex(stack =>
|
||||
stack.getClassName() === "javax.net.ssl.SSLPeerUnverifiedException"
|
||||
);
|
||||
const callingFunctionStack = stackTrace[exceptionStackIndex + 1];
|
||||
|
||||
const className = callingFunctionStack.getClassName();
|
||||
const methodName = callingFunctionStack.getMethodName();
|
||||
|
||||
console.log(` Thrown by ${className}->${methodName}`);
|
||||
|
||||
const callingClass = Java.use(className);
|
||||
const callingMethod = callingClass[methodName];
|
||||
|
||||
if (callingMethod.implementation) return; // Already patched by Frida - skip it
|
||||
|
||||
console.log(' Attempting to patch automatically...');
|
||||
const returnTypeName = callingMethod.returnType.type;
|
||||
|
||||
callingMethod.implementation = function () {
|
||||
console.log(` --> Bypassing ${className}->${methodName} (automatic exception patch)`);
|
||||
|
||||
// This is not a perfect fix! Most unknown cases like this are really just
|
||||
// checkCert(cert) methods though, so doing nothing is perfect, and if we
|
||||
// do need an actual return value then this is probably the best we can do,
|
||||
// and at least we're logging the method name so you can patch it manually:
|
||||
|
||||
if (returnTypeName === 'void') {
|
||||
return;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
console.log(` [+] ${className}->${methodName} (automatic exception patch)`);
|
||||
} catch (e) {
|
||||
console.log(' [ ] Failed to automatically patch failure');
|
||||
}
|
||||
|
||||
return this.$init(str);
|
||||
};
|
||||
console.log('[+] SSLPeerUnverifiedException auto-patcher');
|
||||
} catch (err) {
|
||||
console.log('[ ] SSLPeerUnverifiedException auto-patcher');
|
||||
}
|
||||
|
||||
/// -- Specific targeted hooks: -- ///
|
||||
|
||||
// HttpsURLConnection
|
||||
try {
|
||||
const HttpsURLConnection = Java.use("javax.net.ssl.HttpsURLConnection");
|
||||
HttpsURLConnection.setDefaultHostnameVerifier.implementation = function (hostnameVerifier) {
|
||||
console.log(' --> Bypassing HttpsURLConnection (setDefaultHostnameVerifier)');
|
||||
return; // Do nothing, i.e. don't change the hostname verifier
|
||||
};
|
||||
console.log('[+] HttpsURLConnection (setDefaultHostnameVerifier)');
|
||||
} catch (err) {
|
||||
console.log('[ ] HttpsURLConnection (setDefaultHostnameVerifier)');
|
||||
}
|
||||
try {
|
||||
const HttpsURLConnection = Java.use("javax.net.ssl.HttpsURLConnection");
|
||||
HttpsURLConnection.setSSLSocketFactory.implementation = function (SSLSocketFactory) {
|
||||
console.log(' --> Bypassing HttpsURLConnection (setSSLSocketFactory)');
|
||||
return; // Do nothing, i.e. don't change the SSL socket factory
|
||||
};
|
||||
console.log('[+] HttpsURLConnection (setSSLSocketFactory)');
|
||||
} catch (err) {
|
||||
console.log('[ ] HttpsURLConnection (setSSLSocketFactory)');
|
||||
}
|
||||
try {
|
||||
const HttpsURLConnection = Java.use("javax.net.ssl.HttpsURLConnection");
|
||||
HttpsURLConnection.setHostnameVerifier.implementation = function (hostnameVerifier) {
|
||||
console.log(' --> Bypassing HttpsURLConnection (setHostnameVerifier)');
|
||||
return; // Do nothing, i.e. don't change the hostname verifier
|
||||
};
|
||||
console.log('[+] HttpsURLConnection (setHostnameVerifier)');
|
||||
} catch (err) {
|
||||
console.log('[ ] HttpsURLConnection (setHostnameVerifier)');
|
||||
}
|
||||
|
||||
// SSLContext
|
||||
try {
|
||||
const X509TrustManager = Java.use('javax.net.ssl.X509TrustManager');
|
||||
const SSLContext = Java.use('javax.net.ssl.SSLContext');
|
||||
|
||||
const TrustManager = Java.registerClass({
|
||||
// Implement a custom TrustManager
|
||||
name: 'dev.asd.test.TrustManager',
|
||||
implements: [X509TrustManager],
|
||||
methods: {
|
||||
checkClientTrusted: function (chain, authType) { },
|
||||
checkServerTrusted: function (chain, authType) { },
|
||||
getAcceptedIssuers: function () { return []; }
|
||||
}
|
||||
});
|
||||
|
||||
// Prepare the TrustManager array to pass to SSLContext.init()
|
||||
const TrustManagers = [TrustManager.$new()];
|
||||
|
||||
// Get a handle on the init() on the SSLContext class
|
||||
const SSLContext_init = SSLContext.init.overload(
|
||||
'[Ljavax.net.ssl.KeyManager;', '[Ljavax.net.ssl.TrustManager;', 'java.security.SecureRandom'
|
||||
);
|
||||
|
||||
// Override the init method, specifying the custom TrustManager
|
||||
SSLContext_init.implementation = function (keyManager, trustManager, secureRandom) {
|
||||
console.log(' --> Bypassing Trustmanager (Android < 7) request');
|
||||
SSLContext_init.call(this, keyManager, TrustManagers, secureRandom);
|
||||
};
|
||||
console.log('[+] SSLContext');
|
||||
} catch (err) {
|
||||
console.log('[ ] SSLContext');
|
||||
}
|
||||
|
||||
// TrustManagerImpl (Android > 7)
|
||||
try {
|
||||
const array_list = Java.use("java.util.ArrayList");
|
||||
const TrustManagerImpl = Java.use('com.android.org.conscrypt.TrustManagerImpl');
|
||||
|
||||
// This step is notably what defeats the most common case: network security config
|
||||
TrustManagerImpl.checkTrustedRecursive.implementation = function(a1, a2, a3, a4, a5, a6) {
|
||||
console.log(' --> Bypassing TrustManagerImpl checkTrusted ');
|
||||
return array_list.$new();
|
||||
}
|
||||
|
||||
TrustManagerImpl.verifyChain.implementation = function (untrustedChain, trustAnchorChain, host, clientAuth, ocspData, tlsSctData) {
|
||||
console.log(' --> Bypassing TrustManagerImpl verifyChain: ' + host);
|
||||
return untrustedChain;
|
||||
};
|
||||
console.log('[+] TrustManagerImpl');
|
||||
} catch (err) {
|
||||
console.log('[ ] TrustManagerImpl');
|
||||
}
|
||||
|
||||
// OkHTTPv3 (quadruple bypass)
|
||||
try {
|
||||
// Bypass OkHTTPv3 {1}
|
||||
const okhttp3_Activity_1 = Java.use('okhttp3.CertificatePinner');
|
||||
okhttp3_Activity_1.check.overload('java.lang.String', 'java.util.List').implementation = function (a, b) {
|
||||
console.log(' --> Bypassing OkHTTPv3 (list): ' + a);
|
||||
return;
|
||||
};
|
||||
console.log('[+] OkHTTPv3 (list)');
|
||||
} catch (err) {
|
||||
console.log('[ ] OkHTTPv3 (list)');
|
||||
}
|
||||
try {
|
||||
// Bypass OkHTTPv3 {2}
|
||||
// This method of CertificatePinner.check could be found in some old Android app
|
||||
const okhttp3_Activity_2 = Java.use('okhttp3.CertificatePinner');
|
||||
okhttp3_Activity_2.check.overload('java.lang.String', 'java.security.cert.Certificate').implementation = function (a, b) {
|
||||
console.log(' --> Bypassing OkHTTPv3 (cert): ' + a);
|
||||
return;
|
||||
};
|
||||
console.log('[+] OkHTTPv3 (cert)');
|
||||
} catch (err) {
|
||||
console.log('[ ] OkHTTPv3 (cert)');
|
||||
}
|
||||
try {
|
||||
// Bypass OkHTTPv3 {3}
|
||||
const okhttp3_Activity_3 = Java.use('okhttp3.CertificatePinner');
|
||||
okhttp3_Activity_3.check.overload('java.lang.String', '[Ljava.security.cert.Certificate;').implementation = function (a, b) {
|
||||
console.log(' --> Bypassing OkHTTPv3 (cert array): ' + a);
|
||||
return;
|
||||
};
|
||||
console.log('[+] OkHTTPv3 (cert array)');
|
||||
} catch (err) {
|
||||
console.log('[ ] OkHTTPv3 (cert array)');
|
||||
}
|
||||
try {
|
||||
// Bypass OkHTTPv3 {4}
|
||||
const okhttp3_Activity_4 = Java.use('okhttp3.CertificatePinner');
|
||||
okhttp3_Activity_4['check$okhttp'].implementation = function (a, b) {
|
||||
console.log(' --> Bypassing OkHTTPv3 ($okhttp): ' + a);
|
||||
return;
|
||||
};
|
||||
console.log('[+] OkHTTPv3 ($okhttp)');
|
||||
} catch (err) {
|
||||
console.log('[ ] OkHTTPv3 ($okhttp)');
|
||||
}
|
||||
|
||||
// Trustkit (triple bypass)
|
||||
try {
|
||||
// Bypass Trustkit {1}
|
||||
const trustkit_Activity_1 = Java.use('com.datatheorem.android.trustkit.pinning.OkHostnameVerifier');
|
||||
trustkit_Activity_1.verify.overload('java.lang.String', 'javax.net.ssl.SSLSession').implementation = function (a, b) {
|
||||
console.log(' --> Bypassing Trustkit OkHostnameVerifier(SSLSession): ' + a);
|
||||
return true;
|
||||
};
|
||||
console.log('[+] Trustkit OkHostnameVerifier(SSLSession)');
|
||||
} catch (err) {
|
||||
console.log('[ ] Trustkit OkHostnameVerifier(SSLSession)');
|
||||
}
|
||||
try {
|
||||
// Bypass Trustkit {2}
|
||||
const trustkit_Activity_2 = Java.use('com.datatheorem.android.trustkit.pinning.OkHostnameVerifier');
|
||||
trustkit_Activity_2.verify.overload('java.lang.String', 'java.security.cert.X509Certificate').implementation = function (a, b) {
|
||||
console.log(' --> Bypassing Trustkit OkHostnameVerifier(cert): ' + a);
|
||||
return true;
|
||||
};
|
||||
console.log('[+] Trustkit OkHostnameVerifier(cert)');
|
||||
} catch (err) {
|
||||
console.log('[ ] Trustkit OkHostnameVerifier(cert)');
|
||||
}
|
||||
try {
|
||||
// Bypass Trustkit {3}
|
||||
const trustkit_PinningTrustManager = Java.use('com.datatheorem.android.trustkit.pinning.PinningTrustManager');
|
||||
trustkit_PinningTrustManager.checkServerTrusted.implementation = function () {
|
||||
console.log(' --> Bypassing Trustkit PinningTrustManager');
|
||||
};
|
||||
console.log('[+] Trustkit PinningTrustManager');
|
||||
} catch (err) {
|
||||
console.log('[ ] Trustkit PinningTrustManager');
|
||||
}
|
||||
|
||||
// Appcelerator Titanium
|
||||
try {
|
||||
const appcelerator_PinningTrustManager = Java.use('appcelerator.https.PinningTrustManager');
|
||||
appcelerator_PinningTrustManager.checkServerTrusted.implementation = function () {
|
||||
console.log(' --> Bypassing Appcelerator PinningTrustManager');
|
||||
};
|
||||
console.log('[+] Appcelerator PinningTrustManager');
|
||||
} catch (err) {
|
||||
console.log('[ ] Appcelerator PinningTrustManager');
|
||||
}
|
||||
|
||||
// OpenSSLSocketImpl Conscrypt
|
||||
try {
|
||||
const OpenSSLSocketImpl = Java.use('com.android.org.conscrypt.OpenSSLSocketImpl');
|
||||
OpenSSLSocketImpl.verifyCertificateChain.implementation = function (certRefs, JavaObject, authMethod) {
|
||||
console.log(' --> Bypassing OpenSSLSocketImpl Conscrypt');
|
||||
};
|
||||
console.log('[+] OpenSSLSocketImpl Conscrypt');
|
||||
} catch (err) {
|
||||
console.log('[ ] OpenSSLSocketImpl Conscrypt');
|
||||
}
|
||||
|
||||
// OpenSSLEngineSocketImpl Conscrypt
|
||||
try {
|
||||
const OpenSSLEngineSocketImpl_Activity = Java.use('com.android.org.conscrypt.OpenSSLEngineSocketImpl');
|
||||
OpenSSLEngineSocketImpl_Activity.verifyCertificateChain.overload('[Ljava.lang.Long;', 'java.lang.String').implementation = function (a, b) {
|
||||
console.log(' --> Bypassing OpenSSLEngineSocketImpl Conscrypt: ' + b);
|
||||
};
|
||||
console.log('[+] OpenSSLEngineSocketImpl Conscrypt');
|
||||
} catch (err) {
|
||||
console.log('[ ] OpenSSLEngineSocketImpl Conscrypt');
|
||||
}
|
||||
|
||||
// OpenSSLSocketImpl Apache Harmony
|
||||
try {
|
||||
const OpenSSLSocketImpl_Harmony = Java.use('org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl');
|
||||
OpenSSLSocketImpl_Harmony.verifyCertificateChain.implementation = function (asn1DerEncodedCertificateChain, authMethod) {
|
||||
console.log(' --> Bypassing OpenSSLSocketImpl Apache Harmony');
|
||||
};
|
||||
console.log('[+] OpenSSLSocketImpl Apache Harmony');
|
||||
} catch (err) {
|
||||
console.log('[ ] OpenSSLSocketImpl Apache Harmony');
|
||||
}
|
||||
|
||||
// PhoneGap sslCertificateChecker (https://github.com/EddyVerbruggen/SSLCertificateChecker-PhoneGap-Plugin)
|
||||
try {
|
||||
const phonegap_Activity = Java.use('nl.xservices.plugins.sslCertificateChecker');
|
||||
phonegap_Activity.execute.overload('java.lang.String', 'org.json.JSONArray', 'org.apache.cordova.CallbackContext').implementation = function (a, b, c) {
|
||||
console.log(' --> Bypassing PhoneGap sslCertificateChecker: ' + a);
|
||||
return true;
|
||||
};
|
||||
console.log('[+] PhoneGap sslCertificateChecker');
|
||||
} catch (err) {
|
||||
console.log('[ ] PhoneGap sslCertificateChecker');
|
||||
}
|
||||
|
||||
// IBM MobileFirst pinTrustedCertificatePublicKey (double bypass)
|
||||
try {
|
||||
// Bypass IBM MobileFirst {1}
|
||||
const WLClient_Activity_1 = Java.use('com.worklight.wlclient.api.WLClient');
|
||||
WLClient_Activity_1.getInstance().pinTrustedCertificatePublicKey.overload('java.lang.String').implementation = function (cert) {
|
||||
console.log(' --> Bypassing IBM MobileFirst pinTrustedCertificatePublicKey (string): ' + cert);
|
||||
return;
|
||||
};
|
||||
console.log('[+] IBM MobileFirst pinTrustedCertificatePublicKey (string)');
|
||||
} catch (err) {
|
||||
console.log('[ ] IBM MobileFirst pinTrustedCertificatePublicKey (string)');
|
||||
}
|
||||
try {
|
||||
// Bypass IBM MobileFirst {2}
|
||||
const WLClient_Activity_2 = Java.use('com.worklight.wlclient.api.WLClient');
|
||||
WLClient_Activity_2.getInstance().pinTrustedCertificatePublicKey.overload('[Ljava.lang.String;').implementation = function (cert) {
|
||||
console.log(' --> Bypassing IBM MobileFirst pinTrustedCertificatePublicKey (string array): ' + cert);
|
||||
return;
|
||||
};
|
||||
console.log('[+] IBM MobileFirst pinTrustedCertificatePublicKey (string array)');
|
||||
} catch (err) {
|
||||
console.log('[ ] IBM MobileFirst pinTrustedCertificatePublicKey (string array)');
|
||||
}
|
||||
|
||||
// IBM WorkLight (ancestor of MobileFirst) HostNameVerifierWithCertificatePinning (quadruple bypass)
|
||||
try {
|
||||
// Bypass IBM WorkLight {1}
|
||||
const worklight_Activity_1 = Java.use('com.worklight.wlclient.certificatepinning.HostNameVerifierWithCertificatePinning');
|
||||
worklight_Activity_1.verify.overload('java.lang.String', 'javax.net.ssl.SSLSocket').implementation = function (a, b) {
|
||||
console.log(' --> Bypassing IBM WorkLight HostNameVerifierWithCertificatePinning (SSLSocket): ' + a);
|
||||
return;
|
||||
};
|
||||
console.log('[+] IBM WorkLight HostNameVerifierWithCertificatePinning (SSLSocket)');
|
||||
} catch (err) {
|
||||
console.log('[ ] IBM WorkLight HostNameVerifierWithCertificatePinning (SSLSocket)');
|
||||
}
|
||||
try {
|
||||
// Bypass IBM WorkLight {2}
|
||||
const worklight_Activity_2 = Java.use('com.worklight.wlclient.certificatepinning.HostNameVerifierWithCertificatePinning');
|
||||
worklight_Activity_2.verify.overload('java.lang.String', 'java.security.cert.X509Certificate').implementation = function (a, b) {
|
||||
console.log(' --> Bypassing IBM WorkLight HostNameVerifierWithCertificatePinning (cert): ' + a);
|
||||
return;
|
||||
};
|
||||
console.log('[+] IBM WorkLight HostNameVerifierWithCertificatePinning (cert)');
|
||||
} catch (err) {
|
||||
console.log('[ ] IBM WorkLight HostNameVerifierWithCertificatePinning (cert)');
|
||||
}
|
||||
try {
|
||||
// Bypass IBM WorkLight {3}
|
||||
const worklight_Activity_3 = Java.use('com.worklight.wlclient.certificatepinning.HostNameVerifierWithCertificatePinning');
|
||||
worklight_Activity_3.verify.overload('java.lang.String', '[Ljava.lang.String;', '[Ljava.lang.String;').implementation = function (a, b) {
|
||||
console.log(' --> Bypassing IBM WorkLight HostNameVerifierWithCertificatePinning (string string): ' + a);
|
||||
return;
|
||||
};
|
||||
console.log('[+] IBM WorkLight HostNameVerifierWithCertificatePinning (string string)');
|
||||
} catch (err) {
|
||||
console.log('[ ] IBM WorkLight HostNameVerifierWithCertificatePinning (string string)');
|
||||
}
|
||||
try {
|
||||
// Bypass IBM WorkLight {4}
|
||||
const worklight_Activity_4 = Java.use('com.worklight.wlclient.certificatepinning.HostNameVerifierWithCertificatePinning');
|
||||
worklight_Activity_4.verify.overload('java.lang.String', 'javax.net.ssl.SSLSession').implementation = function (a, b) {
|
||||
console.log(' --> Bypassing IBM WorkLight HostNameVerifierWithCertificatePinning (SSLSession): ' + a);
|
||||
return true;
|
||||
};
|
||||
console.log('[+] IBM WorkLight HostNameVerifierWithCertificatePinning (SSLSession)');
|
||||
} catch (err) {
|
||||
console.log('[ ] IBM WorkLight HostNameVerifierWithCertificatePinning (SSLSession)');
|
||||
}
|
||||
|
||||
// Conscrypt CertPinManager
|
||||
try {
|
||||
const conscrypt_CertPinManager_Activity = Java.use('com.android.org.conscrypt.CertPinManager');
|
||||
conscrypt_CertPinManager_Activity.isChainValid.overload('java.lang.String', 'java.util.List').implementation = function (a, b) {
|
||||
console.log(' --> Bypassing Conscrypt CertPinManager: ' + a);
|
||||
return true;
|
||||
};
|
||||
console.log('[+] Conscrypt CertPinManager');
|
||||
} catch (err) {
|
||||
console.log('[ ] Conscrypt CertPinManager');
|
||||
}
|
||||
|
||||
// CWAC-Netsecurity (unofficial back-port pinner for Android<4.2) CertPinManager
|
||||
try {
|
||||
const cwac_CertPinManager_Activity = Java.use('com.commonsware.cwac.netsecurity.conscrypt.CertPinManager');
|
||||
cwac_CertPinManager_Activity.isChainValid.overload('java.lang.String', 'java.util.List').implementation = function (a, b) {
|
||||
console.log(' --> Bypassing CWAC-Netsecurity CertPinManager: ' + a);
|
||||
return true;
|
||||
};
|
||||
console.log('[+] CWAC-Netsecurity CertPinManager');
|
||||
} catch (err) {
|
||||
console.log('[ ] CWAC-Netsecurity CertPinManager');
|
||||
}
|
||||
|
||||
// Worklight Androidgap WLCertificatePinningPlugin
|
||||
try {
|
||||
const androidgap_WLCertificatePinningPlugin_Activity = Java.use('com.worklight.androidgap.plugin.WLCertificatePinningPlugin');
|
||||
androidgap_WLCertificatePinningPlugin_Activity.execute.overload('java.lang.String', 'org.json.JSONArray', 'org.apache.cordova.CallbackContext').implementation = function (a, b, c) {
|
||||
console.log(' --> Bypassing Worklight Androidgap WLCertificatePinningPlugin: ' + a);
|
||||
return true;
|
||||
};
|
||||
console.log('[+] Worklight Androidgap WLCertificatePinningPlugin');
|
||||
} catch (err) {
|
||||
console.log('[ ] Worklight Androidgap WLCertificatePinningPlugin');
|
||||
}
|
||||
|
||||
// Netty FingerprintTrustManagerFactory
|
||||
try {
|
||||
const netty_FingerprintTrustManagerFactory = Java.use('io.netty.handler.ssl.util.FingerprintTrustManagerFactory');
|
||||
netty_FingerprintTrustManagerFactory.checkTrusted.implementation = function (type, chain) {
|
||||
console.log(' --> Bypassing Netty FingerprintTrustManagerFactory');
|
||||
};
|
||||
console.log('[+] Netty FingerprintTrustManagerFactory');
|
||||
} catch (err) {
|
||||
console.log('[ ] Netty FingerprintTrustManagerFactory');
|
||||
}
|
||||
|
||||
// Squareup CertificatePinner [OkHTTP<v3] (double bypass)
|
||||
try {
|
||||
// Bypass Squareup CertificatePinner {1}
|
||||
const Squareup_CertificatePinner_Activity_1 = Java.use('com.squareup.okhttp.CertificatePinner');
|
||||
Squareup_CertificatePinner_Activity_1.check.overload('java.lang.String', 'java.security.cert.Certificate').implementation = function (a, b) {
|
||||
console.log(' --> Bypassing Squareup CertificatePinner (cert): ' + a);
|
||||
return;
|
||||
};
|
||||
console.log('[+] Squareup CertificatePinner (cert)');
|
||||
} catch (err) {
|
||||
console.log('[ ] Squareup CertificatePinner (cert)');
|
||||
}
|
||||
try {
|
||||
// Bypass Squareup CertificatePinner {2}
|
||||
const Squareup_CertificatePinner_Activity_2 = Java.use('com.squareup.okhttp.CertificatePinner');
|
||||
Squareup_CertificatePinner_Activity_2.check.overload('java.lang.String', 'java.util.List').implementation = function (a, b) {
|
||||
console.log(' --> Bypassing Squareup CertificatePinner (list): ' + a);
|
||||
return;
|
||||
};
|
||||
console.log('[+] Squareup CertificatePinner (list)');
|
||||
} catch (err) {
|
||||
console.log('[ ] Squareup CertificatePinner (list)');
|
||||
}
|
||||
|
||||
// Squareup OkHostnameVerifier [OkHTTP v3] (double bypass)
|
||||
try {
|
||||
// Bypass Squareup OkHostnameVerifier {1}
|
||||
const Squareup_OkHostnameVerifier_Activity_1 = Java.use('com.squareup.okhttp.internal.tls.OkHostnameVerifier');
|
||||
Squareup_OkHostnameVerifier_Activity_1.verify.overload('java.lang.String', 'java.security.cert.X509Certificate').implementation = function (a, b) {
|
||||
console.log(' --> Bypassing Squareup OkHostnameVerifier (cert): ' + a);
|
||||
return true;
|
||||
};
|
||||
console.log('[+] Squareup OkHostnameVerifier (cert)');
|
||||
} catch (err) {
|
||||
console.log('[ ] Squareup OkHostnameVerifier (cert)');
|
||||
}
|
||||
try {
|
||||
// Bypass Squareup OkHostnameVerifier {2}
|
||||
const Squareup_OkHostnameVerifier_Activity_2 = Java.use('com.squareup.okhttp.internal.tls.OkHostnameVerifier');
|
||||
Squareup_OkHostnameVerifier_Activity_2.verify.overload('java.lang.String', 'javax.net.ssl.SSLSession').implementation = function (a, b) {
|
||||
console.log(' --> Bypassing Squareup OkHostnameVerifier (SSLSession): ' + a);
|
||||
return true;
|
||||
};
|
||||
console.log('[+] Squareup OkHostnameVerifier (SSLSession)');
|
||||
} catch (err) {
|
||||
console.log('[ ] Squareup OkHostnameVerifier (SSLSession)');
|
||||
}
|
||||
|
||||
// Android WebViewClient (double bypass)
|
||||
try {
|
||||
// Bypass WebViewClient {1} (deprecated from Android 6)
|
||||
const AndroidWebViewClient_Activity_1 = Java.use('android.webkit.WebViewClient');
|
||||
AndroidWebViewClient_Activity_1.onReceivedSslError.overload('android.webkit.WebView', 'android.webkit.SslErrorHandler', 'android.net.http.SslError').implementation = function (obj1, obj2, obj3) {
|
||||
console.log(' --> Bypassing Android WebViewClient (SslErrorHandler)');
|
||||
};
|
||||
console.log('[+] Android WebViewClient (SslErrorHandler)');
|
||||
} catch (err) {
|
||||
console.log('[ ] Android WebViewClient (SslErrorHandler)');
|
||||
}
|
||||
try {
|
||||
// Bypass WebViewClient {2}
|
||||
const AndroidWebViewClient_Activity_2 = Java.use('android.webkit.WebViewClient');
|
||||
AndroidWebViewClient_Activity_2.onReceivedSslError.overload('android.webkit.WebView', 'android.webkit.WebResourceRequest', 'android.webkit.WebResourceError').implementation = function (obj1, obj2, obj3) {
|
||||
console.log(' --> Bypassing Android WebViewClient (WebResourceError)');
|
||||
};
|
||||
console.log('[+] Android WebViewClient (WebResourceError)');
|
||||
} catch (err) {
|
||||
console.log('[ ] Android WebViewClient (WebResourceError)');
|
||||
}
|
||||
|
||||
// Apache Cordova WebViewClient
|
||||
try {
|
||||
const CordovaWebViewClient_Activity = Java.use('org.apache.cordova.CordovaWebViewClient');
|
||||
CordovaWebViewClient_Activity.onReceivedSslError.overload('android.webkit.WebView', 'android.webkit.SslErrorHandler', 'android.net.http.SslError').implementation = function (obj1, obj2, obj3) {
|
||||
console.log(' --> Bypassing Apache Cordova WebViewClient');
|
||||
obj3.proceed();
|
||||
};
|
||||
} catch (err) {
|
||||
console.log('[ ] Apache Cordova WebViewClient');
|
||||
}
|
||||
|
||||
// Boye AbstractVerifier
|
||||
try {
|
||||
const boye_AbstractVerifier = Java.use('ch.boye.httpclientandroidlib.conn.ssl.AbstractVerifier');
|
||||
boye_AbstractVerifier.verify.implementation = function (host, ssl) {
|
||||
console.log(' --> Bypassing Boye AbstractVerifier: ' + host);
|
||||
};
|
||||
} catch (err) {
|
||||
console.log('[ ] Boye AbstractVerifier');
|
||||
}
|
||||
|
||||
// Appmattus
|
||||
try {
|
||||
const appmatus_Activity = Java.use('com.appmattus.certificatetransparency.internal.verifier.CertificateTransparencyInterceptor');
|
||||
appmatus_Activity['intercept'].implementation = function (a) {
|
||||
console.log(' --> Bypassing Appmattus (Transparency)');
|
||||
return a.proceed(a.request());
|
||||
};
|
||||
console.log('[+] Appmattus (Transparency)');
|
||||
} catch (err) {
|
||||
console.log('[ ] Appmattus (Transparency)');
|
||||
}
|
||||
|
||||
console.log("Unpinning setup completed");
|
||||
console.log("---");
|
||||
});
|
||||
|
||||
}, 0);
|
||||
|
38
frida/frida_scripts/printStrings.js
Normal file
38
frida/frida_scripts/printStrings.js
Normal file
@ -0,0 +1,38 @@
|
||||
var objc_copyClassNamesForImage = new NativeFunction(
|
||||
Module.findExportByName(null, 'objc_copyClassNamesForImage'),
|
||||
'pointer',
|
||||
['pointer', 'pointer']
|
||||
);
|
||||
var free = new NativeFunction(Module.findExportByName(null, 'free'), 'void', ['pointer']);
|
||||
var classes = new Array(count);
|
||||
var p = Memory.alloc(Process.pointerSize);
|
||||
|
||||
Memory.writeUInt(p, 0);
|
||||
|
||||
var path = ObjC.classes.NSBundle.mainBundle().executablePath().UTF8String();
|
||||
var pPath = Memory.allocUtf8String(path);
|
||||
var pClasses = objc_copyClassNamesForImage(pPath, p);
|
||||
var count = Memory.readUInt(p);
|
||||
for (var i = 0; i < count; i++) {
|
||||
var pClassName = Memory.readPointer(pClasses.add(i * Process.pointerSize));
|
||||
classes[i] = Memory.readUtf8String(pClassName);
|
||||
}
|
||||
|
||||
free(pClasses);
|
||||
|
||||
var tree = {};
|
||||
classes.forEach(function(name) {
|
||||
var clazz = ObjC.classes[name];
|
||||
var chain = [name];
|
||||
while (clazz = clazz.$superClass) {
|
||||
chain.unshift(clazz.$className);
|
||||
}
|
||||
|
||||
var node = tree;
|
||||
chain.forEach(function(clazz) {
|
||||
node[clazz] = node[clazz] || {};
|
||||
node = node[clazz];
|
||||
});
|
||||
});
|
||||
|
||||
send(tree);
|
105
frida/frida_scripts/raptor_android_enum.js
Normal file
105
frida/frida_scripts/raptor_android_enum.js
Normal file
@ -0,0 +1,105 @@
|
||||
/*
|
||||
* raptor_frida_android_enum.js - Java class/method enumerator
|
||||
* Copyright (c) 2017 Marco Ivaldi <raptor@0xdeadbeef.info>
|
||||
*
|
||||
* Frida.re JS functions to enumerate Java classes and methods
|
||||
* declared in an iOS app. See https://www.frida.re/ and
|
||||
* https://codeshare.frida.re/ for further information on this
|
||||
* powerful tool.
|
||||
*
|
||||
* "We want to help others achieve interop through reverse
|
||||
* engineering" -- @oleavr
|
||||
*
|
||||
* Example usage:
|
||||
* # frida -U -f com.target.app -l raptor_frida_android_enum.js --no-pause
|
||||
*
|
||||
* Get the latest version at:
|
||||
* https://github.com/0xdea/frida-scripts/
|
||||
*/
|
||||
|
||||
// enumerate all Java classes
|
||||
function enumAllClasses()
|
||||
{
|
||||
var allClasses = [];
|
||||
var classes = Java.enumerateLoadedClassesSync();
|
||||
|
||||
classes.forEach(function(aClass) {
|
||||
try {
|
||||
var className = aClass.match(/[L](.*);/)[1].replace(/\//g, ".");
|
||||
}
|
||||
catch(err) {return;} // avoid TypeError: cannot read property 1 of null
|
||||
allClasses.push(className);
|
||||
});
|
||||
|
||||
return allClasses;
|
||||
}
|
||||
|
||||
// find all Java classes that match a pattern
|
||||
function findClasses(pattern)
|
||||
{
|
||||
var allClasses = enumAllClasses();
|
||||
var foundClasses = [];
|
||||
|
||||
allClasses.forEach(function(aClass) {
|
||||
try {
|
||||
if (aClass.match(pattern)) {
|
||||
foundClasses.push(aClass);
|
||||
}
|
||||
}
|
||||
catch(err) {} // avoid TypeError: cannot read property 'match' of undefined
|
||||
});
|
||||
|
||||
return foundClasses;
|
||||
}
|
||||
|
||||
// enumerate all methods declared in a Java class
|
||||
function enumMethods(targetClass)
|
||||
{
|
||||
var hook = Java.use(targetClass);
|
||||
var ownMethods = hook.class.getDeclaredMethods();
|
||||
hook.$dispose;
|
||||
|
||||
return ownMethods;
|
||||
}
|
||||
|
||||
/*
|
||||
* The following functions were not implemented because deemed impractical:
|
||||
*
|
||||
* enumAllMethods() - enumerate all methods declared in all Java classes
|
||||
* findMethods(pattern) - find all Java methods that match a pattern
|
||||
*
|
||||
* See raptor_frida_ios_enum.js for a couple of ObjC implementation examples.
|
||||
*/
|
||||
|
||||
// usage examples
|
||||
setTimeout(function() { // avoid java.lang.ClassNotFoundException
|
||||
|
||||
Java.perform(function() {
|
||||
|
||||
// enumerate all classes
|
||||
///*
|
||||
var a = enumAllClasses();
|
||||
a.forEach(function(s) {
|
||||
console.log(s);
|
||||
});
|
||||
//*/
|
||||
|
||||
// find classes that match a pattern
|
||||
/*
|
||||
var a = findClasses(/password/i);
|
||||
a.forEach(function(s) {
|
||||
console.log(s);
|
||||
});
|
||||
*/
|
||||
|
||||
// enumerate all methods in a class
|
||||
/*
|
||||
var a = enumMethods("com.target.app.PasswordManager")
|
||||
a.forEach(function(s) {
|
||||
console.log(s);
|
||||
});
|
||||
*/
|
||||
|
||||
});
|
||||
}, 0);
|
||||
|
183
frida/frida_scripts/raptor_android_trace.js
Normal file
183
frida/frida_scripts/raptor_android_trace.js
Normal file
@ -0,0 +1,183 @@
|
||||
/*
|
||||
* raptor_frida_android_trace.js - Code tracer for Android
|
||||
* Copyright (c) 2017 Marco Ivaldi <raptor@0xdeadbeef.info>
|
||||
*
|
||||
* Frida.re JS script to trace arbitrary Java Methods and
|
||||
* Module functions for debugging and reverse engineering.
|
||||
* See https://www.frida.re/ and https://codeshare.frida.re/
|
||||
* for further information on this powerful tool.
|
||||
*
|
||||
* "We want to help others achieve interop through reverse
|
||||
* engineering" -- @oleavr
|
||||
*
|
||||
* Many thanks to @inode-, @federicodotta, @leonjza, and
|
||||
* @dankluev.
|
||||
*
|
||||
* Example usage:
|
||||
* # frida -U -f com.target.app -l raptor_frida_android_trace.js --no-pause
|
||||
*
|
||||
* Get the latest version at:
|
||||
* https://github.com/0xdea/frida-scripts/
|
||||
*/
|
||||
|
||||
// generic trace
|
||||
function trace(pattern)
|
||||
{
|
||||
var type = (pattern.toString().indexOf("!") === -1) ? "java" : "module";
|
||||
|
||||
if (type === "module") {
|
||||
|
||||
// trace Module
|
||||
var res = new ApiResolver("module");
|
||||
var matches = res.enumerateMatchesSync(pattern);
|
||||
var targets = uniqBy(matches, JSON.stringify);
|
||||
targets.forEach(function(target) {
|
||||
traceModule(target.address, target.name);
|
||||
});
|
||||
|
||||
} else if (type === "java") {
|
||||
|
||||
// trace Java Class
|
||||
var found = false;
|
||||
Java.enumerateLoadedClasses({
|
||||
onMatch: function(aClass) {
|
||||
if (aClass.match(pattern)) {
|
||||
found = true;
|
||||
var className = aClass.match(/[L](.*);/)[1].replace(/\//g, ".");
|
||||
traceClass(className);
|
||||
}
|
||||
},
|
||||
onComplete: function() {}
|
||||
});
|
||||
|
||||
// trace Java Method
|
||||
if (!found) {
|
||||
try {
|
||||
traceMethod(pattern);
|
||||
}
|
||||
catch(err) { // catch non existing classes/methods
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// find and trace all methods declared in a Java Class
|
||||
function traceClass(targetClass)
|
||||
{
|
||||
var hook = Java.use(targetClass);
|
||||
var methods = hook.class.getDeclaredMethods();
|
||||
hook.$dispose;
|
||||
|
||||
var parsedMethods = [];
|
||||
methods.forEach(function(method) {
|
||||
parsedMethods.push(method.toString().replace(targetClass + ".", "TOKEN").match(/\sTOKEN(.*)\(/)[1]);
|
||||
});
|
||||
|
||||
var targets = uniqBy(parsedMethods, JSON.stringify);
|
||||
targets.forEach(function(targetMethod) {
|
||||
traceMethod(targetClass + "." + targetMethod);
|
||||
});
|
||||
}
|
||||
|
||||
// trace a specific Java Method
|
||||
function traceMethod(targetClassMethod)
|
||||
{
|
||||
var delim = targetClassMethod.lastIndexOf(".");
|
||||
if (delim === -1) return;
|
||||
|
||||
var targetClass = targetClassMethod.slice(0, delim)
|
||||
var targetMethod = targetClassMethod.slice(delim + 1, targetClassMethod.length)
|
||||
|
||||
var hook = Java.use(targetClass);
|
||||
var overloadCount = hook[targetMethod].overloads.length;
|
||||
|
||||
console.log("Tracing " + targetClassMethod + " [" + overloadCount + " overload(s)]");
|
||||
|
||||
for (var i = 0; i < overloadCount; i++) {
|
||||
|
||||
hook[targetMethod].overloads[i].implementation = function() {
|
||||
console.warn("\n*** entered " + targetClassMethod);
|
||||
|
||||
// print backtrace
|
||||
// Java.perform(function() {
|
||||
// var bt = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new());
|
||||
// console.log("\nBacktrace:\n" + bt);
|
||||
// });
|
||||
|
||||
// print args
|
||||
if (arguments.length) console.log();
|
||||
for (var j = 0; j < arguments.length; j++) {
|
||||
console.log("arg[" + j + "]: " + arguments[j]);
|
||||
}
|
||||
|
||||
// print retval
|
||||
var retval = this[targetMethod].apply(this, arguments); // rare crash (Frida bug?)
|
||||
console.log("\nretval: " + retval);
|
||||
console.warn("\n*** exiting " + targetClassMethod);
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// trace Module functions
|
||||
function traceModule(impl, name)
|
||||
{
|
||||
console.log("Tracing " + name);
|
||||
|
||||
Interceptor.attach(impl, {
|
||||
|
||||
onEnter: function(args) {
|
||||
|
||||
// debug only the intended calls
|
||||
this.flag = false;
|
||||
// var filename = Memory.readCString(ptr(args[0]));
|
||||
// if (filename.indexOf("XYZ") === -1 && filename.indexOf("ZYX") === -1) // exclusion list
|
||||
// if (filename.indexOf("my.interesting.file") !== -1) // inclusion list
|
||||
this.flag = true;
|
||||
|
||||
if (this.flag) {
|
||||
console.warn("\n*** entered " + name);
|
||||
|
||||
// print backtrace
|
||||
console.log("\nBacktrace:\n" + Thread.backtrace(this.context, Backtracer.ACCURATE)
|
||||
.map(DebugSymbol.fromAddress).join("\n"));
|
||||
}
|
||||
},
|
||||
|
||||
onLeave: function(retval) {
|
||||
|
||||
if (this.flag) {
|
||||
// print retval
|
||||
console.log("\nretval: " + retval);
|
||||
console.warn("\n*** exiting " + name);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
// remove duplicates from array
|
||||
function uniqBy(array, key)
|
||||
{
|
||||
var seen = {};
|
||||
return array.filter(function(item) {
|
||||
var k = key(item);
|
||||
return seen.hasOwnProperty(k) ? false : (seen[k] = true);
|
||||
});
|
||||
}
|
||||
|
||||
// usage examples
|
||||
setTimeout(function() { // avoid java.lang.ClassNotFoundException
|
||||
|
||||
Java.perform(function() {
|
||||
|
||||
// trace("com.target.utils.CryptoUtils.decrypt");
|
||||
// trace("com.target.utils.CryptoUtils");
|
||||
// trace("CryptoUtils");
|
||||
// trace(/crypto/i);
|
||||
trace("exports:*!write*");
|
||||
|
||||
});
|
||||
}, 0);
|
||||
|
70
frida/frida_scripts/ssl_pinning.js
Normal file
70
frida/frida_scripts/ssl_pinning.js
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
Android SSL Re-pinning frida script v0.2 030417-pier
|
||||
|
||||
$ adb push burpca-cert-der.crt /data/local/tmp/cert-der.crt
|
||||
$ frida -U -f it.app.mobile -l frida-android-repinning.js --no-pause
|
||||
|
||||
https://techblog.mediaservice.net/2017/07/universal-android-ssl-pinning-bypass-with-frida/
|
||||
|
||||
UPDATE 20191605: Fixed undeclared var. Thanks to @oleavr and @ehsanpc9999 !
|
||||
*/
|
||||
|
||||
setTimeout(function(){
|
||||
Java.perform(function (){
|
||||
console.log("");
|
||||
console.log("[.] Cert Pinning Bypass/Re-Pinning");
|
||||
|
||||
var CertificateFactory = Java.use("java.security.cert.CertificateFactory");
|
||||
var FileInputStream = Java.use("java.io.FileInputStream");
|
||||
var BufferedInputStream = Java.use("java.io.BufferedInputStream");
|
||||
var X509Certificate = Java.use("java.security.cert.X509Certificate");
|
||||
var KeyStore = Java.use("java.security.KeyStore");
|
||||
var TrustManagerFactory = Java.use("javax.net.ssl.TrustManagerFactory");
|
||||
var SSLContext = Java.use("javax.net.ssl.SSLContext");
|
||||
|
||||
// Load CAs from an InputStream
|
||||
console.log("[+] Loading our CA...")
|
||||
var cf = CertificateFactory.getInstance("X.509");
|
||||
|
||||
try {
|
||||
var fileInputStream = FileInputStream.$new("/data/local/tmp/cert-der.crt");
|
||||
}
|
||||
catch(err) {
|
||||
console.log("[o] " + err);
|
||||
}
|
||||
|
||||
var bufferedInputStream = BufferedInputStream.$new(fileInputStream);
|
||||
var ca = cf.generateCertificate(bufferedInputStream);
|
||||
bufferedInputStream.close();
|
||||
|
||||
var certInfo = Java.cast(ca, X509Certificate);
|
||||
console.log("[o] Our CA Info: " + certInfo.getSubjectDN());
|
||||
|
||||
// Create a KeyStore containing our trusted CAs
|
||||
console.log("[+] Creating a KeyStore for our CA...");
|
||||
var keyStoreType = KeyStore.getDefaultType();
|
||||
var keyStore = KeyStore.getInstance(keyStoreType);
|
||||
keyStore.load(null, null);
|
||||
keyStore.setCertificateEntry("ca", ca);
|
||||
|
||||
// Create a TrustManager that trusts the CAs in our KeyStore
|
||||
console.log("[+] Creating a TrustManager that trusts the CA in our KeyStore...");
|
||||
var tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
|
||||
var tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
|
||||
tmf.init(keyStore);
|
||||
console.log("[+] Our TrustManager is ready...");
|
||||
|
||||
console.log("[+] Hijacking SSLContext methods now...")
|
||||
console.log("[-] Waiting for the app to invoke SSLContext.init()...")
|
||||
|
||||
SSLContext.init.overload("[Ljavax.net.ssl.KeyManager;", "[Ljavax.net.ssl.TrustManager;", "java.security.SecureRandom").implementation = function(a,b,c) {
|
||||
console.log("[o] App invoked javax.net.ssl.SSLContext.init...");
|
||||
SSLContext.init.overload("[Ljavax.net.ssl.KeyManager;", "[Ljavax.net.ssl.TrustManager;", "java.security.SecureRandom").call(this, a, tmf.getTrustManagers(), c);
|
||||
console.log("[+] SSLContext initialized with our custom TrustManager!");
|
||||
}
|
||||
});
|
||||
},0);
|
||||
|
||||
|
||||
|
||||
|
3
frida/frida_scripts/trace.js
Normal file
3
frida/frida_scripts/trace.js
Normal file
@ -0,0 +1,3 @@
|
||||
Java.perform(function() {
|
||||
console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new()))
|
||||
});
|
11
frida/frida_start.sh
Executable file
11
frida/frida_start.sh
Executable file
@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
|
||||
#
|
||||
|
||||
printf "Starting frida server..\n\n"
|
||||
|
||||
|
||||
adb shell /data/local/tmp/frida-server &
|
||||
|
||||
|
||||
|
25
frida/get_frida_server.sh
Executable file
25
frida/get_frida_server.sh
Executable file
@ -0,0 +1,25 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
|
||||
|
||||
|
||||
|
||||
printf "\nChecking processor type of attached Android..\n\n"
|
||||
|
||||
|
||||
adb shell getprop | grep abi
|
||||
|
||||
|
||||
|
||||
printf "\nNEXT: \nDownload matching frida-server from: https://github.com/frida/frida/releases\n"
|
||||
|
||||
printf "\n\nThen extract frida-server and push to Android with: \n"
|
||||
|
||||
printf "adb push ./frida-server /data/local/tmp\nadb shell chmod +x /data/local/tmp/frida-server\n"
|
||||
|
||||
# adb push ./frida-server /data/local/tmp
|
||||
# adb shell chmod +x /data/local/tmp/frida-server
|
||||
|
||||
|
||||
|
||||
|
17
frida/install_frida.sh
Executable file
17
frida/install_frida.sh
Executable file
@ -0,0 +1,17 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
|
||||
|
||||
printf "Installing frida tools and python venv..\n\n"
|
||||
|
||||
sudo apt install python3-venv
|
||||
|
||||
pip install frida-tools
|
||||
|
||||
|
||||
|
||||
printf "\nChecking frida version..\n"
|
||||
|
||||
frida --version
|
||||
|
||||
|
7
frida/tracers/trace_opens.sh
Executable file
7
frida/tracers/trace_opens.sh
Executable file
@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
|
||||
frida-trace -U -i open Mi\ Claro
|
||||
|
||||
|
||||
|
7
frida/tracers/trace_recvs.sh
Executable file
7
frida/tracers/trace_recvs.sh
Executable file
@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
|
||||
frida-trace -U -i recvm* Mi\ Telcel
|
||||
|
||||
|
||||
|
7
frida/tracers/trace_sends.sh
Executable file
7
frida/tracers/trace_sends.sh
Executable file
@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
|
||||
frida-trace -U -i send* Mi\ Telcel
|
||||
|
||||
|
||||
|
24
grab_apk.sh
Executable file
24
grab_apk.sh
Executable file
@ -0,0 +1,24 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
|
||||
|
||||
# adb shell pm list packages
|
||||
|
||||
#BUNDLE_ID="com.duckduckgo.mobile.android"
|
||||
BUNDLE_ID=$1
|
||||
|
||||
|
||||
mkdir -p ./apks
|
||||
|
||||
printf "Downloading bundle id: $BUNDLE_ID\n\n"
|
||||
|
||||
APK=$(adb shell pm path $BUNDLE_ID)
|
||||
printf "\nAPK path on device: $APK\n"
|
||||
|
||||
APK=`echo $APK | awk '{print $NF}' FS=':' | tr -d '\r\n'`
|
||||
printf "\napk file: $APK\n"
|
||||
|
||||
NEW_APK_FP="./apks/$BUNDLE_ID.apk"
|
||||
|
||||
adb pull $APK $NEW_APK_FP
|
||||
printf "\nDownloaded apk file: $NEW_APK_FP\n"
|
23
install_all.sh
Executable file
23
install_all.sh
Executable file
@ -0,0 +1,23 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
|
||||
|
||||
|
||||
printf "Installing mitmproxy binaries and genymotion..\n\n"
|
||||
|
||||
wget https://snapshots.mitmproxy.org/9.0.1/mitmproxy-9.0.1-linux.tar.gz -O mitmproxy.tar.gz
|
||||
|
||||
|
||||
mkdir -p ./mitmprox
|
||||
tar -xvf ./mitmproxy.tar.gz -C ./mitmprox
|
||||
|
||||
rm -v mitmproxy.tar.gz
|
||||
printf "\nInstalled mitmproxy binaries at ./mitmprox\n"
|
||||
|
||||
|
||||
wget https://dl.genymotion.com/releases/genymotion-3.1.2/genymotion-3.1.2-linux_x64.bin
|
||||
chmod +x ./genymotion-3.1.2-linux_x64.bin
|
||||
./genymotion-3.1.2-linux_x64.bin --yes
|
||||
|
||||
|
||||
|
20
jadx/install_jadx.sh
Executable file
20
jadx/install_jadx.sh
Executable file
@ -0,0 +1,20 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
|
||||
|
||||
printf "\nInstalling Jadx..\n"
|
||||
|
||||
|
||||
git clone https://github.com/skylot/jadx.git
|
||||
|
||||
|
||||
cd jadx
|
||||
|
||||
./gradlew dist
|
||||
|
||||
|
||||
#export PATH=$PATH:path/to/build/jadx/bin/jadx
|
||||
|
||||
|
||||
|
||||
|
15
setup_scripts/install_mobsf.sh
Executable file
15
setup_scripts/install_mobsf.sh
Executable file
@ -0,0 +1,15 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
|
||||
|
||||
|
||||
printf "\n\nInstalling mobsf framework..\n"
|
||||
|
||||
sudo apt install python3.8-venv -y
|
||||
|
||||
git clone https://github.com/MobSF/Mobile-Security-Framework-MobSF.git
|
||||
cd Mobile-Security-Framework-MobSF
|
||||
./setup.sh
|
||||
|
||||
|
||||
|
17
setup_scripts/install_prereqs.sh
Executable file
17
setup_scripts/install_prereqs.sh
Executable file
@ -0,0 +1,17 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
|
||||
|
||||
|
||||
|
||||
printf "Installing prereqs including python3, pip, dev-tools, and apktool..\n"
|
||||
|
||||
|
||||
sudo apt install python3 -y
|
||||
|
||||
sudo apt install python3-pip -y
|
||||
|
||||
sudo apt install build-essential -y
|
||||
|
||||
|
||||
sudo apt install apktool -y
|
24
setup_scripts/make_root_ca.sh
Executable file
24
setup_scripts/make_root_ca.sh
Executable file
@ -0,0 +1,24 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
|
||||
|
||||
printf "Copying mitm cert to root certs on Android...\n\n"
|
||||
|
||||
|
||||
mkdir -p certs_mitm
|
||||
cd ./certs_mitm
|
||||
|
||||
cp -v ~/.mitmproxy/mitmproxy-ca-cert.cer .
|
||||
|
||||
hashed_name=`openssl x509 -inform PEM -subject_hash_old -in mitmproxy-ca-cert.cer | head -1` && cp mitmproxy-ca-cert.cer $hashed_name.0
|
||||
|
||||
|
||||
adb remount
|
||||
adb push $hashed_name.0 /etc/security/cacerts/
|
||||
|
||||
adb shell chmod 644 /etc/security/cacerts/$hashed_name.0
|
||||
adb reboot
|
||||
|
||||
printf "\nFinished copying mitm cert to system certs on Android\n\n"
|
||||
|
||||
|
13
start_all.sh
Executable file
13
start_all.sh
Executable file
@ -0,0 +1,13 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
|
||||
|
||||
printf "Stopping genymotion and mitmproxy tools...\n\n"
|
||||
|
||||
|
||||
|
||||
./mitmprox/mitmweb &
|
||||
|
||||
./genymotion/genymotion &
|
||||
|
||||
|
14
stop_all.sh
Executable file
14
stop_all.sh
Executable file
@ -0,0 +1,14 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
|
||||
|
||||
printf "Stopping genymotion and mitmproxy tools...\n\n"
|
||||
|
||||
|
||||
pkill genymotion
|
||||
|
||||
pkill mitmweb
|
||||
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user