Android逆向:二进制xml文件解析(Start Tag Chunk)

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: 在Android中,xml文件经过编译后都是不可读的二进制文件。今天我们来解析一下这个二进制文件的内容,看看如何与我们的源码进行对应。

前言


在Android中,xml文件经过编译后都是不可读的二进制文件。今天我们来解析一下这个二进制文件的内容,看看如何与我们的源码进行对应。


XML文件结构


在Android中,xml文件经过编译后都是不可读的二进制文件。它的结构如图:

网络异常,图片无法展示
|


简单说一下大概的结构:

  • Header Chunk:8个byte,type+headersize+fileszie
  • String Chunk:字符串池
  • ResourceId Chunk: 系统的资源id,即0x01xxxxxx这种
  • XMLContent Chunk:xml内容的结


其中XMLContent Chunk是主要部分,是一个集合,从图中可以看到它包含多种类型的数据结构,其中Start Namespace Chunk、End Namespace Chunk和Text Chunk这三种类型数据有可能不存在。而Start Tag Chunk和End Tag Chunk一定存在。

Start Tag Chunk和End Tag Chunk就是一个xml tag,如<View /><View ></>,所以它们是成对出现的。


但是要注意不是一个Start Tag Chunk后面一定跟着一个End Tag Chunk,比如嵌套<Layout ><View /></Layout>,这种情况则是Start Tag Chunk + Start Tag Chunk + End Tag Chunk + End Tag Chunk

所以End Tag Chunk中基本没有什么信息,大部分信息都在Start Tag Chunk中,这也是我们这篇文章讨论的重点。


Start Tag Chunk Header


下面是Start Tag Chunk的一个实例:

网络异常,图片无法展示
|


下面我们一步步解析它。

从上面的图中可以清楚的看到Start Tag Chunk的结构。不过没展示的是Start Tag Chunk包含header和body结构。

Header的结构如下:


struct ResXMLTree_node
    {
    struct ResChunk_header header; 
    uint32_t lineNumber;
    struct ResStringPool_ref comment;
};
复制代码


这里type(2byte)+ headersize(2byte,header大小固定是16byte)+ chunksize(4byte)+ lineNum(4byte)+ comment(4byte)

结合示例来看,其中橙色部分02011000 74000000 00000000 FFFFFFFF便是header。其中:

0201是type;1000是headersize,考虑字节就是16;74000000是chunksize,是116byte,除去header的16byte,body的大小应该是100byte,后面会验证;00000000是lineNum;FFFFFFFF是没有comment的默认值。


Start Tag Chunk Body


header后面就是body,body主要分两部分,第一部分是有关tag的基本信息,第二部分则是Atrributes。

第一部分结构如下:


struct ResXMLTree_attrExt
    {
    struct ResStringPool_ref ns; 
    struct ResStringPool_ref name; 
    uint16_t attributeStart; 
    uint16_t attributeSize; 
    uint16_t attributeCount; 
    uint16_t idIndex;
    uint16_t classIndex;
    uint16_t styleIndex;
};
复制代码


其中:

  • ns: 命名空间,在字符串池中的索引。如果没有就是0xFFFFFFFF。(4byte)
  • name: 元素名称,在字符串池中的索引 。(4byte)
  • AttributeStart: 属性段的相对body的偏移,由于这部分大小固定,所以这个偏移也是固定的20byte 。(2byte)
  • AttributeSize: 每个属性的大小,固定是20byte 。(2byte)
  • AttributeCount: 属性的总数 。(2byte)
  • idIndex: 第几个属性表示id 。(2byte)
  • classIndex: 第几个属性表示class 。(2byte)
  • styleIndex: 第几个属性表示style 。(2byte)


结合上面的例子来看,其中绿色部分FFFFFFFF 09000000 14001400 04000100 00000000便是这一部分,其中:

FFFFFFFF表示没有命名空间;09000000表示元素名是字符串池第10个;第一个1400是偏移量,即20byte;第二个1400表示每个属性大小是20byte;0400表示一共有4个属性;0100表示第一个属性是id;00000000表示没有class和style。

这个tag实际是下面的代码:


<ImageView
    android:id="@+id/image1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/fio" />
复制代码


可以看到它一共有四个属性,而第一个属性是id。如果我们去字符串池中找,会发现第10字符串是ImageView。

注意:我们可以验证上面的body大小,这部分大小固定是20byte,而每个属性大小是20byte,一共四个,所以body的大小正好是上面说过的100byte。


Atrributes


接下就是Atrributes,Atrributes是一系列Entry结构的集合,每个Entry的结构如下:


struct ResXMLTree_attribute{
     struct ResStringPool_ref ns;
     struct ResStringPool_ref name;
     struct ResStringPool_ref rawValue; 
     struct Res_value typedValue;
};
复制代码


其中:

  • Ns: 属性的命名空间,在字符串池中的索引,比如xmlns:android="http://schemas.android.com/apk/res/android这种。(4byte)
  • Name:  属性的名称,在字符串池中的索引。(4byte)
  • rawValue: 属性的值的原始 XML 文字中字符串在 string indices 中的索引。(4byte)
  • TypeValue: 是一个表示属性值的结构体。(8byte)


这里的TypeValue的结构如下


struct Res_value {
        uint16_t size;
        uint8_t res0;
        uint8_t dataType;
        uint32_t data;
}
复制代码


其中:

  • Size:表示 Res_value 的大小。可以看到这里固定是8byte大小,所以size固定是0x80。(2byte)
  • Res0: 始终为 0 (1byte)
  • dataType: 值的类型。(1byte)
  • data:属性值。(4byte)


其中dataType类型如下:


public static final int TYPE_NULL = 0x00;
public static final int TYPE_REFERENCE = 0x01;
public static final int TYPE_ATTRIBUTE = 0x02;
public static final int TYPE_STRING = 0x03;
public static final int TYPE_FLOAT = 0x04;
public static final int TYPE_DIMENSION = 0x05;
public static final int TYPE_FRACTION = 0x06;
public static final int TYPE_DYNAMIC_REFERENCE = 0x07;
public static final int TYPE_FIRSTINT = 0x10;          // Beginning of integer flavors...
public static final int TYPE_INT_DEC = 0x10;           // n..n.
public static final int TYPE_INT_HEX = 0x11;           // 0xn..n.
public static final int TYPE_INT_BOOLEAN = 0x12;       // 0 or 1, "false" or "true"
public static final int TYPE_FIRST_COLOR_INT = 0x1c;   // Beginning of color integer flavors...
public static final int TYPE_INT_COLOR_ARGB8 = 0x1c;   // #aarrggbb.
public static final int TYPE_INT_COLOR_RGB8 = 0x1d;    // #rrggbb.
public static final int TYPE_INT_COLOR_ARGB4 = 0x1e;   // #argb.
public static final int TYPE_INT_COLOR_RGB4 = 0x1f;    // ##rgb.
public static final int TYPE_LAST_COLOR_INT = 0x1f;    // ..end of integer flavors.
public static final int TYPE_LAST_INT = 0x1f;          // ...end of integer flavors.
复制代码


结合上面的例子来看,蓝色部分便是Atrributes,我们取其中一个来看,比如:

0D000000 03000000 FFFFFFFF 08000001 3800077F

其中:

0D000000表示字符串池第15个是命名空间;03000000表示字符串池第4个是属性名称;FFFFFFFF表示没有rawValue。

0800表示TypeValue的大小是8byte;00是resId,固定值;01表示属性值是一个资源索引;3800077F就是资源索引,即resId是0x7F070038。

再结合实际代码,这个属性上面代码中的第一个属性,所以是android:id="@+id/image1"。所以它的属性值是@+id/image1,是一个资源索引,在

R.java中


public static final int image1=0x7F070038;
复制代码


可以看到image1正是0x7F070038。


总结


这样Start Tag Chunk结构我们就分析完了,有些细节没有说,比如属性值不同的type的表现形式,大体上是差不多的,大家有兴趣可以自己研究一下。


目录
相关文章
|
28天前
|
存储 Java 文件存储
微服务——SpringBoot使用归纳——Spring Boot使用slf4j进行日志记录—— logback.xml 配置文件解析
本文解析了 `logback.xml` 配置文件的详细内容,包括日志输出格式、存储路径、控制台输出及日志级别等关键配置。通过定义 `LOG_PATTERN` 和 `FILE_PATH`,设置日志格式与存储路径;利用 `&lt;appender&gt;` 节点配置控制台和文件输出,支持日志滚动策略(如文件大小限制和保存时长);最后通过 `&lt;logger&gt;` 和 `&lt;root&gt;` 定义日志级别与输出方式。此配置适用于精细化管理日志输出,满足不同场景需求。
132 1
|
2月前
|
移动开发 安全 Java
Android历史版本与APK文件结构
通过以上内容,您可以全面了解Android的历史版本及其主要特性,同时掌握APK文件的结构和各部分的作用。这些知识对于理解Android应用的开发和发布过程非常重要,也有助于在实际开发中进行高效的应用管理和优化。希望这些内容对您的学习和工作有所帮助。
274 83
|
5月前
|
Java 开发工具 Android开发
Android与iOS开发环境搭建全解析####
本文深入探讨了Android与iOS两大移动操作系统的开发环境搭建流程,旨在为初学者及有一定基础的开发者提供详尽指南。我们将从开发工具的选择、环境配置到第一个简单应用的创建,一步步引导读者步入移动应用开发的殿堂。无论你是Android Studio的新手还是Xcode的探索者,本文都将为你扫清开发道路上的障碍,助你快速上手并享受跨平台移动开发的乐趣。 ####
|
23天前
|
监控 Shell Linux
Android调试终极指南:ADB安装+多设备连接+ANR日志抓取全流程解析,覆盖环境变量配置/多设备调试/ANR日志分析全流程,附Win/Mac/Linux三平台解决方案
ADB(Android Debug Bridge)是安卓开发中的重要工具,用于连接电脑与安卓设备,实现文件传输、应用管理、日志抓取等功能。本文介绍了 ADB 的基本概念、安装配置及常用命令。包括:1) 基本命令如 `adb version` 和 `adb devices`;2) 权限操作如 `adb root` 和 `adb shell`;3) APK 操作如安装、卸载应用;4) 文件传输如 `adb push` 和 `adb pull`;5) 日志记录如 `adb logcat`;6) 系统信息获取如屏幕截图和录屏。通过这些功能,用户可高效调试和管理安卓设备。
|
1月前
|
XML JavaScript Android开发
【Android】网络技术知识总结之WebView,HttpURLConnection,OKHttp,XML的pull解析方式
本文总结了Android中几种常用的网络技术,包括WebView、HttpURLConnection、OKHttp和XML的Pull解析方式。每种技术都有其独特的特点和适用场景。理解并熟练运用这些技术,可以帮助开发者构建高效、可靠的网络应用程序。通过示例代码和详细解释,本文为开发者提供了实用的参考和指导。
67 15
|
6月前
|
ARouter Android开发
Android不同module布局文件重名被覆盖
Android不同module布局文件重名被覆盖
|
4月前
|
存储 Linux API
深入探索Android系统架构:从内核到应用层的全面解析
本文旨在为读者提供一份详尽的Android系统架构分析,从底层的Linux内核到顶层的应用程序框架。我们将探讨Android系统的模块化设计、各层之间的交互机制以及它们如何共同协作以支持丰富多样的应用生态。通过本篇文章,开发者和爱好者可以更深入理解Android平台的工作原理,从而优化开发流程和提升应用性能。
|
4月前
|
Java 调度 Android开发
安卓与iOS开发中的线程管理差异解析
在移动应用开发的广阔天地中,安卓和iOS两大平台各自拥有独特的魅力。如同东西方文化的差异,它们在处理多线程任务时也展现出不同的哲学。本文将带你穿梭于这两个平台之间,比较它们在线程管理上的核心理念、实现方式及性能考量,助你成为跨平台的编程高手。
|
5月前
|
开发框架 Dart Android开发
安卓与iOS的跨平台开发:Flutter框架深度解析
在移动应用开发的海洋中,Flutter作为一艘灵活的帆船,正引领着开发者们驶向跨平台开发的新纪元。本文将揭开Flutter神秘的面纱,从其架构到核心特性,再到实际应用案例,我们将一同探索这个由谷歌打造的开源UI工具包如何让安卓与iOS应用开发变得更加高效而统一。你将看到,借助Flutter,打造精美、高性能的应用不再是难题,而是变成了一场创造性的旅程。
|
5月前
|
安全 Java Linux
深入解析Android系统架构及其对开发者的意义####
【10月更文挑战第21天】 本文旨在为读者揭开Android操作系统架构的神秘面纱,探讨其如何塑造现代移动应用开发格局。通过剖析Linux内核、硬件抽象层、运行时环境及应用程序框架等关键组件,揭示Android平台的强大功能与灵活性。文章强调了理解Android架构对于开发者优化应用性能、提升用户体验的重要性,并展望了未来技术趋势下Android的发展方向。 ####
129 0

热门文章

最新文章

推荐镜像

更多
  • DNS