文章目录
-
-
- 零、题目
- 一、压缩包内容
- 二、建立工作目录
- 三、解压逆向包
- [四、识别 .app 文件](#四、识别 .app 文件)
- [五、继续解 .hap](#五、继续解 .hap)
- [六、找数据加密 app 的包名](#六、找数据加密 app 的包名)
- [七、提取 app 字符串](#七、提取 app 字符串)
- 八、找初始化密码至少几位
- 九、找加密后的文件后缀
- [十、找 app 自动识别几种图片后缀](#十、找 app 自动识别几种图片后缀)
- [分析自定义加密 so 模块导入了几个方法](#分析自定义加密 so 模块导入了几个方法)
- [十二、从手机检材中找到 app 数据](#十二、从手机检材中找到 app 数据)
- [十三、分析 app 设置的密码](#十三、分析 app 设置的密码)
- [十四、分析 .tb 文件的加密算法](#十四、分析 .tb 文件的加密算法)
- 十五、写解密脚本
- 十六、找门锁密码
- 十七、找推荐的游戏叫什么
- [十八、找加密图片中的隐藏 flag](#十八、找加密图片中的隐藏 flag)
-
零、题目
1.【填空题 15分】 分析倩倩手机逆向包,数据加密app的包名是什么?【答案格式:com.komeiji.satori】
-
【填空题 10分】 接上题,初始化app时需要至少几位数的密码?【答案格式:10】
-
【填空题 5分】 接上题,加密后的文件名的后缀是什么?【答案格式:.enc】
-
【填空题 5分】 接上题,app会自动识别几种后缀的文件为图片类型?【答案格式:8】
-
【填空题 5分】 接上题,app共从用于自定义加密的so模块导入了几个方法?【答案格式:8】
-
【填空题 5分】 接上题,app设置的密码是多少?【答案格式:514aa11a4191a98】
-
【填空题 5分】 接上题,app中存储的门锁密码是多少?【答案格式:5141141919810】
-
【填空题 5分】 接上题,加密图片里面的隐藏的flag是多少?【答案格式:flag{123456!}】
一、压缩包内容

二、建立工作目录
在桌面新建一个目录,例如:
D:\qianqian_reverse
把文件放进去:
D:\qianqian_reverse\倩倩手机逆向包.rar
然后新建几个文件夹:
D:\qianqian_reverse\01_unpack
D:\qianqian_reverse\02_app
D:\qianqian_reverse\03_hap
D:\qianqian_reverse\04_phone_files
D:\qianqian_reverse\05_decrypted
D:\qianqian_reverse\scripts
目录含义:
01_unpack 放 rar 解压后的内容
02_app 放 .app 解包后的内容
03_hap 放 .hap 解包后的内容
04_phone_files 放手机检材中提取出来的 app 数据文件
05_decrypted 放解密后的文件
scripts 放 Python 脚本
三、解压逆向包
得到的fpt-default-signed.app放到:
bash
\qianqian_reverse\01_unpack\

四、识别 .app 文件
重命名为.zip

解开:

重点文件是:
bash
entry-default.hap
五、继续解 .hap
.hap 也是压缩包。
复制到:
bash
\qianqian_reverse\03_hap\

继续解压。
用 7-Zip 解压。

得到
bash
entry-default
├── module.json
├── resources.index
├── ets
│ └── modules.abc
├── libs
│ └── arm64-v8a
│ ├── libcrypto.so
│ └── libc++_shared.so
└── resources

这几个是重点:
bash
module.json
ets\modules.abc
libs\arm64-v8a\libcrypto.so
module.json 是鸿蒙应用的模块配置文件,相当于安卓的 AndroidManifest.xml。
ets/modules.abc 是鸿蒙 ArkTS 编译后的字节码文件,简单的说,就是这个 APP 的所有业务代码。
libs/arm64-v8a/libcrypto.so 是OpenSSL 加密库,鸿蒙 / 安卓底层都用它。
六、找数据加密 app 的包名
打开:
bash
\qianqian_reverse\03_hap\module.json
搜索:
bash
bundleName
bundleName 是鸿蒙(HarmonyOS)应用的唯一标识包名。

所以第一题答案是:
bash
com.koishi.fpt
七、提取 app 字符串
接下来分析:
bash
ets\modules.abc
刚刚说了这个是鸿蒙 ArkTS 编译后的字节码文件。读者不需要完全反编译,先提取字符串就够用。
接下来我介绍两种方法。
方法 1:用 Linux / WSL / Git Bash
bash
strings ets/modules.abc > modules_strings.txt

得到:

方法 2:Windows PowerShell
如果你有 Sysinternals 的 strings.exe,执行:
bash
strings.exe .\ets\modules.abc > modules_strings.txt

两种方法都可以。
八、找初始化密码至少几位
然后在 modules_strings.txt 中没找到。
这不是说这个方式是没用的,这是一种探索题目的过程。
那接下来应该怎么做呢?
笔者依旧给出两种方法。
方法1:写一个从二进制文件里提取并查找 UTF-8 编码的中文字符串的脚本
python
from pathlib import Path
# 读取二进制文件
b = Path('modules.abc').read_bytes()
# 查找指定中文
for word in ['密码','至少']:
bs = word.encode()
print(word,b.find(bs))
# 正则匹配提取连续的可打印字符加中文 UTF - 8 序列(长度大于4)
import re
matches = re.findall(
rb'(?:[\x09\x0a\x0d\x20-\x7e]|[\xe4-\xe9][\x80-\xbf]{2}){4,}',
b
)
# 过滤包含中文的字符
cjk = []
for m in matches:
try:
t = m.decode('utf-8')
if any ('\u4e00' <= ch <= '\u9fff' for ch in t):
cjk.append(t)
except:
pass # 解码失败就直接跳过
# 结果
print('cjk count',len(cjk))
for t in cjk[:200]:
print(repr(t[:200])) # repr 方便查看不可见字符

结果6位出来了。
方法二:用工具abc-decompiler打开modules.abc,然后在AuthPage里面即可找到
AuthPage 就是认证页面 / 登录页面 / 密码验证页面的意思。
下载地址:https://github.com/ohos-decompiler/abc-decompiler

九、找加密后的文件后缀

可以知道是.tb。
.tb 是鸿蒙页面编译后的二进制文件,存 UI 和字符串,也就是加密后的文件。
我们可以在modules_strings.txt中找到。

鸿蒙系统一般也就这种加密文件。
当然,反编译后也可以找到。

十、找 app 自动识别几种图片后缀
在:
python
modules_strings.txt
搜索这些关键词:
python
jpg
jpeg
png
gif
webp
直接搜jpg。
可以看到图片类型相关后缀:
python
jpg
jpeg
png
gif
webp

一共 5 种。
注意,这里附近可能还能看到视频后缀:
python
mp4
mov
avi
mkv
但题目问的是:
图片类型
所以只统计图片后缀。
依旧,反编译后也可以找到。

分析自定义加密 so 模块导入了几个方法
重点文件:
python
\qianqian_reverse\03_hap\libs\arm64-v8a\libcrypto.so
这个是 app 自定义的 native 加密模块。
python
strings libs/arm64-v8a/libcrypto.so > libcrypto_strings.txt


可能要AI去分析

或者在反编译中找:

这个 a b c d 文件夹是原始包名被混淆后的结果,不具备实际语义。
在 d 文件中发现 q1 和 s1 两个方法从 libcrypto.so 中导入了方法。
不过ChatGPT 5.5给的解释是
rot13
xorEncrypt
这两个方法。
答案都是2。
十二、从手机检材中找到 app 数据
需要找到这个 app 的数据目录。包名是:
python
com.koishi.fpt
所以在手机检材中搜索:
python
com.koishi.fpt
重点找这些文件:
python
vault_prefs
*.tb
你需要把找到的文件复制到:
python
D:\qianqian_reverse\04_phone_files\
最终这个目录中应该有类似文件:
python
04_phone_files
├── vault_prefs
├── 139346145_p0.png.tb
├── Snipaste_2026-04-03_10-56-53.jpg.tb
└── b88c3348-9389-4fad-8cd6-3490e6bbdd26.json.tb
其中:
python
vault_prefs
是 app 保存密码信息的偏好配置文件。
几个 .tb 文件是被加密后的文件。

十三、分析 app 设置的密码
打开:
python
04_phone_files\vault_prefs

可以看到 XML 内容:
xml
<string key="password_hash">217sr94q01679u39</string>
<string key="salt">yqWpy+rJX82gRZuCjoB16w==</string>
关键字段是:
xml
password_hash = 217sr94q01679u39
但是这个不是最终明文密码。
因为 libcrypto.so 里有一个方法:
xml
rot13
所以要对它做 ROT13。
怎么确定是rot13的呢?

到AuthPage类。

e1.w1(this.password)的意思是密码做哈希。
e12.v1()的意思是生成随机盐。

登录时调用 e1.z1 进行验证。
我们接着跟进w1和z1。
在这里找:

找到:

w1(密码) 就是调用 q1 (密码)。
z1验证密码就是把输入的密码再加密一遍,和本地保存的 hash 对比。
那跟进去q1。

打开so文件。
Shift+F12打开字符串窗口。



追踪5D58函数。

这段是鸿蒙 NAPI 注册代码。

v4 是一个方法列表。
定位D8F0。


接下来定位5DE0。

这里我们细致的分析:
以小写字母为例(因为题目里面密码就是小写字母):
c
v11 = 97; // a
v12 = 175;
计算:
c
v12 + v13 = 175 + 97 = 272
因为代码里面有:
c
((v12 + v13) & 0xFFu)
所以取低 8 位:
c
272 & 0xFF = 16 //(其实就是 272 - 256 = 16)
然后:
c
79 * 16 >> 11 = 1264 >> 11 = 0
所以最终:
c
新字符 = 175 + 97 - 26 * 0 + 97
= 369
但赋值给 char,只保留低 8 位:
c
369 & 0xFF = 113
ASCII 113 是:q
所以:
c
a -> q
a 往后数 16 位就是 q。
发现不是ROT13,而是ROT16。

这里为什么是10而不是16,是因为CyberChef用正向参数表示,我们做的是还原,反向前移16位,就是正向后移10位。
答案:
c
217cb94a01679e39
十四、分析 .tb 文件的加密算法
这里开始要分析xorEncrypt了,因为图片是xor异或加密的。

在603C里面。

这么一大段。
c
v9 = 输入数据 input
v13 = 输出数据 out
v11 = 输入长度 input_len
v25 = key 字符串
v22 = key 长度 key_len
v24 = 当前下标 i
其中:
c
v24 - v24 / v22 * v22
就是:
c
v24 % v22
(这里是要训练的表达式: a - a / b * b等价于a % b )
所以核心代码可以改写成:
c
out[i] = (key[i % key_len] + (i % key_len)) ^ input[i];
更自然地写就是:
c
out[i] = input[i] ^ (key[i % key_len] + (i % key_len));
文字表达就是:
c
输出字节 = 原始字节 XOR (key[i % key长度] + i % key长度)
也就是:
c
out[i] = data[i] ^ (key[i % n] + (i % n))
因为 XOR 加密和解密是同一个过程,所以用同样算法可以解密 .tb 文件。
这里的 key 使用 app 存储的值:
c
217sr94q01679u39
不是 ROT13 后的明文密码。
十五、写解密脚本
在:
c
D:\qianqian_reverse\scripts\
新建:
c
decrypt_tb.py //脚本借助大模型写的
python
from pathlib import Path
# 自动获取当前脚本所在目录(不用手动改路径)
BASE = Path(__file__).parent.parent # 脚本在 scripts 里,自动定位到上级 qianqian_reverse
# 手机检材中提取出来的加密文件目录
IN_DIR = BASE / "04_phone_files"
# 解密输出目录
OUT_DIR = BASE / "05_decrypted"
OUT_DIR.mkdir(exist_ok=True, parents=True) # parents=True 自动创建多级目录
# 注意:这里使用 vault_prefs 里保存的 password_hash
KEY = "217sr94q01679u39"
def xor_crypt(data: bytes, key: str) -> bytes:
key_bytes = key.encode()
key_len = len(key_bytes)
result = bytearray()
for i, b in enumerate(data):
k = key_bytes[i % key_len]
offset = i % key_len
result.append(b ^ ((k + offset) & 0xff))
return bytes(result)
def decrypt_file(path: Path):
data = path.read_bytes()
dec = xor_crypt(data, KEY)
# 去掉 .tb 后缀
if path.name.endswith(".tb"):
out_name = path.name[:-3]
else:
out_name = path.name + ".dec"
out_path = OUT_DIR / out_name
out_path.write_bytes(dec)
print(f"[+] {path.name} -> {out_name}")
def main():
tb_files = list(IN_DIR.glob("*.tb"))
if not tb_files:
print("[-] 没有找到 .tb 文件,请检查 04_phone_files 目录")
return
for file in tb_files:
decrypt_file(file)
print("\n[+] 解密完成!文件保存在 05_decrypted 文件夹中")
if __name__ == "__main__":
main()


十六、找门锁密码
打开解密后的 JSON 文件:
python
05_decrypted\b88c3348-9389-4fad-8cd6-3490e6bbdd26.json

十七、找推荐的游戏叫什么
打开解密后的图片:
python
05_decrypted\Snipaste_2026-04-03_10-56-53.jpg
这是一张聊天截图。

里面有一句话,大意是:
我刷打了半天另一款平面射击类类银河恶魔城游戏呢,叫 zero sievert
所以推荐的游戏叫:
python
ZERO Sievert
十八、找加密图片中的隐藏 flag
打开解密后的图片:
python
05_decrypted\139346145_p0.png

表面上是一张图片。
但题目说:
加密图片里面隐藏的 flag

010直接打开,翻到尾部就找到了,当然也可以用用 strings 搜索 flag。