搞安卓逆向我们都会遇到算法加密,通常我们都是hook写好脚本,frida注入看结果,然后在hook再去跟结果,平常逆向的产品多了再怎么都会遇到底层加密算法想同的产品,重复的去写hook太麻烦了,于是我整理了一份市场上通用的加密算法通杀脚本,涵盖MD5,SHA,MAC,DES,3DES,AES,RSA以及数字签名的算法通杀hook,使用这脚本只要系统函数底层调用了此加密的api就一定能hook到值,再去打印出堆栈就更好的定位到关键代码,并且秉着技术交流的想法对每种算法hook做进一步解释说明,此系列一个加密一篇文章
封装工具函数堆栈函数的打印一定要封装进去,如果说我们hook到加密值得话那么就顺带调用他的堆栈直接跟栈做代码定位就方便多了
function stack_print() {
console.log(
Java.use("android.util.Log")
.getStackTraceString(
Java.use("java.lang.Throwable").$new()
)
);
}
为了便于我们对数据得查看编码函数也一定要安排上,因为大多时候我们hook底层的API函数得到的都是数组值形式
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());
}
DES算法通杀hook
先看java底层算法的调用,我们可以看到不管是加密还是解密底层的都用到了Cipher,Cipher的init是需要hook的可以得到传入的数值,doFinal也需要得到加密后的数值
public class DES {
//加密算法
public static String encryptDES(String plainText) throws Exception {
//初始化密钥
SecretKeySpec desKey = new SecretKeySpec(new byte[]{1, 2, 3, 4, 5, 6, 7, 8}, "DES");
//初始化IV
IvParameterSpec ivParameterSpec = new IvParameterSpec("12345678".getBytes());
//算法名,模式信息
Cipher des = Cipher.getInstance("DES/CBC/PKCS5Padding");
des.init(1, desKey, ivParameterSpec);
return ByteString.of(des.doFinal(plainText.getBytes())).base64();
}
//解密算法
public static String decryptDES(String cipherText) throws Exception {
SecretKeySpec desKey = new SecretKeySpec(new byte[]{1, 2, 3, 4, 5, 6, 7, 8}, "DES");
IvParameterSpec ivParameterSpec = new IvParameterSpec("12345678".getBytes());
Cipher des = Cipher.getInstance("DES/CBC/PKCS5Padding");
des.init(2, desKey, ivParameterSpec);
return new String(des.doFinal(ByteString.decodebase64(cipherText).toByteArray()));
}
}
init方法是有七个重载的都写上,不常用的给个打印信息就行,doFinal也是七个重载
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') 被调用了!");
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') 被调用了!");
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') 被调用了!");
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') 被调用了!");
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') 被调用了!");
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') 被调用了!");
return this.init.apply(this, arguments);
}
cipher.init.overload('int', 'java.security.Key').implementation = function () {
console.log("Cipher.init('int', 'java.security.Key') 被调用了!");
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') 被调用了!");
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') 被调用了!");
return this.doFinal.apply(this, arguments);
}
cipher.doFinal.overload('[B', 'int').implementation = function () {
console.log("Cipher.doFinal('[B', 'int') 被调用了!");
return this.doFinal.apply(this, arguments);
}
cipher.doFinal.overload('[B', 'int', 'int', '[B').implementation = function () {
console.log("Cipher.doFinal('[B', 'int', 'int', '[B') 被调用了!");
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') 被调用了!");
return this.doFinal.apply(this, arguments);
}
cipher.doFinal.overload().implementation = function () {
console.log("Cipher.doFinal() 被调用了!");
return this.doFinal.apply(this, arguments);
}
cipher.doFinal.overload('[B').implementation = function () {
console.log("Cipher.doFinal('[B') 被调用了!");
var algorithm = this.getAlgorithm();
var tag = algorithm + " 调用doFinal 得到的数据:";
var data = arguments[0];
toUtf8(tag, data);
toHex(tag, data);
tobase64(tag, data);
var result = this.doFinal.apply(this, arguments);
var tags = algorithm + " 调用doFinal返回输出的数据:";
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') 被调用了!");
var algorithm = this.getAlgorithm();
var tag = algorithm + " 调用doFinal 得到的数据:";
var data = arguments[0];
toUtf8(tag, data);
toHex(tag, data);
tobase64(tag, data);
var result = this.doFinal.apply(this, arguments);
var tags = algorithm + " 调用doFinal返回输出的数据:";
toHex(tags, result);
tobase64(tags, result);
console.log("=======================================================", arguments[1], arguments[2]);
return result;
}



