Browse Source

adding re env setup

master
Beau Kujath 1 year ago
parent
commit
7a00e8fc58
  1. 54
      README.md
  2. 38
      frida/__handlers__/libc.so/open.js
  3. 38
      frida/__handlers__/libc.so/send.js
  4. 38
      frida/__handlers__/libc.so/sendfile.js
  5. 38
      frida/__handlers__/libc.so/sendmmsg.js
  6. 38
      frida/__handlers__/libc.so/sendmsg.js
  7. 38
      frida/__handlers__/libc.so/sendto.js
  8. 11
      frida/col_pin_pass.sh
  9. 28
      frida/frida_scripts/classers.js
  10. 5
      frida/frida_scripts/enumerate_methods.js
  11. 455
      frida/frida_scripts/file_access.js
  12. 66
      frida/frida_scripts/frida_certpin_pass.js
  13. 251
      frida/frida_scripts/hook-finder.js
  14. 148
      frida/frida_scripts/http-connection.js
  15. 731
      frida/frida_scripts/multiple_unpinning.js
  16. 1
      frida/frida_scripts/other-enumerate.js
  17. 523
      frida/frida_scripts/pass2.js
  18. 38
      frida/frida_scripts/printStrings.js
  19. 105
      frida/frida_scripts/raptor_android_enum.js
  20. 183
      frida/frida_scripts/raptor_android_trace.js
  21. 70
      frida/frida_scripts/ssl_pinning.js
  22. 3
      frida/frida_scripts/trace.js
  23. 11
      frida/frida_start.sh
  24. 25
      frida/get_frida_server.sh
  25. 17
      frida/install_frida.sh
  26. 7
      frida/tracers/trace_opens.sh
  27. 7
      frida/tracers/trace_recvs.sh
  28. 7
      frida/tracers/trace_sends.sh
  29. 24
      grab_apk.sh
  30. 23
      install_all.sh
  31. 20
      jadx/install_jadx.sh
  32. 15
      setup_scripts/install_mobsf.sh
  33. 17
      setup_scripts/install_prereqs.sh
  34. 24
      setup_scripts/make_root_ca.sh
  35. 13
      start_all.sh
  36. 14
      stop_all.sh

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

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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

@ -0,0 +1 @@
Java.perform(function(){Java.enumerateLoadedClasses({"onMatch":function(className){ console.log(className) },"onComplete":function(){}})})

523
frida/frida_scripts/pass2.js

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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

@ -0,0 +1,7 @@
#!/bin/bash
#
frida-trace -U -i open Mi\ Claro

7
frida/tracers/trace_recvs.sh

@ -0,0 +1,7 @@
#!/bin/bash
#
frida-trace -U -i recvm* Mi\ Telcel

7
frida/tracers/trace_sends.sh

@ -0,0 +1,7 @@
#!/bin/bash
#
frida-trace -U -i send* Mi\ Telcel

24
grab_apk.sh

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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

@ -0,0 +1,13 @@
#!/bin/bash
#
printf "Stopping genymotion and mitmproxy tools...\n\n"
./mitmprox/mitmweb &
./genymotion/genymotion &

14
stop_all.sh

@ -0,0 +1,14 @@
#!/bin/bash
#
printf "Stopping genymotion and mitmproxy tools...\n\n"
pkill genymotion
pkill mitmweb
Loading…
Cancel
Save