查看原文
其他

Android逆向与病毒分析

2016-12-06 qtfreet00@YSRC 同程安全应急响应中心

本文由同程旅游安全团队对内移动安全培训的PPT整理而来,面向对象为对移动安全感兴趣的研发同事,所以讲的有些宽泛。介绍了入门Android逆向需要掌握的一些知识点, 通过简单的几个案例讲解Android app常用的分析和破解手段, 讲解Android上常见的反调试和对抗逆向的手段,并通过修改系统源码来实现反反调试。 介绍一下常见的病毒特征和预防手段, 最后讲解一些关于Android SubStrate Hook相关的内容。文章最后留了一个CrackMe,据说解出之后会有神奇的事情发生。


0x0 什么是逆向

逆向工程(又称逆向技术),是一种产品设计技术再现过程,即对一项目标产品进行逆向分析及研究,从而演绎并得出该产品的处理流程、组织结构、功能特性及技术规格等设计要素,以制作出功能相近,但又不完全一样的产品。逆向工程源于商业及军事领域中的硬件分析。其主要目的是在不能轻易获得必要的生产信息的情况下,直接从成品分析,推导出产品的设计原理。

 

0x1 如何学习安卓逆向

  • 学习java基础,最好有Android开发基础

  • 学习c语言基础,了解常用的函数

  • 学习了解常见的apk内文件格式(dex,xml,so)

  • 学习常用Java,Android开发工具的使用(Idea,Android Studio)

  • 学习常用Android逆向工具的使用(Android Killer,Jeb,apktool,jadx,Ida)

  • 学习了解smali语言,能够进行一定的编辑和修改

  • 学习了解Arm语法

  • 学习网络抓包,了解常用抓包工具的使用,BurpSuite,Charles

  • 了解常用的加解密算法和编码,Aes,Rsa,Des,Tea,Base64,md5

 

0x2 常用的破解手段

  • 通过敏感字段,直接搜索关键点进行爆破

  • 算法分析,尝试还原算法

  • 网络验证,尝试网络抓包篡改数据

  • 静态分析

  • 动态调试

  • Xposed,SubStrate对关键点进行hook

 

0x3 简单实战

  1. 简单爆破



如图所示,要执行到弹出Congratulations的话,那if判断就必须为真,s是设备id加盐后md5的值,checkcode是用户输入的值,这里最简单的方式就是去掉这个if里的判断,使其永真,反编译该段代码,如下:



关键点就是if-eqz v5,:cond_0,这里的v5值就是上面s和checkcode对比后的结果,if-eqz v5的含义则为如果v5等于0,则跳转到cond_0,而cond_0为失败函数,此处最简单的修改方式就是直接删除这一句判断,让程序强行走到成功处,这种验证手段在时下一些app中依然常见。

 

2.某CrackMe so简单算法分析








该函数有三个参数,在jni中,默认第一个参数为jniEnv指针,第二个参数为jobect对象,第三个才是真正java传过来的参数,由46行的getStringUtfChars可知a3参数类型为jstring,对应java中的String类型,真正的逻辑从113行开始,v41为v40的指针,即指向的用户输入数据的第一个字符,此处判断当用户输入数据是否大于12位,并且判断每位的值是否等于v22,v21每位数据异或后的值,如果其中一个条件不成立,则都跳转到失败处,那知道算法逻辑后,就可以写出对应的解密算法:



 那so一般如何分析java层函数调用:

  • 通过System.loadLibrary找到该方法对应的so文件,使用ida载入后查找导出函数,native函数注册的两种形式:

  • 静态注册:java_xxx_xxx_xxx_类名_方法名(参数)

  • 动态注册:RegisterNatives

  • 正常情况下,一般开发者认为so已经足够安全,从而不会考虑so文件的防护。

 

0x4 对抗逆向

  • 利用第三方加固

  • 代码,字符串加密

  • ollvm指令混淆

  • 签名验证

  • Dex文件验证

  • 反调试(AntiDebug)

 

  1. 检测TracerPid



TracerPid代表跟踪该进程的进程pid值,正常情况下,TracerPid默认为0,当调试器附加上该进程后,TracerPid的值就会改变为非0值,反调试即通过该手段检测当前app是否处于调试状态,如果是则自动结束该进程。

 

2.检测调试端口



常用调试器IDA中的android_server默认端口为23946,反调试即可检测/proc/net/tcp下是否存在该端口,如果存在,依然结束自身。

 

0x5 反-反调试

针对上面两个反调试案例,如何躲过TracerPid的检测,常用的检测方式为读取/proc/{pid}/status和/proc/{pid}/task/{pid}/stat的值来判断是否处于反调试。

  1. 定制系统




修改Android内核文件,在对应的检测点处,对TracerPid强制赋值为0,并将当前任务状态中的T,t(Trace running和Trace stop)都置为s,这样无论如何检测TracerPid,都只能获取到0。

 

0x6 病毒分析

  1. 常见病毒类型:

  • 锁机软件

  • 隐私窃取

  • 广告病毒

  • 扣费病毒

 

2. 病毒常见加密手段

  • 利用第三方厂商加固

  • 利用Android系统对apk中文件的执行流程对其中部分文件进行修改以达到对抗反编译的效果

  • 代码,字符串混淆

  • 子母包分离,将病毒本体放在云端,本地只做加载




如图,修改任意xml文件的文件头,将固定字符03 00改成任意其它字符,都可以使apktool反编译失败,但不影响程序正常执行。

 

3. 常见病毒执行流程

  • 锁机病毒:诱导用户进行安装,打开时提示用户申请设备管理器和root权限,成功获取到权限后即将病毒本体释放到system/app下,重启设备后通过app构造的一个错误的全屏页面覆盖整个屏幕,从而实现类似于锁机的目的。



  • 隐私窃取病毒:针对4.4及以上,病毒在启动时会诱导用户设置该app会默认短信应用,4.4以下无需设置,一旦成功获取到权限,app会在后台开启一个service用来监听短信,联系人以及其它信息的变化,并通过多个service,broadcast对该service进行守护,app定期会将这些信息发送到病毒作者手机号或者邮箱里,通过短信将该病毒app群发给联系人,使其他人中招。

  • 手段升级:为防止一些邮箱和手机号或者对抗病毒分析人员,病毒可能会将此类敏感指令隐藏,通过服务器或者手机号进行下发,app监听到有新的指令时,则执行对应的操作。

 

4. 预防

  • 使用最新的Android系统,新版本Android系统在权限机制上约束了部分敏感权限。

  • 在正规市场和官网上下载App。

  • 如无特殊需要请不要root

  • 不点击任何短信中的网址。

  • 刷机!

 

0x7 SubStrate Hook

Android常见的hook手段有.Got表hook和inline hook(概念较为繁琐,建议百度),Substrate则是inline hook中的一种,那如何简单的理解inline hook,其实就是直接修改函数的汇编实现,比如在函数前加一条jmp指令来跳转到自己的函数,执行完目标逻辑后再跳转回原函数。

官网: http://www.cydiasubstrate.com

Substrate是一个android上可以hook native代码的hook框架,可以实现对Android底层代码的劫持修改。

 

  1. 获取明文https数据

  2. 在android上使用https协议时,会使用system/lib下的libssl.so配合开发者提供的证书对数据包进行加密,常规的在捕获https数据时,只需要利用抓包工具(burpsuite,charles)导入伪证书就可以成功获取明文的数据包,当app有严格的证书校验时,此类方法将不可再使用。





如果通过简单的hook手段,就可以简单的打印出协议包的内容,当然我们还可以通过添加一定的方法来篡改协议包。

 

  1. 简单脱壳

Android上App加固已经发展了四代,第一代为整体加固,在app运行时,壳会释放真正的dex到内存,第二代为类抽取,本地反编译只能看到方法名,方法体全部被抽空,运行时全部填充回去,第三代加固为类抽取+被动式加载,当app执行到某个方法时,该方法才会被还原,第四代为vmp加固,实质即为在dalvik虚拟机之前再嵌套一层虚拟机用来翻译壳函数,转成正常的dalvik指令集后再交与dalvik执行。

针对第二代加固,网上有非常好的开源工具可供参考:dexhunter

针对第三代加固,常见的思路为可以HookDalvik_dalvik_system_DexFile_defineClassNative函数,原始dex加载时,枚举所有的DexClassDef,对所有的class,调用dvmDefineClass进行类加载。

 

Hook示例针对第一代加固:

  • 在第一代和第二代以及当前部分加固中依然使用了整体加固,在阅读Android系统源码时发现DEX在执行时会调用defineClassNative去执行类方法,而传进来的参数中就包含了DvmDex指针,通过该指针即可拿到一个DexFile实例。

 




如上通过对defineNativeClass进行hook,拿到DvmDex结构体指针后就可以通过pid值拿到该进程的名字,通过DvmDex就可以拿到DexFile指针,最后通过DexFile就可以得到该dex的起始地址和文件大小,直接dump保存即可。

 

最后留个 CrackMe 作为培训小作业,感兴趣的同学可以扫描下方二维码关注 YSRC 公众号后发送 “crackme” 获取下载链接。


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存