今天我们聊些啥?许久不见,是该聊些啥了,话不多说,先来个五毛钱得,聊一聊 胡小毛 的 Android 逆向之路吧,当然,你们想知道的一定不是走了这么远的路,胡小毛今年是不是又长高了,那么我们开始看看他又 Get 到的新 zishi 吧(本文内容为 MaoXH 总结,喜大奔普,胡小毛的新id:MaoXH<毛小胡>)。
切入正题,胡小毛在学习 Android 逆向的过程中又有所总结,先来看看 apk 文件结构:
首先拿一款普通 app 讲解,用 zip 压缩文件打开会出现以下文件夹:
Assets 目录用来存放需要打包到 Android 应用程序的静态资源文件,例如图片资源文件、 JSON 配置文件、渠道配置文件、二进制数据文件、 HTML5 离线资源文件等。与 res/raw 目录不同的是, assets 目录支持任意深度的子目录,同时该目录下面的文件不会生成资源 ID 。
Lib 目录存放的是当前 app 所用得到的 so 动态链接库文件, so 文件就是利用底层的 c 、 c++ 代码实现的。
META-INF 目录存放的是所用到的证书签名文件,包括: MANIFEST.MF (摘要文件)、 CERT.SF 和 CERT.RSA 。其中 MANIFEST.MF 文件是对每个文件的 SHA-256-Digest ; CERT.SF 是对每个文件的头 3 行进行 SHA-256-Digest ; CERT.RSA 这个文件保存了签名和公钥证书。
Res 目录放应用的资源文件,包括图片资源、字符串资源、颜色资源、尺寸资源等,这个目录下面的资源都会出现在资源清单文件 R.java 的索引中。
AndroidManifest.xml : Android 项目的系统清单文件, Android 应用的四大组件( Activity 、 Service 、 BroadcastReceiver 和 ContentProvider )均在此配置和声明。
classes.dex :应用程序的可执行文件。若 APP 有多个 dex ,是因为当前的方法数超过 65535 ,进行了分包处理。如果未超过,则只有一个 dex 。 Android 的所有代码都集中在此。可以通过反编译工具 dex2jar 转化成 jar 包,再通过 jd-gui 查看其代码。
resources.arsc :资源索引表,用来描述具有 ID 值的资源的配置信息。
看完了上面的 apk 的文件结构,我就要开始我们的正戏了,首先是“小二,上图 ~ ,上长图 ~ ”
放心,不是表情包
上图就是一个 apk 包的细化打包流程,包含了每个细化过程可能会用到的工具,各位看官可多注意橘色标注字体部分。然后我们再看一下应用安装涉及到的如下几个目录:
system/app --------------- 系统自带的应用程序,获得 adb root 权限才能删除
data/app --------------- 用户程序安装的目录。安装时把 apk 文件复制到此目录
data/data --------------- 存放应用程序的数据
data/dalvik-cache-------- 将 apk 中的 dex 文件安装到 dalvik-cache 目录下 (dex 文件是 dalvik 虚拟机的可执行文件 , 其大小约为原始 apk 文件大小的四分之一 )
复制 APK 安装包到 data/app 目录下,解压并扫描安装包,把 dex 文件 (Dalvik 字节码 ) 保存到 dalvik-cache 目录,并在 data/data 目录下创建对应的应用数据目录。
删除安装过程中在上述三个目录下创建的文件及目录。
有事好好说,没事干啥提虚拟机啊,胡小毛也是搞得我晕头转向,莫慌,仔细瞧瞧,发现小毛得学习思路还是可圈可点得。上面提到得 dalvik 虚拟机,可能并未引起各位看官的注意力,所以这边再多唠叨一遍。
首先是 java 虚拟机,我们知道 java 语言有一个很重要的特性就是 “ 跨平台 ” 可以做到 “ 一次编译,到处运行 ” 的效果。怎样才能有这样的特性呢?主要就是依靠的 java 虚拟机( JVM )。当我们编写好一个 java 程序之后如 test.java 。然后将其编译为一个字节码文件 test.class 。在 java 虚拟机上运行这个字节码文件, java 虚拟机就可以把字节码文件解释成具体平台上的机器指令执行,而实现了 java 的跨平台特性。
然后我们需要知道的是 Android 是基于 Dalvik 虚拟机 (DVM) 或 art 虚拟机 (aot 机制 ) 的。 Dalvik 虚拟机主要应用于 Android5.0 及以前,而ART(Android Runtime)虚拟机是 Android 4.4 发布的,用来替换 Dalvik 虚拟机,Android 4.4 默认采用 DVM,但是可以选择使用 ART。在 Android 5.0 版本中默认使用 ART,DVM 从此退出历史舞台。
而JDM、DVM、ART之间的关系可参考下图:
还记得之前提到的META-INF目录吗?里面的签名证书文件就是对apk进行签名过程中生成,apk签名过程可以总结如下:
1、对Apk中的每个文件做一次算法(数据SHA1摘要+Base64编码),保存到MANIFEST.MF文件中,具体作法可以理解为程序遍历APK包中的所有文件,对非目录、非签名文件的文件,逐个用SHA1生成摘要信息,再用Base64进行编码后保存。基于此文件的安全机制可以进行文件完整性校验:如果APK包的文件被修改,在APK安装校验时,被修改的文件与MANIFEST.MF的校验信息不同,程序将无法正常安装,同理CERT.SF和CERT.RSA文件同样应用于apk的完整性校验。
MANIFEST.MF文件格式如下:
2、对MANIFEST.MF整个文件做一次算法(数据SHA1摘要+Base64编码),存放到CERT.SF文件的头属性中,再对MANIFEST.MF文件中各个属性块做一次算法(数据SHA1摘要+Base64编码),存到到一个属性块中。
CERT.SF文件格式如下:
3、对CERT.SF文件做签名,内容存档到CERT.RSA中,所以CERT.RSA是一个加密文件,所以它长的很难看,不信的自己去看:
了解了上面apk的签名过程,我们可以深入思考一下下面这段话(某大神原话):
假如我们是一个非法者,想要篡改apk内容,我们怎么做呢?如果我们只把原文件改动了(比如加入了自己的病毒代码),那么重新打包后系统就会认为文件的SHA1-Base64值和MF的不一致导致安装失败,既然这样,那我们就改一下MF让他们一致呗?如果只是这样那么系统就会发现MF文件的内容的SHA1-Base64与SF不一致,还是会安装失败,既然这样,那我们就改一下SF和MF一致呗?如果这么做了,系统就会发现RSA解密后的值和SF的SHA1不一致,安装失败。那么我们让加密后的值和SF的SHA1一致就好了呗,但是呢,这个用来签名加密的是私钥,公钥随便玩,但是私钥我们却没有,所以没法做到一致。所以说上面的过程环环相扣,最后指向了RSA非对称加密的保证。
最后我们必须要知道 签名机制只是保证了 apk 的完整性 ,具体是不是自己的 apk 包,系统并不知道,所以对于上面的通过 apk 签名 进行完整性校验,攻击者可以通过直接重签名,让所有的信息都一致就能绕过校验,这样重签名后就可以安装了。 所以对于应用签名是否被篡改,那就是另一门学问了……
1、https://blog.csdn.net/loongago/article/details/89646920
2、https://www.jianshu.com/p/a37d3be0a341
3、https://blog.csdn.net/lostinai/article/details/54694564?utm_source=blogxgwz3
移动安全(一)|Android设备root及神器Xposed框架安装
>>关于我们:
WhITECat安全小组隶属于起源实验室分支安全小组,主要致力于分享小组成员技术研究成果、最新的漏洞新闻、安全招聘以及其他安全相关内容。团队成员暂时由起源实验室核心成员、一线安全厂商、某研究院、漏洞盒TOP10白帽子等人员组成。
本文作者:辞令_WhITECat