近期有个小伙伴发我一个数据库加密的应用分析,发现是近期友商出的一个题目,分析后整理一下过程,首先发我APK的同时,也发我了他的解析思路,但是我分析后发现过于麻烦,不够简洁,所以重新按着自己的思路分析的。
实验素材与环境:
程序名称:马铃薯视频
应用程序包名:plus.H5B8E45D3
实验环境:雷电模拟器4.0.39
APK运行环境:安卓7.1
分析工具:JEB
分析步骤:
1. 查看默认位置/data/data/包名/database/数据库是否加密,排除加密数据库存储在其他路径,发现确实该目录下确实有一个test.db,利用数据库查看工具打开,发现确实有密码,那就确定了该数据库确实是目标数据库。
2. 利用反编译工具进行APK逆向,查看java代码
3. 利用掌握的线索直接搜索test.db,定位到代码
发现后面的getWritableDatabase()方法,对于加密数据库而言,往往getWritableDatabase中会附加数据库密钥,也就是getWritableDatabase(db_password)。所以我们目前需要分析的就是getWritableDatabase(WebAppActivity.getMD5(WebAppActivity.bytesToHex(new byte[]{97, 98, 99, 100, 101, 102}).substring(1, 3)))里面的值。看着有点长我们简化一下。其实很简单;
外层其实就是一个getMD5(),
里面就是一个bytesToHex(byte[]{97, 98, 99, 100, 101, 102}).substring(1,3),我们先计算bytesToHex(byte[]{97, 98, 99, 100, 101, 102}),
在bytesToHex()里面就是一个byte类型的数组{97, 98, 99, 100, 101, 102}
我们可以手工先将这个数组转换一成十六进制的数。
可以利用本地的计算器来转换,手工转换前两个97,98
97转换成十六进制就是61
98转换成十六进制就是62
后面的类似
最终得到:616263646566
当然我们也可以用脚本验证一下,我们可以扣出来原来的bytesToHex()
放入我们本地的java编译器中,我们打印一下
bytesToHex(new byte[]{97, 98, 99, 100, 101, 102})
最后结果和我们手工转换的一样都是:616263646566
那么现在bytesToHex(byte[]{97, 98, 99, 100, 101, 102})=616263646566
bytesToHex(byte[]{97, 98, 99, 100, 101, 102}).substring(1,3)=
616263646566.substring(1,3)=
16
这里简单介绍一下substring()
最后就是getMD5()
同理我们扣出原来的算法直接调用即可,最后还原验证的加密过程就是:
转换后的十六进制数是:616263646566
截取后的加密的原文是:16
数据库加密的密文是:c74d97b01eae257e44aa9d5bade97baf
当然也可以用frida hook,根据我们静态分析的过程,我们直接hook getMD5()最简单。
原文始发于微信公众号(盘古石取证):一次简单的手机数据库解密