有小半年没有去学习了,这是前几天突然看到的文章--qq音乐sign算法还原源码放送及jsvmp全流程分析,qq音乐的sign居然是个jsvmp,我之前弄得时候都没看,直接补了两行代码就可以了,不过本着学习的态度,而且我一直搞不懂jsvmp,虽然明白原理,但是在面对入栈出栈的一系列操作,依然还是很懵逼的状态。
今天就来拿这个简单点的jsvmp去实验,只讲我是怎么去推导的,当然这一切都是结合着大佬的文章来完成的。
废话不多说,进入今天的正题。
搞jsvmp首先就是打断点,这是大佬们经常说的,但是对于从来没有接触过的人来说,很难,因为不知道在哪里去打断点,我的理解是和webpack打包一样,都有一个中间的分发器,那我们找到这个地方,然后插桩,应该会有很多有用的信息打印出来(个人猜测,也不是很懂)。
我们直接在这里打上断点,运行看日志
我这里打印出来3000多条日志,接下来,我们就一点一点的看这些日志。
这里可以看到有一个base64的子码表,上面还有一个字典表。
这里有一步 __sign_hash_20200305 函数,如果你看代码的话,会在后面看到有这个函数
大体扫一遍,就猜出了 这是一个md5加密,至于到底是不是,我们验证一下,
看到这个函数后面跟了一串字符,我们就大胆的去猜测,这就是入参
果然,我猜的没错,那是不是最后几个字段就是方法和参数,这个还有待考究 ,继续往下看,看到对结果进行了转大写。
这里可以看到对navigator.userAgent进行了判断,这个test是啥方法,往上面再看一点,就可以发现是 RegExp 的方法
这就是这几段日志的运行逻辑 ,最后把这个false赋予这个数组的第13位,我们可以把后面几行日志复制出来
第13位赋值为false,继续往下看
这里看到了location.href,其实补环境也就补这两个就能出结果了。
这个列表应该是自身的代码,并没有找到生成方法
可以看到,即将对列表进行map操作
可以看到,"C496EB283AA82ECB999AD253A5464314" 的 第 21 位就是 2
那么大体的算法就是
接着 list join 拼接,一直没看结果,我们先看一下结果 zzb2ea49d61elu7bpkljqaeriwiaqkreg98694825
zzb 2ea49d61 elu7bpkljqaeriwiaqkreg98694825
这一段就在结果里,继续往下看
和上面一样
直接看结果
98694825 就是结果的最后几位,那现在还有 头部 3 个,以及中间几位,其实头部是写死的,也就剩下中间的。
这个list 和上面的一样,没有生成方法,那他应该也是有用的 ,其实接下来应该从后面去推的,但是这样有点别扭,我这边就从正面去推。
看一下这一小段日志,依然和 "C496EB283AA82ECB999AD253A5464314" 这段md5有关系,
取第一位,为c,然后从字典表中找到 c所指向的数字,为 12,那么这个54,38从哪来,直接搜,发现后面都是,那应该就是写死的,54和38做什么操作能为16,这个我是试的,我也不是很懂这些操作,这样应该最简单,毕竟运算符是有限的,
12*16 = 192
接下来找到4对应的4 和 192进行 ^ 操作得到 196
然后用 196 ^ 212 push到一个新数组,重复上面的操作,直到遍历完 md5的字符串,那么现在可以根据这些操作大概的写出算法
往下翻就会看到结果是一样的,接下来就是操作这个新数组了,对他进行操作,来获取中间的数据
先取了3个分别放入列表 22 23 24 的位置
我们先往后面看看,需要这几个数字来推算结果,那这几个数字从哪来,就往前翻
看到 25 26 27 28 4位分别放着结果,那就是来看这四位上的数据怎么生成的
先看25 拿出16 进行 16>>2 然后 25 这个就等于 4 ,这个是最简单的
接着看 26
首先 取 16 操作 这里 a=16 b=187 ,大概就是这个意思,我也不知道该怎么去说了,都是一些试的工作
27
28
再往下翻依然是这样的,可以猜出for 循环那个 新数组 一次取3个参数,最后还要判断一下参数不足的情况,也很简单,最终这段算法如下,至于有的时候,0>>4 或者 0<<4 或者 0&4都是 0 这个结果的时候,先随便写一个,等出现别的参数的时候,会很容易判断到底是什么运算符
最终代码,看上面大佬的文章说页面之前是不一样的,我就不清楚了,只是拿这个js练练手,熟悉一下jsvmp怎么破解,难得俺也不会。。。
let md5 = require('md5-node');
function middle(ls) {
let resNum = []
function test(a, b, c) {
let r25 = a >> 2
if (b !== undefined && c !== undefined) {
let r26 = a & 3
let r26_2 = r26 << 4
let r26_3 = b >> 4
let r26_4 = r26_2 | r26_3
let r27 = b & 15
let r27_2 = r27 << 2
let r27_3 = r27_2 | (c >> 6)
let r28 = c & 63
resNum.push(r25)
resNum.push(r26_4)
resNum.push(r27_3)
resNum.push(r28)
} else {
let r10 = a >> 2
let r11 = a & 3
let r11_2 = r11 << 4
resNum.push(r10)
resNum.push(r11_2)
}
}
for (let i = 0; i < ls.length; i += 3) {
if (ls[i] !== undefined && ls[i + 1] !== undefined && ls[i + 2] !== undefined) {
test(ls[i], ls[i + 1], ls[i + 2])
} else {
test(ls[i], undefined, undefined)
}
}
let res = []
resNum.forEach((item) => {
let zd = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='
res.push(zd[item])
})
res = res.join('')
return res
}
function head(md5Str) {
let res = [];
[21, 4, 9, 26, 16, 20, 27, 30].map(x => {
res.push(md5Str[x])
})
return res.join('')
}
function tail(md5Str) {
let res = [];
[18, 11, 3, 2, 1, 7, 6, 25].map(x => {
res.push(md5Str[x])
})
return res.join('')
}
function getLs(md5Str) {
let zd = {
"0": 0,
"1": 1,
"2": 2,
"3": 3,
"4": 4,
"5": 5,
"6": 6,
"7": 7,
"8": 8,
"9": 9,
"A": 10,
"B": 11,
"C": 12,
"D": 13,
"E": 14,
"F": 15
}
let ol = [212, 45, 80, 68, 195, 163, 163, 203, 157, 220, 254, 91, 204, 79, 104, 6]
let res = []
let j = 0
for (let i = 0; i < md5Str.length; i += 2) {
let one = zd[md5Str[i]]
let two = zd[md5Str[i + 1]]
let r = one * 16 ^ two
res.push(r ^ ol[j])
j += 1
}
return res
}
function sign(params) {
let md5Str = md5(params).toUpperCase()
let h = head(md5Str)
let e = tail(md5Str)
let ls = getLs(md5Str)
let m = middle(ls)
let res = ('zzb' + h + m + e).toLowerCase()
let r = RegExp(/[\\/+]/g)
res = res.replace(r, '')
return res
}
console.log(sign('{"comm":{"cv":4747474,"ct":24,"format":"json","inCharset":"utf-8","outCharset":"utf-8","notice":0,"platform":"yqq.json","needNewCode":1,"uin":0,"g_tk_new_20200303":5381,"g_tk":5381},"req_1":{"module":"music.globalComment.CommentRead","method":"GetReplyCommentList","param":{"RootCmId":"1!beu.a6oPFn6eDtAiQIvWlaRWmVKREp0SoANGpzZ41b-v9TBHJJ5LX8Ak6TciMJgJ","LastCommentSeqNo":"","PageSize":10,"LastRankScore":"","RankType":1,"PicEnable":1}}}'))