1. frida
//自吐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()); } // toBase64([48,49,50,51,52]); // toHex([48,49,50,51,52]); // toUtf8([48,49,50,51,52]); //console.log(Java.enumerateLoadedClassesSync().join("\n")); // MD5/SHA等 var messageDigest = Java.use("java.security.MessageDigest"); messageDigest.update.overload('byte').implementation = function (data) { console.log("MessageDigest.update('byte') is called!"); return this.update(data); } messageDigest.update.overload('java.nio.ByteBuffer').implementation = function (data) { console.log("MessageDigest.update('java.nio.ByteBuffer') is called!"); return this.update(data); } messageDigest.update.overload('[B').implementation = function (data) { console.log("MessageDigest.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); } messageDigest.update.overload('[B', 'int', 'int').implementation = function (data, start, length) { console.log("MessageDigest.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); } messageDigest.digest.overload().implementation = function () { console.log("MessageDigest.digest() is called!"); 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!"); 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!"); 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; } //Mac 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; } //cipher 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; } //signature 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; }});
/*** Java层标准算法hook*/Java.perform(function () { /** 打印堆栈 */ function showStack() { let Throwable = Java.use("java.lang.Throwable"); let stackTraceString = Java.use("android.util.Log").getStackTraceString(Throwable.$new()) console.log(stackTraceString); } let ByteString = Java.use("com.android.okhttp.okio.ByteString"); /** * 字节数组转为Base64 */ function toBase64(tag, data) { console.log(tag + " Base64:" + ByteString.of(data).base64()); } /** * 字节数组转为16进制 */ function toHex(tag, data) { console.log(tag + " Hex:" + ByteString.of(data).hex()); } /** * 字节数组转为明文 */ function toUtf8(tag, data) { console.log(tag + " Utf8:" + ByteString.of(data).utf8()); } /** * 打印字节数组对应的输出数据 */ function printData(tag, data) { toBase64(tag, data); toHex(tag, data); toUtf8(tag, data); } /*** * 消息摘要算法hook * update 压入数据 * digest 返回加密结果 */ function hookMessageDigest() { let MessageDigest = Java.use("java.security.MessageDigest"); MessageDigest.update.overload('byte').implementation = function (b) { showStack(); console.log("MessageDigest.update.overload('byte') is called!"); let result = this.update.apply(this, arguments); let algorithm = this.getAlgorithm(); printData(algorithm + " update param", Java.array('byte', [b])) console.log("============================================================"); return result; } MessageDigest.update.overload('[B').implementation = function (byteArr) { showStack(); console.log("MessageDigest.update.overload('[B') is called!"); let result = this.update.apply(this, arguments); let algorithm = this.getAlgorithm(); printData(algorithm + " update param", byteArr); console.log("============================================================"); return result; } MessageDigest.digest.overload().implementation = function () { showStack(); console.log("MessageDigest.digest.overload() is called!"); let result = this.digest.apply(this, arguments); let algorithm = this.getAlgorithm(); printData(algorithm + " digest result", result); console.log("============================================================"); return result; } MessageDigest.digest.overload('[B').implementation = function (byteArr) { showStack(); console.log("MessageDigest.digest.overload('[B') is called!"); let result = this.digest.apply(this, arguments); let algorithm = this.getAlgorithm(); printData(algorithm + " digest param", byteArr); printData(algorithm + " digest result", result); console.log("============================================================"); return result; } MessageDigest.digest.overload('[B', 'int', 'int').implementation = function (byteArr, start, length) { showStack(); console.log("MessageDigest.digest.overload('[B', 'int', 'int') is called!"); let result = this.digest.apply(this, arguments); let algorithm = this.getAlgorithm(); printData(algorithm + " digest param", byteArr); printData(algorithm + " digest result", result); console.log("============================================================" + "开始位置:" + start + " 截取长度:" + length); return result; } } /** * Mac算法hook * 1.init 初始化,秘钥 * 2.update 压入数据 * 3.doFinal 加密 */ function hookMac() { let Mac = Java.use("javax.crypto.Mac"); Mac.init.overload('java.security.Key').implementation = function (key) { showStack(); console.log("Mac.init.overload('java.security.Key') is called!"); let result = this.init.apply(this, arguments); let algorithm = this.getAlgorithm(); printData(algorithm + " init key", key.getEncoded()) console.log("============================================================"); return result; } Mac.update.overload('byte').implementation = function (b) { showStack(); console.log("Mac.update.overload('byte') is called!"); let result = this.update.apply(this, arguments); let algorithm = this.getAlgorithm(); printData(algorithm + " update param", Java.array('byte', [b])) console.log("============================================================"); return result; } Mac.update.overload('[B').implementation = function (byteArr) { showStack(); console.log("Mac.update.overload('[B') is called!"); let result = this.update.apply(this, arguments); let algorithm = this.getAlgorithm(); printData(algorithm + " update param", byteArr) console.log("============================================================"); return result; } Mac.update.overload('[B', 'int', 'int').implementation = function (byteArr, start, length) { showStack(); console.log("Mac.update.overload('[B', 'int', 'int') is called!"); let result = this.update.apply(this, arguments); let algorithm = this.getAlgorithm(); printData(algorithm + " update param", byteArr) console.log("============================================================" + "开始位置:" + start + " 截取长度:" + length); return result; } Mac.doFinal.overload().implementation = function () { showStack(); console.log("Mac.doFinal.overload() is called!"); let result = this.doFinal.apply(this, arguments); let algorithm = this.getAlgorithm(); printData(algorithm + " doFinal result", result) console.log("============================================================"); return result; } } /** * DES,DESEde,AES,RSA * 1.init 加密类型,key,iv * 2.donFinal压入数据,得到结果 update压入结果有问题 */ function hookCipher() { function printResult(cipherObj, result, args) { let algorithm = cipherObj.getAlgorithm(); let mode; if (cipherObj.opmode.value === 1) { mode = "加密"; } else { mode = "解密"; } console.log(algorithm + " mode:", mode); if (cipherObj.getParameters() != null) { printData(algorithm + " key", cipherObj.getParameters().getEncoded()); printData(algorithm + " iv", cipherObj.getIV()); } printData(algorithm + " doFinal param", args[0]); printData(algorithm + " doFinal result", result); console.log("============================================================"); } let Cipher = Java.use("javax.crypto.Cipher"); // 不常用重载,打印调用即可,根据堆栈信息在具体去看 // init暂时注释 Cipher.init.overload('int', 'java.security.cert.Certificate', 'java.security.SecureRandom').implementation = function (key) { showStack(); console.log("Cipher.init.overload('int', 'java.security.cert.Certificate', 'java.security.SecureRandom') is called!"); let result = this.apply(this, arguments); return result; } Cipher.init.overload('int', 'java.security.Key', 'java.security.AlgorithmParameters', 'java.security.SecureRandom').implementation = function (key) { showStack(); console.log("Cipher.init.overload('int', 'java.security.Key', 'java.security.AlgorithmParameters', 'java.security.SecureRandom') is called!"); let result = this.apply(this, arguments); return result; } // ECB模式,不带iv Cipher.init.overload('int', 'java.security.Key', 'java.security.SecureRandom').implementation = function () { showStack(); console.log("Cipher.init.overload('int', 'java.security.Key', 'java.security.SecureRandom') is called!"); let result = this.init.apply(this, arguments); let algorithm = this.getAlgorithm(); let mode; if (arguments[0] === 1) { mode = "加密"; } else { mode = "解密"; } console.log(algorithm + " init mode:" + mode); try { // RSA使用私钥调用getEncoded() 会报错,异常捕获,具体逻辑,根据堆栈,去APP分析 printData(algorithm + " init key", arguments[1].getEncoded()); } catch (e) { console.log(e); } console.log("============================================================"); return result; } // CBC模式,带iv Cipher.init.overload('int', 'java.security.Key', 'java.security.spec.AlgorithmParameterSpec', 'java.security.SecureRandom').implementation = function () { showStack(); console.log("Cipher.init.overload('int', 'java.security.Key', 'java.security.spec.AlgorithmParameterSpec', 'java.security.SecureRandom') is called!"); let result = this.init.apply(this, arguments); let algorithm = this.getAlgorithm(); let ivParameterSpecObj = Java.cast(arguments[2], Java.use("javax.crypto.spec.IvParameterSpec")); let mode; if (arguments[0] === 1) { mode = "加密"; } else { mode = "解密"; } console.log(algorithm + " init mode:" + mode); printData(algorithm + " init key", arguments[1].getEncoded()); printData(algorithm + " init iv", ivParameterSpecObj.getIV()); console.log("============================================================"); return result; } Cipher.doFinal.overload().implementation = function () { showStack(); console.log("Cipher.doFinal.overload() is called!"); let result = this.doFinal.apply(this, arguments); printResult(this, result, arguments); return result; } Cipher.doFinal.overload('[B').implementation = function () { showStack(); console.log("Cipher.doFinal.overload('[B') is called!"); let result = this.doFinal.apply(this, arguments); printResult(this, result, arguments); return result; } Cipher.doFinal.overload('[B', 'int').implementation = function () { showStack(); console.log("Cipher.doFinal.overload('[B', 'int') is called!"); let result = this.doFinal.apply(this, arguments); printResult(this, result, arguments); return result; } Cipher.doFinal.overload('[B', 'int', 'int').implementation = function () { showStack(); console.log("Cipher.doFinal.overload('[B', 'int', 'int') is called!"); let result = this.doFinal.apply(this, arguments); printResult(this, result, arguments); return result; } Cipher.doFinal.overload('[B', 'int', 'int', '[B').implementation = function () { showStack(); console.log("Cipher.doFinal.overload('[B', 'int', 'int', '[B') is called!"); let result = this.doFinal.apply(this, arguments); printResult(this, result, arguments); return result; } Cipher.doFinal.overload('[B', 'int', 'int', '[B', 'int').implementation = function () { showStack(); console.log("Cipher.doFinal.overload('[B', 'int', 'int', '[B', 'int') is called!"); let result = this.doFinal.apply(this, arguments); printResult(this, result, arguments); return result; } } /** * 签名算法hook * 私钥 */ function hookSignature() { let Signature = Java.use("java.security.Signature"); Signature.initSign.overload('java.security.PrivateKey').implementation = function () { showStack(); console.log("Signature.initSign.overload('java.security.PrivateKey') is called!"); let result = this.initSign.apply(this, arguments); let algorithm = this.getAlgorithm(); try { // RSA使用Hex编码的私钥调用getEncoded() 会报错,异常捕获,具体逻辑,根据堆栈,去APP分析 printData(algorithm + " init key", arguments[0].getEncoded()); } catch (e) { console.log(JSON.stringify(arguments[0]) + "|" + e); } console.log("============================================================"); return result; } Signature.update.overload('byte').implementation = function () { showStack(); console.log("Signature.update.overload('byte') is called!"); let result = this.update.apply(this, arguments); let algorithm = this.getAlgorithm(); printData(algorithm + " update param", Java.array('byte', [b])) console.log("============================================================"); return result; } Signature.update.overload('[B', 'int', 'int').implementation = function () { showStack(); console.log("Signature.update.overload('[B', 'int', 'int') is called!"); let result = this.update.apply(this, arguments); let algorithm = this.getAlgorithm(); printData(algorithm + " update param", arguments[0]); console.log("============================================================"); return result; } Signature.sign.overload().implementation = function () { showStack(); console.log("Signature.sign.overload() is called!"); let result = this.sign.apply(this, arguments); let algorithm = this.getAlgorithm(); printData(algorithm + " sign result", result); console.log("============================================================"); return result; } Signature.sign.overload('[B', 'int', 'int').implementation = function () { showStack(); console.log("Signature.sign.overload('[B', 'int', 'int') is called!"); let result = this.sign.apply(this, arguments); let algorithm = this.getAlgorithm(); printData(algorithm + " sign param", arguments[0]); printData(algorithm + " sign result", result); console.log("============================================================"); return result; } } /** * Base64hook */ function hookBase64() { let Base64 = Java.use("android.util.Base64"); Base64.encodeToString.overload('[B', 'int').implementation = function () { let result = this.encodeToString.apply(this, arguments); printData("Base64 param", arguments[0]); console.log("-------------------------------"); console.log("Base64 result:" + result); console.log("============================================================"); return result; } } // 消息摘要算法hook hookMessageDigest(); // Mac算法hook hookMac(); // hookCipher hookCipher(); // 数据签名算法hook hookSignature(); // hookBase64编码 hookBase64();})