解析resources.arsc文件

828 阅读2分钟

resources.arsc 是 Android APK 包中一个二进制格式的资源索引表,用来存放应用里所有资源(字符串、布局、颜色、样式、图片引用等)的编译后信息。它在 APK 解压后通常位于根目录下,与 AndroidManifest.xmlclasses.dex 并列。

resources.arsc格式解析很重要,现在很多应用为了缩减应用包的大小开始对资源进行混淆,就用到这个文件格式。应用安全防护中通过对资源混淆来做到安全应用,也用到这个文件格式。

一、通过apktool反编译,直接获取资源索引ID

如果顺利的话,apktool反编译后,会有一个res目录,这个目录包含了layout、drawable,values,各个资源文件。而apk中所有的资源索引ID,则被统一存放在values/public.xml

public.png

public.xml中的每个条目,格式如下:

<public type="layout" name="view_item_balance" id="0x7f0d02f4"/>

type,类型;name,资源名;id,资源的id。

二、使用Python + Androguard解析resoures.arsc文件

androguard 4.1.3

import os
from androguard.core.axml import ARSCParser

def parse_arsc(arsc_path, output_file=None):
    # 检查文件存在
    if not os.path.isfile(arsc_path):
        print(f"错误: 找不到文件 {arsc_path}")
        sys.exit(1)

    # 读取 resources.arsc 二进制数据
    with open(arsc_path, 'rb') as f:
        data = f.read()

    # 初始化解析器
    parser = ARSCParser(data)

    lines = []
    # 输出字符串池
    lines.append('=== String Pool ===')
    try:
        count = parser.get_string_count()
        for idx in range(count):
            s = parser.get_string(idx)
            lines.append(f'{idx}: {s}')
    except AttributeError:
         lines.append("\n")
        # 兼容老版本方法
        # for idx, s in enumerate(parser.get_string()):
        #     lines.append(f'{idx}: {s}')



    # 输出包名
    lines.append('\n=== Packages ===')
    for pkg in parser.get_packages_names():
        lines.append(pkg)

    # 提示如何解析资源条目
    lines.append('\n=== 资源条目提示 ===')
    lines.append('要解析具体资源条目,请调用:')
    lines.append('    parser.get_resolved_res_configs(res_id)')
    lines.append('其中 res_id 是一个整数形式的资源 ID (0xPPTTEEEE)。')
    lines.append('例如:')
    lines.append('    value_map = parser.get_resolved_res_configs(0x7f020000)')
    lines.append('    print(value_map)')



    output = "\n".join(lines)
    if output_file:
        with open(output_file, 'w', encoding='utf-8') as out:
            out.write(output)
        print(f'已将资源信息导出到: {output_file}')
    else:
        print(output)

if __name__ == '__main__':
    if len(sys.argv) < 2:
        print('用法: python parse_arsc_direct.py <resources.arsc> [输出文件]')
        sys.exit(1)

    arsc_file = sys.argv[1]
    out_file = sys.argv[2] if len(sys.argv) > 2 else None
    parse_arsc(arsc_file, out_file)