Android: 逆向篇(一)
Admin Lv3

工程师们擅于将工程细节隐藏起来,而逆向工程师们擅于将这些暴露出来。

介绍

简单地来说,安卓逆向是对已经打包好的APP进行反编译、源码分析、还原APP实现逻辑的一门技术。

APK文件目录结构

Android应用程序包(Android application package,APK),是Android操作系统使用的一种应用程序包文件格式。一个APK文件内包含被编译的代码文件(.dex 文件),文件资源(resources),电子资产(assets),证书(certificates),和清单文件(manifest file)。APK 文件与JAR文件的构造方式相似,都是基于ZIP文件格式。

图片加载出错啦!

res目录

res是resource的缩写,这个目录存放资源文件,该文件夹下的所有文件都会被映射到Android工程的.R文件中,生成对应的ID,访问的时候直接使用资源ID即可。res文件夹下可以包含多个文件夹,每个文件夹对应存放不同类型资源,其中anim存放动画文件;drawable目录存放图像资源;layout目录存放布局文件;values目录存放一些特征值相关的文件,colors.xml存放color颜色值,dimens.xml定义尺寸值,string.xml定义字符串的值,styles.xml定义样式对象;raw是可以直接复制到设备中的任意文件,他们无需编译。

assets目录

用于存放需要打包到APK中的静态文件,和res的不同点在于,assets目录支持任意深度的子目录,用户可以根据自己的需求任意部署文件夹架构,而且res目录下的文件会在.R文件中生成对应的资源ID,assets不会自动生成对应的ID,访问的时候需要调用AssetManager类。里面可以存放一些html文件或者图片等资源。

lib目录

这里存放应用程序依赖的native库文件,一般是用C/C++编写,这里的lib库可能包含4中不同类型,根据CPU型号的不同,大体可以分为ARM,ARM-v7a,MIPS,X86,分别对应着ARM架构,ARM-V7架构,MIPS架构和X86架构。

META-INF目录

保存应用的签名信息,签名信息可以验证APK文件的完整性。Android SDK在打包APK时会计算APK包中所有文件的完整性,并且把这些完整性保存到META-INF文件夹下,应用程序在安装的时候首先会根据META-INF文件夹校验APK的完整性,这样就可以保证APK中的每一个文件都不能被篡改。以此来确保APK应用程序不被恶意修改或者病毒感染,有利于确保Android应用的完整性和系统的安全性。META-INF目录下包含的文件有CERT.RSA,CERT.DSA,CERT.SF和MANIFEST.MF,其中CERT.RSA是开发者利用私钥对APK进行签名的签名文件,CERT.SF,MANIFEST.MF记录了文件中文件的SHA-1哈希值。

AndroidManifest.xml

Android应用程序的配置文件,是一个用来描述Android应用“整体资讯”的设定文件,简单来说,相当于Android应用向Android系统“自我介绍”的配置文件,Android系统可以根据这个“自我介绍”完整地了解APK应用程序的资讯,每个Android应用程序都必须包含一个AndroidManifest.xml文件,且它的名字是固定的,不能修改。我们在开发Android应用程序的时候,一般都把代码中的每一个Activity,Service,Provider和Receiver在AndroidManifest.xml中注册,只有这样系统才能启动对应的组件,另外这个文件还包含一些权限声明以及使用的SDK版本信息等等。程序打包时,会把AndroidManifest.xml进行简单的编译,便于Android系统识别,编译之后的格式是AXML格式。

*.dex

传统的Java程序,首先先把Java文件编译成class文件,字节码都保存在了class文件中,Java虚拟机可以通过解释执行这些class文件。而Dalvik虚拟机是在Java虚拟机进行了优化,执行的是Dalvik字节码,而这些Dalvik字节码是由Java字节码转换而来,一般情况下,Android应用在打包时通过AndroidSDK中的dx工具将Java字节码转换为Dalvik字节码。dx工具可以对多个class文件进行合并,重组,优化,可以达到减小体积,缩短运行时间的目的。

resources.arsc

用来记录资源文件和资源ID之间的映射关系,用来根据资源ID寻找资源。Android的开发是分模块的,res目录专门用来存放资源文件,当在代码中需要调用资源文件时,只需要调用findviewbyId()就可以得到资源文件,每当在res文件夹下放一个文件,aapt就会自动生成对应的ID保存在.R文件,我们调用这个ID就可以,但是只有这个ID还不够,.R文件只是保证编译程序不报错,实际上在程序运行时,系统要根据ID去寻找对应的资源路径,而resources.arsc文件就是用来记录这些ID和资源文件位置对应关系的文件。

APK打包流程

图片加载出错啦!
  • 使用 aapt(The Android Asset Packing Tool) 对资源文件进行打包,生成 R.java 文件;
  • 如果项目中使用到了 AIDL(Android Interface Definition Language)提供的服务,则需要使用 AIDL 工具解析 AIDL 接口文件生成相应的 Java 代码;
  • 使用 javac 将 R.java 和 AIDL 文件编译为 .class 文件;
  • 使用 dx 工具将 class 和第三方的 library 转换为 dex 文件;
  • 利用 apkbuilder 将第一步编译后的资源、第四步生成的 .dex 文件,以及一些其它资源打包到 APK 文件中;
  • 这一步主要是对 APK 进行签名。可以分为两种情况,如果我们是要发布 App,那就采用 RealeaseKeystore 签名;反之,我们如果只是想要对 App 进行调试,那就使用 debug.keystore 签名;
  • 在发布正式版之前,需要将 APK 包中资源文件距离文件的起始偏移修改为 4 字节的整数倍数,这样,在之后运行 App 的时候,速度会比较快;

APK安装流程

图片加载出错啦!
  • 复制apk安装包到/data/app目录下,解压并扫描安装包;
  • 向资源管理器注入apk资源;
  • 解析AndroidManifest文件,并在/data/data目录下创建对应的应用数据目录;
  • 若APK中有lib库,系统会判断这些so库的名字,查看是否以lib开头,是否以.so结尾,再根据CPU的架构解压对应的so库到/data/data/{pkg}/lib下;
  • 针对dalvik/art环境优化dex文件,保存到dalvik-cache目录;
  • 将AndroidManifest文件解析出的组件、权限注册到PackageManagerService;
  • 完成后发送广播;