__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) }