
回复
【本文正在参加 2023「盲盒」+码有奖征文活动】 https://ost.51cto.com/posts/25284
@toc
前段时间,我开发了一个开源的跨平台的hap查看器,支持win、mac、linux,可以解析查看API9+ Stage模型的应用,后续还做了一个android版的(开源地址和软件截图见文章底部)。那今天我们来讲一下核心功能的具体实现原理,以及逆向解析应用名的初步方案是如何形成的。
module.json
的明文的描述文件,这里包含了应用的基本信息,我们只需要通过程序读取并解析json读取需要的值即可,下面给出一些java代码片段HapInfo hapInfo = new HapInfo();
ZipFile zipFile = null;
try {
hapInfo.hapFilePath = hapFilePath;
zipFile = new ZipFile(hapFilePath);
// 读取module.json
JSONObject module = getEntryToJsonObject(zipFile, "module.json");
// app.
hapInfo.packageName = module.getByPath("app.bundleName", String.class);
hapInfo.versionName = module.getByPath("app.versionName", String.class);
hapInfo.versionCode = module.getByPath("app.versionCode", String.class);
hapInfo.vendor = module.getByPath("app.vendor", String.class);
hapInfo.minAPIVersion = module.getByPath("app.minAPIVersion", String.class);
hapInfo.targetAPIVersion = module.getByPath("app.targetAPIVersion", String.class);
hapInfo.apiReleaseType = module.getByPath("app.apiReleaseType", String.class);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("HAP file parse failed");
} finally {
IoUtil.close(zipFile);
}
我们需要先遍历module.abilities
下所有的Ability信息,优先去找与启动AbilityName
一致的Ability信息,如果找不到默认取第一个,然后再解析子属性中的icon
的相对路径值,前面拼上 resources/base/media/
,后面拼上 .png
就是完整的图标路径了,然后根据此路径读取并加载图片即可。
// module.
hapInfo.mainElement = module.getByPath("module.mainElement", String.class);
// 解析图标
JSONArray moduleAbilities = module.getByPath("module.abilities", JSONArray.class);
JSONObject targetAbility = null;
try {
targetAbility = (JSONObject) moduleAbilities.get(0);
} catch (Exception ignore) {}
for (Object item : moduleAbilities) {
JSONObject ability = (JSONObject) item;
if (hapInfo.mainElement.equals(ability.get("name", String.class))) {
targetAbility = ability;
break;
}
}
if (targetAbility != null) {
String iconName = targetAbility.get("icon", String.class).split(":")[1];
String iconPath = String.format("resources/base/media/%s.png", iconName);
hapInfo.iconPath = iconPath;
hapInfo.iconBytes = getEntryToBytes(zipFile, iconPath);
hapInfo.icon = getEntryToImage(zipFile, iconPath);
}
resources.index
文件中。resources.index
的文件,这个就是应用工程里面所有资源文件最终打包的产物,是用一个名为 restool 的开源工具进行构建的,同时 restool
其实就在sdk安装目录下的toolchains子目录中。apktool
等逆向工具能快速准确地反编译看到明文的资源文件010Editor
分别打开几个应用内的 resources.index
文件,在 十六进制视图
下做一些分析和对比,尝试寻找有是否有一定的规律// 特征分析(??????代表应用名称)
00 2C 00 00 00 09 00 00 00 03 00 00 01 0D 00 ?????? 00 13 00 // 设备信息
00 24 00 00 00 09 00 00 00 03 00 00 01 05 00 ?????? 00 13 00 // F-OH
00 28 00 00 00 09 00 00 00 03 00 00 01 10 00 ?????? 00 0C 00 // 搜狗输入法
// 关键特征
00 00 00 09 00 00 00 03 00 00 01
// 伪正则
00 ?? 00 00 00 09 00 00 00 03 00 00 01 ?? 00 ?????? 00 ?? 00
// 正则
(00.{2}0000000900000003000001.{2}00)(.*?)(00.{2}00)
// Java代码片段
byte[] resBytes = getEntryToBytes(zipFile, "resources.index");
String resHex = HexUtil.encodeHexStr(resBytes).toUpperCase();
String appNameHex = ReUtil.get("(00.{2}0000000900000003000001.{2}00)(.*?)(00.{2}00)", resHex, 2);
String appName = HexUtil.decodeHexStr(appNameHex);
https://gitee.com/ohos-dev/hap-viewer
https://gitee.com/ohos-dev/hap-viewer-android