1

一、已知防护策略
1.不可或缺的混淆

Java 是一种跨平台、解释型语言,Java 源代码编译成的class文件中有大量包含语义的变量名、方法名的信息,很容易被反编译为Java 源代码。为了防止这种现象,我们可以对Java字节码进行混淆。混淆不仅能将代码中的类名、字段、方法名变为无意义的名称,保护代码,也由于移除无用的类、方法,并使用简短名称对类、字段、方法进行重命名缩小了程序的大小。

ProGuard由shrink、optimize、obfuscate和preverify四个步骤组成,每个步骤都是可选的,需要哪些步骤都可以在脚本中配置。 参见ProGuard官方介绍。

压缩(Shrink):侦测并移除代码中无用的类、字段、方法、和特性(Attribute)。
优化(Optimize):分析和优化字节码。
混淆(Obfuscate): 使用a、b、c、d这样简短而无意义的名称,对类、字段和方法进行重命名。

上面三个步骤使代码size更小,更高效,也更难被逆向工程。

预检(Preveirfy): 在java平台上对处理后的代码进行预检。

一般来说优化和预检选项在Android中是关闭的,脚本如下:
-dontoptimize 表示不进行优化,建议使用此选项,因为根据proguard-android-optimize.txt中的描述,优化可能会造成一些潜在风险,不能保证在所有版本的Dalvik上都正常运行。
-dontpreverify 表示不进行预校验。这个预校验是作用在Java平台上的,Android平台上不需要这项功能,去掉之后还可以加快混淆速度。 (在安装apk过程中系统会对dex校验及优化成odex) 作为防护来说对于混淆的需求就是Obfuscate,增加阅读代码的难度。

2.签名校验
校验各个文件的信息,比如微信的dex文件校验,阿里聚安全的签名文件校验等高强度操作。

第一:直接在本地做防护,如果发现签名不一致直接退出应用
第二:将签名信息携带请求参数中参与加密,服务端进行签名校验,失败就返回错误数据即可

Android的签名机制可以有效防止应用二次签名后不能覆盖安装,具体原理这里不分析了,但也导致安装了二次签名的apk,无法覆盖安装正常签名的apk,所以在很容易被二次签名的防护基础上进行签名校验是有必要的,当然如果很难被反编译攻破就可以酌情考虑了。

3、反调试异常检测 1)so跟踪调试是基于进程的注入技术,然后使用Linux中的ptrace机制,进行调试目标进程的ptrace提供了一种使父进程得以监视和控制子进程的方式,它还能够改变子进程中的寄存器和内核映像,因而可以实现断点调试和系统调用的跟踪

ptrace机制有一个特点,就是如果一个进程被调试了,在他进程的status文件中有一个字段TracerPid会记录调试者的进程id值,可以选择两种方式:
1.轮训查看文件:/proc/[myPid]/status,读取TracerPid字段的值,发现大于0,就立马退出程序
2.一般一个进程只能被附加一次,我们在pojie调试的时候都会附加需要调试应用的进程,如果我们先占坑,父进程附加自己,那么后面在附加调试就会失败

调试状态检查
1.检查应用是否属于debug模式 直接调用Android中的flag属性:ApplicationInfo.FLAG_DEBUGGABLE,判断是否属于debug模式,为了防止现在有人为了调试应用将应用反编译在AndroidManifest.xml中添加:android:debuggable属性值,将其设置true。然后就可以进行调试。
2.检查应用是否处于调试状态 借助系统的一个api来进行判断:android.os.Debug.isDebuggerConnected();这个就是判断当前应用有没有被调试

3.循环检查端口 查看设备的tcp端口使用情况 cat /proc/net/tcp 比如Frida框架,他的端口号是27042和27043,以及进程名是frida-server

4、加固方案 加固的基本步骤如下:
从App原始apk文件里获取到原始dex文件对原始dex文件进行加密,并将加密后的dex文件和相关的存放到assert目录用脱壳dex文件替换原始apk文件里的dex文件;脱壳dex文件的作用主要有两个,一个是解密加密后的dex文件;二是基于dexclassloader动态加载解密后的dex文件因为原始apk文件已经被修改,所以需要删除原始apk的签名信息,即删除META-INF目录下的.RSA、.SF 和MANIFEST.MF文件生成加固后的apk文件对加固后的apk文件进行签名,apk加固完成。
dex加固主要是防止被静态反编译,进而获取源码并修改

除了以上业务相关性弱的防护方案,还有防被抓包,防被hook等和业务密切相关的防护方案,如传输数据加密,防作弊等策略。

以上每个防护策略都有对应的应对之道,当然攻克了不代表不能防,防护只是增加攻克的难度和时间,攻防没有永远的胜利方,有人攻就有人防,防护策略也在不断的升级更新换代。

要深入理解Android安全防护,就必须了解Android应用的结构。

二、APK(Android PacKage)结构

assets目录: 用于存放需要打包到APK中的静态文件,和res的不同点在于,assets目录支持任意深度的子目录,用户可以根据自己的需求任意部署文件夹架构
lib目录: 程序依赖的native库(so库)
META-INF目录: 存放应用程序签名和证书的目录,包含的文件有CERT.RSA,CERT.DSA,CERT.SF和MANIFEST.MF,其中CERT.RSA是开发者利用私钥对APK进行签名的签名文件,CERT.SF,MANIFEST.MF记录了文件中文件的SHA-1哈希值

res目录: 存放应用程序的资源,存在这个文件夹下的所有文件都会映射到Android工程的.R文件中,生成对应的ID,res文件夹下可以包含多个文件夹,其中anim存放动画文件;drawable目录存放图像资源;layout目录存放布局文件;values目录存放一些特征值,colors.xml存放color颜色值,dimens.xml定义尺寸值,string.xml定义字符串的值,styles.xml定义样式对象;xml文件夹存放任意xml文件,在运行时可以通过Resources.getXML()读取;raw是可以直接复制到设备中的任意文件,他们无需编译。
resources.arsc: 资源配置文件,用来记录资源文件和资源ID之间的映射关系,用来根据资源ID寻找资源
AndroidManifest.xml: 应用程序的配置文件,程序打包时,会把AndroidManifest.xml进行简单的编译,便于Android系统识别,编译之后的格式是AXML格式。
classes.dex: dex可执行文件,传统的Java程序,首先先把Java文件编译成class文件,字节码都保存在了class文件中,Java虚拟机可以通过解释执行这些class文件。而Dalvik虚拟机是在Java虚拟机进行了优化,执行的是Dalvik字节码,而这些Dalvik字节码是由Java字节码转换而来,一般情况下,Android应用在打包时通过AndroidSDK中的dx工具将Java字节码转换为Dalvik字节码。dx工具可以对多个class文件进行合并,重组,优化,可以达到减小体积,缩短运行时间的目的。

对于逆向首入门槛就是dex,了解dex的数据结构对防护和逆向都是极其重要的,dex文件结构分析文章非常多,这里不多赘述,不了解的先去了解下。

对于Android防护目前流行的最后方案就是加固,某些应用市场已经把加固和上架进行了绑定,说明加固的逆向难度公认度是很高的。

上面介绍了加固的基本步骤,市面上的加固方案都大同小异,最核心的部分就是对apk/dex进行加密-解析-动态加载,对dex加密各有各的方式和算法,了解dex结构和动态加载之后就可以对不同加固方案进行具体分析了,不过分析大厂的apk之后发现都没有对dex进行加固就令人深思,也许在客户端的防护只是门槛,服务端的防护及防作弊才是终极防护策略,而加固会增加崩溃的概率,作为大流量的app来说万分之一的概率也是很高的,而对dex加固的安全性并不是最高的,所以放弃对dex加固也是有迹可循的。

作为Android应用开发者来说,navite层的代码具有更高的挑战性,大部分Android开发者并不熟悉c/c++开发,所以so的加固应运而生。

动态链接库so: 动态链接库是程序运行时加载的库,当动态链接库正确安装后,所有的程序都可以使用动态库来运行程序。动态链接库是目标文件的集合,目标文件在动态链接库中的组织方式是按照特殊方式形成的。库中函数和变量的地址是相对地址,不是绝对地址,其真实地址在调用动态库的程序加载时形成。 so文件是基于ELF(Executable and Linking Format)文件格式。而so是共享目标文件,所以要想对so文件进行加密就必须了解

ELF文件格式: 可执行链接格式(Executable and Linking Format)最初是由 UNIX 系统实验室(UNIX System Laboratories,USL)开发并发布的,作为应用程序二进制接口(Application Binary Interface,ABI)的一部分。工具接口标准(Tool Interface Standards,TIS)委员会将还在发展的 ELF 标准选作为一种可移植的目标文件格式,可以在 32 位 Intel 体系结构上的很多操作系统中使用。

目标文件有三种类型: 可重定位文件(Relocatable File) .o)包含适合于与其他目标文件链接来创建可执行文件或者共享目标文件的代码和数据。 可执行文件(Executable File) .exe) 包含适合于执行的一个程序,此文件规定了exec() 如何创建一个程序的进程映像。 共享目标文件(Shared Object File) .so) 包含可在两种上下文中链接的代码和数据。首先链接编辑器可以将它和其它可重定位

文件和共享目标文件一起处理, 生成另外一个目标文件。其次动态链接器(Dynamic Linker)可能将它与某 个可执行文件以及其它共享目标一起组合,创建进程映像。

目标文件全部是程序的二进制表示,目的是直接在某种处理器上直接执行。

通过对so中的section和函数进行加密来加固对逆向的难度会提高很多,虽然对于了解so的人来说并不是难事,比如动态调试一下,或者dump出内存中运行的dex,所以没有绝对的安全,只有相对的攻防。


中关村科金
136 声望13 粉丝

北京中关村科金技术有限公司(简称“中关村科金”)是国内领先的对话式AI技术解决方案提供商,成立于2014年,注册资本14亿元,总部位于北京,在上海、重庆、深圳、杭州、成都等地设有分支机构,公司规模近千人,其...