# libweapon VIMG 纯算实现记录 > 状态:已完成 > > 约束:运行时不依赖 Frida、抓包、APK、ELF、Unicorn 或 app-fields。 ## 1. 最终结论 `passport_account_image` 是客户端本地确定性生成值: ```text mf(context, event).a().toString() -> Engine.pr(99999, 0, javaLength * 2, json) -> VIMG_$AI_<32hex> -> WeaponHI.img / wcfg["a_y_q_z"] -> mobile/checker、requestMobileCode、mobileVerifyCode ``` `wcfg` 只负责本地缓存。`$AI_` 不是服务端签发值,`/f/a/p` 也不是 登录票据的生成前置条件。 目标样本: ```text 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 ```text 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 初始状态: ```text 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 个字: ```python folded = [0] * 16 for index, word in enumerate(source_words): folded[index % 16] ^= word ``` 随后执行自定义 IV 的 10 轮 BLAKE2s 压缩: ```text 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 字节: ```text ADD_BASE = 0c35ff3dcbfefb3f3efd6539fd39efcd H2[i] = ((ADD_BASE[i] + 3) & 0xff) XOR H1_TEXT[i] AI[i] = H2[i] XOR (2dd345c0)[i % 4] ``` 最终: ```text 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 字节真实 `mf` JSON 可由 oracle 重新生成完全相同 的 base 和 `$AI_`。 ## 8. CLI 短信登录每次生成全新画像、在线注册 DFP,并在注册完成后用当前云 DID 现场生成 `passport_account_image`: ```powershell uv run python -m tools.sms_login_cli --mobile MOBILE ``` 已有验证码时跳过发码: ```powershell 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`。