4.2 KiB
4.2 KiB
libweapon VIMG 纯算实现记录
状态:已完成
约束:运行时不依赖 Frida、抓包、APK、ELF、Unicorn 或 app-fields。
1. 最终结论
passport_account_image 是客户端本地确定性生成值:
mf(context, event).a().toString()
-> Engine.pr(99999, 0, javaLength * 2, json)
-> VIMG_<base64>$AI_<32hex>
-> WeaponHI.img / wcfg["a_y_q_z"]
-> mobile/checker、requestMobileCode、mobileVerifyCode
wcfg 只负责本地缓存。$AI_ 不是服务端签发值,/f/a/p 也不是
登录票据的生成前置条件。
目标样本:
out/p0_64_extract/lib/arm64-v8a/libweapon.2.2174a68a..so
SHA256 5d7681c583c66b35e0ee3ce558e5a1ff7fa5be44f19a1e217acc2224455837d7
2. Java 与 JNI 链
wc.k()调用Engine.pr(ze.v0, 0, s2.a(str) * 2, str)。ze.v0 = 99999。str = new mf(context, event).a().toString()。- mode 0 对应 native
0x19ea90。 0x19ea90依次调用 base 生成器0x1a1850和 AI 生成器0x1a2d94。
3. VIMG Base
payload_bytes = JNI modified UTF-8(payload)
plain = 2d 3d 00 00 7d 01 || LE16(len(payload_bytes)) || payload_bytes
native_buffer = plain XOR 0x55
cipher = ChaCha20-IETF(native_buffer, fixed_state, counter=1)
base = "VIMG_" + Base64(cipher)
ChaCha 初始状态:
1783595e 8dc26a78 2599184e 729781d3
2adef3f4 9876ef16 9abed34f 9103de12
a92157f6 a9a24ff4 9138d3fd 2a2193f3
00000001 74f4cbcd 98c26a78 ab99184e
轮函数是标准 20 轮 ChaCha,旋转量为 16/12/8/7。
4. AI H1
将完整 VIMG_... ASCII 文本按小端 uint32 分组。调用方每批处理最多
64 个字,native 压缩函数先折叠为 16 个字:
folded = [0] * 16
for index, word in enumerate(source_words):
folded[index % 16] ^= word
随后执行自定义 IV 的 10 轮 BLAKE2s 压缩:
H0:
aa98186e f3ccd768 99531aae 669781d3
125fd5b4 9883595e 74f4cbcd 98c26a78
IV:
ab99184e f3ccd768 99531aae 669781d3
125fd5b4 9883595e 74f4cbcd 98c26a78
- counter 是累计处理的 uint32 字数。
- 最后一批令
v[14] ^= 0xffffffff。 - sigma 是标准 BLAKE2s 10x16 消息置换表。
- 输出为 8 个低 32 位链值。
- H1 文本为 8 个
%08x直接拼接,末尾附一个空格。
5. AI H2
H2 只使用 H1 文本前 16 个 ASCII 字节:
ADD_BASE = 0c35ff3dcbfefb3f3efd6539fd39efcd
H2[i] = ((ADD_BASE[i] + 3) & 0xff) XOR H1_TEXT[i]
AI[i] = H2[i] XOR (2dd345c0)[i % 4]
最终:
passport_account_image = base + "$AI_" + hex(AI)
6. mf Payload
core/weapon_mf.py 按 mf.a() 的 JSONObject 插入顺序构造字段,包括:
- 设备型号、厂商、Android 版本和本地 DID。
- elapsedRealtime、uptime、启动时间和 boot count。
- Weapon 上报时间与本地报告计数器。
- 样本中的反调试/环境状态字段。
同一轮登录只生成一次票据,并复用于预检、发码和验码。
7. 实现与验证
生产实现:
core/weapon_vimg.py:VIMG base、H1/H2、完整票据与反解。core/weapon_mf.py:设备 JSON 和 profile 票据生成。tools/sms_login_cli.py:纯算票据接入登录链。
分析 oracle:
tools/libweapon_vimg_oracle.py:仅用于离线差分,不进入生产路径。
验证结果:
- 固定 native 向量覆盖空输入、UTF-8、ChaCha 跨块、H1 跨 16/64 字。
- 21 组不同长度随机输入与 Unicorn native oracle 逐字节一致。
- 捕获票据反解出的 757 字节真实
mfJSON 可由 oracle 重新生成完全相同 的 base 和$AI_。
8. CLI
短信登录每次生成全新画像、在线注册 DFP,并在注册完成后用当前云 DID 现场生成
passport_account_image:
uv run python -m tools.sms_login_cli --mobile MOBILE
已有验证码时跳过发码:
uv run python -m tools.sms_login_cli `
--mobile MOBILE `
--code CODE
CLI 不提供设备画像、app-fields、WCFG 或复现种子的注入入口,避免把历史设备 状态带入下一次登录。
DFP 在线注册可能把本地初始 DID 替换为云 DID。主 APP 随后调用
WeaponHI.setG(currentDid),所以 mf 字段 03000 必须使用注册后的
DeviceProfile.did,并与登录 query 的 did 保持一致,不能继续使用
local_did。