==请帮忙点点赞,点个关注,谢谢!!==
本文发布的技术与代码仅供技术交流和学习使用,严禁用于数据采集等任何违法活动。请确保合法使用,并独立承担不当使用带来的法律责任。
一、逆向教程
1.我们先来看看返回的数据
点下一页,有个请求返回了数据,是密文。那就该来找找解密函数了。
2.解密函数的定位
hook一段神秘代码。
(function() {
var parse_ = JSON.parse;
JSON.parse = function(arg) {
console.log("断点----->", arg);
debugger;
return parse_(arg);
}})();
注入完,再点一下翻页。
这不就hook住了嘛,不过这里还是密文所以继续单步运行。(如果是明文那就要往前跟栈)
一直运行,终于是看到明文了。看这个b()方法,传入了密文,返回了明文。那这里肯定就是解密函数咯。最后返回了a,a中有一个关键字AES,那这里应该是AES解密,不过还是要深入分析,看都传了些什么进去。先把这块代码拿下来。
//逐步分析代码,完整代码在文章底部
function b(t) {
var e = d.a.enc.Hex.parse(t)
, n = d.a.enc.Base64.stringify(e)
, a = d.a.AES.decrypt(n, f, {
iv: m,
mode: d.a.mode.CBC,
padding: d.a.pad.Pkcs7
})
, r = a.toString(d.a.enc.Utf8);
return r.toString()
}
aa = '密文,太长了这里就不放了'
s = b(aa)
console.log(s)
3.深入分析
头尾各打一个断点,刷新一下网页,把hook给刷没。
逐步分析,先来看看d.a是个啥。
发现他是一个方法类。那这里我们直接用crypto-js库来代替.
//逐步分析代码,完整代码在文章底部
const CryptoJS = require("crypto-js")
function b(t) {
var e = CryptoJS.enc.Hex.parse(t)
, n = CryptoJS.enc.Base64.stringify(e)
, a = CryptoJS.AES.decrypt(n, f, {
iv: m,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
})
, r = a.toString(CryptoJS.enc.Utf8);
return r.toString()
}
aa = '密文,太长了这里就不放了'
s = b(aa)
console.log(s)
运行一下,报错了f没有被定义。那接着找f是啥。
往头上找一找,或者断点定位跳转一下。(m也是和f一样,这里就不再赘述了)
f和m两个传入的参数固定,那直接把最后生成的值复制下来。
//逐步分析代码,完整代码在文章底部
const CryptoJS = require("crypto-js")
f = {
"words": [
1148467306,
964118391,
624314466,
2019968622
],
"sigBytes": 16
}
m = {
"words": [
808530483,
875902519,
943276354,
1128547654
],
"sigBytes": 16
}
function b(t) {
var e = CryptoJS.enc.Hex.parse(t)
, n = CryptoJS.enc.Base64.stringify(e)
, a = CryptoJS.AES.decrypt(n, f, {
iv: m,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
})
, r = a.toString(CryptoJS.enc.Utf8);
return r.toString()
}
aa = '密文,太长了这里就不放了'
s = b(aa)
console.log(s)
再运行一下,出值了。
完毕!
二、Python还原解密函数
===帮忙点点赞,谢谢!!===
JS中用的标准库,那这里用python的Crypto库来还原一下。
from Crypto.Cipher import AES
import base64
# 定义输入数据
f = {
"words": [
1148467306,
964118391,
624314466,
2019968622
],
"sigBytes": 16
}
m = {
"words": [
808530483,
875902519,
943276354,
1128547654
],
"sigBytes": 16
}
def words_to_bytes(words, sig_bytes):
"""将 words 转换为字节数组"""
result = b""
for word in words:
result += word.to_bytes(4, byteorder='big')
return result[:sig_bytes]
def decrypt_aes(hex_string):
# 将 f 和 m 转换为字节数组
key = words_to_bytes(f["words"], f["sigBytes"])
iv = words_to_bytes(m["words"], m["sigBytes"])
# 将 hex 转换为字节数组并进行 Base64 编码
ciphertext_bytes = bytes.fromhex(hex_string)
ciphertext_base64 = base64.b64encode(ciphertext_bytes)
# 创建 AES 解密器
cipher = AES.new(key, AES.MODE_CBC, iv)
# 解密数据并移除填充
plaintext_bytes = cipher.decrypt(base64.b64decode(ciphertext_base64))
padding_length = plaintext_bytes[-1]
plaintext = plaintext_bytes[:-padding_length].decode('utf-8')
return json.loads(plaintext)
# 示例调用
hex_string = "接口返回的加密数据"
plaintext = decrypt_aes(hex_string) # 解密
print(plaintext)
或者直接用execjs库直接调用JS
import json
import execjs
def decodeData(respContent):
file = open('decode_data.js', mode='r', encoding='utf-8')
js = file.read()
file.close()
decUrlJs = execjs.compile(js)
dataJson = decUrlJs.call('b', respContent)
data = json.loads(dataJson)
return data
print(decodeData('接口返回的加密数据'))
三、声明
本文发布的技术与代码仅供技术交流和学习使用,严禁用于数据采集等任何违法活动。请确保合法使用,并独立承担不当使用带来的法律责任。
未经允许禁止转载