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 = undefinedconst 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 = undefinedconst 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']
十二、技巧①
当我们找不到某个函数在哪里的时候,只要在控制台打印这个函数,然后在控制台点击打印的结果,即可跳转到该函数。