Android APP开发之frida hook自吐算法
The following article is from Python爬虫与数据挖掘 Author Python进阶者
大家好,我是码农星期八,上次有一篇密码学的文章,里面大概说了一下常用的安卓加密。
本次来搞一下Java层的自吐算法。
前置工作
因为加密算法最终的格式都需要转成base64或者hex,所以需要把这些函数先定义一下
//打印堆栈
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");
//输出base64格式数据
function toBase64(tag, data) {
console.log(tag + " Base64: ", ByteString.of(data).base64());
}
//输出hex格式数据
function toHex(tag, data) {
console.log(tag + " Hex: ", ByteString.of(data).hex());
}
//输出10格式数据
function toUtf8(tag, data) {
console.log(tag + " Utf8: ", ByteString.of(data).utf8());
}
什么是自吐算法
我们在进行安卓开发的时候,如果想使用Java层的加密函数进行加密,那必定是要触发相关函数的。
并且即使是字符串混淆,这些系统的关键字是不能混淆的。
比如MD5是由MessageDigest
这个类生成的。
所以如果我们整理一下,hook了相关的关键字,如果调用了相关加密库,必定是要经过我们的hook。
这样,嘿嘿嘿,似乎又方便了一步。
MD5和SHA1自吐
MD5加密主要逻辑
SHA加密主要逻辑
其实可以发现,MD5和SHA1的流程基本是一样的,除了后面写入的算法名不同。
所以这俩是可以用一个的。
根据整理,需要hook update
和digest
即可。
update
拿到的是压入的数据。digest
可以拿到压入的数据和返回的加密数据。
代码
var messageDigest = Java.use("java.security.MessageDigest");
messageDigest.update.overload('byte').implementation = function (data) {
console.log("↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓");
console.log("MessageDigest.update('byte') is called!");
showStacks();
console.log("↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑");
return this.update(data);
}
messageDigest.update.overload('java.nio.ByteBuffer').implementation = function (data) {
console.log("↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓");
console.log("MessageDigest.update('java.nio.ByteBuffer') is called!");
showStacks();
console.log("↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑");
return this.update(data);
}
messageDigest.update.overload('[B').implementation = function (data) {
console.log("↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓");
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("↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓");
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:", start);
console.log("length:", length);
showStacks();
console.log("↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑");
return this.update(data, start, length);
}
messageDigest.digest.overload().implementation = function () {
console.log("↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓");
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);
showStacks();
console.log("↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑");
return result;
}
messageDigest.digest.overload('[B').implementation = function (data) {
console.log("↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓");
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);
showStacks();
console.log("↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑");
return result;
}
messageDigest.digest.overload('[B', 'int', 'int').implementation = function (data, start, length) {
console.log("↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓");
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:", start);
console.log("length:", length);
showStacks();
console.log("↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑");
return result;
}
效果
MAC自吐
MAC加密主要逻辑
MAC主要是需要一个密钥。压入数据用的是update
。获取数据用的是doFinal
。
所以需要hook init
和update
和doFinal
代码
var mac = Java.use("javax.crypto.Mac");
mac.init.overload('java.security.Key', 'java.security.spec.AlgorithmParameterSpec').implementation = function (key, AlgorithmParameterSpec) {
console.log("↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓");
console.log("Mac.init('java.security.Key', 'java.security.spec.AlgorithmParameterSpec') is called!");
showStacks();
console.log("↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑");
return this.init(key, AlgorithmParameterSpec);
}
mac.init.overload('java.security.Key').implementation = function (key) {
console.log("↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓");
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);
showStacks();
console.log("↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑");
return this.init(key);
}
mac.update.overload('byte').implementation = function (data) {
console.log("↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓");
console.log("Mac.update('byte') is called!");
showStacks();
console.log("↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑");
return this.update(data);
}
mac.update.overload('java.nio.ByteBuffer').implementation = function (data) {
console.log("↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓");
console.log("Mac.update('java.nio.ByteBuffer') is called!");
showStacks();
console.log("↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑");
return this.update(data);
}
mac.update.overload('[B').implementation = function (data) {
console.log("↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓");
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);
showStacks();
console.log("↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑");
return this.update(data);
}
mac.update.overload('[B', 'int', 'int').implementation = function (data, start, length) {
console.log("↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓");
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:", start);
console.log("length:", length);
showStacks();
console.log("↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑");
return this.update(data, start, length);
}
mac.doFinal.overload().implementation = function () {
console.log("↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓");
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);
showStacks();
console.log("↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑");
return result;
}
示例
DES/DESede/AES/RSA
DES/DESede/AES/RSA
这几个加密。都是通过Cipher
来进行实例化的。
基本加密逻辑一样
init
压入key。因为 DES/DESede/AES/RSA
的update
压入有问题,所以直接hookdoFinal
就好了。
代码
// DES/DESede/AES/RSA
var cipher = Java.use("javax.crypto.Cipher");
cipher.init.overload('int', 'java.security.cert.Certificate').implementation = function () {
console.log("↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓");
console.log("Cipher.init('int', 'java.security.cert.Certificate') is called!");
showStacks();
console.log("↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑");
return this.init.apply(this, arguments);
}
cipher.init.overload('int', 'java.security.Key', 'java.security.SecureRandom').implementation = function () {
console.log("↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓");
console.log("Cipher.init('int', 'java.security.Key', 'java.security.SecureRandom') is called!");
showStacks();
console.log("↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑");
return this.init.apply(this, arguments);
}
cipher.init.overload('int', 'java.security.cert.Certificate', 'java.security.SecureRandom').implementation = function () {
console.log("↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓");
console.log("Cipher.init('int', 'java.security.cert.Certificate', 'java.security.SecureRandom') is called!");
showStacks();
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("↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓");
console.log("Cipher.init('int', 'java.security.Key', 'java.security.AlgorithmParameters', 'java.security.SecureRandom') is called!");
showStacks();
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("↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓");
console.log("Cipher.init('int', 'java.security.Key', 'java.security.spec.AlgorithmParameterSpec', 'java.security.SecureRandom') is called!");
showStacks();
console.log("↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑");
return this.init.apply(this, arguments);
}
cipher.init.overload('int', 'java.security.Key', 'java.security.AlgorithmParameters').implementation = function () {
console.log("↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓");
console.log("Cipher.init('int', 'java.security.Key', 'java.security.AlgorithmParameters') is called!");
showStacks();
console.log("↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑");
return this.init.apply(this, arguments);
}
cipher.init.overload('int', 'java.security.Key').implementation = function () {
console.log("↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓");
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);
}
showStacks();
console.log("↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑");
return this.init.apply(this, arguments);
}
cipher.init.overload('int', 'java.security.Key', 'java.security.spec.AlgorithmParameterSpec').implementation = function () {
console.log("↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓");
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);
showStacks();
console.log("↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑");
return this.init.apply(this, arguments);
}
cipher.doFinal.overload('java.nio.ByteBuffer', 'java.nio.ByteBuffer').implementation = function () {
console.log("↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓");
console.log("Cipher.doFinal('java.nio.ByteBuffer', 'java.nio.ByteBuffer') is called!");
showStacks();
console.log("↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑");
return this.doFinal.apply(this, arguments);
}
cipher.doFinal.overload('[B', 'int').implementation = function () {
console.log("↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓");
console.log("Cipher.doFinal('[B', 'int') is called!");
showStacks();
console.log("↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑");
return this.doFinal.apply(this, arguments);
}
cipher.doFinal.overload('[B', 'int', 'int', '[B').implementation = function () {
console.log("↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓");
console.log("Cipher.doFinal('[B', 'int', 'int', '[B') is called!");
showStacks();
console.log("↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑");
return this.doFinal.apply(this, arguments);
}
cipher.doFinal.overload('[B', 'int', 'int', '[B', 'int').implementation = function () {
console.log("↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓");
console.log("Cipher.doFinal('[B', 'int', 'int', '[B', 'int') is called!");
showStacks();
console.log("↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑");
return this.doFinal.apply(this, arguments);
}
cipher.doFinal.overload().implementation = function () {
console.log("↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓");
console.log("Cipher.doFinal() is called!");
showStacks();
console.log("↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑");
return this.doFinal.apply(this, arguments);
}
cipher.doFinal.overload('[B').implementation = function () {
console.log("↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓");
console.log("Cipher.doFinal('[B') is called!");
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);
showStacks();
console.log("↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑");
return result;
}
cipher.doFinal.overload('[B', 'int', 'int').implementation = function () {
console.log("↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓");
console.log("Cipher.doFinal('[B', 'int', 'int') is called!");
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[1],);
console.log("arguments[2]:", arguments[2]);
showStacks();
console.log("↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑");
return result;
}
效果
签名算法
签名算法是混合算法,先记着就行。
代码
//签名算法
var signature = Java.use("java.security.Signature");
signature.update.overload('byte').implementation = function (data) {
console.log("↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓");
console.log("Signature.update('byte') is called!");
showStacks();
console.log("↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑");
return this.update(data);
}
signature.update.overload('java.nio.ByteBuffer').implementation = function (data) {
console.log("↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓");
console.log("Signature.update('java.nio.ByteBuffer') is called!");
showStacks();
console.log("↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑");
return this.update(data);
}
signature.update.overload('[B', 'int', 'int').implementation = function (data, start, length) {
console.log("↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓");
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:", start);
console.log("length:", length);
showStacks();
console.log("↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑");
return this.update(data, start, length);
}
signature.sign.overload('[B', 'int', 'int').implementation = function () {
console.log("↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓");
console.log("Signature.sign('[B', 'int', 'int') is called!");
showStacks();
console.log("↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑");
return this.sign.apply(this, arguments);
}
signature.sign.overload().implementation = function () {
console.log("↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓");
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);
showStacks();
console.log("↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑");
return result;
}
实战效果
xx牛.apk
只要用了Java层的加密,这个方式就能直接都hook出来。
完整代码
z_Java层自吐.js
推荐阅读
哆啦安全团队推出了系列零基础安全课程的速成培训班,后续还会推出系列定制版Android安全手机(开源Android镜像+安全,构建开源生态),欢迎关注"哆啦安全",有兴趣的可以加微信进群!