注:app放在文章末尾,需要自取
APP扫描:
扫描发现flutter框架
搜索界面抓包分析一下
请求包:
请求包中似乎没有什么重点
看看响应包:
返回了encData参数,base64加密后的
b64解不出来,乱码,大概率是经过其他加密的。
结合 Base64 解码失败后的非明文表现,初步怀疑后续仍存在对称解密层(AES/DES/SM4),并且数据很长。
使用jadx搜不到encData参数,转战so文件
在Flutter架构中:
libflutter.so 负责“怎么运行 Flutter”
libapp.so 负责“这个 App 具体运行什么逻辑”
打开libapp.so之前,先用Blutter还原一下。
Blutter 是 Flutter Android Release App 的 Dart AOT 分析工具,核心价值是帮你从 libapp.so 里提取 Object Pool、字符串、符号、汇编和 Frida 模板(worawit/blutter: Flutter Mobile Application Reverse Engineering Tool)。具体的使用教程可以问AI或者上网搜索,这里就跳过了
还原后能看一些函数的具体名字,不至于盲目分析。如果直接使用ida 打开libapp.so,所有函数都是sub_开头,几乎无法分析
在IDA中搜索encData
只搜索到一个,发现也没有交叉引用

这里尝试去hook 调用该地址也没hook到
hook代码:
之前已经知道,参数最后编码成base64,这里搜索一下base64

这里有不少base64相关函数,全部hook一遍,看看谁被调用了,hook的时候打印参数和返回值内存,看看能不能找到encData一样的数据。
hook代码:
结果:

Hook的结果发现不少函数参数或者返回值是encData
根据 hook 命中结果筛选调用链,观察函数名字,只有dart_convert_Base64Codec::decode_4845e0最符合,其他大概率都是此函数下游调用链
IDA中搜索看一下dart_convert_Base64Codec::decode_4845e0此函数

很正常的base64函数,往下追可以追到其他base64函数调用链。
直接X看下此函数的被谁调用,追到了encrypt_encrypt_Encrypter::decrypt64_484308

这里将base64解密的值大概率传给了最后的return加密函数
hook一下最后return的encrypt_encrypt_Encrypter::decrypt_48436c()看下参数和返回值
hook代码:
输出:
可以看到返回值已经将encData解密出来了,参数中arg3也有值得关注的,JhbGciOiJIUzI1Ni一个16位字符串,这里留意一下可能包含着密钥或者IV信息
接下来继续,看能不能找到加密方式/密码/IV之类的信息
往下继续追一下encrypt_encrypt_Encrypter::decrypt_48436c(),直接进入函数

里面套了一个加密函数4843b4(),传入的参数继承自48436c()没有变化,接着进入encrypt_encrypt_Encrypter::decryptBytes_4843b4去查看

追到这里就恍然大悟了,AES加密,并且传入的参数也变化了
hook一下encrypt_encrypt_Encrypter::decryptBytes_48441c()看看能不能找到一些信息
hook代码(和上一个hook代码一样,只需修改 0x48436C --> 0x48441c 即可)
输出:
在 encrypt_encrypt_AES::decrypt_48441c 的参数 dump 中,可以明确观察到 AES/CBC/PKCS7 字样,说明该响应字段的核心解密算法可定位为 AES-CBC-PKCS7。
同时,在参数内存中还出现了 JhbGciOiJIUzI1Ni 这一字符串片段,其与请求头 aut 中 JWT 头部内容一致,说明认证材料可能参与了解密流程或参数构造,这里猜测为密钥或者IV;返回值也是解密的正常可见字符串结果。

接下来目标是确定密钥和IV的具体值
经过长时间的分析,我们返回到encrypt_encrypt_Encrypter::decrypt64_484308()来分析

刚才在分析的时候,我们hook了48436c(),hook结果中已经发现了JhbGciOiJIUzI1Ni字符串:
因为猜测这里大概率是密钥或者IV,但是在调用此函数时已经生成了这个字符串了,是48436c()的参数,说明密钥/IV的生成函数还在前面
X追一下encrypt_encrypt_Encrypter::decrypt64_484308()的调用链

这里直接发现了Key和IV
第一个红框中的每一行代码的解释:
1.分配一个 Key 对象。
2.把前面 substring() 的结果取出来,放到 v18。
3.把这个 Key 对象保存到局部变量里,后面还要继续用。
4.Key.fromUtf8(sub)
第二个红框中的每一行代码的解释:
1.分配一个 IV 对象。
2.把前面 substring() 的结果取出来,放到 v20。
3.把这个 IV 对象保存到局部变量里,后面还要继续用。
4.IV.fromUtf8(sub)
再往上看代码,无论是v18还是v20都是从一个变量里被赋值的,这样就能解释了Key和IV的值一样
实在不放心的话,可以hook一下encrypt_encrypt_Encrypted::ctor_fromUtf8_4ac39c(),用之前hook的代码,改个地址就可以
输出截取关键部分:
这里完全可以证明key和iv是一个值,都是JhbGciOiJIUzI1Ni
最后解密验证一下

解密一下,结果出来了。
encData 处理链为:
key / iv 来源于本地存储固定切片
key 与 iv 在当前函数中来源相同
懂的都懂:WVVoU01HTklUVFpNZVRrelpESkdNV1ZwTlhOWlZ6VTJZak5XTTB4dFRuWmlVemx3Vmtob2JsbDZUbmRaZW14dFRXMW5TelZoSzBjMU5rTkNUMnBLZGsxVVRUMD0=
推荐一下比较好用的 Frida 工具:Frida-Hookers
传播安全知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 2026-5-13 10:24
被Mengz3编辑
,原因: