Android系统由于其开源的属性,市场上针对开源代码定制的ROM参差不齐,在系统层面的安全防范和易损性都不一样,android应用市场对app的审核相对 iOS来说也比较宽泛,为很多漏洞提供了可乘之机。市场上一些主流的app虽然多少都做了一些安全防范,但由于大部分app不涉及资金安全,所以对安全的重视程度不够。本文通过几个题目可以让你基本了解android中简单的但比较经典的漏洞、以及简单的android注册机开发的思路。阅读本文,你可能需要了解android逆向的基本知识和常用工具、非常简单的java语言、smali的语法知识。本文适合android入门初学者,最基本的东西。大佬请无视!
一、短信欺诈漏洞
Android系统有一套比较完善的安全体系,权限管理就是其中的一部分。当应用需要操作敏感数据时,需要申请相应的权限。
该系统漏洞能够使攻击者无需申请任何权限发送短信到用户收件箱。
出现该漏洞的原因是Android系统的com.android.mms.transaction.SmsReceiverService系统服务未判断启动服务的调用者,攻击者可以通过该应用发送伪装短信到用户收件箱。本漏洞实质上是一种能力的泄漏。
理解了原理以后基本上查阅一下资料基本上就很简单了,通过查阅资料得到以下两个是短信发送代码中关键的两个点:(详细的apk源码和apk见附件第一题)
1、构造短信发送代码:
2、通过这个服务发送:
注意这两个关键点,然后自己写个布局文件里面做好自己想要的布局,这里我们用了相对布局,然后分别用了两个EditText和TextView控件加一个button控件然后在Acvtivity里面做好逻辑,传递这个intent就可以了。
3、完成上述代码编译签名以后得到app的界面,我们可以自己构造任意号码任意短信内容如下图所示。
4、收到短信,通知栏如图:
7、查看短信内容,任意构造的短信漏洞成功利用:
代码参考链接:https://github.com/thomascannon/android-sms-spoof(本人非作者)
二、签名漏洞
利用相关工具将crackme.apk反编译得到java源码,阅读理解逻辑,将代码中的逻辑修改,得到我们需要植入的程序crackme_killer.apk(这里只是为了演示理解签名漏洞,稍作修改改变了签名漏洞的逻辑,使任意注册码都可以注册成功)其中比较关键的一个点就是植入的classed.dex是在原apk的基础上构造的恶意程序,因为漏洞的关键点在于,Android假设一个APK包中的文件是不会重名的。可实际上Zip格式是允许一个Zip文件包含具有相同文件命的文件。Android在安装应用时,会抽取APK包中每个文件,进行签名验证。但如果碰到了相同文件名的文件,则只会校验第二个文件,而忽略第一个文件。另外在应用运行前会释放classes.dex到/data/dalvik-cache/目录生成优化过的odex文件,然后再运行。这个阶段如果APK里有两个classes.dex,就只会抽取第一个classes.dex进行优化,而忽略第二个。所以,如果我们将一个APK包中放入两个classes.dex文件。第一个classes.dex是被我们篡改过的恶意dex文件;第二个classes.dex是原来这个APK中的classes.dex文件。那么在签名验证时,就会验证原来的classes.dex,因此通过验证;而执行时,却执行了被篡改过的第一个classes.dex。要注意的是植入的classes.dex需要是基于源文件篡改的apk提取的classes.dex,因为apk包里除了这个包以外,还有其他的资源文件和一些申明的文件。实验中碰到的最多的错误是安装的时候提示 没有证书或者成功安装但运行失败。下面是我最终成功的结果步骤。
1) 篡改crackme.apk反编译修改smali文件重新生成crackme_killer.apk,抽取出其classes.dex保存改名为classes.dcx..(事实证明如果直接将篡改过的classes.dex拖进去是不可以的)
2) 用7z打开原APK包,删除其中的classes.dex,保存退出7z。
3) 依次将classes.dcx和保存的classes.dex,通过7z塞入APK,然后保存退出7z
4) 用UltraEdit编辑修改过的APK,查找“classes.dcx”,修改为“classes.dex”(共有两处),然后保存。
5) 终端输入:adbinstall crackme.apk (这里的crackme.apk是篡改过的,附件里已经改成my_result.apk
6) 正常的没有经过篡改的crackme.apk界面:
7) 利用上述步骤篡改过的apk包:
8) 植入crackme_killer.apk后的crackme.app安装成功,点击valide植入成功:
植入的crackme_killer.apk文件、crackme.app原始文件、植入后的文件my_result.apk见附件中第二题。
9) 上述是windows下利用7zip,UE成功植入的步骤。
另附linux下bash脚本(利用unzip写进去,网上有相关的博客说明):
#!/bin/bashif [ $# != 2 ];then echo 'Usage: $0 ' ; exit1 ; fiPLATFORM='$1'INJECT='$2'if [ ! -f'$PLATFORM' ]; then echo 'ERROR: $PLATFORM does not exist'; exit 1; fiif [ ! -f'$INJECT' ]; then echo 'ERROR: $INJECT does not exist' ;exit 1; fimkdir tmpcd tmpunzip ../$PLATFORMcp ../$INJECT./out.apkcat >poc.py<-eof#! sr/bin/pythonimport="" zipfileimport="" sysz="zipfile.ZipFile(sys.argv[1]," 'a')z.write(sys.argv[2])z.close()printsys.argv[2],'write="" succed="" to="" ',sys.argv[1]eofchmod="" 777="" poc.pyecho="" 'writepoc="" file="" succeed'lsfor="" f="" in="" `find="" .-type="" f="" |sed="" -e="" 's:^\./::g'="" |egrep="" -v="" '(poc.py|out.apk)'`="" ;do="" aapt="" add="" -v="" out.apk="" '$f'="" ;="" if="" [="" $?="" !="0" ];="" then="" ./poc.py="" out.apk'$f'="" ;="" fi="" ;="" doneecho="" 'just="" fordebug'ls="" cp="" out.apk../evil.apkcd="" ..rm="" -rf="" tmpecho="" 'modifiedapk:="">
三、破解Crackme2.apk
1、拿到这crackeme2.apk,分别用apktool、dex2jar,backsmali,JD-GU工具解压、得到java源码和smali源码。
2 将我们需要破解的apk放到模拟器里安装,得到如下界面:
3 很明显,这里做了虚拟机检测机制,后续会分析如何绕过这个检测机制,但我们先把它放到真机或者更高级的android模拟器下安装(这里选用夜神模拟器,后面说的真机均指这个高级模拟器,模拟器是指AVD的模拟器),得到如下界面。很明显我们的模拟器检测机制在这个模拟器中并不起作用,这是因为AVD自带的模拟器机制中一些deviceId是全0,后面我们开发注册机的时候,注册机在模拟器运行的时候可以看到区别。
4.用jd-gui打开dex2jar提取出来的jar文件,查看java源码,阅读代码逻辑。或者直接用jeb工具打开apk。这里可以选择不同的工具如jeb、ApkIDE来查看代码,建议根据自己平时的喜好来选择,这个地方起初我碰到了一些坑,不同工具解析出来的代码有一些不同。包括下面最后有个做注册机的时候,源码也起到了很大的作业。有些工具反编译的时候可能会丢失掉一些关键信息。下面是同一段代码两个反编译工具解析的结果,很显然是不同的。
得到java源码以后,很好阅读。整个界面就只有一个图片,阅读源码,找到对应位置,我们知道android活动的生命周期第一个是Oncreat,那我们就从这里看起,Main中的oncreat:5 似乎没有找到有价值的信息,既然是一把锁的图片,我们搜索一下png就定位到了关键点:
6 、继续阅读下面的代码,由于是绕过了模拟器检测机制,直接看这里:
7 找到这个函数
8 都是赋值语句,这样应该就简单了吧,看一下对应的smali,要擅用搜索,发现最后是将v5 的值赋值给v0.最后返回v0的值。
10 那这样就简单了,将0x0改成0x1就可以了。
11、编译签名安装,成功破解:
12、上述只是在真机环境下破解成功的,还不过瘾,我们在模拟器下来试试如何绕过模拟器检测机制,模拟器下界面是这样:
13 在packageCom.zAWS.KeygenMe搜索相关字符串“MAC”定位源码,这里有两个函数,第一个显示是challenge1的字符串,想必下面的一个是下一个challenge的函数吧:
14 找到调用者两个函数的地方,两处调用了_emulator_dete函数,一处_emulator_dete1函数。
15 根据周围的字符串函数等定位到smali源码,修改if(main._mac_address == null)的判断将nez改为eqz(如果不等于0改为如果等于0):
经过调试第一个if(main.mostCurrent._mywifi.ABLoadWifi(main.processBA))的逻辑并不需要修改,在我的模拟器里面这个if也能为真,对应源码在这里,
这里不需要修改,如果这里和上述的地方一起修改了,就会跳到最下面的那个else语句,反而影响我们最后的结果。这里开始误导了我一段时间。
16 完成上述一处的修改后我们就来到了challenge2:
17 根据上面的源码,我们还是直接修改if(v3== 0) 这个逻辑:
将nez改为eqz:
18 原以为应该就快成功了,结果报了下面这个空指针的错误。
19 、上述这个地方很是烦心,没有认真分析这个空指针,以为这条路行不通,又耽搁了一段时间,最后好好分析上述界面,发现是这里有问题,定位到上述那个函数,猜测可能是模拟器里面mac.address为空,引发了这个函数执行空指针,检查接下来的代码发现没有用到这个参数了:
20、简单暴力的方法,直接删掉这句没用的函数调用,如下图框柱的地方
21 、终于绕过了这个模拟器检测机制:
22 根据我们在真机中调试的方法,把0x0改成0x1就成功解锁了。相关apk文件见附件中第三题。
四、注册机开发
通过apktool或者直接解压解包提取classes.dex,利用dex2jar 转换得到源码文件。然后利用jd-gui查看源码文件可得到算法。或者直接使用JEB工具得到源码:
关键算法:
基本算法就是得到手机的id 然后利用上述算法计算得到一系列字符串和输入的字符串进行对比,相等则注册成功。由于本次实验需要获得deviceID,需要利用真机或其他高级模拟器调试。Eclipse自带的AVD获得的device id 始终为000000000000000。
1、通过反编译得到的源码,我们可以得到基本的算法,将其复制到eclipse做下修改:
2、然后用两个空间TextView显示下就可以了:
3、其中很重要的一个点在于注册机要给读的权限(这里卡了一段时间,调试知道的)如下图:
4、最终注册机跑的结果为(前面为真机,右图为AVD自带模拟器):
5复制注册码到软件注册成功:
6 成功注册:
注册机apk和源码在附件第四题里。
相关apk及附件链接:http://pan.baidu.com/s/1geBdqUn