是时候来一波逆向技术分析了之Android Resources.arsc

简介: 近日,我国在中国文昌航天发射场,用长征五号遥四运载火箭成功发射首次火星探测任务天问一号探测器,火箭飞行约2167秒后,成功将探测器送入预定轨道,开启火星探测之旅,迈出了我国行星探测第一步

近日,我国在中国文昌航天发射场,用长征五号遥四运载火箭成功发射首次火星探测任务天问一号探测器,火箭飞行约2167秒后,成功将探测器送入预定轨道,开启火星探测之旅,迈出了我国行星探测第一步

/ 前言 /

gradle 中,配置如下代码可以将无用的资源移除:

android {
    ...
    buildTypes {
        release {
            shrinkResources true
            minifyEnabled true
        }
    }
}

“shrinkResources”资源压缩功能,它需要配合ProGurad的“minifyEnabled”功能同时使用。

如果ProGuard把部分无用代码移除,这些代码所引用的资源也会被标记为无用资源,然后通过资源压缩功能将它们移除。

这个看起来很不错,但是实际上却有些待改进的地方。

对于一些无用的 String、ID、Attr、Dimen 等资源,实际上还存在于 .arsc 文件中。

对于Drawable、Layout这些无用资源,shrinkResources也没有真正把它们删掉,而是仅仅替换为一个空文件。

还是用例子说话吧,我们写一个初始demo(为了减少资源,这里连一个依赖库都不引入,appcompat 也不要),里面有些无用的资源:

strings.xml

<resources>
    ...
    <string name="unused_string">这是个无用的字符串</string>
</resources>

activity_old_main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="old main activity" />
</android.support.constraint.ConstraintLayout>

build.gradle

buildTypes {
    debug {
        proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
    }
    release {
        shrinkResources true
        minifyEnabled true
        proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
    }
}

我们这里,有一个无用的字符串:unused_string,有一个无用布局文件:activity_old_main,可以打 debug 与 release 包,release 包配置了混淆,先使用 010Editor 分析一下 debug 包的 .arsc 文件,看看这两个文件的信息是否存在。

/ 字符串池 /

可以看到,这个无用文件的路径是存在的。路径存在字符串池中,这里储存了资源路径与strings.xml中定义的字符串等等一些资源。

/ 资源名称字符串池 /

在package中,也是有这两个资源的数据,它们也是在字符串池中,注意与上面的字符串池的区别。

/ 资源类型字符串池 /

这里的字符串池储存的是资源的 类型 与 名称。我们展开 typeStrings 可以看到类型:

/ ResTable_type /

注意到,string 是 strdata 数组第 6+1 个元素,所以,我们展开 ResTable_typeSpec typeSpec[6] 后面的 typeType,可以看到:

这里可以看到,我们定义的 app_name,unused_string,但是他们的值却看不到,我刚开始以为是模板出错了,后来想了一下,可能是因为如果是图片等资源的话,根本就解析不出来。

所以这里的 value 应该是指向的第一个字符串池,里面储存的是资源路径,拿到资源路径后再去加载资源。理论上值就是上面字符串池中的索引引用。

layout 也是一样的,这里就不贴图了。有的 typeType 会有多个,是因为不同配置的原因:

可以看到,这里 mipmap 有6个,是因为我们的 res 目录里面就有 6 个 mipmap 文件夹,其作用就是用作适配的。不同的手机会从不同的结构体中读取资源。

/ ResTable_entry与Res_value /

还是要重点说一下, ResTable_entry 与 Res_value,最简单的理解就是:

<bool name="abc_action_bar_embed_tabs">false</bool>

ResTable_entry 里面存了 abc_action_bar_embed_tabs,但是不是直接存的,存的是上面字符串池的字符索引。

Res_value 里面存了当前资源的类型,我们需要先要搞清楚它的类型,然后,再去 data 里面去拿资源路径。

我们拿,app_name 来说明一下,arsc 是如何根据 resourceId 来获取资源的。


我们可以看到,该资源的类型 id 为 7。其 entry 的偏移为 0(它是 entry 数组的第 1 项)。

所以它的 resourceId 为 0x7F070000。那么这个是怎么得出来的呢?

首先,7F 是 packageId,包的命名空间,取值范围为[0x01, 0x7F],一般第三方应用均为7F,系统的为 01。
07 是资源类型id,这里代表的是 string。
0000 就是在 entry 中的偏移。

它的data为0,指向的是第一个字符串池中的第1项,其内容是 Sample。

OK,这里我们对 arsc 应该有一定的了解了,再回到主题,看看 release 包有哪些变化呢?

这里,我就不贴图了,结果就是 .arsc 文件是一样的,连大小都一样。但是我们去 res 目录里面发现,activity_old_main.xml 文件变了。

debug 包里面的文件,有 540 个字节,但是 release 包里面的文件只有 104 个字节,使用编辑器打开,发现 release 包里面的文件数据都是 null,与上面的提到的类似,变成了一个空文件。

所以,shrinkResources 并没有我们想的那么美好。

/ ResTable_map_entry /

还有,对于 style 与 attr 来说,他们的储存方式又不一样,为啥呢?从写法就可以看出来:

<attr name="buttonTintMode">
    <enum name="src_over" value="3"/>
    <enum name="src_in" value="5"/>
    <enum name="src_atop" value="9"/>
    <enum name="multiply" value="14"/>
    <enum name="screen" value="15"/>
    <enum name="add" value="16"/>
</attr>
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
</style>

这种写法,显然不能像 string drawable 一样,搞个键值对,只能使用 map:

这个map 里面没啥东西,是因为我把 AppTheme 里面的东西都删了。

其实,我这里讲的很粗,但是我研究了几天这个文件结构,发现比较重要的东西就是这些了,除非你想对 arsc 做自定义处理,否则的话了解上面的东西也就够了。再深入的话,需要去查看对应的 C 结构,然后搞懂每个字段的意义。

老罗的文章讲这个讲的很细,但是对于现在的我来说,看完就忘,因为用不到,所以我暂时只深入到这里吧…

有个额外的东西需要说一下,我特么还在 stackoverflow 上提了问题。

关于字符串常量头的结构:

struct ResStringPool_header
{
    struct ResChunk_header header;
    // Number of strings in this pool (number of uint32_t indices that follow
    // in the data).
    uint32_t stringCount;
    // Number of style span arrays in the pool (number of uint32_t indices
    // follow the string indices).
    uint32_t styleCount;
    // Flags.
    enum {
        // If set, the string index is sorted by the string values (based
        // on strcmp16()).
        SORTED_FLAG = 1<<0,
        // String pool is encoded in UTF-8
        UTF8_FLAG = 1<<8
    };
    uint32_t flags;
    // Index from header of the string data.
    uint32_t stringsStart;
    // Index from header of the style data.
    uint32_t stylesStart;
}

string 与 stringStart 都好理解,style 是个啥,字符串还有样式???

老罗的文章中说,mango b 与 i 就是字符串样式。

注意到第四个字符串“mango”,它实际表示的是一个字符串“mango”,不过它的前三个字符“man”通过b标签来描述为粗体的,而后两个字符通过i标签来描述为斜体的。字符串“mango”来有两个sytle,第一个style表示第1到第3个字符是粗体的,第二个style表示第4到第5个字符是斜体的。

我使用 010Editor 打开后,发现 styleCount 为 1。

相关文章
|
3月前
|
存储 Java 开发工具
Android开发的技术与开发流程
Android开发的技术与开发流程
161 1
|
7月前
|
开发工具 Android开发
Android平台GB28181设备接入端语音广播技术探究和填坑指南
GB/T28181-2016官方规范和交互流程,我们不再赘述。
|
7月前
|
编解码 Android开发 数据安全/隐私保护
Android平台外部编码数据(H264/H265/AAC/PCMA/PCMU)实时预览播放技术实现
好多开发者可能疑惑,外部数据实时预览播放,到底有什么用? 是的,一般场景是用不到的,我们在开发这块前几年已经开发了非常稳定的RTMP、RTSP直播播放模块,不过也遇到这样的场景,部分设备输出编码后(视频:H.264/H.265,音频:AAC/PCMA/PCMU)的数据,比如无人机或部分智能硬件设备,回调出来的H.264/H.265数据,除了想转推到RTMP、轻量级RTSP服务或GB28181外,还需要本地预览甚至对数据做二次处理(视频分析、实时水印字符叠加等,然后二次编码),基于这样的场景诉求,我们开发了Android平台外部编码数据实时预览播放模块。
|
6月前
|
存储 传感器 定位技术
《移动互联网技术》 第四章 移动应用开发: Android Studio开发环境的使用方法:建立工程,编写源程序,编译链接,安装模拟器,通过模拟器运行和调试程序
《移动互联网技术》 第四章 移动应用开发: Android Studio开发环境的使用方法:建立工程,编写源程序,编译链接,安装模拟器,通过模拟器运行和调试程序
68 0
|
2月前
|
人工智能 vr&ar Android开发
探索安卓与iOS系统的技术进展
【2月更文挑战第4天】本文将探讨安卓与iOS两大操作系统在最新技术进展方面的差异与相似之处。我们将分析它们在人工智能、增强现实、隐私保护等方面的创新和发展,并展望未来可能出现的趋势。通过对比这两个操作系统的技术特点,读者将能够更好地了解并选择适合自己需求的智能设备。
|
7月前
|
开发工具 Android开发
Android平台GB28181设备接入端预置位查询(PresetQuery)探讨和技术实现
之前blog介绍了GB28181云台控制(PTZCmd)相关,本文主要是介绍下GB28181预置位查询。
|
3月前
|
安全 算法 JavaScript
安卓逆向 -- 关键代码定位与分析技术
安卓逆向 -- 关键代码定位与分析技术
42 0
|
3月前
|
SQL API Android开发
展望2022:Android 开发最新技术动向
展望2022:Android 开发最新技术动向
111 0
展望2022:Android 开发最新技术动向
|
6月前
|
测试技术 开发工具 数据库
《移动互联网技术》第十一章 Android应用工程案例: 掌握Android系统的需求分析和设计以及 Android项目的程序测试和版本管理方法
《移动互联网技术》第十一章 Android应用工程案例: 掌握Android系统的需求分析和设计以及 Android项目的程序测试和版本管理方法
71 0
|
6月前
|
设计模式 网络协议 Java
《移动互联网技术》 第十章 系统与通信: 掌握Android系统的分层架构设计思想和基于组件的设计模式
《移动互联网技术》 第十章 系统与通信: 掌握Android系统的分层架构设计思想和基于组件的设计模式
65 0