这篇文章其实是前面的Traceview+frida这对绝配的组合的一个案例,不了解的可以去可以去看我直接写的几篇文章,这次以之前的一个搞的投资APP为例,这个应用数据是加密的,而且apk本身是360加固的,当时一看麻烦又要脱壳又要逆向就没弄,这次正好拿它来开整。
点击投资这个页面(或者刷新)
方法一:我们可以直接hook Cipher.init这个关键函数就能获得所有的模式,key和iv了,下面给出脚本
Java.perform(function x() {
function toHexString(byteArray) {
return Array.prototype.map.call(byteArray, function(byte) {
return ('0' + (byte & 0xFF).toString(16)).slice(-2);
}).join('');
}
var Cipher = Java.use('javax.crypto.Cipher');
var iv_parameter_spec = Java.use("javax.crypto.spec.IvParameterSpec");
Cipher.init.overload("int", "java.security.Key", "java.security.spec.AlgorithmParameterSpec").implementation = function (arg1,arg2,arg3) {
send("arg1: "+arg1);
//refer to https://11x256.github.io/Frida-hooking-android-part-5/
var b = arg2.getEncoded();
var printable_key = ""
for (var i = 0; i < b.length; i++){
printable_key += (b[i].toString(16) + "");
}
send("key: "+printable_key);
var temp=new Uint8Array(Java.cast(arg3, iv_parameter_spec).getIV());
send("iv: "+toHexString(temp));
this.init(arg1,arg2,arg3);
};
});
当然这只适用于密钥是可见明文的情况,下面给出更通用的方法。
方法二:对比AES的解密实现,重点关注下面三个地方
使用frida来hook这三个地方,注意1,3两处我们要hook构造函数,和普通的2处函数是有区别的,要用$init这种形式,并且要return this.$init(arg1,arg2)调用原始的函数实现。(其中 cipher.init(Cipher.DECRYPT_MODE, keySpec, iv)函数并不能找到这个重载)。 然后坑点又来了,这个bytes类型并不能直接打印,会输出[object Object],然后搜索了好多也没解决问题,这里应该用到一个Google搜索的技巧——双引号,这样精确匹配
使用Frida逆向分析Android应用与BLE设备的通信 按照这篇文章所说的稍作修改终于可以打印byte数组了(注意这里不能用js里的fromCharCode转换成String,因为APP的密钥等不一定是可见明文,应该输出原始的十六进制数据)……我们分别来hook AES的mode,Key,iv,脚本如下
# -*- coding:utf-8 -*-
import frida, sys
def on_message(message, data):
if message['type'] == 'send':
print("[*] {0}".format(message['payload']))
else:
print(message)
jscode = """
Java.perform(function x() {
// Function to hook is defined here
var UtiEncrypt = Java.use('com.bianlidai123.bc.encrypt.UtiEncrypt');
// Whenever button is clicked
UtiEncrypt.decryptAES.overload('java.lang.String').implementation = function (arg1) {
// Show a message to know that the function got called
var sign=this.decryptAES(arg1);
send("arg1:"+arg1);
send("sign:"+sign);
return sign;
};
var Cipher = Java.use('javax.crypto.Cipher');
Cipher.getInstance.overload('java.lang.String').implementation = function (arg1) {
var sign2=this.getInstance(arg1);
send("Instance:"+arg1);
return sign2;
};
var SecretKeySpec = Java.use('javax.crypto.spec.SecretKeySpec');
SecretKeySpec.$init.overload('[B', 'java.lang.String').implementation = function (arg1,arg2) {
hexstr="";
for (i=0;i<arg1.length;i++)
{
b=(arg1[i]>>>0)&0xff;
n=b.toString(16);
hexstr += ("00" + n).slice(-2)+" ";
}
send("Key: " + hexstr);
//send("init1:"+arg1+arg2);
return this.$init(arg1,arg2);
};
var IvParameterSpec = Java.use('javax.crypto.spec.IvParameterSpec');
IvParameterSpec.$init.overload('[B').implementation = function (arg1) {
hexstr="";
for (i=0;i<arg1.length;i++)
{
b=(arg1[i]>>>0)&0xff;
n=b.toString(16);
hexstr += ("00" + n).slice(-2)+" ";
}
send("Iv: " + hexstr);
//send("init4:"+arg1);
return this.$init(arg1);
};
});
"""
process = frida.get_usb_device().attach(8309)
script = process.create_script(jscode)
script.on('message', on_message)
print('[*] Running CTF')
script.load()
sys.stdin.read()
成功获取到Key和iv之后,我们就可以去解密数据了
这样就完成了一次不需要脱壳加逆向就能解密APP的数据了!!!