Android应用攻与防


本文约3000字,阅读约需7分钟。


安卓系统是由谷歌推出的一款移动终端,由于开源,所以国内出现了许多使用相关系统的厂商,比如小米,oppo,vivo,魅族等。

在国内,这些系统的用户群体甚多。我们日常使用的社交、游戏、工作等应用,很多都装在安卓系统上。

由于安卓系统的开源性,很多安全问题也随之而来。那么,在安卓系统上运行的应用又是如何保证自身安全的呢?

本文通过实战挖洞,展现一下Android应用的防守与攻击方式。


1

简介

为了避免应用被攻击,各种应用在投产前会用一些技术手段进行加固。但是在持续对抗下,总会出现各种反加固的手段。

部分开发者可能忽视应用的安全性,各大应用市场上也有很多未采取加固手段或进行简单加固的应用。

首先,我们来看一看一个未进行任何加固手段的应用,运行起来有多危险。

下图是开发工程师加密身份证号的AES加密算法。AES算法能保证身份证号以密文形式在网络上传输,不被他人窃取,将代码打包安装在我们手机中运行。


由于安卓应用包很容易获取,源码包被攻击者拿去反编译,反编译结果如下图:


对比开发者写的代码和攻击者反编译的代码,几乎完全一样,攻击者很容易分析出我们的代码逻辑,从而造成破坏。

如上面程序,拿到我们加密算法逻辑,对传输中的加密内容进行解密,来获取身份证号。

由此可见,没有做任何安全防护的安卓源码犹如“裸奔”。

2

防守原理

上面实例可见,没有加固的安卓应用,运行起来是相当危险的。下面介绍几种常见的应用加固方式。包括源码混淆、应用加壳、应用运行环境检测。

源代码混淆保护

混淆是将代码中的类、方法、变量等信息进行重命名,把它们改成一些如“a,b,c,d”这样毫无意义的名字,这样就增加了攻击者逆向难度。混淆效果图如下:


应用加壳保护

加壳是在二进制的程序中植入一段代码,在运行的时候优先取得程序的控制权,做一些额外的工作。

应用加固的一种手法对原始二进制原文进行隐藏。简单描述就是代码隐藏了,只有程序运行时才会还原。

我们将上面加密身份证号的应用加壳,然后使用工具反编译如下,已经看不到任何源码信息。

攻击者如果想要攻击,第一步就需要脱壳。我这里是只进行简单的加固,对安卓的关键dex文件整体加固,只有在运行的时候才会还原原有dex文件。当然还有其他不同类型的加壳手段。
 

安卓应用加壳大致经历了四代:

第一代——壳Dex整体加密:

原理是对dex这个文件进行整体加密加壳,存放在APK的资源中,运行时将加密后的dex文件在内存中解密,并让Dalvik虚拟机动态加载执行。

第二代——壳Dex抽取:

通过将代码中的方法名和方法体进行分离,对分离的方法体进行加密处理,同时被加密的方法体中注入解密接口。运行加固包,执行被加密函数时,通过调用其中的解密接口,对当前方法进行解密。

第三代——壳混合加密:

结合第一、二代的加固优点,根据应用的实际情况采用不同的混合加固方式,从而达到加固效果和强度的最优化。

第四代——壳vmp保护:

VMP技术是将原来的可执行代码转换为自定义的字节码,这些自定义的字节码只能由自定义的虚拟机解释器执行。

应用运行环境检测保护

安卓应用如果不进行运行环境检测,就像你在一个装着针孔摄像头的房间睡觉,却不进行安全排查。显然,这样很容易引发很多安全问题。

安卓应用亦是如此。我们需要检测手机是不是有root权限、装了危险应用、设置了代理、开启了调试模式等等。


比如检测root。检测在常用目录下是否存在su命令,如存在,我们此时可以提示用户有风险或者强行退出。

publicstatic boolean checkRootPathSU(){Filef=null;FinalStringkSuSearchPaths[]={"/system/bin/","/system/xbin/","/system/sbin/","/sbin/","/vendor/bin/"};try{for(inti=0;i<kSuSearchPaths.length;i++){f=newFile(kSuSearchPaths[i]+"su");if(f!=null&&f.exists()){Log.i(LOG_TAG,"findsu in : "+kSuSearchPaths[i]);returntrue;}}}catch(Exceptione){e.printStackTrace();}returnfalse;}

检测代理,发现我们在抓包,就断开连接。

publicstatic boolean isWifiProxy(Context context) {Finalboolean IS_ICS_OR_LATER = Build.VERSION.SDK_INT >=Build.VERSION_CODES.ICE_CREAM_SANDWICH;StringproxyAddress;intproxyPort;if(IS_ICS_OR_LATER) {proxyAddress= System.getProperty("http.proxyHost");StringportStr = System.getProperty("http.proxyPort");proxyPort= Integer.parseInt((portStr != null ? portStr : "-1"));}else {proxyAddress= android.net.Proxy.getHost(context);proxyPort= android.net.Proxy.getPort(context);}Log.i("代理信息","proxyAddress:"+proxyAddress + "prot : " proxyPort")return(!TextUtils.isEmpty(proxyAddress)) && (proxyPort != -1);}

3

实战攻击

国庆某SRC有三倍金币活动,在家正好挖到某个App逻辑漏洞,发现该App不用充钱,也能成为永久VIP会员。

特意写个过程分享一下。由于涉及到隐私问题,关键信息进行打码处理。仅提供了详细的攻击过程,给大家做个参考。

挖洞思路如下:

反编译—脱壳—抓包—绕过代理检测—静态分析—写脚本hook—动态修改—攻击成功。

拿到攻击目标应用安装包.apk文件。首先进行反编译,查看源码情况:


发现应用包已进行加壳处理。直接上工具进行脱壳。我这里使用frida_dexdump进行脱壳。

打印目标应用进程PID= 17460:


执行脱壳命令:


发现脱出来很多dex文件,为了方便分析,使用apktool进行解包,替换dex后重打包。

重打包apktoolb 原始版-oC:\Users\11.apk。


脱壳前后进行对比,发现脱出来很多源代码:



手机运行该应用,发现有个会员功能,会员需要付费购买。

此时,心里想该应用会员校验机制复杂不复杂?能不能绕过支付成为会员?

直接开搞。

手机设置代理,开启BurpSuite进行抓包。一打开目标软件就“网络异常”,说明这个应用检测了运行环境,检测到手机开了代理就断开连接。



查看脱壳后的源码,发现进行了代理检测:


既然有代理检测我们就不设置代理,采用一种透明代理模式。

在BurpSuite中监听80和443这两个端口,并且将其设置为透明代理模式:


手机连接电脑,以下命令:


再查看Burpsuite,此时已经能抓到包,成功绕过代理检测:


点击关于我的信息,查看返回包,发现有关于会员信息的关键字VIP,VipstartTime,VipendTime,isVIP等等。记住这些关键字,然后去源代码里面直接搜索,发现有相关信息:


静态分析跟踪调用逻辑关系,发现判断是不是会员用了isVip进行判定,该字段值是true就是会员,false是非会员:


编写Fridahook脚本,让判断会员的方法一直返回ture。把会员到期时间也进行更换,指定一个返回时间戳,后面还需要更换两个关键参数,这里就不放出来了。


手机端开启frida-server:


PC端执行我们的脚本:


进行了动态修改,此时查看手机页面,已经成为了会员,绕过成功,使用一下会员才有的功能,发现亦能使用。


到这里攻击已经完成,回顾一下破解思路:

首先拿到应用包,查看是否进行加壳——答案是已加壳。抓包发现进行了环境检测,使用透明代理模式进行绕过。

随后我们进行逆向分析代码,成功找到绕过支付成为VIP的逻辑漏洞。

使用frida进行hook动态修改,修改运行中的代码,成功成为会员,攻击成功。

4

总结

对于安卓App应用来说,没有绝对的安全。

在持续的攻防对抗下,防守技术和攻击技术都不断在进步与升级。就现有的防守技术来说,都只是提升了整体的安全性,提高了攻击的成本。所以,对抗永无止境,我们要再接再厉。


- END -


往期推荐

记一次卑微的渗透测试

pwn入门之栈入门

MYSQL另类利用方式

长按下方图片即可关注

点击下方阅读原文,加入社群,读者作者无障碍交流


免责声明:文章内容不代表本站立场,本站不对其内容的真实性、完整性、准确性给予任何担保、暗示和承诺,仅供读者参考,文章版权归原作者所有。如本文内容影响到您的合法权益(内容、图片等),请及时联系本站,我们会及时删除处理。查看原文

为您推荐