这是一篇用于补充的文章,用于补充一年以后的变化,前三部分请查看 https://antibot.blog/ (注:我不是前三部分的作者)
前情提要
近期 twitter 开始在很多 web 请求校验 x-client-transaction-id
,不符合的会直接返回 404
,花了点时间琢磨了前三篇文章的内容
前三篇合起来大概讲的就是,请求的 method
(大写)和 path
,以及 twitter 网页中的 twitter-site-verification
和来自四个 svg 的 d
属性的值的二维数组经过一系列的变换处理得到一串用于请求 header
的 x-client-transaction-id
的 base64
文本
原作者在 blog 留下了 反混淆脚本 和 id生成工具 的仓库链接,但都已经删库,我在社区找到了其他 fork ,链接请看文末 #参考
结合原作者和另一个宣称已经修复好这个问题的项目d60/twikit的源码,我修复好了 golang 版的 id生成工具 并总结出这篇文章
获取动态的值
twitter-site-verification
原作者称之为 key
document.querySelectorAll("[name^=tw]")[0].getAttribute("content")
d属性
原文的 frames
,太抽象了,英语不太好的我想了很久才弄明白
[...document.querySelectorAll('[id^=loading-x-anim-]>g>path:nth-child(2)')].map(
node => node.getAttribute('d')
)
顺带提一句,四张 svg 的形状都是 X Corp. 的标志 𝕏 的样子
ROW_INDEX 和 KEY_BYTES_INDICES
go 版没有这个概念,估计当时没考虑过这个问题,这两来自 python 版,从文件名格式为 ondemand.s.<hex>.js
(比如 ondemand.s.fc2aec5a.js) 的 js 文件提取
ON_DEMAND_FILE_REGEX = re.compile(
r"""['|\"]{1}ondemand\.s['|\"]{1}:\s*['|\"]{1}([\w]*)['|\"]{1}""", flags=(re.VERBOSE | re.MULTILINE))
INDICES_REGEX = re.compile(
r"""(\(\w{1}\[(\d{1,2})\],\s*16\))+""", flags=(re.VERBOSE | re.MULTILINE))
提取到四个数值,第一个为 ROW_INDEX
,后三个组成的数组就是 KEY_BYTES_INDICES
修复问题
不论是 golang 版还是 python 版,都有一些待修正的问题,我按照执行顺序一一列出来
精度问题
Bezier Epsilon
go float64 自身就存在精度问题,所以……接受有损耗的事实吧……尽管这些值遇到别的语言可能会没有任何问题
最开始借鉴的那个 js库 的精度是 1e-5
,而我去翻了 Firefox 和 WebKit 的源码,它们的精度分别是 1e-6
和 1e-7
下面这个例子在修改成 1e-6
以后输出就正确了
以下案例计算 rgb 值得到的结果是 [181.80453949578018, 55.27301397059616, 82.49921158086055]
,四舍五入取整后与浏览器计算结果 rgb(182, 55, 83)
不相符
{
"twitter_site_verification": [208,199,89,137,6,185,69,209,243,208,119,16,83,58,15,170,216,83,56,143,153,0,87,140,13,50,56,45,49,75,198,181,246,254,156,17,240,127,70,115,251,22,182,217,231,143,26,195],
"2d_array": [[155,169,92,23,59,95,64,16,131,74,114],[234,145,20,13,70,244,247,15,245,162,37],[244,19,47,147,157,138,119,8,223,84,26],[249,162,66,213,147,244,254,212,85,205,10],[95,141,167,167,103,78,83,136,134,44,61],[92,106,95,65,180,27,159,203,160,12,75],[100,227,195,73,96,95,247,241,165,71,228],[154,77,65,25,47,238,76,245,119,196,83],[45,4,40,240,1,148,191,152,10,221,28],[190,176,29,229,131,241,157,156,188,5,75],[203,46,108,139,74,31,20,93,236,194,244],[236,139,223,98,69,108,100,107,203,69,215],[62,252,4,255,52,230,9,223,91,63,50],[89,128,73,28,225,4,174,196,176,141,149],[203,63,95,137,92,208,250,197,85,13,3],[127,95,199,140,115,172,59,227,83,241,0]],
"ondemand_s_hex": "9494e08",
"row_index": 13,
"key_bytes_indices": [18,23,22]
}
frameTime
算法中有一个很重要的值 frameTime
的精度要求四舍五入到整十,即 frameTime-5 <= frameTime <= frameTime+4 (frameTime%10 === 0)
的结果是一样的,原作者在第二篇都写出来了,结果最后的代码却又没加上去,导致我花了大量时间在研究为什么算出来的结果跟 twitter 的结果不一致
// If the comment is in Chinese, it means the code is generated by chatgpt
func calculateFrameTime(keyBytes []int, indices []int) int {
// 初始化结果为1(乘法的初始值)
frameTime := 1
for _, index := range indices {
// keyBytes[index] % 16 的结果累乘
log.Println(frameTime, index, keyBytes[index], keyBytes[index]%16)
frameTime *= keyBytes[index] % 16
}
log.Println(keyBytes, indices, frameTime)
return frameTime
}
frameTime := int(math.Round(float64(calculateFrameTime(keyBytes, DEFAULT_KEY_BYTES_INDICES))/10) * 10)
curves
只要保留两位小数,不需要后面一大串
curves := [4]float64{}
for i := 0; i < len(row); i++ {
curves[i] = toFixed(a(float64(row[i]), b(i), 1.0), 2)
}
color hex
实际变换颜色时,最终 rgb 的值会有下面四种情况
value<0
:由于不会有负数,所以计算得到的负数等同于0
;value>=256
:同样的道理当值大于等于256
时,应当为ff
0<=value<=15
:当colorValue
的值小于等于f
时,不需要补0
前缀,只要一位即可- 其他情况转十六进制即可
for i := 0; i < len(color)-1; i++ {
if color[i] > 0 {
roundedColor := math.Round(color[i])
if roundedColor >= 256 {
strArr = append(strArr, "ff")
} else {
strArr = append(strArr, strings.TrimPrefix(hex.EncodeToString([]byte{byte(roundedColor)}), "0"))
}
} else {
strArr = append(strArr, "0")
}
}
角度
文章作者处理后的代码里面有一段
_r = (n, W, t, r) => {
const o = n * (t - W) / 255 + W;
return r ? Math.floor(o) : o["toFixed"](2);
}
而后面获取目标角度时也有这个函数出现:_r(numArr[6], 60, 360, !0)
,所以目标角度的值需要向下取整
matrix
当 matrix 有值等于 0
或者 1
时,转换成字符串会位数不够,所以需要额外判断
if rounded == float64(1) {
strArr = append(strArr, "1")
} else if rounded == float64(0) {
strArr = append(strArr, "0")
} else {
strArr = append(strArr, "0"+strings.ToLower(floatToHex(rounded)[1:]))
}
DEFAULT_KEYWORD
概念来自 python 版,值从 bird
变成了 obfiowerehiring
,原 blog 称之为 keyWord
var keyWord = "obfiowerehiring"
hash := sha256.Sum256([]byte(fmt.Sprintf(`%s!%s!%v%s%s`, method, path, timeNow, keyWord, strings.Join(strArr, ""))))
ADDITIONAL_RANDOM_NUMBER
概念来自 python 版,值从 1
变成 3
var ADDITIONAL_RANDOM_NUMBER = 3
bytes = append(bytes, ADDITIONAL_RANDOM_NUMBER)
其他
- 原作者提供的反混淆脚本偶尔能用,但不是一直可用
参考
- Twitter Header: Part 1
- twitter-tid-deobf (原仓库已删除,这是其中一个 fork 备份)
- twitter-tid-generator (原仓库已删除,这是其中一个 fork 备份)
- twikit