吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 279|回复: 2
上一主题 下一主题
收起左侧

[Android 原创] 最新款flutter影视壳请求响应加密全面分析之解密篇

[复制链接]
跳转到指定楼层
楼主
吾苏同在 发表于 2026-7-3 14:09 回帖奖励
本帖最后由 吾苏同在 于 2026-7-3 14:23 编辑

声明:分析所用的脚本文件,都在帖子最后的链接里面


App MINO,某追忆等等同类型影视壳子

工具BlutterIDA ProFridaHttpCanary

涉及加密方式:RSA-OAEPAES-GCMHMAC-SHA256


准备工作:
1. Blutter解包,flutter应用
2. 去除抓包检测:vpn,复制匿名闭包的地址(0x4ba614,然后去IDA Pro或者其它汇编工具


第一行修改为 MOV X0,#0
行修改为 RET




抓包分析:

这里看见api/sync/push,出现的次数比较多


oss-rg-china-mainland.aliyuncs.com:响应加密

/api/health:无加密,验证软件是否修改


api/captcha/rotate/init:验证码请求,有带头部,响应带一个64位的id加密


api/sync/preferences:带头部,请求数据("data": 密文)和响应加密("data": 密文)


api/sync/push:带头部,请求数据("bundle":密文)和响应加密("bundle":密文)


整理验证,主要逆向点:
api/sync/preferences:可以重发多次,响应数据会变(不带头部也可以重发)


api/sync/push不可重发,响应数据出现401非法请求(必须带头部,验证有效token

按照其它影视壳的手段,大概率是
AES加密

分析流程:
so混淆,正常的手段无法用,所以只能用正则搜索偏移,写了一个find_string.py脚本,定位字符串位置pp.txt搜索AES,结果有14个,通过筛选发现可疑的


把偏移值填入find_string.py


IDA PRO运行文件得到一直地址



AES字符串位置




blutter_frida.js(修改过的),hook这个函数0x477A00

操作手机,无继续输出日志,看来不是这个函数,继续查看0x477a00的引用,有三个函数,通过hook三个函数,其中0x98CE90线路加密数据,是oss-rg-china-mainland.aliyuncs.com响应解密的函数,不过无后续输出日志,再往上找结果:Hook了一圈无任何有用信息

换思路:通过查找api/sync/push字符串地址这里我手动补上字符串


通过确定hook最终sub_9B8A2C函数是正确位置



返回值有解密之后的数据,同时有输出libnative-crypto.so


调用libnative-crypto.so的函数进行解密


查看libnative-crypto.so

通过hook发现,关键函数有_h9m , _a7x , _d3k , _r2e , _g5b , _p6y

函数分析:

_h9mHMAC-SHA256):参数:a1 HMAC_key a2 :密文,a3 :数据长度
原理:aes密文拼接13位时间戳和_g5b返回的随机base6416位),得到data,然后mbedtls_md_hmac计算HMAC(key, data),将 32 字节结果转换为 64 字符小写 hexx-req-token的值)

_a7xAES-256-GCM加密):参数:a1 32 字节 aes密钥, a2 :明文,a3 :明文长度
原理:先Base64 解码 key_b64 得到 32 字节 AES key,再调用 mbedtls_ctr_drbg_random 生成 12 字节 IVmbedtls_gcm_setkey(v21, MBEDTLS_CIPHER_ID_AES, key, 256)sub_39764 + sub_3992C 对结果做 Base64 编码后返回字符串

_d3kAES-256-GCM解密):参数:a1 32 字节 aes密钥,a2 :密文,a3 :数据长度原理:取密文hex前面12字节作为IV,取密文后16字节作为Tag

_r2eRSA-OAEP 加密)参数:公钥, 明文,长度
原理:调用_p6y函数获取公钥,mbedtls_pk_parse_public_key 解析 PEM 公钥,mbedtls_rsa_set_padding(rsa, 1, 9) 1 =v21, 9 =MBEDTLS_MD_SHA256,即 RSA-OAEP-SHA256

_p6y(公钥获取位置)原理:把字符串片段拼接成完整 PEM 公钥



拼接完整之后是
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAum4qpnurnzUExfnum4UY
3fmE2370KvssufETUZCfqf9o5953xAQ3sciU/FrOTQY29LrwbYgBizZUFVBNUgeJ
9hMkdywRUU3qnQlarz2D4FMDIJo3Z7x0G8CD4f47CpQ9c5LsiyWi4GTVEEMrkiDr
KHn2/AtJ4sHdC/LsYiuv6tCNrY7Qoy0zrKFk0OcNL+8uNLZyCvEp7I8MoQlxWGmR
siCXwQZUIdDjbPpZ92sNt+OH9THi2QcPlZxfoYPgNo5VfJAm4FUpGnr/R7k+2Sy7
JSYGCWcpd8fDCx5GIn/CmhblUQqlYD2+Au+S9SMpL+BTelGebss8/eK2nVHL7Uh5xwIDAQAB
-----END PUBLIC KEY-----


_g5b(随机数生成)参数:int len(字节长度)
原理:mbedtls_ctr_drbg_random 生成指定长度随机字节,返回 Base64 编码字符串(主要生成aes密钥(32位)和x-req-trace的值(16位))。


hook脚本:hook_all.js 抓包和hook结合分析,得到下面,加解密流程图:


后续的aes的密钥都是从来api/sync/preferences响应数据解密得来的keyhmackey

分析验证:
rsa_encrypt.pyaes_decrypt.pyhmac_encrypt.py的脚本在帖子最后的链接里面。

注意:
1.每次请求的body都带Authorization":"user_id+JWT+iat",这个jwt签名值,好像是随机生成的,但是有时效(Authorization的值可以用base64直接解密,第一次请求api/sync/preferences的头部带这个给服务器记录,iat是签名值到期时间戳)。

2.请求头部的content-length,这个长度是通过“aes加密数据+x-req-ts(时间戳)+x-req-trace_g5b(随机数)”的总字节减24字节,得到的值。

总结:对比一代版本,作者也是下功夫了。不过加解密方式放在另一个so文件,脱离dart层,给逆向难度降低少了很多,希望作者继续改进一下。
帖子所用的脚本文件和流程图下载链接:https://wwbkx.lanzoum.com/b02sgpn2xg     密码:bx3e

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

沙发
xhr2025 发表于 2026-7-6 17:05
分析的很详细,这个壳子现在好像还检测frida
3#
 楼主| 吾苏同在 发表于 2026-7-6 19:13 |楼主
xhr2025 发表于 2026-7-6 17:05
分析的很详细,这个壳子现在好像还检测frida

没有呀,我hook的时候,没出现这个问题,有相关软件嘛?
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-7-7 02:13

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表