QQ音乐sign vmp逆向

定位

复制代码
return u = ie(r.data)

跟进return u = ie(r.data)

发现是个vmp

下日志断点然后分析log日志

分析

前缀

7CB69B11F03F540463B696AE679DF97A7ED34709

复制代码
通过将log给ai,ai告诉我说这是sha1

入参是啥?

复制代码
搜索 finalize
发现一个数组 SHA-1 常量 [undefined, 1732584193, 4023233417, 2562383102, 3285377520, false, true, 2147483648, 4294967295, 4294967296, 1518500249, 1859775393, 1894007588]

分析得知
{"comm":{"cv":4747474,"ct":24,"format":"json","inCharset":"utf-8","outCharset":"utf-8","notice":0,"platform":"yqq.json","needNewCode":1,"uin":2573298872,"g_tk_new_20200303":1415120135,"g_tk":1415120135},"req_1":{"module":"music.musicsearch.HotkeyService","method":"GetHotkeyForQQMusicMobile","param":{"searchid":"32782922762486672","remoteplace":"txt.yqq.top","from":"yqqweb"}},"req_2":{"module":"music.musicHall.MusicHallPlatformSvr","method":"GetFocus","param":{"ForceBig":1}},"req_3":{"module":"newalbum.NewAlbumServer","method":"get_new_album_area","param":{}},"req_4":{"module":"newalbum.NewAlbumServer","method":"get_new_album_info","param":{"area":1,"sin":0,"num":20}},"req_5":{"module":"musicToplist.ToplistInfoServer","method":"GetAll","param":{}},"req_6":{"module":"MvService.MvInfoProServer","method":"GetNewMv","param":{"style":0,"tag":0,"start":0,"size":40}},"req_7":{"module":"music.paycenterapi.LoginStateVerificationApi","method":"GetChargeAccount","param":{"appid":"mlive"}}}
得到 7CB69B11F03F540463B696AE679DF97A7ED34709

E014616分析

复制代码
h[16] = "7CB69B11F03F540463B696AE679DF97A7ED34709";
h[95] = [23, 14, 6, 36, 16, 40, 7, 19]; // 固定数组
h[139] = h[95].map(i => h[16][i]);
h[8] = h[139].join("");

h[16][23] = "E"
h[16][14] = "0"
h[16][6]  = "1"
h[16][36] = "4"
h[16][16] = "6"
h[16][40] = undefined
h[16][7]  = "1"
h[16][19] = "6"

得到 97DBD30 

中缀

复制代码
SHA1 十六进制字符串按 2 位一组转字节,然后和固定数组逐位 XOR。
十进制就是:
[124, 182, 155, 17, 240, 63, 84, 4, 99, 182, 150, 174, 103, 157, 249, 122, 126, 211, 71, 9]

日志里这个数组:
xor_key = [89, 39, 179, 150, 218, 82, 58, 252, 177, 52, 186, 123, 120, 64, 242, 133, 143, 161, 121, 179]

然后逐位异或:

124 ^ 89  = 37
182 ^ 39  = 145
155 ^ 179 = 40
17  ^ 150 = 135
240 ^ 218 = 42
...
9   ^ 179 = 186

[37, 145, 40, 135, 42, 109, 110, 248, 210, 130, 44, 213, 31, 221, 11, 255, 241, 114, 62, 186] base64
new RegExp("[\\/+]", "g") 正则将/去掉
JZEohyptbvjSgizVH90LFyPro

后缀

复制代码
SHA1 字符串
   ↓
用 [23,14,6,36,16,40,7,19] 抽字符
   ↓
得到 E014616
   ↓
用 E014616 作为种子/中间值
   ↓
生成 [16,1,32,12,19,27,8,5]
[16, 1, 32, 12, 19, 27, 8, 5] 解码
6C756DFB

拼接

复制代码
zzc + E014616 + JZEohyptbvjSgizVH90LFyPro + 6C756DFB

执行 toLowerCase

复制代码
zzce014616jzeohyptbvjsgizvh90lfypro6c756dfb

很简单 附代码

复制代码
import hashlib
import base64
import json
from typing import List


IDX_1 = [23, 14, 6, 36, 16, 40, 7, 19]
IDX_2 = [16, 1, 32, 12, 19, 27, 8, 5]

XOR_KEY = [
    89, 39, 179, 150, 218,
    82, 58, 252, 177, 52,
    186, 123, 120, 64, 242,
    133, 143, 161, 121, 179
]


def pick_chars(s: str, idx: List[int]) -> str:
    return "".join(s[i] if 0 <= i < len(s) else "" for i in idx)


def get_sign(json_str: str) -> str:
    sha1_hex = hashlib.sha1(json_str.encode("utf-8")).hexdigest().upper()

    part1 = pick_chars(sha1_hex, IDX_1)

    sha_bytes = bytes.fromhex(sha1_hex)

    xor_bytes = bytes(
        b ^ k
        for b, k in zip(sha_bytes, XOR_KEY)
    )

    mid = base64.b64encode(xor_bytes).decode()
    mid = mid.replace("/", "").replace("+", "").replace("=", "")

    part2 = pick_chars(sha1_hex, IDX_2)

    return "zzc" + part1 + mid + part2


data = {"comm":{"cv":4747474,"ct":24,"format":"json","inCharset":"utf-8","outCharset":"utf-8","notice":0,"platform":"yqq.json","needNewCode":1,"uin":2573298872,"g_tk_new_20200303":1415120135,"g_tk":1415120135},"req_1":{"module":"music.musicsearch.HotkeyService","method":"GetHotkeyForQQMusicMobile","param":{"searchid":"32782922762486672","remoteplace":"txt.yqq.top","from":"yqqweb"}},"req_2":{"module":"music.musicHall.MusicHallPlatformSvr","method":"GetFocus","param":{"ForceBig":1}},"req_3":{"module":"newalbum.NewAlbumServer","method":"get_new_album_area","param":{}},"req_4":{"module":"newalbum.NewAlbumServer","method":"get_new_album_info","param":{"area":1,"sin":0,"num":20}},"req_5":{"module":"musicToplist.ToplistInfoServer","method":"GetAll","param":{}},"req_6":{"module":"MvService.MvInfoProServer","method":"GetNewMv","param":{"style":0,"tag":0,"start":0,"size":40}},"req_7":{"module":"music.paycenterapi.LoginStateVerificationApi","method":"GetChargeAccount","param":{"appid":"mlive"}}}

json_str = json.dumps(data, separators=(",", ":"), ensure_ascii=False)

print(json_str)
print(get_sign(json_str).lower())

声明

本文章中所有内容仅供学习交流使用,不用于其他任何目的,不提供完整代码,抓包内容、敏感网址、数据接口等均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关!

本文章未经许可禁止转载,禁止任何修改后二次传播,擅自使用本文讲解的技术而导致的任何意外,作者均不负责,若有侵权,请联系作者立即删除!

相关推荐
明天…ling3 小时前
Upload-Labs (Pass1-Pass21) 完整通关思路与源码分析
android·网络安全·渗透测试·burpsuite·upload-labs·文件上传绕过·靶场复现
Python私教4 小时前
Codex 写出的代码能跑却算错钱:我用 3 个测试拆穿一次 AI 编程幻觉
python·单元测试·ai编程
Python私教4 小时前
我只写了一个 add 工具,终于把 MCP 的 Host、Client、Server 跑明白了
python·ai编程·mcp
小大宇5 小时前
python milvus 案例
开发语言·python·milvus
BerryS3N6 小时前
Java 后端转型大模型:Demo 能跑不等于能上线
java·人工智能·python·java后端·spring ai·langchain4j·大模型转型
制造数据与AI践行者老蒋6 小时前
智联工坊实战:从“金鱼记忆”到“记住了”:给制造Agent装上记忆芯片的完整指南
人工智能·python·langchain·制造
某林2126 小时前
ros从底层硬件到 Web 端部署
python·机器人·硬件架构·ros2
码云骑士6 小时前
82-微调模型评估-自动化评测-人工评测-A-B测试实战
运维·python·自动化
FBI HackerHarry浩6 小时前
AI大模型开发V2第四阶段机器学习概述
人工智能·python·机器学习
axinawang7 小时前
第22课 石头剪刀布
python