之前我们成功破解了某头条的 a_bogus、msToken、_signature 参数,今天来挑战一个新平台——某吧的用户关注功能jt参数!这个参数设计相当巧妙,通过二级接口生成,是某吧反爬体系中的重要环节。掌握了它的JS逆向解密方法,就能实现自动化关注功能。本章将完整分享jt参数的逆向全过程,重点讲解如何通过数据抓包实战找到加密入口。
本文目录
- 数据抓包实战:锁定关注接口
- 参数溯源:发现二级加密机制
- XHR断点定位加密入口
- 堆栈分析与加密逻辑追踪
- 扣取加密代码
- 参数分析与调试技巧
- 本地运行与结果验证
- 常见问题与解决方案(FAQ)
- 获取完整课件
1. 数据抓包实战:锁定关注接口
首先按F12打开浏览器开发者工具,切换到Network(网络)面板,并确保录制状态为开启(建议勾选”Preserve log”防止请求被清除)。在某吧中任意选择一个用户,点击“关注”按钮,此时网络面板中会出现一系列请求。
通过筛选XHR请求,很快就能发现目标接口:/home/post/follow。仔细查看这个POST请求的载荷(Payload),其中包含了我们要破解的关键参数——jt,同时还包含其他参数如id(用户ID)、un(用户昵称)等。

2. jt参数溯源:发现二级加密机制
通过全局搜索jt参数的值,发现jt参数并不是直接生成的,而是来自另一个接口的响应!在/home/post/follow请求之前,可以看到一个关键接口:
/abot/api/v1/tpl/commit

这个接口的响应数据中包含了一个t参数,而这个t参数的值正是/home/post/follow接口中使用的jt值!更重要的是,/abot/api/v1/tpl/commit接口的请求主体是一个加密字段,格式为:
CODED--v20ezLvhHO=QsO>Zau4^)gFbY/Kg]/2h`h7dDK9MoK:V]q0ZwcB^U+GcY+........

这就是本次JS逆向解密的关键发现:jt参数实际上是一个二级加密的结果!我们需要先破解/abot/api/v1/tpl/commit接口的加密逻辑,才能最终获得可用的jt参数。这种设计增加了逆向难度,是典型的企业级反爬策略。
3. XHR断点定位加密入口
现在我们需要找到CODED-开头的加密字符串是如何生成的。由于js文件中没有CODED-明码关键词,我们采用XHR断点的方式进行定位。这是JS逆向解密常用的手段。
在源代码/来源面板中,点击右侧的“+”号添加XHR断点,输入:
/abot/api/v1/tpl/commit
重新点击关注按钮触发操作,代码执行会在请求发出前自动暂停。此时在Call Stack(调用堆栈)中,我们可以看到完整的函数调用链条,通常会有多个匿名函数和异步调用。


通过分析调用堆栈,我们成功定位到了生成CODED-加密字符串的核心代码段:
var t = JSON[_0x1d3c("0x1b")](x)
, n = this[_0x1d3c("0x2be")](_0x422d33[_0x1d3c("0x1b6")](t));
e[_0x1d3c("0x2c8")](_0x1d3c("0x2c9"), _0x1d3c("0x1b7")),
e.send(d + n)
通过控制台调试和代码分析,我们可以解析出这些函数的真实功能:

使用控制台输入以下命令来解析混淆函数:
// 解析_0x1d3c函数的真实含义
_0x1d3c("0x1b6"); // 输出: "encode"
_0x1d3c("0x2be"); // 输出: "encrypt"
_0x1d3c("0x1b");// 输出: "stringify"
d // 输出: "CODED--v20"
这段代码揭示了CODED-加密字符串的生成过程:
var t = JSON.stringify(x),
n = this.encrypt(_0x422d33.encode(t));
e.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"),
e.send('CODED--v20' + n)
JSON.stringify(x)– 将数据对象序列化为JSON字符串_0x422d33.encode(t)– 对JSON字符串进行Base64编码预处理this.encrypt(...)– 核心加密函数,生成最终的加密内容'CODED--v20' + n– 添加固定前缀形成最终请求体
4. 堆栈分析与加密逻辑追踪
现在我们需要深入分析这二个关键函数:
_0x422d33.encode()– 数据预处理函数(Base64编码)this.encrypt()– 核心加密函数(位移加密)
因此,原始代码的实际逻辑为:
n = this.encrypt(_0x422d33.encode(t));
现在我们需要重点分析this.encrypt()和_0x422d33.encode()这两个函数。
通过进一步调试分析,我们成功还原了这两个关键函数的实现逻辑:

this.encrypt() 是一个自定义的位移加密函数,而 _0x422d33.encode() 是一个经过修改的Base64编码器。
加密函数详细解析:
// 核心加密函数 - 字符位移加密
function encrypt(x)
{
for (var c = "", d = 0; d < x.length; d++)
{ var _ = x.charCodeAt(d), e = d % 32;
// 动态偏移量,基于字符位置计算 // 只对特定ASCII范围的字符进行加密
(41-122) c += _ <= 122 && _ >= 41 ? (_ + e > 122 ? String.fromCharCode(40 + _ - 122 + e) :
// 溢出处理:循环到41开始
String.fromCharCode(_ + e)
// 正常偏移 ) :
String.fromCharCode(x.charCodeAt(d)) // 保持原样
}
return c; }
这个加密算法的特点是:
- 使用动态偏移量(基于字符位置取模32)
- 只对ASCII码41-122范围内的字符进行加密
- 处理溢出情况,实现循环移位
- 其他字符保持原样,避免破坏数据格式
Base64编码器解析:
// 自定义Base64编码器 var _0x422d33 = { keyStr: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=',
encode: function(x)
{ var output = ""; var chr1, chr2, chr3, enc1, enc2, enc3, enc4; var i = 0;
// 先进行UTF-8编码
x = this.utf8Encode(x);
while (i < x.length)
{
chr1 = x.charCodeAt(i++);
chr2 = x.charCodeAt(i++);
chr3 = x.charCodeAt(i++);
enc1 = chr1 >> 2; enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); enc4 = chr3 & 63;
if (isNaN(chr2)) { enc3 = enc4 = 64; } else if (isNaN(chr3)) { enc4 = 64;
} output = output + this.keyStr.charAt(enc1) + this.keyStr.charAt(enc2) + this.keyStr.charAt(enc3) + this.keyStr.charAt(enc4);
}
return output;
}, // UTF-8编码和解码方法
utf8Encode: function(string) {
// ... UTF-8编码实现
}, utf8Decode: function(utftext)
{
// ... UTF-8解码实现
} };
完整加密流程总结:
- 原始数据通过
JSON.stringify()序列化为JSON字符串 - 使用自定义Base64编码器进行编码(包含UTF-8预处理)
- 对Base64字符串进行位移加密(动态偏移)
- 添加
CODED--v20前缀形成最终请求体 - 发送到
/abot/api/v1/tpl/commit接口获取jt参数 - 在关注接口中使用获取到的jt参数
5. JS逆向解密扣取加密代码
现在我们需要将这两个核心函数完整地扣取出来。以下是完整的加密代码实现:
/** * 某吧jt参数加密完整实现 */
// 位移加密函数
function encrypt(x) {
for (var c = "", d = 0; d < x.length; d++) {
var _ = x.charCodeAt(d),
e = d % 32;
c += _ <= 122 && _ >= 41 ? _ + e > 122 ? String.fromCharCode(40 + _ - 122 + e) : String.fromCharCode(_ + e) :
String.fromCharCode(x.charCodeAt(d))
}
return c
}
// Base64编码工具对象
var _0x422d33 = {
keyStr: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=',
encode: function(x) {
var c = "",
d = void 0,
_ = void 0,
e = void 0,
t = void 0,
n = void 0,
a = void 0,
r = void 0,
i = 0;
for (x = this['utf8Encode'](x); i < x.length;)
d = x.charCodeAt(i++),
_ = x.charCodeAt(i++),
e = x.charCodeAt(i++),
t = d >> 2,
n = (3 & d) << 4 | _ >> 4,
a = (15 & _) << 2 | e >> 6,
r = 63 & e,
isNaN(_) ? a = r = 64 : isNaN(e) && (r = 64),
c = c + this['keyStr'].charAt(t) + this.keyStr.charAt(n) + this['keyStr'].charAt(a) + this['keyStr']
.charAt(r);
return c
},
decode: function(x) {
var c = "",
d = void 0,
_ = void 0,
e = void 0,
t = void 0,
n = void 0,
a = void 0,
r = void 0,
i = 0;
for (x = x.replace(/[^A-Za-z0-9\+\/\=]/g, ""); i < x.length;)
t = this['keyStr'].indexOf(x.charAt(i++)),
n = this['keyStr'].indexOf(x.charAt(i++)),
a = this['keyStr'].indexOf(x.charAt(i++)),
r = this['keyStr'].indexOf(x.charAt(i++)),
d = t << 2 | n >> 4,
_ = (15 & n) << 4 | a >> 2,
e = (3 & a) << 6 | r,
c += String.fromCharCode(d),
64 !== a && (c += String.fromCharCode(_)),
64 !== r && (c += String.fromCharCode(e));
return c = this['utf8Decode'](c)
},
utf8Encode: function(x) {
x = x.replace(/\r\n/g, "\n");
for (var c = "", d = 0; d < x.length; d++) {
var _ = x.charCodeAt(d);
_ < 128 ? c += String.fromCharCode(_) : _ > 127 && _ < 2048 ? (c += String.fromCharCode(_ >> 6 |
192),
c += String.fromCharCode(63 & _ | 128)) : (c += String.fromCharCode(_ >> 12 | 224),
c += String.fromCharCode(_ >> 6 & 63 | 128),
c += String.fromCharCode(63 & _ | 128))
}
return c
},
utf8Decode: function(x) {
for (var c = "", d = 0, _ = 0, e = 0, t = 0; d < x.length;)
_ = x.charCodeAt(d),
_ < 128 ? (c += String.fromCharCode(_),
d++) : _ > 191 && _ < 224 ? (e = x.charCodeAt(d + 1),
c += String.fromCharCode((31 & _) << 6 | 63 & e),
d += 2) : (e = x.charCodeAt(d + 1),
t = x.charCodeAt(d + 2),
c += String.fromCharCode((15 & _) << 12 | (63 & e) << 6 | 63 & t),
d += 3);
return c
}
}
/** * 生成commit接口请求体的主函数 *
@param {Object} data - 要加密的原始数据对象 *
@returns {string} CODED--v20开头的加密字符串 */
function getCommit(data)
{
var jsonString = JSON.stringify(data);
var base64Encoded = _0x422d33.encode(jsonString);
var encrypted = encrypt(base64Encoded);
return 'CODED--v20' + encrypted;
}
6. 参数分析与调试技巧
先来查看一下需要加密的参数结构。在控制台输入 t 或 x,可以看到传入的加密参数是一个复杂的JSON对象:

典型参数结构包含:
{ "lt": "1752044129609", // 时间戳 "ct": "1752044129609", // 客户端时间戳 "action": "follow", // 操作类型 "uid": "123456789", // 目标用户ID "from": "profile", // 来源页面 "v": "3.0.16", // 版本号 "ut": "" // 用户token或其他标识 // ... 其他字段 }
调试技巧:
- 中间值输出: 在加密函数关键位置添加
console.log打印中间值 - 变量监控: 使用浏览器调试器的
Watch功能监控变量变化 - 逐步执行: 使用F10逐步执行观察每一步的加密结果
- 对比验证: 对比浏览器生成的结果与本地计算结果
- 参数捕获: 使用以下代码在控制台捕获完整参数:
copy(t)
7. 本地运行与结果验证
将上述代码保存为 jt_encrypt.js 文件,并添加测试代码:
// 测试代码
var testData = { "lt": "1752044129609", "ct": "1752044129609", "action": "follow", "uid": "123456789", "from": "profile", "v": "3.0.16", "ut": "" };
console.log("原始数据:", JSON.stringify(testData));
console.log("Base64编码后:", _0x422d33.encode(JSON.stringify(testData)));
console.log("位移加密后:", encrypt(_0x422d33.encode(JSON.stringify(testData))));
console.log("最终加密结果:"); console.log(getCommit(testData));
在终端中输入 node jt_encrypt.js 运行:

运行结果将生成完整的 CODED--v20... 格式的加密字符串,可以直接用于某吧的API请求。
验证方法:
- 字符串对比: 将本地生成的加密字符串与浏览器中的进行逐字符对比
- 接口测试: 使用生成的加密字符串实际调用commit接口测试
- 状态检查: 检查接口返回状态是否为200且包含有效的t参数
- 端到端测试: 使用获取到的t参数作为jt调用关注接口完成整个流程
8. 常见问题与解决方案(FAQ)
Q1: 为什么本地生成的加密结果与浏览器中的不一致?
A: 首先检查参数是否完全一致,特别是时间戳字段。建议使用copy(t)命令直接从浏览器复制完整参数,确保数据一致性。
Q2: 加密算法在不同环境下表现是否一致?
A: 由于是纯JavaScript逻辑实现,在不同浏览器和Node.js环境中表现应该一致。但要注意字符编码的一致性。
Q3: 如何验证加密结果是否正确?
A: 可以通过与浏览器中生成的加密字符串进行逐字符对比,或者实际调用接口验证返回结果。
Q4: 遇到”Invalid character”错误怎么办?
A: 这通常是UTF-8编码处理不一致导致的。检查utf8Encode函数是否正确处理了中文字符。
Q5: 加密函数会随时间变化吗?
A: 有可能。某吧可能会更新加密算法或版本号(v20)。如果发现接口失效,首先检查加密前缀和算法逻辑是否变化。
9. 获取完整课件
关注公众号:孤狼网络科技,回复:jt,即可获取本文涉及的完整代码课件。包含:
- 完整的加密函数代码(含详细注释)
- 参数配置示例和测试用例
- 详细的调试笔记和技巧文档
- 常见错误排查指南和解决方案
- 更新通知和算法变更追踪
总结
通过本文的JS逆向,我们成功破解了某吧jt参数的二级加密机制。从数据抓包到加密逻辑分析,完整展示了逆向工程的思维流程和技术方法。重点掌握了:
- XHR断点的正确使用方法和技巧
- 调用堆栈分析和加密入口定位
- 自定义Base64和位移加密算法的分析方法
- 本地代码还原和验证的正确流程
下期预览
以上就是本次 “jt参数逆向” 实战的全部内容。希望本篇JS逆向教程对您有所帮助。林石工作室下期将为您带来《JS逆向解密教程2:某吧顶贴神器_BSK参数解密教程》的解析,感谢关注。

