Android进阶之路程序员Android开发

Android安全防护之旅---字符串批量加密工具(AndStr

2019-01-22  本文已影响82人  cff70524f5cf

一、支付宝防护策略

现在很多应用在为了安全对应用做了很多防护方式,之前我也介绍了很多防护策略:Android中几行代码让你的应用变得更加安全;文中也提到了应用安全防护的最终目标是防止别人看到你的代码,我们也知道这里的最终方式都是加固操作,但是加固有一些缺点,而这些确定导致现在很多公司应用并不会去选择他,所以一些其他的防护策略就出来了,包括防hook,防调试等操作。今天我们再来看一下如何把应用中的常量字符串信息进行加密,这个意义还是很大的,而这个主要是看到支付宝应用中是这么做的:

看到支付宝内部的字符串信息全部使用Base64进行编码操作了,这样做的目的也很简单,因为我们在进行反编译破解的时候如果是这么直接的字符串信息,那么对于破解就太简单了,我们可以直接全局搜索字符串信息很快定位到我们想要的地方,如果这种加密操作我们全局搜索字符串信息肯定是找不到的。但是支付宝这种的加密算法就太简单了,我们可以写一个解密方法然后在直接操作即可。

二、工具编写

我们可能知道把代码中的字符串常量进行加密之后可以防护,但是如果项目中的常量字符串很多,这样手动去替换是很麻烦的,而且每个开发者不可能总是记住这件事的,无意中就定义了一个常量就操作了,所以我们需要写一个自动脚本在项目编译期间自动替换即可,这个工具就是我们本文需要介绍的重点。工具其实不难,因为是编译器,那么我们可能需要对编译后的class文件进行操作,我们知道Android中项目编译流程如下:

我们写好这个工具然后利用gradle脚本,在编译后的class文件做操作即可,那么这个工具其实也很简单,输入class文件,输出就是加密之后的class文件了,为什么操作class文件呢,首先操作class文件有一个很好的工具asm和javassist,本人偏向于asm,著名的热修复框架Robust就是依靠这个工具进行操作的:Android热修复框架Robust原理解析

接下来我们就开始编写这个工具,asm框架可以自行网上搜索一下用法很简单,我们输入是一个class文件,那么我们可以编译这个class文件的字节码信息,如何找到字符串常量信息呢?这个我们可以借助Eclipse中的Bytecode插件进行查看类的字节码信息,比如这里编写一个简单的案例:

我们看到这里只要是字符串信息就是LDC指令,那么我们可以借助asm库拦截方法中的每条LDC指令即可:

这里的参数就是LDC指令的值,这里可以做一个判断,如果是字符串类型那么就是我们代码中的原始字符串信息,这里需要调用加密算法进行加密,然后在插入我们需要解密的字符串信息,那么插入这条指令怎么编写呢?这个不用自己去查阅,直接用Bytecode插件即可:

看到插件就是如此方便和牛逼,这样我们就有了这条指令,直接编写asm代码即可,当然如果没有这个插件,我们可以利用javap命令反编译class文件查看也是可以的:

而且这里会把类的静态常量字段也看的一清二楚字节指令,这一点Bytecode就没法看到了。所以javap指令才是最靠谱的,有了这些指令就可以直接用asm编写代码了,这里先用一个简单的class文件操作:

首先我们需要获取类中所有的常量字段值进行保存,后面进行添加操作:

在类的初始化方法中进行字段加密操作,这里注意一定要是方法的返回指令之前添加的,然后就是在LDC指令拦截之后进行添加

这样我们的工具就大致写完了,用一个案例class文件进行操作一下看看效果:

这里看到把这个类的所有字符串信息进行加密操作了,这里是单个文件操作,因为后面我们需要把这个弄成一个工具集成到项目中操作,所以输入是class文件目录,我们需要遍历这个目录获取所有的class文件逐一操作,操作完成之后替换原始的class文件,当然我们还需要添加一些keep操作,就是比如哪些类是不需要进行操作的,比如系统类就可以不用进行操作:

这样我们就可以把工具打包成jar然后集成到项目中:

我们只需要修改一下gradle即可,因为操作的是字节码文件,所以可以在java编译之后做这件事,添加一个java执行名即可,这里可以添加keep文件。运行一下即可:

然后用jadx工具查看编译后的apk文件,看到内部代码的字符串常量全部进行加密操作了,这样我们的apk被别人拿到之后全局搜索字符串肯定就是失败了。

三、疑问解答

到这里我们把工具写完了,但是这里可能大家有几个疑问:

第一个问题:加密算法

这个加密算法是需要在两个地方调用,一个是工具中需要调用加密方法和解密方法,而项目中也必须要有这么个加密算法类,而且类名也必须一样不然调用执行就报错了,当然大家可以修改一下这个工具实现自定义加密算法逻辑即可。对于这个加密算法我们可以放到so中进行操作,然后在ollvm处理一下,这样安全度就更高了。

第二个问题:这样就一定安全吗?

还是那句话,没有绝对的安全,这样做了加密操作的确可以防护搜索了,但是能防护hook吗?我可以不用解析出加密算法,因为我们最终的目的是获取解密后的字符串信息,那么我们就可以直接hook这个解密方法,打印解密之后的字符串信息即可。这样做的确比直接搜索有点麻烦,但是这个也是破解的常规套路,打印消息可以更快的定位信息。所以不管你上层如何牛逼的加密,哥不关心,我们只关心结果。要结果就hook!

第三个问题:这样做的效率问题怎么办?

的确我们从上面的代码可以看到原本只是从常量池获取字符串信息的,但是现在得调用一个方法,如果这个方法的加密算法复杂点那么效率就不可以言语了,所以对于项目中不是很重要的模块,可以keep一下,不要把所有的常量都进行加密,不过反编译支付宝之后发现他全部用Base64编码了一下,不知道他们是如何考虑效率和安全这两个问题的衡量标准的。

第四个问题:这样做代码量增加怎么办?

从上面可以看到对每个字符串原本的LDC命令后面都插入了一条调用解密方法的指令代码,那么如果项目中的字符串很多,代码可定有所增加,这样我们就需要对一些不重要的模块字符串不采用加密操作。当然如果数量控制在一定范围内代码不会增加很多,应用的包体积也不会增加很多。

本文我们看到或者说以后大家要是对于项目中批量做一件事情,一般就是这个思路,操作字节码因为有先有的库asm和javassist方便快捷,同时直接在编译java文件之后进行操作也是最好的时机。

四、结尾

想获取更多面试资料和高阶安卓资料吗?想提升自己的技术吗?想进阿里吗? 关注+点赞+加群:185873940 免费获取!

本群提供Android高阶开发资料分享,高级UI、性能优化、IOC架构设计、架构师课程等Android高阶开发资料及面试资料!

上一篇下一篇

猜你喜欢

热点阅读