https://ying.baichuan-ai.com/
目录
一、发起提问
二、观察发现有两个加密参数:X-Bc-Sig和X-Bc-Ts
三、观察JS调用栈
四、从JS中搜索 X-Bc-Sig和X-Bc-Ts
五、断点并分析参数的生成方式
六、分析入参
七、发现关键的o方法调用了一个i()方法
八、验证结果
九、python执行Node.JS获取参数(本地安装了Node环境)
十、python本地执行JS(本地未安装Node.js环境)
十一、实际应用
一、发起提问
二、观察发现有两个加密参数:X-Bc-Sig和X-Bc-Ts
三、观察JS调用栈
四、从JS中搜索 X-Bc-Sig和X-Bc-Ts
发现只有_app-xxxxx.js文件中存在X-Bc-Sig
五、断点并分析参数的生成方式
六、分析入参
一个参数是固定字符串:"uwlACMuXQApWgO0Q"
一个参数是时间戳组成的动态字符串:"1721891456251retry=3&thread_info=[object Object]"
七、发现关键的o方法调用了一个i()方法
找了一圈没找到i()方法,无奈我只好在控制台打印一下,看看这个i()是什么样的
断点挺住,在去控制台打印一下
七、模拟生成
1、先将关键的o方法复制出来
2、模拟i()方法
3、 调用o方法和截取逻辑复制过来
4、构建参数
我们可以看到n是当前时间戳 n = Date.now()
r是混淆参数 undefined
a是由时间戳组成的固定字符串
八、验证结果
九、python执行Node.JS获取参数(本地安装了Node环境)
import execjs
# JavaScript代码
js_code = """
const CryptoJS = require("crypto-js");
function i() {
return CryptoJS
}
function o(t, e) {
let r = i().enc.Utf8.parse("0000000000000000");
return i().AES.encrypt(t, i().enc.Utf8.parse(e), {
iv: r,
mode: i().mode.CBC,
padding: i().pad.Pkcs7
}).toString()
}
//构建入参
const n = '1721892945291'
const r = undefined
const a = `${n.toString()}retry=3&thread_info=[object Object]`
// 执行关键o函数
let s = o(a, r ? r.substring(0, 16) : "uwlACMuXQApWgO0Q");
// 截取逻辑
s.length > 64 && (s = s.substring(0, 64))
result = {
"x-bc-sig": s,
"x-bc-ts": n.toString()
}
return result
"""
# 编译JavaScript代码
ctx = execjs.compile(js_code)
# 执行JavaScript代码并获取结果
result = ctx.call("JSON.stringify")
# 输出结果
print(result)
十、python本地执行JS(本地未安装Node.js环境)
将crypto-js下载到本地:
crypto-js.min.js
CRYPTO-JS.MIN.JS: DOWNLOAD - CDNPKG
encryption.js
//encryption.js
//引入本地加密库
const CryptoJS = require('./crypto-js.min.js');
function i() {
return CryptoJS
}
function o(t, e) {
let r = i().enc.Utf8.parse("0000000000000000");
return i().AES.encrypt(t, i().enc.Utf8.parse(e), {
iv: r,
mode: i().mode.CBC,
padding: i().pad.Pkcs7
}).toString()
}
//构建入参
const n = '1721892945291'
const r = undefined
const a = `${n.toString()}retry=3&thread_info=[object Object]`
// 执行关键o函数
let s = o(a, r ? r.substring(0, 16) : "uwlACMuXQApWgO0Q");
// 截取逻辑
return s.length > 64 && (s = s.substring(0, 64)),
{
"x-bc-sig": s,
"x-bc-ts": n.toString()
}
import execjs
# 读取crypto-js库文件和你的JavaScript代码
with open('crypto-js.min.js', 'r', encoding='utf-8') as file:
crypto_js_code = file.read()
with open('encryption.js', 'r', encoding='utf-8') as file:
script_code = file.read()
# 整合JavaScript代码
js_code = crypto_js_code + "\n" + script_code
# 编译JavaScript代码
ctx = execjs.compile(js_code)
# 执行JavaScript代码并获取结果
result = ctx.call("JSON.stringify")
# 输出结果
print(result)
十一、实际应用
发现runs接口的签名和delete接口的签名有所不同
runs直接对时间戳签名就可以
delete接口需要对时间戳和id进行双重签名
我只能写成两个function来供python调用
//引入本地加密库
const CryptoJS = require('./crypto-js.min.js');
function i() {
return CryptoJS
}
function o(t, e) {
let r = i().enc.Utf8.parse("0000000000000000");
return i().AES.encrypt(t, i().enc.Utf8.parse(e), {
iv: r,
mode: i().mode.CBC,
padding: i().pad.Pkcs7
}).toString()
}
function runs_sign() {
//构建入参
const n = Date.now()
const r = undefined
const a = `${n.toString()}retry=3&thread_info=[object Object]`
// const a = `${n.toString()}id=6042075`
// 执行关键o函数
let s = o(a, r ? r.substring(0, 16) : "uwlACMuXQApWgO0Q");
// 截取逻辑
return s.length > 64 && (s = s.substring(0, 64)),
{
"x-bc-sig": s,
"x-bc-ts": n.toString()
}
}
function delete_sign(id) {
//构建入参
const n = Date.now()
const r = undefined
const a = `${n.toString()}id=${id}`
// 执行关键o函数
let s = o(a, r ? r.substring(0, 16) : "uwlACMuXQApWgO0Q");
// 截取逻辑
return s.length > 64 && (s = s.substring(0, 64)),
{
"x-bc-sig": s,
"x-bc-ts": n.toString()
}
}
def get_runs_sign_and_timestamp(self):
"""
获取访问签名和时间戳
"""
# 读取crypto-js库文件和你的JavaScript代码
with open('crypto-js.min.js', 'r', encoding='utf-8') as file:
crypto_js_code = file.read()
with open('encryption.js', 'r', encoding='utf-8') as file:
script_code = file.read()
# 整合JavaScript代码
js_code = crypto_js_code + "\n" + script_code
# 编译JavaScript代码
ctx = execjs.compile(js_code)
# 执行JavaScript代码并获取结果
result = ctx.call("runs_sign")
return result['x-bc-sig'], result['x-bc-ts']
def get_delete_sign_and_timestamp(self, id):
"""
获取删除签名和时间戳
"""
# 读取crypto-js库文件和你的JavaScript代码
with open('crypto-js.min.js', 'r', encoding='utf-8') as file:
crypto_js_code = file.read()
with open('encryption.js', 'r', encoding='utf-8') as file:
script_code = file.read()
# 整合JavaScript代码
js_code = crypto_js_code + "\n" + script_code
# 编译JavaScript代码
ctx = execjs.compile(js_code)
# 执行JavaScript代码并获取结果
result = ctx.call("delete_sign", id)
return result['x-bc-sig'], result['x-bc-ts']
十二、技巧①
当我们找不到某个函数在哪里的时候,只要在控制台打印这个函数,然后在控制台点击打印的结果,即可跳转到该函数。