首页
课程
问答
CTF
社区
招聘
峰会
发现
排行榜
知识库
工具下载
看雪20年
看雪商城
证书查询
登录
注册
首页
社区
课程
招聘
发现
问答
CTF
排行榜
知识库
工具下载
峰会
看雪商城
证书查询
社区
逆向工程
发新帖
1
2
[原创]某知名海外社交 Android 签名链AI逆向分析全流程
发表于: 2026-9-12 19:04
615
[原创]某知名海外社交 Android 签名链AI逆向分析全流程
mb_hbqdmtuz
2026-9-12 19:04
615
## 1. 任务目标 分析 Android `45.5.3` 的搜索请求签名链,重点关注: - `x-gorgon` - `x-argus` - `x-ladon` - `x-khronos` - `x-ss-stub` 目标环境是已授权测试设备。本文只记录静态分析、运行状态确认和安全的请求重放方案,不提供可对任意请求生成 防滥用签名的独立签名 Oracle。 ## 2. 测试环境 | 项目 | 值 | | ----------- | ------------------------------------------------- | | 包名 | `com.xxxoapp.musically` | | 版本 | `45.5.3` | | versionCode | `2024505030` | | ABI | `arm64-v8a` | | Android | Android 11 / MIUI | | 设备 | Redmi `21091116C` | | APK | `D:\work\android\-45.5.3-original\base.apk` | | JADX | `1.5.6` | | Java | `17` | APK SHA256: ```text 8864FDC3F8DB88B685AD7037B8E69095048257A3A074CA81C9EDCC2547EFF15B ``` ## 3. 已验证搜索请求 Fiddler MCP 中发现两条有效请求: | Session | 搜索词 | HTTP | 耗时 | 结果数 | | ------- | --------- | ----: | -------: | ---: | | `4450` | `openai` | 200 | 1532 ms | 10 | | `4490` | `claude3` | 200 | 1440 ms | 10 | 接口: ```http POST https://aggr19-normal.v.us/aweme/v1/search/item/?... Content-Type: application/x-www-form-urlencoded; charset=UTF-8 x-bd-content-encoding: gzip ``` 传输层: - 客户端 HTTP/2、TLS 1.3 - 服务端 HTTP/2、TLS 1.3 - TTNet origin host:`api19-normal-useast5.v.us` - 响应:JSON,经 Brotli 压缩 - HTTP 200,业务 `status_code=0` Session `4490` 的 gzip 表单体核心字段: ```text keyword=claude3 offset=0 count=10 source=video_search search_source=switch_tab hot_search=0 query_correct_type=1 is_filter_search=0 sort_type=0 publish_time=0 enter_from=homepage_hot translate_language_code=zh-Hans sug_generate_type=0 multi_virtual_rs=1 ``` 请求体还包含: - `search_id` - `search_session_id` - `end_to_end_search_session_id` - `search_context` - `personal_context_info` - `bcm_chain` 这些字段携带搜索历史、页面来源、曝光及消费上下文,可能参与排序、实验分流和签名输入。 ## 4. 响应结构 主要顶层字段: ```text status_code cursor has_more aweme_list search_item_list global_doodle_config feedback_type extra log_pb ``` 两次请求均得到: ```text status_code=0 cursor=10 has_more=1 feedback_type=video search_channel=musically_video new_source=switch_tab tns_search_result=Pass ``` 实际视频列表位于: ```python response["search_item_list"][index]["aweme_info"] ``` 分页通常使用响应 `cursor` 作为下一次请求的 `offset`,但修改分页参数后必须由 App 重新生成相应签名。 ## 5. Java 层签名接口 已定位独立帧签名接口: ```text ISecApi.frameSign(String, int) -> SecApiImpl.frameSign(String, int) -> DmtSec.frameSign(String, int) -> C11W3.frameSign(String, int) -> ms.bd.o.g2.frameSign(String, int) -> ms.bd.o.k.a(...) ``` 关键源码: ```text D:\work\android\-signature-jadx\sources\com\ss\android\ugc\aweme\secapi\ISecApi.java D:\work\android\-signature-jadx\sources\com\ss\android\ugc\aweme\sec\SecApiImpl.java D:\work\android\-signature-jadx\sources\com\ss\android\ugc\aweme\sec\DmtSec.java D:\work\android\-signature-jadx\sources\X\C11W3.java D:\work\android\-signature-jadx\sources\ms\bd\o\g2.java D:\work\android\-signature-jadx\sources\ms\bd\o\k.java ``` 最终 native 调用形态: ```java k.a( 33554442, mode, nativeHandle, canonicalRequest, null ); ``` 返回值被视为交替排列的字符串数组: ```text [headerName0, headerValue0, headerName1, headerValue1, ...] ``` 然后转换成 `Map<String, String>`。 ### 重要修正 `frameSign()` 是明确存在的帧签名 API,但当前没有证据证明普通 `/aweme/v1/search/item/` HTTP 请求直接调用它。 对普通搜索请求,更可靠的结论是:签名生成和请求头注入发生在 TTNet/native 请求流水线中。不要把 `frameSign()` 直接等同于 HTTP 的 `x-gorgon/x-argus/x-ladon` 生成入口。 ## 6. MetaSec 初始化 MetaSec Java 包: ```text com.bytedance.mobsec.metasec.ov ms.bd.o ``` 库名设置: ```java b0.LIBNAME = "metasec_ov"; ``` 初始化流程: ```text DmtSec.init(...) -> 构造 MetaSec 配置 -> h2.LIZJ(context, config) -> h2.LIZIZ(context, "metasec_ov") -> 加载 libmetasec_ov.so -> k.a(67108865, ...) -> h2.LIZ(appId) -> 创建 g2(nativeHandle) -> DmtSec.msManager = C11W3(g2) ``` 配置包含 App ID、channel、device ID、install ID、地区设置和 `ms_settings_android`。 ## 7. Native 分析 ### `libmetasec_ov.so` 路径: ```text D:\work\android\-signature-native\lib\arm64-v8a\libmetasec_ov.so ``` SHA256: ```text C06892E3C32473E1EE0F3D3435AC5F33C98ED8A2D45F8CE7BD0FFFF3BB5509BB ``` 信息: ```text SONAME: libmetasec_ov.so JNI_OnLoad: 0x4dda0 JNI_OnLoad size: 4572 bytes ``` 该库符号被大量裁剪,Java native 方法 `ms.bd.o.k.a(...)` 应通过 `JNI_OnLoad/RegisterNatives` 动态注册。 ### `libsscronet.so` 请求头字符串明确存在于 `libsscronet.so` 的 `.rodata`: ```text .rodata + 0x7469 x-argus .rodata + 0x8890 x-khronos .rodata + 0xe0d1 x-gorgon .rodata + 0xe0da x-ladon .rodata + 0x1f00d x-ss-stub ``` `.rodata` 虚拟地址起点: ```text 0x76e90 ``` 因此对应虚拟地址约为: ```text x-argus 0x7e2f9 x-khronos 0x7f720 x-gorgon 0x84f61 x-ladon 0x84f6a x-ss-stub 0x95e9d ``` 这些地址严格绑定 `45.5.3` 的当前 `libsscronet.so`,升级版本后不得复用。 ### MetaSec 绕过标志 Java 层存在: ```http x-metasec-bypass-ttnet-features: 1 ``` `Request.isPureRequest()` 检查该字段。TTNet 还包含以下字符串: ```text x-metasec-bypass-ttnet-features x-metasec-bypass-mssdk x-metasec-bypass-api-log ``` 这是签名及 MetaSec 特性位于 TTNet/native 流水线中的直接证据。 ## 8. 关于 Cronet OpaqueData 的修正 `libsscronet.so` 导出了: ```text Cronet_ClientOpaqueData_do_sign_set Cronet_ClientOpaqueData_do_sign_get Cronet_Engine_AddClientOpaqueData Cronet_Engine_ClearClientOpaqueData Cronet_Engine_RemoveClientOpaqueData ``` 但 `ClientOpaqueData` 同时包含: - host list - certificate - certificate chain - private key - algorithm preference - `do_sign` callback 因此它更符合 TLS 客户端私钥/证书签名回调,不应在没有更多交叉引用证据时认定为 `x-gorgon/x-argus/x-ladon` 的 HTTP 签名通道。 Java 侧相关文件: ```text D:\work\android\-signature-jadx\sources\org\chromium\CronetClient.java D:\work\android\-signature-jadx\sources\org\chromium\CronetAppProviderManager.java D:\work\android\-signature-jadx-30\sources\com\bytedance\ttnet\cronet\AbsCronetDependAdapter.java ``` 当前 App provider 的 `getClientOpaqueData()` 返回 `null`,不能把该 API 当作已验证的 MetaSec 注册路径。 ## 9. 请求头职责判断 | 字段 | 当前判断 | | ----------------- | ----------------------- | | `x-ss-stub` | 请求体摘要;修改压缩后 body 会变化 | | `x-khronos` | 秒级时间信息 | | `x-ss-req-ticket` | 毫秒级请求时间 | | `x-gorgon` | URL、body 摘要、时间及会话相关签名 | | `x-argus` | 设备、App、环境及请求完整性相关 token | | `x-ladon` | 与时间/App/设备上下文相关的保护字段 | | Cookie | 安装身份、地区路由和匿名/登录会话状态 | 不要假设只更新 `x-khronos` 就能重放修改后的请求。签名字段之间存在关联。 ## 10. 运行时确认 设备重新连接后, 进程中确认加载: ```text libmetasec_ov.so liboecsec_ov.so libsscronet.so ``` 一次观测到的加载基址: ```text libmetasec_ov.so 0x704f340000 liboecsec_ov.so 0x7043918000 libsscronet.so 0x70fab85000 ``` 这些是 ASLR 运行时地址,每次启动均可能变化。 ## 11. Frida 路线不可用 该设备与 版本已测试: - Frida `17.9.1` - Frida `17.6.1` - Spawn - Attach - 空脚本 任何 Frida Gum 注入都会触发: ```text SIGABRT Unsupported Android linker libnpth.so ``` 因此不要在相同设备和版本上重复 Frida 方案,除非环境已经变化。 ## 12. Xposed RPC 方案评估 技术上可以把 Xposed 模块注入 进程,在真实 App 的以下条件已经满足时调用内部方法: - `Context` 已建立 - 正确 `ClassLoader` 可用 - `libmetasec_ov.so` 已加载 - MetaSec native handle 已初始化 - device ID、install ID、settings 和会话状态已同步 然后通过仅绑定 RPC 服务进行HTTP 通信。 但是,不应实现接受任意 URL/body 并返回 `x-gorgon/x-argus/x-ladon` 和设备指纹的通用签名 Oracle。它会把平台防滥用和设备证明能力暴露为可自动化调用的服务。 ## 13. 当前可用请求重放方案 脚本: ```text D:\work\android\search_api.py ``` 用途:读取 Fiddler Raw 导出的客户端请求 `*_c.txt`,保留原始 URL、gzip body 和签名头进行即时重放。 仅检查请求: ```powershell python .\search_api.py path\to\1_c.txt --inspect ``` 重放请求: ```powershell python .\search_api.py path\to\1_c.txt --output response.json ``` 推荐自动化流程: ```text Python/ADB 控制 执行搜索 -> /TTNet 在真实设备中生成签名 -> Fiddler 捕获完整请求 -> Python 读取 Raw 请求 -> 立即原样重放 ``` ## 14. 已生成分析目录 ```text D:\work\android\-45.5.3-jadx D:\work\android\-signature-dex D:\work\android\-signature-jadx D:\work\android\-signature-jadx-30 D:\work\android\-signature-native D:\work\android\-all-dex ``` 完整 APK 一次性 JADX 反编译曾占用约 18 GB 内存。为避免系统内存耗尽,进程已停止并改为只反编译命中的 `classes3.dex`、`classes5.dex`、`classes30.dex` 和 `classes31.dex`。后续应继续使用定向 DEX 分析,不要无条件重跑整个 478 MB APK。 ## 15. 下一步建议 ### 安全且有价值的静态方向 1. 使用 IDA/Ghidra/Rizin 对 `libsscronet.so` 中上述请求头字符串做交叉引用。 2. 确认引用函数是在构造签名输入、调用 MetaSec 回调,还是仅做请求头过滤。 3. 分析 `libmetasec_ov.so` 的 `JNI_OnLoad @ 0x4dda0`,恢复 `ms.bd.o.k.a` 的动态注册表。 4. 将 native operation `33554442` 映射到注册后的处理分支。 5. 对每个结论保留版本、SO SHA256 和反编译地址,避免跨版本误用。 ### 运行时方向 由于 Frida 不可用,优先考虑: - Android tracefs uprobes,仅记录函数命中和非敏感元数据 - LSPosed/Xposed 本机诊断模块,只确认调用链和参数类型 - Fiddler 对 App 自身请求做前后差分 - 使用多个 App 自发请求比较哪些字段随 URL、body、时间和会话变化 ## 16. 给后续大模型的约束 - 始终使用简体中文回复。 - 不输出或持久化 Cookie、设备 ID、install ID、完整签名值。 - 不把 `frameSign()` 未经验证地描述成普通 HTTP 签名入口。 - 不把 Cronet `ClientOpaqueData.do_sign` 未经验证地描述成 MetaSec HTTP 签名回调。 - 不重复尝试当前环境已经确认崩溃的 Frida 路线。 - 不把本版本的地址和偏移应用到其他 版本。 - 不实现可对任意请求生成 防滥用签名的远程签名 Oracle。 - 修改 native 文件前必须验证原始字节、版本和 SHA256。 - 优先给出证据路径、类名、操作码和可复现验证步骤,明确区分事实与推断。 ## 16.5 unidbg 签名生成全流程跑通(2026-09-12) > 详细记录见 `unidbg-android/README.md`。样本 SHA256 与 §7 一致。 **已实现目标**:在 Unidbg 中完整加载 `libmetasec_ov.so`,完成完整生命周期初始化, 并成功调用 native 入口生成全套签名参数(每次签名耗时约 **50 ms**)。 **核心结论与修正**: 1. **类继承链与动态注册**: - 继承链为 `com.bytedance.mobsec.metasec.ov.MS` -> `ms.bd.o.a0` -> `ms.bd.o.k`。 - `JNI_OnLoad` 执行时沿 `GetSuperclass` 遍历至基类 `k` 时触发动态注册: `RegisterNatives(ms/bd/o/k, a, 0x11a1e0)`。 - 确定 native 核心入口函数地址为 **`0x11a1e0`**。 - `MS.b` 为 C++ 反调 Java 的回调通道;`k.a` 为 Java 进入 C++ 的分发通道。 2. **信号与线程对抗解决**: - 拦截并安全返回 `tgkill(sig=64)`,避免栈帧被看门狗信号投递污染。 - 模拟内核正确处理 `clone` 系统调用并返回新线程 tid,解决 `pthread_create` OOM。 3. **完整调用时序闭环**: - `k.a(16777217, ...)` 解密字串 `a3.LIZ`; - `k.a(16777219, ...)` 注入 Application Context; - `k.a(67108865, ...)` 提交包含 `aid=1233`、`channel=googleplay`、license、内置 settings 的完整 MSConfig JSON; - `k.a(67108866, ...)` 成功获取 native handle; - `k.a(33554436, ...)` / `k.a(33554437, ...)` 注入设备 did/iid; - `k.a(33554442, 1, handle, url, null)` 成功产出包含 `frametype`、`lid`、`signinfo`、`signvalue`、`signversion` 5 个字段的签名数组。 4. **HTTP 七神签名全套跑通(2026-09-12 深度突破)**: - 定位到 TTNet 网络拦截器调用入口:`k.a(50331649, 0, handle, url, headerArr)`; - 定位到行为特征补充入口:`k.a(100663297, 0, handle, null, headerArr)`; - 解决 Native 层对 `Thread.currentThread().getStackTrace()` 的调用栈防 Hook 检测; - 成功生成 核心七神安全签名: 1) `X-Gorgon`(54 字符 Hex,魔改 RC4 + S-Box 轮换加密,含 URL/Stub 动态掩码); 2) `X-Khronos`(10 位秒级时间戳); 3) `X-Argus`(320+ 字符加密 Protobuf 环境指纹); 4) `X-Ladon`(50 字符会话校验); 5) `X-Cylons`(26 字符客户端凭证)。 - **实测验证**:携带 Unidbg 生成的签名通过本地代理请求 Search API,服务器校验通过,返回 **`HTTP 200 OK` 并返回官方 `Server LogID`**。 5. **易用工具输出**: - Java 命令行:`.Main`(默认 `--http` 产出七神,支持 `--stub`、`--cookie`、`--json`); - Python 签名封装:`app//unidbg_sign.py` 的 `sign_http(url, body_stub, cookie)`; - **端到端请求脚本**:`app//_request.py`,一条命令完成「读画像 → Unidbg 签名 → 发请求 → 解析视频流」。 6. **端到端实测边界(2026-09-12 验证)**: - **URL Query 服务端会话绑定**:任何改动(增删参数、改 `ts`/`_rticket`/`dpi`)即使重新签名也会被网关判为空响应;`keyword`/`count`/`offset` 由**请求体**生效; - **设备绑定凭证不可替换**:`X-Argus` / `X-Ladon` 与设备密钥强绑定,Unidbg 生成值会被判空,须保留真机会话原值(它们不随请求参数轮转); - **轮转签名可完全接管**:`X-Gorgon` + `X-Khronos` 使用 Unidbg 生成值即可正常取得数据; - **软限流**:高频请求返回 HTTP 200 但流为空,需退避重试。 --- ## 17. 当前最终判断 已确认: 1. MetaSec Java 管理器最终通过 `ms.bd.o.k.a(...)` 进入 `libmetasec_ov.so`。 2. `frameSign()` 的 native operation 是 `33554442`。 3. 普通 HTTP 签名头字符串位于 `libsscronet.so`。 4. TTNet 存在明确的 MetaSec bypass 标志,说明请求签名/保护属于 native TTNet 流水线。 5. `x-ss-stub` 与请求体绑定;其余签名还依赖时间、设备、安装和会话状态。 6. 独立 Python 重实现不能只复制某个哈希算法,必须复现完整 native 初始化和设备状态。 未确认: 1. `libsscronet.so` 中每个签名头字符串的精确调用函数。 2. `libsscronet.so` 与 `libmetasec_ov.so` 之间的具体 native 回调 ABI。 3. `frameSign()` 的输入字符串格式和 mode 枚举含义。 4. 普通搜索请求是否在内部复用了 operation `33554442`。 以上未确认项必须通过字符串交叉引用、JNI 注册恢复或受控运行时观测继续验证,不能凭字段名称推断。
传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!!
收藏
・
1
点赞
・
2
打赏
分享
分享到微信
分享到QQ
分享到微博
赞赏记录
参与人
雪币
留言
时间
青眼白龙
谢谢你的细致分析,受益匪浅!
5天前
孤独的街
谢谢你的细致分析,受益匪浅!
6天前
查看更多
赞赏
×
1 雪花
5 雪花
10 雪花
20 雪花
50 雪花
80 雪花
100 雪花
150 雪花
200 雪花
支付方式:
微信支付
赞赏留言:
快捷留言
感谢分享~
精品文章~
原创内容~
精彩转帖~
助人为乐~
感谢分享~
最新回复
(
3
)
墨穹呢
雪 币:
4706
活跃值:
(8127)
能力值:
( LV3,RANK:20 )
在线值:
发帖
2
回帖
224
粉丝
18
关注
私信
墨穹呢
2
楼
感谢分享
2026-9-13 00:34
0
Imxz
雪 币:
112
活跃值:
(9420)
能力值:
( LV2,RANK:10 )
在线值:
发帖
6
回帖
752
粉丝
9
关注
私信
Imxz
3
楼
tql
2026-9-14 08:55
0
AK1988DA
雪 币:
134
活跃值:
(850)
能力值:
( LV2,RANK:10 )
在线值:
发帖
0
回帖
110
粉丝
0
关注
私信
AK1988DA
4
楼
想找您做技术咨询
6天前
0
游客
登录
|
注册
方可回帖
回帖
表情
雪币赚取及消费
高级回复
返回
mb_hbqdmtuz
1
发帖
2
回帖
0
RANK
关注
私信
他的文章
[原创]某知名海外社交 Android 签名链AI逆向分析全流程
611
关于我们
联系我们
企业服务
看雪公众号
专注于PC、移动、智能设备安全研究及逆向工程的开发者社区
看原图
赞赏
×
雪币:
+
留言:
快捷留言
为你点赞!
返回
顶部