__dyn 是一个动态数据,包含一些关于页面状态的信息。
在请求接口的参数中,会看到一个叫做 __dyn 的参数。
先全局搜索一下,看看会有什么结果。
这里找到一个 StaticSiteData
模块,建立了一个对象,__dyn 对应的键名是 jsmod_key
。再根据找到的结果再搜索看看有没有其它的线索。
这里找到了 jsmod_key
的赋值方式 c("ServerJSDefine").getLoadedModuleHash()
把开头的 c
换成 require
,尝试在 Console 调用一下 ServerJSDefine
模块,实验一下结果是否和 __dyn 参数一致。
看起来找对地方了,接下来再看看 · 这个函数是怎么实现的。
getLoadedModuleHash
这里面又调用了 toCompressedString
函数,那么再接着往下找,看看这个函数是怎么实现的。
这里就找到了 toCompressedString
的实现方法。
不过看起来都是从 $1
这个变量里面的内容进行计算,但是这里并没有提供什么内容,是一个空数组。
function a () {
this.$1 = [],
this.$2 = null
}
不过我在网页的模块里面找到了模块的标识或者索引,例如截图里的例子
IntlCurrentLocale: 5954
CookieDomain: 6421
JSSelfProfilerTrackedInteractions: 6918
CurrentAdAccountInitialData: 6828
只需要筛选出每个模块的标识或者索引就可以了,有可能会在 body 里面,也有可能会在 head 里面,所以合并成一个数组
const bodyData = document.body.innerHTML.match(/\},([0-9])+\]/gi)
const headData = document.head.innerHTML.match(/\},([0-9])+\]/gi)
const combinedData = bodyData.concat(headData)
const arr = []
for (const item in combinedData) {
if (combinedData[item] != null) {
const extractedNumber = combinedData[item].replace(/\},|]/g, '')
if (parseInt(extractedNumber) >= 7) {
arr.push(parseInt(extractedNumber))
}
}
}
然后再遍历 数组 中的每个数字,将 bitMap
中对应索引的位置设置为 1,表示该数字存在于 数组中。这样,bitMap
就成为了一个简单的表示数字存在性的位图。后续的压缩过程利用了这个 bitMap
来计算连续相同值的数量。
const bitMap = []
for (const item in arr) {
bitMap[arr[item]] = 1
}
将刚才写入的 `bitMap` 数组压缩数据,并且转换成文本值的二进制数据。
```Javascript
const compressedBits = []
let count = 1
let currentBit = bitMap[0] || 0
const currentBitString = currentBit.toString(2)
for (let i = 1; i < bitMap.length; i++) {
const nextBit = bitMap[i] || 0
if (nextBit === currentBit) {
count++
} else {
compressedBits.push(convertToBinaryString(count))
currentBit = nextBit
count = 1
}
}
最后再将二进制转换成 base64 结果就出来了。
function convertToBase64String (binaryString) {
const list = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_'
const sixBitChunks = (binaryString + '00000').match(/[01]{6}/g)
let base64String = ''
for (let i = 0; i < sixBitChunks.length; i++) {
base64String += list[parseInt(sixBitChunks[i], 2)]
}
return base64String
}
和 getLoadedModuleHash
对比后结果是一致的,那么 __dyn 的参数就已经还原出来了。
在开头收集模块的标识或者索引的时候,这个数据也可以随机生成伪造参数。经过我的测试发现这个数据的长度大概在 115 到 265 之间,而且是大于 7 的,那么就可以根据下面的代码随机生成一段数据
const arr = []
const count = Math.floor(Math.random() * (265 - 115 + 1)) + 115
const allNumbers = Array.from({ length: 7331 - 7 + 1 }, (_, i) => i + 7)
for (let i = 0; i < count; i++) {
const randomIndex = Math.floor(Math.random() * allNumbers.length)
const randomNumber = allNumbers[randomIndex]
arr.push(randomNumber)
allNumbers.splice(randomIndex, 1)
}