x圈

目标:逆向分析出其登录数据包中的各种字段

抓包分析

发现了有一个加密字段codeSign

跑一下java层自吐算法脚本


Java.perform(function () {

function showStacks() {
console.log(
Java.use("android.util.Log")
.getStackTraceString(
Java.use("java.lang.Throwable").$new()
)
);
}

function logOutPut(msg) {
Java.use("android.util.Log").d("xiaojianbang", "frida inject: " + msg);
}

var ByteString = Java.use("com.android.okhttp.okio.ByteString");
function toBase64(tag, data) {
//logOutPut(tag + " Base64: " + ByteString.of(data).base64());
console.log(tag + " Base64: " + ByteString.of(data).base64());
}
function toHex(tag, data) {
//logOutPut(tag + " Hex: " + ByteString.of(data).hex());
console.log(tag + " Hex: " + ByteString.of(data).hex());
}
function toUtf8(tag, data) {
//logOutPut(tag + " Utf8: " + ByteString.of(data).utf8());
console.log(tag + " Utf8: " + ByteString.of(data).utf8());
}
// toBase64([48,49,50,51,52]);
// toHex([48,49,50,51,52]);
// toUtf8([48,49,50,51,52]);
//console.log(Java.enumerateLoadedClassesSync().join("\n"));

var messageDigest = Java.use("java.security.MessageDigest");
messageDigest.update.overload('byte').implementation = function (data) {
console.log("MessageDigest.update('byte') is called!");
showStacks();
return this.update(data);
}
messageDigest.update.overload('java.nio.ByteBuffer').implementation = function (data) {
console.log("MessageDigest.update('java.nio.ByteBuffer') is called!");
showStacks();
return this.update(data);
}
messageDigest.update.overload('[B').implementation = function (data) {
console.log("MessageDigest.update('[B') is called!");
showStacks();
var algorithm = this.getAlgorithm();
var tag = algorithm + " update data";
toUtf8(tag, data);
toHex(tag, data);
toBase64(tag, data);
console.log("=======================================================");
return this.update(data);
}
messageDigest.update.overload('[B', 'int', 'int').implementation = function (data, start, length) {
console.log("MessageDigest.update('[B', 'int', 'int') is called!");
showStacks();
var algorithm = this.getAlgorithm();
var tag = algorithm + " update data";
toUtf8(tag, data);
toHex(tag, data);
toBase64(tag, data);
console.log("=======================================================", start, length);
return this.update(data, start, length);
}
messageDigest.digest.overload().implementation = function () {
console.log("MessageDigest.digest() is called!");
showStacks();
var result = this.digest();
var algorithm = this.getAlgorithm();
var tag = algorithm + " digest result";
toHex(tag, result);
toBase64(tag, result);
console.log("=======================================================");
return result;
}
messageDigest.digest.overload('[B').implementation = function (data) {
console.log("MessageDigest.digest('[B') is called!");
showStacks();
var algorithm = this.getAlgorithm();
var tag = algorithm + " digest data";
toUtf8(tag, data);
toHex(tag, data);
toBase64(tag, data);
var result = this.digest(data);
var tags = algorithm + " digest result";
toHex(tags, result);
toBase64(tags, result);
console.log("=======================================================");
return result;
}
messageDigest.digest.overload('[B', 'int', 'int').implementation = function (data, start, length) {
console.log("MessageDigest.digest('[B', 'int', 'int') is called!");
showStacks();
var algorithm = this.getAlgorithm();
var tag = algorithm + " digest data";
toUtf8(tag, data);
toHex(tag, data);
toBase64(tag, data);
var result = this.digest(data, start, length);
var tags = algorithm + " digest result";
toHex(tags, result);
toBase64(tags, result);
console.log("=======================================================", start, length);
return result;
}

var mac = Java.use("javax.crypto.Mac");
mac.init.overload('java.security.Key', 'java.security.spec.AlgorithmParameterSpec').implementation = function (key, AlgorithmParameterSpec) {
console.log("Mac.init('java.security.Key', 'java.security.spec.AlgorithmParameterSpec') is called!");
return this.init(key, AlgorithmParameterSpec);
}
mac.init.overload('java.security.Key').implementation = function (key) {
console.log("Mac.init('java.security.Key') is called!");
var algorithm = this.getAlgorithm();
var tag = algorithm + " init Key";
var keyBytes = key.getEncoded();
toUtf8(tag, keyBytes);
toHex(tag, keyBytes);
toBase64(tag, keyBytes);
console.log("=======================================================");
return this.init(key);
}
mac.update.overload('byte').implementation = function (data) {
console.log("Mac.update('byte') is called!");
return this.update(data);
}
mac.update.overload('java.nio.ByteBuffer').implementation = function (data) {
console.log("Mac.update('java.nio.ByteBuffer') is called!");
return this.update(data);
}
mac.update.overload('[B').implementation = function (data) {
console.log("Mac.update('[B') is called!");
var algorithm = this.getAlgorithm();
var tag = algorithm + " update data";
toUtf8(tag, data);
toHex(tag, data);
toBase64(tag, data);
console.log("=======================================================");
return this.update(data);
}
mac.update.overload('[B', 'int', 'int').implementation = function (data, start, length) {
console.log("Mac.update('[B', 'int', 'int') is called!");
var algorithm = this.getAlgorithm();
var tag = algorithm + " update data";
toUtf8(tag, data);
toHex(tag, data);
toBase64(tag, data);
console.log("=======================================================", start, length);
return this.update(data, start, length);
}
mac.doFinal.overload().implementation = function () {
console.log("Mac.doFinal() is called!");
var result = this.doFinal();
var algorithm = this.getAlgorithm();
var tag = algorithm + " doFinal result";
toHex(tag, result);
toBase64(tag, result);
console.log("=======================================================");
return result;
}

var cipher = Java.use("javax.crypto.Cipher");
cipher.init.overload('int', 'java.security.cert.Certificate').implementation = function () {
console.log("Cipher.init('int', 'java.security.cert.Certificate') is called!");
return this.init.apply(this, arguments);
}
cipher.init.overload('int', 'java.security.Key', 'java.security.SecureRandom').implementation = function () {
console.log("Cipher.init('int', 'java.security.Key', 'java.security.SecureRandom') is called!");
return this.init.apply(this, arguments);
}
cipher.init.overload('int', 'java.security.cert.Certificate', 'java.security.SecureRandom').implementation = function () {
console.log("Cipher.init('int', 'java.security.cert.Certificate', 'java.security.SecureRandom') is called!");
return this.init.apply(this, arguments);
}
cipher.init.overload('int', 'java.security.Key', 'java.security.AlgorithmParameters', 'java.security.SecureRandom').implementation = function () {
console.log("Cipher.init('int', 'java.security.Key', 'java.security.AlgorithmParameters', 'java.security.SecureRandom') is called!");
return this.init.apply(this, arguments);
}
cipher.init.overload('int', 'java.security.Key', 'java.security.spec.AlgorithmParameterSpec', 'java.security.SecureRandom').implementation = function () {
console.log("Cipher.init('int', 'java.security.Key', 'java.security.spec.AlgorithmParameterSpec', 'java.security.SecureRandom') is called!");
return this.init.apply(this, arguments);
}
cipher.init.overload('int', 'java.security.Key', 'java.security.AlgorithmParameters').implementation = function () {
console.log("Cipher.init('int', 'java.security.Key', 'java.security.AlgorithmParameters') is called!");
return this.init.apply(this, arguments);
}

cipher.init.overload('int', 'java.security.Key').implementation = function () {
console.log("Cipher.init('int', 'java.security.Key') is called!");
var algorithm = this.getAlgorithm();
var tag = algorithm + " init Key";
var className = JSON.stringify(arguments[1]);
if(className.indexOf("OpenSSLRSAPrivateKey") === -1){
var keyBytes = arguments[1].getEncoded();
toUtf8(tag, keyBytes);
toHex(tag, keyBytes);
toBase64(tag, keyBytes);
}
console.log("=======================================================");
return this.init.apply(this, arguments);
}
cipher.init.overload('int', 'java.security.Key', 'java.security.spec.AlgorithmParameterSpec').implementation = function () {
console.log("Cipher.init('int', 'java.security.Key', 'java.security.spec.AlgorithmParameterSpec') is called!");
var algorithm = this.getAlgorithm();
var tag = algorithm + " init Key";
var keyBytes = arguments[1].getEncoded();
toUtf8(tag, keyBytes);
toHex(tag, keyBytes);
toBase64(tag, keyBytes);
var tags = algorithm + " init iv";
var iv = Java.cast(arguments[2], Java.use("javax.crypto.spec.IvParameterSpec"));
var ivBytes = iv.getIV();
toUtf8(tags, ivBytes);
toHex(tags, ivBytes);
toBase64(tags, ivBytes);
console.log("=======================================================");
return this.init.apply(this, arguments);
}

cipher.doFinal.overload('java.nio.ByteBuffer', 'java.nio.ByteBuffer').implementation = function () {
console.log("Cipher.doFinal('java.nio.ByteBuffer', 'java.nio.ByteBuffer') is called!");
showStacks();
return this.doFinal.apply(this, arguments);
}
cipher.doFinal.overload('[B', 'int').implementation = function () {
console.log("Cipher.doFinal('[B', 'int') is called!");
showStacks();
return this.doFinal.apply(this, arguments);
}
cipher.doFinal.overload('[B', 'int', 'int', '[B').implementation = function () {
console.log("Cipher.doFinal('[B', 'int', 'int', '[B') is called!");
showStacks();
return this.doFinal.apply(this, arguments);
}
cipher.doFinal.overload('[B', 'int', 'int', '[B', 'int').implementation = function () {
console.log("Cipher.doFinal('[B', 'int', 'int', '[B', 'int') is called!");
showStacks();
return this.doFinal.apply(this, arguments);
}
cipher.doFinal.overload().implementation = function () {
console.log("Cipher.doFinal() is called!");
showStacks();
return this.doFinal.apply(this, arguments);
}

cipher.doFinal.overload('[B').implementation = function () {
console.log("Cipher.doFinal('[B') is called!");
showStacks();
var algorithm = this.getAlgorithm();
var tag = algorithm + " doFinal data";
var data = arguments[0];
toUtf8(tag, data);
toHex(tag, data);
toBase64(tag, data);
var result = this.doFinal.apply(this, arguments);
var tags = algorithm + " doFinal result";
toHex(tags, result);
toBase64(tags, result);
console.log("=======================================================");
return result;
}
cipher.doFinal.overload('[B', 'int', 'int').implementation = function () {
console.log("Cipher.doFinal('[B', 'int', 'int') is called!");
showStacks();
var algorithm = this.getAlgorithm();
var tag = algorithm + " doFinal data";
var data = arguments[0];
toUtf8(tag, data);
toHex(tag, data);
toBase64(tag, data);
var result = this.doFinal.apply(this, arguments);
var tags = algorithm + " doFinal result";
toHex(tags, result);
toBase64(tags, result);
console.log("=======================================================", arguments[1], arguments[2]);
return result;
}

var signature = Java.use("java.security.Signature");
signature.update.overload('byte').implementation = function (data) {
console.log("Signature.update('byte') is called!");
return this.update(data);
}
signature.update.overload('java.nio.ByteBuffer').implementation = function (data) {
console.log("Signature.update('java.nio.ByteBuffer') is called!");
return this.update(data);
}
signature.update.overload('[B', 'int', 'int').implementation = function (data, start, length) {
console.log("Signature.update('[B', 'int', 'int') is called!");
var algorithm = this.getAlgorithm();
var tag = algorithm + " update data";
toUtf8(tag, data);
toHex(tag, data);
toBase64(tag, data);
console.log("=======================================================", start, length);
return this.update(data, start, length);
}
signature.sign.overload('[B', 'int', 'int').implementation = function () {
console.log("Signature.sign('[B', 'int', 'int') is called!");
return this.sign.apply(this, arguments);
}
signature.sign.overload().implementation = function () {
console.log("Signature.sign() is called!");
var result = this.sign();
var algorithm = this.getAlgorithm();
var tag = algorithm + " sign result";
toHex(tag, result);
toBase64(tag, result);
console.log("=======================================================");
return result;
}
});

很轻松地看出了这是对我们输入的一些数据进行了md5加密得到的

某电影

目标:去除更新弹窗

在设置界面,我们点击一下版本检测,便会弹出更新弹窗

使用smali-trace定位到了关键类(虽然我目前不会用)。。。。

var utils = Java.use("com.m1905.mobilefree.adapter.mine.SettingActivity");

hook一下这个类下面的函数,看看弹出这个界面时候调用了哪个函数

Java.perform(function () {
function showStack(){
var log = Java.use("android.util.Log");
var throwable = Java.use("java.lang.Throwable");
console.log(log.getStackTraceString(throwable.$new()));
}
function hookFunc(methodName){
console.log(methodName);
var overloadArr = utils[methodName].overloads;
for(let j=0 ;j<overloadArr.length;j++){
var overload = overloadArr[j];
var params = "";
overload.implementation = function (){
for(let k=0; k<arguments.length;k++){
params+=arguments[j]+" ";
}
console.log("SettingActivity." + methodName + " is called! params is: ", params);
showStack();
return this[methodName].apply(this, arguments);
}
}
}
var utils = Java.use("com.m1905.mobilefree.adapter.mine.SettingActivity");
var methods = utils.class.getDeclaredMethods();
for (var i = 0; i < methods.length; i++) {
var methodName = methods[i].getName();
hookFunc(methodName);
}
});

点击版本检测按钮,发现checkUpdate被调用

所以直接hook掉这个函数就可以了

Java.perform(function () {
let SettingActivity = Java.use("com.m1905.mobilefree.adapter.mine.SettingActivity");
SettingActivity.checkUpdate.implementation = function (){
console.log("SettingActivity.checkUpdate is called");
}
});

某宝玩

目标:去除强制更新、解决提交乱码问题、还原加密算法

去除强制更新

一进入这个app便会弹出更新窗口,且无法点击其他地方,无法关闭。这真是太不爽了,身为逆向人员怎么能够忍受呢。

抓包看看

看到了检查更新的字段,说明这个app是通过服务器来检查更新的,查壳发现这个app也是没有壳的,于是想到,我们直接使用jadx反编译这个app然后搜索这个post字段,hook掉发包即可

轻轻松松就搜到了

查找一下相关用例,便可以定位到这个函数,发现这个函数也没有什么业务代码,直接hook掉它就行了

Java.perform(function () {
let MainActivity = Java.use("com.hfzs.zhibaowan.ui.MainActivity");
MainActivity.checkUpdate.implementation = function () {
console.log("hyq");
}
});

由于这个强制更新界面是我们一启动app就出现的的,所以我们要通过spawn的方式启动

解决提交乱码问题

抓一个登录的包,发现提交数据是乱码

这种乱码,一般都是字节,我们可以hook一下getBytes一探究竟

Java.perform(function () {
function showStack(){
var log = Java.use("android.util.Log");
var throwable = Java.use("java.lang.Throwable");
console.log(log.getStackTraceString(throwable.$new()));
}
let MainActivity = Java.use("com.hfzs.zhibaowan.ui.MainActivity");
MainActivity.checkUpdate.implementation = function () {
console.log("hyq");
}
var str = Java.use("java.lang.String");
str.getBytes.overload().implementation = function(){
showStack();
var result = this.getBytes();
var newStr = str.$new(result);
console.log("str.getBytes result.overload(): ",newStr);
return result;
}
str.getBytes.overload('java.lang.String').implementation = function(a){
showStack();
var result = this.getBytes(a);
var newStr = str.$new(result);
console.log("str.getBytes result.overload('java.lang.String'): ",newStr);
return result;
}
});
java.lang.Throwable
at java.lang.String.getBytes(Native Method)
at com.hfzs.zhibaowan.util.Encrypt.encodeStr(Encrypt.java:92)
at com.hfzs.zhibaowan.util.Encrypt.encode(Encrypt.java:23)
at com.hfzs.zhibaowan.network.GetDataImpl.doRequest(GetDataImpl.java:237)
at com.hfzs.zhibaowan.network.GetDataImpl.requestLoginUrl(GetDataImpl.java:1017)
at com.hfzs.zhibaowan.ui.LoginActivity$1.doInBackground(LoginActivity.java:100)
at com.hfzs.zhibaowan.ui.LoginActivity$1.doInBackground(LoginActivity.java:96)
at android.os.AsyncTask$3.call(AsyncTask.java:378)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:289)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:919)

str.getBytes result.overload(): {"appid":"2","username":"13905020820","password":"a12345678","cpsId":"tg001lxx","imei":"732dc9e5-5715-4442-abcf-f96827b5100e"}
java.lang.Throwable
at java.lang.String.getBytes(Native Method)
at com.hfzs.zhibaowan.network.GetDataImpl.doRequest(GetDataImpl.java:238)
at com.hfzs.zhibaowan.network.GetDataImpl.requestLoginUrl(GetDataImpl.java:1017)
at com.hfzs.zhibaowan.ui.LoginActivity$1.doInBackground(LoginActivity.java:100)
at com.hfzs.zhibaowan.ui.LoginActivity$1.doInBackground(LoginActivity.java:96)
at android.os.AsyncTask$3.call(AsyncTask.java:378)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:289)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:919)

str.getBytes result.overload(): x149_170_124_155_151_125_120_167_146_124_170_152_172_206_174_207_179_171_179_155_206_158_195_231_209_221_183_230_205_199_190_172_192_226_190_244_144_150_132_117_146_138_144_191_152_142_148_195_150_183_198_185_180_153_153_206_184_137_187_206_188_199_123_138_127_154_124_155_129_137_127_177_134_125_182_148_112_110_179_224_206_209_181_173_181_214_208_182_189_186_203_181_188_170_190_228_201_230_198_190_130_186_165_140_173_122_144_177_192_179_172_163_126_186_176_163_154_136_156_190_184_208_164_197_171_196_121_120_133_98_126_135_137_104_131_139_141_173_175_166_180_148_178_207_152_208_194_215_185_217_185_197_200_165_126_124_193_222_220_239_197_170_194_171_142_150_132_187_159_153_145_129_86_84y

定位到了一个类似提交数据的地方,查看一下关键类com.hfzs.zhibaowan.network.GetDataImpl

查看完了以后发现很简答,只是将传入的参数进行了base64加密,然后再进行了一个自定算法加密

传入参数:
{"appid":"2","username":"13905020820","password":"a12345678","cpsId":"tg001lxx","imei":"732dc9e5-5715-4442-abcf-f96827b5100e"}
经过base64:
eyJhcHBpZCI6IjIiLCJ1c2VybmFtZSI6IjEzOTA1MDIwODIwIiwicGFzc3dvcmQiOiJhMTIzNDU2NzgiLCJjcHNJZCI6InRnMDAxbHh4IiwiaW1laSI6IjczMmRjOWU1LTU3MTUtNDQ0Mi1hYmNmLWY5NjgyN2I1MTAwZSJ9
经过自定义算法:
x149_170_124_155_151_125_120_167_146_124_170_152_172_206_174_207_179_171_179_155_206_158_195_231_209_221_183_230_205_199_190_172_192_226_190_244_144_150_132_117_146_138_144_191_152_142_148_195_150_183_198_185_180_153_153_206_184_137_187_206_188_199_123_138_127_154_124_155_129_137_127_177_134_125_182_148_112_110_179_224_206_209_181_173_181_214_208_182_189_186_203_181_188_170_190_228_201_230_198_190_130_186_165_140_173_122_144_177_192_179_172_163_126_186_176_163_154_136_156_190_184_208_164_197_171_196_121_120_133_98_126_135_137_104_131_139_141_173_175_166_180_148_178_207_152_208_194_215_185_217_185_197_200_165_126_124_193_222_220_239_197_170_194_171_142_150_132_187_159_153_145_129_86_84y

还原算法

算法在这,极其简单

java

import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;

public class Hello {

public static void main(String[] args) throws Exception {

System.out.println(encode());

}

private static char[] k = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '*', '!'};

public static String encode() {

byte[] byteStr = new byte[]{101,121,74,104,99,72,66,112,90,67,73,54,73,106,73,105,76,67,74,49,99,50,86,121,98,109,70,116,90,83,73,54,73,106,69,49,79,84,89,52,77,68,99,53,78,68,99,51,73,105 ,119,105,99,71,70,122,99,51,100,118,99,109,81,105,79,105,74,104,77,84,73,122,78,68,85,50,13,10,78,122,103,105,76,67,74,106,99,72,78,74,90,67,73,54,73,110,82,110,77,68,65,120,98,72,104,52,73,105,119,105,97,87,49,108,97,83,73,54,73,106,107,119,79,68,77,52,89,84,107,51,76,84,78,109,79,84,69,116,78,68,65,49,90,67,48,52,90,106,99,48,76,84,100,105,13,10,78,106,81,52,77,68,81,51,77,71,69,52,90,
83,74,57,13,10};

StringBuffer stringBuffer = new StringBuffer();
char[] charArray = new String(byteStr).toCharArray();
stringBuffer.append("x");
for (int i = 0; i < charArray.length; i++) {
char c = charArray[i];
char[] cArr = k;
stringBuffer.append(c + cArr[i % cArr.length]);
stringBuffer.append("_");
}
stringBuffer.deleteCharAt(stringBuffer.length() - 1);
stringBuffer.append("y");
return stringBuffer.toString();
}

}

javascript

var k = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '*', '!'];

function encode() {

var byteStr = [101,121,74,104,99,72,66,112,90,67,73,54,73,106,73,105,76,67,74,49,99,50,86,121,98,109,70,116,90,83,73,54,73,106,69,49,79,84,89,52,77,
68,99,53,78,68,99,51,73,105,119,105,99,71,70,122,99,51,100,118,99,109,81,105,79,105,74,104,77,84,73,122,78,68,85,50,13,10,78,122,103,105,76,67,74,
106,99,72,78,74,90,67,73,54,73,110,82,110,77,68,65,120,98,72,104,52,73,105,119,105,97,87,49,108,97,83,73,54,73,106,107,119,79,68,77,52,89,84,107,51,
76,84,78,109,79,84,69,116,78,68,65,49,90,67,48,52,90,106,99,48,76,84,100,105,13,10,78,106,81,52,77,68,81,51,77,71,69,52,90, 83,74,57,13,10];
var result = "x";
for(var i = 0; i < byteStr.length; i++) {
var c = byteStr[i];
result += c + k[i % k.length].charCodeAt(0);
result += "_";
}
result = result.substring(0, result.length -1);
//console.log(result);
result += "y";
console.log(result);
}
encode();

过掉一些证书检测

Java.perform(function () {

/*
hook list:
1.SSLcontext
2.okhttp
3.webview
4.XUtils
5.httpclientandroidlib
6.JSSE
7.network\_security\_config (android 7.0+)
8.Apache Http client (support partly)
9.OpenSSLSocketImpl
10.TrustKit
11.Cronet
*/
// Attempts to bypass SSL pinning implementations in a number of
// ways. These include implementing a new TrustManager that will
// accept any SSL certificate, overriding OkHTTP v3 check()
// method etc.
var X509TrustManager = Java.use('javax.net.ssl.X509TrustManager');
var HostnameVerifier = Java.use('javax.net.ssl.HostnameVerifier');
var SSLContext = Java.use('javax.net.ssl.SSLContext');
var quiet_output = false;

// Helper method to honor the quiet flag.

function quiet_send(data) {

if (quiet_output) {

return;
}

send(data)
}


// Implement a new TrustManager
// ref: https://gist.github.com/oleavr/3ca67a173ff7d207c6b8c3b0ca65a9d8
// Java.registerClass() is only supported on ART for now(201803). 所以android 4.4以下不兼容,4.4要切换成ART使用.
/*
06-07 16:15:38.541 27021-27073/mi.sslpinningdemo W/System.err: java.lang.IllegalArgumentException: Required method checkServerTrusted(X509Certificate[], String, String, String) missing
06-07 16:15:38.542 27021-27073/mi.sslpinningdemo W/System.err: at android.net.http.X509TrustManagerExtensions.<init>(X509TrustManagerExtensions.java:73)
at mi.ssl.MiPinningTrustManger.<init>(MiPinningTrustManger.java:61)
06-07 16:15:38.543 27021-27073/mi.sslpinningdemo W/System.err: at mi.sslpinningdemo.OkHttpUtil.getSecPinningClient(OkHttpUtil.java:112)
at mi.sslpinningdemo.OkHttpUtil.get(OkHttpUtil.java:62)
at mi.sslpinningdemo.MainActivity$1$1.run(MainActivity.java:36)
*/
var X509Certificate = Java.use("java.security.cert.X509Certificate");
var TrustManager;
try {
TrustManager = Java.registerClass({
name: 'org.wooyun.TrustManager',
implements: [X509TrustManager],
methods: {
checkClientTrusted: function (chain, authType) {
},
checkServerTrusted: function (chain, authType) {
},
getAcceptedIssuers: function () {
// var certs = [X509Certificate.$new()];
// return certs;
return [];
}
}
});
} catch (e) {
quiet_send("registerClass from X509TrustManager >>>>>>>> " + e.message);
}

// Prepare the TrustManagers array to pass to SSLContext.init()
var TrustManagers = [TrustManager.$new()];

try {
// Prepare a Empty SSLFactory
var TLS_SSLContext = SSLContext.getInstance("TLS");
TLS_SSLContext.init(null, TrustManagers, null);
var EmptySSLFactory = TLS_SSLContext.getSocketFactory();
} catch (e) {
quiet_send(e.message);
}

send('Custom, Empty TrustManager ready');

// 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');

// Override the init method, specifying our new TrustManager
SSLContext_init.implementation = function (keyManager, trustManager, secureRandom) {

quiet_send('Overriding SSLContext.init() with the custom TrustManager');

SSLContext_init.call(this, null, TrustManagers, null);
};

/*** okhttp3.x unpinning ***/


// Wrap the logic in a try/catch as not all applications will have
// okhttp as part of the app.
try {

var CertificatePinner = Java.use('okhttp3.CertificatePinner');
quiet_send('OkHTTP 3.x Found');
CertificatePinner.check.overload('java.lang.String', 'java.util.List').implementation = function () {
quiet_send('OkHTTP 3.x check() called. Not throwing an exception.');
}

var OkHttpClient$Builder = Java.use('okhttp3.OkHttpClient$Builder');
quiet_send('OkHttpClient$Builder Found');
console.log("hostnameVerifier", OkHttpClient$Builder.hostnameVerifier);
OkHttpClient$Builder.hostnameVerifier.implementation = function () {
quiet_send('OkHttpClient$Builder hostnameVerifier() called. Not throwing an exception.');
return this;
}

var myHostnameVerifier = Java.registerClass({
name: 'com.xiaojianbang.MyHostnameVerifier',
implements: [HostnameVerifier],
methods: {
verify: function (hostname, session) {
return true;
}
}
});

var OkHttpClient = Java.use('okhttp3.OkHttpClient');
OkHttpClient.hostnameVerifier.implementation = function () {
quiet_send('OkHttpClient hostnameVerifier() called. Not throwing an exception.');
return myHostnameVerifier.$new();
}

} catch (err) {

// If we dont have a ClassNotFoundException exception, raise the
// problem encountered.
if (err.message.indexOf('ClassNotFoundException') === 0) {

throw new Error(err);
}
}

// Appcelerator Titanium PinningTrustManager

// Wrap the logic in a try/catch as not all applications will have
// appcelerator as part of the app.
try {

var PinningTrustManager = Java.use('appcelerator.https.PinningTrustManager');

send('Appcelerator Titanium Found');

PinningTrustManager.checkServerTrusted.implementation = function () {

quiet_send('Appcelerator checkServerTrusted() called. Not throwing an exception.');
}

} catch (err) {

// If we dont have a ClassNotFoundException exception, raise the
// problem encountered.
if (err.message.indexOf('ClassNotFoundException') === 0) {

throw new Error(err);
}
}

/*** okhttp unpinning ***/


try {
var OkHttpClient = Java.use("com.squareup.okhttp.OkHttpClient");
OkHttpClient.setCertificatePinner.implementation = function (certificatePinner) {
// do nothing
quiet_send("OkHttpClient.setCertificatePinner Called!");
return this;
};

// Invalidate the certificate pinnet checks (if "setCertificatePinner" was called before the previous invalidation)
var CertificatePinner = Java.use("com.squareup.okhttp.CertificatePinner");
CertificatePinner.check.overload('java.lang.String', '[Ljava.security.cert.Certificate;').implementation = function (p0, p1) {
// do nothing
quiet_send("okhttp Called! [Certificate]");
return;
};
CertificatePinner.check.overload('java.lang.String', 'java.util.List').implementation = function (p0, p1) {
// do nothing
quiet_send("okhttp Called! [List]");
return;
};
} catch (e) {
quiet_send("com.squareup.okhttp not found");
}

/*** WebView Hooks ***/

/* frameworks/base/core/java/android/webkit/WebViewClient.java */
/* public void onReceivedSslError(Webview, SslErrorHandler, SslError) */
var WebViewClient = Java.use("android.webkit.WebViewClient");

WebViewClient.onReceivedSslError.implementation = function (webView, sslErrorHandler, sslError) {
quiet_send("WebViewClient onReceivedSslError invoke");
//执行proceed方法
sslErrorHandler.proceed();
return;
};

WebViewClient.onReceivedError.overload('android.webkit.WebView', 'int', 'java.lang.String', 'java.lang.String').implementation = function (a, b, c, d) {
quiet_send("WebViewClient onReceivedError invoked");
return;
};

WebViewClient.onReceivedError.overload('android.webkit.WebView', 'android.webkit.WebResourceRequest', 'android.webkit.WebResourceError').implementation = function () {
quiet_send("WebViewClient onReceivedError invoked");
return;
};

/*** JSSE Hooks ***/

/* libcore/luni/src/main/java/javax/net/ssl/TrustManagerFactory.java */
/* public final TrustManager[] getTrustManager() */
/* TrustManagerFactory.getTrustManagers maybe cause X509TrustManagerExtensions error */
// var TrustManagerFactory = Java.use("javax.net.ssl.TrustManagerFactory");
// TrustManagerFactory.getTrustManagers.implementation = function(){
// quiet_send("TrustManagerFactory getTrustManagers invoked");
// return TrustManagers;
// }

var HttpsURLConnection = Java.use("com.android.okhttp.internal.huc.HttpsURLConnectionImpl");
HttpsURLConnection.setSSLSocketFactory.implementation = function (SSLSocketFactory) {
quiet_send("HttpsURLConnection.setSSLSocketFactory invoked");
};
HttpsURLConnection.setHostnameVerifier.implementation = function (hostnameVerifier) {
quiet_send("HttpsURLConnection.setHostnameVerifier invoked");
};




/*** Xutils3.x hooks ***/
//Implement a new HostnameVerifier
var TrustHostnameVerifier;
try {
TrustHostnameVerifier = Java.registerClass({
name: 'org.wooyun.TrustHostnameVerifier',
implements: [HostnameVerifier],
method: {
verify: function (hostname, session) {
return true;
}
}
});

} catch (e) {
//java.lang.ClassNotFoundException: Didn't find class "org.wooyun.TrustHostnameVerifier"
quiet_send("registerClass from hostnameVerifier >>>>>>>> " + e.message);
}

try {
var RequestParams = Java.use('org.xutils.http.RequestParams');
RequestParams.setSslSocketFactory.implementation = function (sslSocketFactory) {
sslSocketFactory = EmptySSLFactory;
return null;
}

RequestParams.setHostnameVerifier.implementation = function (hostnameVerifier) {
hostnameVerifier = TrustHostnameVerifier.$new();
return null;
}

} catch (e) {
quiet_send("Xutils hooks not Found");
}

/*** httpclientandroidlib Hooks ***/
try {
var AbstractVerifier = Java.use("ch.boye.httpclientandroidlib.conn.ssl.AbstractVerifier");
AbstractVerifier.verify.overload('java.lang.String', '[Ljava.lang.String', '[Ljava.lang.String', 'boolean').implementation = function () {
quiet_send("httpclientandroidlib Hooks");
return null;
}
} catch (e) {
quiet_send("httpclientandroidlib Hooks not found");
}

/***
android 7.0+ network_security_config TrustManagerImpl hook
apache httpclient partly
***/
var TrustManagerImpl = Java.use("com.android.org.conscrypt.TrustManagerImpl");
// try {
// var Arrays = Java.use("java.util.Arrays");
// //apache http client pinning maybe baypass
// //https://github.com/google/conscrypt/blob/c88f9f55a523f128f0e4dace76a34724bfa1e88c/platform/src/main/java/org/conscrypt/TrustManagerImpl.java#471
// TrustManagerImpl.checkTrusted.implementation = function (chain, authType, session, parameters, authType) {
// quiet_send("TrustManagerImpl checkTrusted called");
// //Generics currently result in java.lang.Object
// return Arrays.asList(chain);
// }
//
// } catch (e) {
// quiet_send("TrustManagerImpl checkTrusted nout found");
// }

try {
// Android 7+ TrustManagerImpl
TrustManagerImpl.verifyChain.implementation = function (untrustedChain, trustAnchorChain, host, clientAuth, ocspData, tlsSctData) {
quiet_send("TrustManagerImpl verifyChain called");
// Skip all the logic and just return the chain again :P
//https://www.nccgroup.trust/uk/about-us/newsroom-and-events/blogs/2017/november/bypassing-androids-network-security-configuration/
// https://github.com/google/conscrypt/blob/c88f9f55a523f128f0e4dace76a34724bfa1e88c/platform/src/main/java/org/conscrypt/TrustManagerImpl.java#L650
return untrustedChain;
}
} catch (e) {
quiet_send("TrustManagerImpl verifyChain nout found below 7.0");
}
// OpenSSLSocketImpl
try {
var OpenSSLSocketImpl = Java.use('com.android.org.conscrypt.OpenSSLSocketImpl');
OpenSSLSocketImpl.verifyCertificateChain.implementation = function (certRefs, authMethod) {
quiet_send('OpenSSLSocketImpl.verifyCertificateChain');
}

quiet_send('OpenSSLSocketImpl pinning')
} catch (err) {
quiet_send('OpenSSLSocketImpl pinner not found');
}
// Trustkit
try {
var Activity = Java.use("com.datatheorem.android.trustkit.pinning.OkHostnameVerifier");
Activity.verify.overload('java.lang.String', 'javax.net.ssl.SSLSession').implementation = function (str) {
quiet_send('Trustkit.verify1: ' + str);
return true;
};
Activity.verify.overload('java.lang.String', 'java.security.cert.X509Certificate').implementation = function (str) {
quiet_send('Trustkit.verify2: ' + str);
return true;
};

quiet_send('Trustkit pinning')
} catch (err) {
quiet_send('Trustkit pinner not found')
}

try {
//cronet pinner hook
//weibo don't invoke

var netBuilder = Java.use("org.chromium.net.CronetEngine$Builder");

//https://developer.android.com/guide/topics/connectivity/cronet/reference/org/chromium/net/CronetEngine.Builder.html#enablePublicKeyPinningBypassForLocalTrustAnchors(boolean)
netBuilder.enablePublicKeyPinningBypassForLocalTrustAnchors.implementation = function (arg) {

//weibo not invoke
console.log("Enables or disables public key pinning bypass for local trust anchors = " + arg);

//true to enable the bypass, false to disable.
var ret = netBuilder.enablePublicKeyPinningBypassForLocalTrustAnchors.call(this, true);
return ret;
};

netBuilder.addPublicKeyPins.implementation = function (hostName, pinsSha256, includeSubdomains, expirationDate) {
console.log("cronet addPublicKeyPins hostName = " + hostName);

//var ret = netBuilder.addPublicKeyPins.call(this,hostName, pinsSha256,includeSubdomains, expirationDate);
//this 是调用 addPublicKeyPins 前的对象吗? Yes,CronetEngine.Builder
return this;
};

} catch (err) {
console.log('[-] Cronet pinner not found')
}
});


//Java.perform(function () {
//
// function showStacks() {
// console.log(
// Java.use("android.util.Log")
// .getStackTraceString(
// Java.use("java.lang.Throwable").$new()
// )
// );
// }
//
// var ByteString = Java.use("com.android.okhttp.okio.ByteString");
//
// function toBase64(tag, data) {
// console.log(tag + " Base64: " + ByteString.of(data).base64());
// }
//
// function toHex(tag, data) {
// console.log(tag + " Hex: " + ByteString.of(data).hex());
// }
//
// function toUtf8(tag, data) {
// console.log(tag + " Utf8: " + ByteString.of(data).utf8());
// }
//
// // toUtf8("xiaojianbang",[48, 49, 50, 51, 52]);
// // toBase64("xiaojianbang",[48, 49, 50, 51, 52]);
// // toHex("xiaojianbang",[48, 49, 50, 51, 52]);
//
// var messageDigest = Java.use("java.security.MessageDigest");
// messageDigest.update.overload('byte').implementation = function (data) {
// console.log("MessageDigest.update('byte') is called!");
// console.log("=======================================================");
// return this.update(data);
// }
// messageDigest.update.overload('java.nio.ByteBuffer').implementation = function (data) {
// console.log("MessageDigest.update('java.nio.ByteBuffer') is called!");
// console.log("=======================================================");
// return this.update(data);
// }
// messageDigest.update.overload('[B').implementation = function (data) {
// console.log("MessageDigest.update('[B') is called!");
// showStacks();
// var algorithm = this.getAlgorithm();
// var tag = algorithm + " update data";
// toUtf8(tag, data);
// toHex(tag, data);
// toBase64(tag, data);
// console.log("=======================================================");
// return this.update(data);
// }
// messageDigest.update.overload('[B', 'int', 'int').implementation = function (data, start, length) {
// console.log("MessageDigest.update('[B', 'int', 'int') is called!");
// showStacks();
// var algorithm = this.getAlgorithm();
// var tag = algorithm + " update data";
// toUtf8(tag, data);
// toHex(tag, data);
// toBase64(tag, data);
// console.log("=======================================================", start, length);
// return this.update(data, start, length);
// }
//
// messageDigest.digest.overload().implementation = function () {
// console.log("MessageDigest.digest() is called!");
// showStacks();
// var result = this.digest();
// var algorithm = this.getAlgorithm();
// var tag = algorithm + " digest result";
// toUtf8(tag, result);
// toHex(tag, result);
// toBase64(tag, result);
// console.log("=======================================================");
// return result;
// }
// messageDigest.digest.overload('[B').implementation = function (data) {
// console.log("MessageDigest.digest('[B') is called!");
// showStacks();
// var algorithm = this.getAlgorithm();
// var tag = algorithm + " digest data";
// toUtf8(tag, data);
// toHex(tag, data);
// toBase64(tag, data);
// var result = this.digest(data);
// var tags = algorithm + " digest result";
// toUtf8(tag, result);
// toHex(tags, result);
// toBase64(tags, result);
// console.log("=======================================================");
// return result;
// }
// messageDigest.digest.overload('[B', 'int', 'int').implementation = function (data, start, length) {
// console.log("MessageDigest.digest('[B', 'int', 'int') is called!");
// showStacks();
// var algorithm = this.getAlgorithm();
// var tag = algorithm + " digest data";
// toUtf8(tag, data);
// toHex(tag, data);
// toBase64(tag, data);
// var result = this.digest(data, start, length);
// var tags = algorithm + " digest result";
// toHex(tags, result);
// toBase64(tags, result);
// console.log("=======================================================", start, length);
// return result;
// }
//
// var mac = Java.use("javax.crypto.Mac");
// mac.init.overload('java.security.Key', 'java.security.spec.AlgorithmParameterSpec').implementation = function (key, AlgorithmParameterSpec) {
// console.log("Mac.init('java.security.Key', 'java.security.spec.AlgorithmParameterSpec') is called!");
// console.log("=======================================================");
// return this.init(key, AlgorithmParameterSpec);
// }
// mac.init.overload('java.security.Key').implementation = function (key) {
// console.log("Mac.init('java.security.Key') is called!");
// var algorithm = this.getAlgorithm();
// var tag = algorithm + " init Key";
// var keyBytes = key.getEncoded();
// toUtf8(tag, keyBytes);
// toHex(tag, keyBytes);
// toBase64(tag, keyBytes);
// console.log("=======================================================");
// return this.init(key);
// }
// mac.update.overload('byte').implementation = function (data) {
// console.log("Mac.update('byte') is called!");
// return this.update(data);
// }
// mac.update.overload('java.nio.ByteBuffer').implementation = function (data) {
// console.log("Mac.update('java.nio.ByteBuffer') is called!");
// console.log("=======================================================");
// return this.update(data);
// }
// mac.update.overload('[B').implementation = function (data) {
// console.log("Mac.update('[B') is called!");
// var algorithm = this.getAlgorithm();
// var tag = algorithm + " update data";
// toUtf8(tag, data);
// toHex(tag, data);
// toBase64(tag, data);
// console.log("=======================================================");
// return this.update(data);
// }
// mac.update.overload('[B', 'int', 'int').implementation = function (data, start, length) {
// console.log("Mac.update('[B', 'int', 'int') is called!");
// var algorithm = this.getAlgorithm();
// var tag = algorithm + " update data";
// toUtf8(tag, data);
// toHex(tag, data);
// toBase64(tag, data);
// console.log("=======================================================", start, length);
// return this.update(data, start, length);
// }
// mac.doFinal.overload().implementation = function () {
// console.log("Mac.doFinal() is called!");
// var result = this.doFinal();
// var algorithm = this.getAlgorithm();
// var tag = algorithm + " doFinal result";
// toUtf8(tag, result);
// toHex(tag, result);
// toBase64(tag, result);
// console.log("=======================================================");
// return result;
// }
// mac.doFinal.overload('[B').implementation = function (data) {
// console.log("Mac.doFinal.overload('[B') is called!");
// return this.doFinal(data);
// }
// mac.doFinal.overload('[B', 'int').implementation = function (output, outOffset) {
// console.log("Mac.doFinal.overload('[B', 'int') is called!");
// console.log("=======================================================");
// return this.doFinal(output, outOffset);
// }
//
// var cipher = Java.use("javax.crypto.Cipher");
// cipher.init.overload('int', 'java.security.cert.Certificate').implementation = function () {
// console.log("Cipher.init('int', 'java.security.cert.Certificate') is called!");
// console.log("=======================================================");
// return this.init.apply(this, arguments);
// }
// cipher.init.overload('int', 'java.security.Key', 'java.security.SecureRandom').implementation = function () {
// console.log("Cipher.init('int', 'java.security.Key', 'java.security.SecureRandom') is called!");
// console.log("=======================================================");
// return this.init.apply(this, arguments);
// }
// cipher.init.overload('int', 'java.security.cert.Certificate', 'java.security.SecureRandom').implementation = function () {
// console.log("Cipher.init('int', 'java.security.cert.Certificate', 'java.security.SecureRandom') is called!");
// console.log("=======================================================");
// return this.init.apply(this, arguments);
// }
// cipher.init.overload('int', 'java.security.Key', 'java.security.AlgorithmParameters', 'java.security.SecureRandom').implementation = function () {
// console.log("Cipher.init('int', 'java.security.Key', 'java.security.AlgorithmParameters', 'java.security.SecureRandom') is called!");
// console.log("=======================================================");
// return this.init.apply(this, arguments);
// }
// cipher.init.overload('int', 'java.security.Key', 'java.security.spec.AlgorithmParameterSpec', 'java.security.SecureRandom').implementation = function () {
// console.log("Cipher.init('int', 'java.security.Key', 'java.security.spec.AlgorithmParameterSpec', 'java.security.SecureRandom') is called!");
// console.log("=======================================================");
// return this.init.apply(this, arguments);
// }
// cipher.init.overload('int', 'java.security.Key', 'java.security.AlgorithmParameters').implementation = function () {
// console.log("Cipher.init('int', 'java.security.Key', 'java.security.AlgorithmParameters') is called!");
// console.log("=======================================================");
// return this.init.apply(this, arguments);
// }
//
// cipher.init.overload('int', 'java.security.Key').implementation = function () {
// console.log("Cipher.init('int', 'java.security.Key') is called!");
// var algorithm = this.getAlgorithm();
// var tag = algorithm + " init Key";
// var className = JSON.stringify(arguments[1]);
// if (className.indexOf("OpenSSLRSAPrivateKey") === -1) {
// var keyBytes = arguments[1].getEncoded();
// toUtf8(tag, keyBytes);
// toHex(tag, keyBytes);
// toBase64(tag, keyBytes);
// }
// console.log("=======================================================");
// return this.init.apply(this, arguments);
// }
// cipher.init.overload('int', 'java.security.Key', 'java.security.spec.AlgorithmParameterSpec').implementation = function () {
// console.log("Cipher.init('int', 'java.security.Key', 'java.security.spec.AlgorithmParameterSpec') is called!");
// var algorithm = this.getAlgorithm();
// var tag = algorithm + " init Key";
// var keyBytes = arguments[1].getEncoded();
// toUtf8(tag, keyBytes);
// toHex(tag, keyBytes);
// toBase64(tag, keyBytes);
// var tags = algorithm + " init iv";
// var iv = Java.cast(arguments[2], Java.use("javax.crypto.spec.IvParameterSpec"));
// var ivBytes = iv.getIV();
// toUtf8(tags, ivBytes);
// toHex(tags, ivBytes);
// toBase64(tags, ivBytes);
// console.log("=======================================================");
// return this.init.apply(this, arguments);
// }
//
// cipher.doFinal.overload('java.nio.ByteBuffer', 'java.nio.ByteBuffer').implementation = function () {
// console.log("Cipher.doFinal('java.nio.ByteBuffer', 'java.nio.ByteBuffer') is called!");
// console.log("=======================================================");
// return this.doFinal.apply(this, arguments);
// }
// cipher.doFinal.overload('[B', 'int').implementation = function () {
// console.log("Cipher.doFinal('[B', 'int') is called!");
// console.log("=======================================================");
// return this.doFinal.apply(this, arguments);
// }
// cipher.doFinal.overload('[B', 'int', 'int', '[B').implementation = function () {
// console.log("Cipher.doFinal('[B', 'int', 'int', '[B') is called!");
// console.log("=======================================================");
// return this.doFinal.apply(this, arguments);
// }
// cipher.doFinal.overload('[B', 'int', 'int', '[B', 'int').implementation = function () {
// console.log("Cipher.doFinal('[B', 'int', 'int', '[B', 'int') is called!");
// console.log("=======================================================");
// return this.doFinal.apply(this, arguments);
// }
// cipher.doFinal.overload().implementation = function () {
// console.log("Cipher.doFinal() is called!");
// console.log("=======================================================");
// return this.doFinal.apply(this, arguments);
// }
//
// cipher.doFinal.overload('[B').implementation = function () {
// console.log("Cipher.doFinal('[B') is called!");
// showStacks();
// var algorithm = this.getAlgorithm();
// var tag = algorithm + " doFinal data";
// var data = arguments[0];
// toUtf8(tag, data);
// toHex(tag, data);
// toBase64(tag, data);
// var result = this.doFinal.apply(this, arguments);
// var tags = algorithm + " doFinal result";
// toUtf8(tags, result);
// toHex(tags, result);
// toBase64(tags, result);
// console.log("=======================================================");
// return result;
// }
// cipher.doFinal.overload('[B', 'int', 'int').implementation = function () {
// console.log("Cipher.doFinal('[B', 'int', 'int') is called!");
// showStacks();
// var algorithm = this.getAlgorithm();
// var tag = algorithm + " doFinal data";
// var data = arguments[0];
// toUtf8(tag, data);
// toHex(tag, data);
// toBase64(tag, data);
// var result = this.doFinal.apply(this, arguments);
// var tags = algorithm + " doFinal result";
// toUtf8(tags, result);
// toHex(tags, result);
// toBase64(tags, result);
// console.log("=======================================================", arguments[1], arguments[2]);
// return result;
// }
//
// var signature = Java.use("java.security.Signature");
// signature.update.overload('byte').implementation = function (data) {
// console.log("Signature.update('byte') is called!");
// return this.update(data);
// }
// signature.update.overload('java.nio.ByteBuffer').implementation = function (data) {
// console.log("Signature.update('java.nio.ByteBuffer') is called!");
// return this.update(data);
// }
// // signature.update.overload('[B').implementation = function (data) {
// // console.log("Signature.update('[B') is called!");
// // var algorithm = this.getAlgorithm();
// // var tag = algorithm + " update data";
// // toUtf8(tag, data);
// // toHex(tag, data);
// // toBase64(tag, data);
// // console.log("=======================================================");
// // return this.update(data);
// // }
// signature.update.overload('[B', 'int', 'int').implementation = function (data, start, length) {
// console.log("Signature.update('[B', 'int', 'int') is called!");
// var algorithm = this.getAlgorithm();
// var tag = algorithm + " update data";
// toUtf8(tag, data);
// toHex(tag, data);
// toBase64(tag, data);
// console.log("=======================================================", start, length);
// return this.update(data, start, length);
// }
//
// signature.initSign.overload('java.security.PrivateKey').implementation = function (key) {
// console.log("Signature.initSign('java.security.PrivateKey') is called!");
// var algorithm = this.getAlgorithm();
// var tag = algorithm + " initSign PrivateKey";
//
// var OpenSSLRSAPrivateKey = Java.use("com.android.org.conscrypt.OpenSSLRSAPrivateKey");
// var realkey = Java.cast(key, OpenSSLRSAPrivateKey).getEncoded();
// toUtf8(tag, realkey);
// toHex(tag, realkey);
// toBase64(tag, realkey);
// console.log("=======================================================");
// return this.initSign(key);
// }
//
// signature.initSign.overload('java.security.PrivateKey', 'java.security.SecureRandom').implementation = function (key, secureRandom) {
// console.log("Signature.initSign('java.security.PrivateKey', 'java.security.SecureRandom') is called!");
// console.log("=======================================================");
// return this.initSign(key, secureRandom);
// }
//
// signature.sign.overload('[B', 'int', 'int').implementation = function () {
// console.log("Signature.sign('[B', 'int', 'int') is called!");
// return this.sign.apply(this, arguments);
// }
// signature.sign.overload().implementation = function () {
// console.log("Signature.sign() is called!");
// var result = this.sign();
// var algorithm = this.getAlgorithm();
// var tag = algorithm + " sign result";
// toHex(tag, result);
// toBase64(tag, result);
// console.log("=======================================================");
// return result;
// }
//
// });


var CertificatePinner = Java.use('okhttp3.CertificatePinner');
CertificatePinner.check$okhttp.implementation = function () {
console.log('OkHTTP 3.x check$okhttp() called. Not throwing an exception.');
}

function showStacks() {
console.log(
Java.use("android.util.Log")
.getStackTraceString(
Java.use("java.lang.Throwable").$new()
)
);
}

var base64 = Java.use("android.util.Base64");
base64.encodeToString.overload('[B', 'int').implementation = function (a, b) {
showStacks();
console.log("base64.encodeToString: ", JSON.stringify(a));
var result = this.encodeToString(a, b);
console.log("base64.encodeToString result: ", result)
return result;
}

var EncryptlibUtils = Java.use("com.pocket.snh48.base.net.utils.EncryptlibUtils");
EncryptlibUtils.MD5.implementation = function (a, b, c, d) {
console.log("EncryptlibUtils.MD5: ", b, c, d);
var result = this.MD5(a, b, c, d);
console.log("EncryptlibUtils.MD5: ", result)
return result;
}