Android apk 二次打包及防范简单体验

Android应用开发完成后编译打包成apk文件,而正式发布的Android应用打包时都会进行签名。而apk的二次打包就是指对已经使用签名文件进行打包的apk进行自己的修改之后,再次签名打包发布的过程。

Android应用发布到应用市场供用户下载的是一个.apk形式的文件,apk文件其实就是一种特殊的文件格式,其实就是资源文件,布局文件,主配置文件,dex文件以及签名验证文件等的文件集合。我们把.apk文件的后缀名修改为.zip包,然后进行解压缩进行查看,就能看到上面说的一些文件目录及文件的罗列,在此不在贴图。具体说到二次打包能干什么,其实就是我们可以对原来的apk文件中的源码进行修改,然后重新编译,进行二次打包,重新发布测试,从而达到我们修改别人的apk文件的目的。

二次打包主要用到3个工具,apktool、dex2jar、jd-gui。dex2jar工具主要作用是将dex文件转变成jar文件,jd-gui工具是用于查看通过dex2jar转变生成的jar文件。apktool用于对apk进行打包。

实际工作中也会遇到对android apk进行各种安全监测,所以对android的安全问题进行相对完整的攻防了解很有必要。Android apk的代码保护在android安全中也是非常重要的一环,如果apk被恶意开发者进行二次打包植入攻击代码将产生非常严重的后果,所以对反编译、二次打包流程及防护有个基本系统的了解也是很有必要,本文将以前写的文档整理了下以做记录。

1、二次打包

为了详细透彻的了解整个过程,先实践如何对应用进行二次打包,然后再对打包签名进行验证,鉴别出应用被恶意打包。

1)准备2个签名文件

准备2个签名文件,一个是代表未篡改前应用的正式签名文件,一个是用于进行二次打包的签名文件。

2)打正式包

使用正式签名文件打包得到apkrepack-release.apk。

3)将正式apk包反编译

将打包好的 apk 放到 apktool 目录下,用 apktool 进行反编译。


pic1.png

输入反编译命令,反编译得到文件夹。


pic2.png

文件夹中的内容如下图所示,包括android的manifest文件AndroidManifest.xml,反编译出来的所有资源res,original文件夹中有META-INF文件夹,里边有签名相关的信息。smali文件夹android代码对应的底层语言文件,smali是Android虚拟机所使用的寄存器语言,通过修改smali文件可以达到修改源代码逻辑的目的。


pic3.png
4)修改代码逻辑

原有代码如下图所示,MainActivity中包含2个TextView,一个Button,按钮点击后显示显示“包被篡改”的文字。tvResign固定显示“这是正常的包”文字,而tvTitle则会校验app是否被重新打包,根据校验结果显示对应的文字。


pic4.png

我们要实现将tvResign显示的文字“这是正常的包”替换为“包被篡改过了!!”,即将tvResign 中显示的文字替换为按钮点击后显示的文字。对应的MainActivity的smali文件如下图所示。只截取关键的initViews和onResume中的方法。


pic5.png

pic6.png

图中红线框内是设置tvTitle文字的代码段,setTextView方法中传入2个参数,一个参数v1即tvResign,另一个参数v2即是要显示的文字,我们所要修改的技术v2对应的值。我们再看initViews中方法的实现,发现没有看到按钮点击后显示文字的代码,只看到了setOnClickListener代码。这个文件中其他部分也没有这个代码,所以那部分代码不在这个文件中。与MainActivity.smali在同一个目录下还有一个文件,如下图所示。


pic7.png

MainActivity$1.smali也是MainActivity.java反编译源码的一部分。


pic8.png

点击按钮显示文本的这部分代码在MainActivity$1.smali文件中,截图如下所示。


pic9.png

截取v1中的文字,替换到前面tvResign设置的文字即可修改tvResign显示的文字。

5) 重新打包
pic10.png

打包完成后生成新的apk包new_repack.apk。但是这个apk包没有签名,android应用的apk要想能安装到手机上必须经过签名,使用android studio debug模式下会有一个默认的签名,但如果想要发布必须使用自己的keystore进行签名才行。

6) 重新签名

将keystore文件放到apktool目录下,与new_repack.apk在同一目录下。签名命令如下:
jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore 签名文件名 -storepass 签名密码 待签名的APK文件名 签名的别名
签名完成后,即可得到重新签名后的apk。


pic11.png

7) 运行结果

pic14.png

如上图所示,左侧为正常包,右侧为二次打包,第二行TextView即为tvResign,右侧显示了被篡改过后的文字,第一行TextView显示签名验证结果,这部分后面继续讲解。

2、二次打包防范-签名验证

防止被二次打包的一种方法是进行签名验证。Android安全的基石之一是所有的app都必须经过数字签名。所以攻击者要对开发者的apk进行代码恶意篡改,重新打包时必须重新进行数字签名,这样就破坏掉了原有的数字签名。所以攻击者肯定会用另一个秘钥进行重新签名,所以如果我们在app中启动时对签名进行校验,就能识别app是否被重新二次打包过,识别出被二次打包后对用户进行提示,防止用户关键信息泄露或被攻击。

1)获取正常keystore签名

获取正常打包所用keystore的签名,在终端窗口中使用keytool输入命令
Keytool –list –v –keystore 你的keystore文件名


pic15.png

如上图所示,记录证书指纹中SHA1码,将此SHA1码拷贝到代码中,作为app是否被重新签名的验证凭据。

2) 验证签名

pic16.png

如图CRITIFICATE_SHA1中即保存的未被篡改的证书指纹,在app运行时与app当前的证书指纹进行比较,如果不一样,说明apk被二次打包重新签名过。这时要给出提示,提醒用户。


pic17.png

3) 结果验证

当app通过签名校验发现app被二次打包重新签名时,给出Toast文字提示,提醒用户apk被篡改,去正规渠道重新下载apk。此方法只能简单校验apk是否被篡改过,而且证书指纹直接写在java代码中也容易被反编译看到破解,甚至修改判断逻辑。更好一点的改进方式是将证书指纹及判断逻辑都用ndk开发,放到so库里面。

Gradle中配置如上图所示,在release版中,minifyEnable要置为true。开启混淆会使编译时间变长,所以debug模式下不应该开启,也没必要开启。默认的一些混淆规则在proguard-android.txt文件中。该文件在android sdk的/tools/proguard文件夹中。该文件中提供了一些默认的混淆规则,这些规则能满足最基本的代码混淆要求,但实际的app开发中我们总是不可避免的要引入第三方库或者jar包,这就需要添加一些额外的混淆规则。这些混淆规则写在工程目录中的proguard-rules.pro文件中。

3、使用第三方加固防止二次打包

使用360加固保对apk进行加固,再进行二次打包。先对其进行反编译,得到的文件与没进行加固的目录有所不同。


pic18.png

图中左侧未加固、右侧加固。最关键的是smali文件也与原来的不一样。


pic19.png

左侧第一个为未加固smali文件,右侧2个为加固后的smali文件。加固后smali文件与未加固的变化很大,极大增加了反编译代码阅读难度。而且再用apktool进行打包时会报错,不能成功进行打包。真正起到了防止二次打包的作用。360加固保通过签名校验保护,能有效避免应用被二次打包。

4、总结

Android apk的代码保护是Android安全的很重要的一部分,代码保护不当很容易被植入恶意代码或者导致一些关键信息泄露,对软件开发者造成损失。通过对android apk反编译及二次打包过程的了解,能对二次打包的流程及危害有一个更清晰的了解,同时也意识到,目前这个安全如果自己做的话,还是会有很多的不足及不完善。可以考虑采用第三方加固方案。

安全防护这方面,原来对android apk代码保护是对代码进行混淆,但是混淆后的代码仅是将变量及类名做了处理,但这还是不够安全,如果代码被拿来进行仔细分析还是能够梳理出软件逻辑。后来又出现了各种加固方案,爱加密加固后的代码dex反编译成jar后,用jd-gui打开后查看,里面的函数实现都被隐藏掉了。有了加固技术,相对应的就有各种脱壳技术,将加固的文件进行脱壳,然后反编译。所以安全防护、代码保护是需要持续关注的课题,进一步研究Android代码保护,可以以脱壳技术为继续深入研究的点。代码保护也仅仅是android安全的一个小方面,android还有很多的安全问题值得去深究。

你可能感兴趣的:(Android apk 二次打包及防范简单体验)