js逆向-哈希算法
前言
静看光阴荏苒,借我喑哑无言
⚠️声明:本文所涉及的爬虫技术及代码仅用于学习、交流与技术研究目的,禁止用于任何商业用途或违反相关法律法规的行为。若因不当使用造成法律责任,概与作者无关。请尊重目标网站的
robots.txt协议及相关服务条款,共同维护良好的网络环境。
1.MD5
1.1简介
简介:全称 MD5 消息摘要算法,又称哈希算法、散列算法,由美国密码学家罗纳德·李维斯特设计,于 1992 年作为 RFC 1321 被公布,用以取代 MD4 算法。摘要算法是单向加密的,也就是说明文通过摘要算法加密之后,是不能解密的。摘要算法的第二个特点密文是固定长度的,它通过一个函数,把任意长度的数据转换为一个长度固定的数据串(通常用16进制的字符串表示)。之所以叫摘要算法,它的算法就是提取明文重要的特征。所以,两个不同的明文,使用了摘要算法之后,有可能他们的密文是一样的,不过这个概率非常的低。
MD5(Message Digest Algorithm 5)是一个广泛使用的 哈希算法,其主要目的是将任意长度的输入数据(例如文本、文件等)转换成一个固定长度的 128位哈希值(通常以 32 字符的十六进制表示)。尽管 MD5 在许多领域得到了广泛应用,但它在现代安全场景中已不再足够安全,特别是由于它容易受到 碰撞攻击。
MD5 的特点:
- 固定长度的输出:无论输入数据的大小如何,MD5 输出的哈希值始终是 128 位(16 字节)的固定长度,通常以 32 个十六进制字符表示。
- 不可逆性:MD5 是单向的,意味着无法从哈希值反推出原始数据(理想情况下)。但随着计算能力的提升,它已被证明不再适用于高度安全的应用。
- 碰撞性:理论上,MD5 是设计为产生唯一哈希值的,但由于存在碰撞攻击(即两个不同的输入数据产生相同的哈希值),它不再被认为是“安全的”哈希函数。
- 速度:MD5 处理速度较快,适合用于较小的数据量的哈希计算。
- 广泛应用:曾经广泛用于文件完整性验证、密码存储等,但由于其安全性问题,许多应用现在已经转向更安全的哈希算法,如 SHA-256。
MD5 的常见用途:
- 数据完整性检查:通过计算文件或消息的 MD5 哈希值,可以确保数据在传输或存储过程中没有被篡改。如果哈希值匹配,则数据未改变;否则,数据可能已被修改。
- 密码存储(不推荐):过去,许多系统使用 MD5 存储密码的哈希值,但现在由于 MD5 的碰撞攻击问题,这种做法已被弃用。现代系统通常使用更强大的哈希算法,如 bcrypt、scrypt 或 Argon2。
- 数字签名:在某些应用中,MD5 也被用于生成数字签名的摘要,尤其是在较老的系统中。
1.2JavaScript实现MD5
安装命令
npm install crypto-js --save

代码
var cryptojs = require('crypto-js')
function test_md5(str){
return cryptojs.MD5(str).toString()
}
console.log(test_md5('peng'))

1.3Python实现实现MD5
MD5哈希视为字符串,而是将其视为十六进制数, MD5哈希长度为128位,通常由32个十六进制数字表示。
代码
import hashlib
def md5_test(str):
md5 = hashlib.md5()
md5.update(str.encode('utf-8'))
return md5.hexdigest() # 返回 MD5 的十六进制哈希值
if __name__ == '__main__':
print(md5_test('peng'))

2.MyToken网站逆向解密
地址:https://www.mytokencap.com/
2.1分析过程
检查请求头,好像没有加密字段

发现请求中code和timestamp会改变
pages=1%2C1&sizes=100%2C100&subject=market_cap&language=zh_CN&legal_currency=USD&code=a9a9ca3adc8c8a459abfaa12fd8cb6d2×tamp=1740763224060&platform=web_pc&v=0.1.0&mytoken=

可以尝试使用关键字搜索,ctrl + shift +f搜索code=
找到了 t.data.code = n,,感觉很像,打个断点调试一下

这个没有进断点,我们使用XHR/提取断点,然后单步调试

单步调试定位到这里发现code赋值了
并且尝试里面每个方法发现(0, c.xZ)是加密的方法
r.__generator)(this, (function(r) {
return t = s.length > 1 && void 0 !== s[1] && s[1],
n = (0,
c.Fk)((0,
l.Z)({}, e, (0,
c.xZ)())),
i = "".concat(null !== (a = "https://api.mytokenapi.com") && void 0 !== a ? a : "http://localhost:3300/api", "/ticker/currencyranklist").concat(t ? "seo" : "", "?").concat(n),
[2, (0,
c.lq)(i)]
}
))

跳转到c.xZ

发现这里进行了code赋值,但是a()返回了个方法
在此处代码断点,并继续跳转到该方法的实现
code: a()(t + "9527" + t.substr(0, 6)),

返回的是个方法,在此处继续断点,然后跳转到实现
: function() {
return e
}

这里就能发现通过e.wordsToBytes(s(t, n))和 e.bytesToHex(r)进行加密
t.exports = function(t, n) {
if (void 0 === t || null === t)
throw new Error("Illegal argument " + t);
var r = e.wordsToBytes(s(t, n));
return n && n.asBytes ? r : n && n.asString ? i.bytesToString(r) : e.bytesToHex(r)
}

2.2实现
核心代码就是对当前时间戳进行了处理,并且加盐了("9527" + t.substr(0, 6))

python只要模拟实现时间戳的md5即可
import time
import hashlib
import requests
url = 'https://api.mytokenapi.com/ticker/currencyranklist?pages=2%2C1&sizes=100%2C100&subject=market_cap&language=en_US&legal_currency=USD&code={}×tamp={}&platform=web_pc&v=0.1.0&mytoken='
t1 = str(int(time.time() * 10000))
va = t1 + '9527' + t1[0:6]
md5 = hashlib.md5()
md5.update(va.encode('utf-8'))
code = md5.hexdigest()
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36'
}
res = requests.get(url.format(code, t1), headers=headers)
print(res.json())

3.SHA
3.1简介
SHA(Secure Hash Algorithm)是由 美国国家安全局(NSA) 设计的一个系列加密哈希函数,它广泛用于信息安全领域,包括数据完整性验证、数字签名等。SHA 用于生成定长的哈希值(摘要),无论输入数据的大小如何,它的输出都是固定的长度。
SHA 的版本很多,其中最常用的是 SHA-1、SHA-256 和 SHA-3。
SHA 的主要版本:
-
SHA-1-
输出长度:160位(20字节)
-
SHA-1 生成一个长度为160位的哈希值。曾被广泛用于数字签名、证书、消息完整性等场景。
-
安全性问题:由于 SHA-1 易受碰撞攻击(两个不同的输入可能产生相同的哈希值),已经不再被认为是安全的。
-
弃用:大部分现代应用已经停止使用 SHA-1,转而使用更强大的 SHA-2 或 SHA-3。
-
-
SHA-2
-
输出长度:256位(SHA-256)、512位(SHA-512)
-
SHA-2 是 SHA-1 的继任者,具有更高的安全性,广泛应用于各类加密协议和数字证书中。
-
SHA-256:最常见的 SHA-2 变体,广泛用于区块链(如比特币)和安全传输(如 HTTPS)中。
-
SHA-512:SHA-2 的另一种变体,输出长度为 512 位,通常在需要更高安全级别的场合使用。
-
-
SHA-3
-
输出长度:可以是224位、256位、384位、512位等
-
SHA-3 是基于 Keccak 算法的全新设计,与 SHA-2 不同,并且提供了更强的安全性。
-
它作为 SHA 系列的最新成员,比 SHA-1 和 SHA-2 更为强大,并且设计上具有更强的抗碰撞和抗预图像攻击的能力。
-
SHA 的用途:
-
数据完整性验证:
- 用于确保数据在传输或存储过程中没有被篡改。例如,当你下载一个文件时,可以查看它的 SHA 哈希值,下载完成后计算该文件的 SHA 哈希值,验证是否一致。
-
数字签名:
- 在数字签名中,哈希值用于生成消息摘要,确保消息的完整性和不可篡改性。
-
密码学应用:
- SHA 常用于加密协议中,例如 TLS/SSL、区块链等,确保信息的安全传输。
-
密码存储:
- 用于存储密码的哈希值,防止密码泄露。特别是在存储用户密码时,一般将密码通过 SHA(或结合盐值)进行哈希,再进行存储。
SHA 的优点:
- 快速:SHA 算法通常处理速度较快,适合大规模的数据处理。
- 不可逆:哈希算法是单向的,从哈希值无法还原回原始数据。
- 唯一性:理想情况下,不同的输入数据会产生不同的哈希值。
- 稳定性:SHA 系列具有高稳定性和良好的抗碰撞性,尤其是 SHA-256 和 SHA-3。
SHA 的缺点
- SHA-1 不安全:已经被证明存在碰撞攻击,不适合用于现代安全应用。
- 性能开销:SHA-2 尽管提供更强的安全性,但相对于 SHA-1 来说,计算开销较大,可能影响性能。
- SHA-3 的复杂性:相比 SHA-2,SHA-3 的设计较为复杂,且对硬件的要求较高。
- 理论碰撞风险:尽管 SHA-2 和 SHA-3 提供强大的抗碰撞性,但随着计算能力的提升,未来某些攻击的潜力仍是不可忽视的。
- 计算成本高:对于大量数据的处理,SHA 算法可能消耗更多的计算资源,影响系统性能。
3.2JavaScript实现SHA
代码
crypto-js开箱即用
var crypto = require('crypto-js')
function get_sha1(str) {
return crypto.SHA1(str).toString()
}
function get_sha224(str) {
return crypto.SHA224(str).toString()
}
function get_shas56(str) {
return crypto.SHA256(str).toString()
}
function get_sha512(str) {
return crypto.SHA512(str).toString()
}
console.log(get_sha1('peng'))
console.log(get_sha224('peng'))
console.log(get_shas56('peng'))
console.log(get_sha512('peng'))

3.3Python实现实现SHA
代码
hashlib开箱即用
import hashlib
def get_sha1(str):
sha1 = hashlib.sha1()
sha1.update(str.encode('utf-8'))
return sha1.hexdigest()
def get_sha224(str):
sha224 = hashlib.sha224()
sha224.update(str.encode('utf-8'))
return sha224.hexdigest()
def get_sha256(str):
sha256 = hashlib.sha256()
sha256.update(str.encode('utf-8'))
return sha256.hexdigest()
def get_sha512(str):
sha512 = hashlib.sha512()
sha512.update(str.encode('utf-8'))
return sha512.hexdigest()
print(get_sha1('peng'))
print(get_sha224('peng'))
print(get_sha256('peng'))
print(get_sha512('peng'))

4.红人点集网站逆向解密
地址:http://www.hh1024.com/#/login?redirect=%2FrealTimeLiving
好像网站有点问题登录不上

5.HMAC
5.1简介
HMAC(Hash-based Message Authentication Code,基于哈希的消息认证码)是一种用于数据完整性校验和身份认证的加密技术。它结合了哈希函数(如 SHA-256、SHA-512)和密钥,确保消息在传输过程中未被篡改。
HMAC:全称散列消息认证码、密钥相关的哈希运算消息认证码,于 1996 年提出,1997 年作为 RFC 2104 被公布,HMAC 加密算法是一种安全的基于加密 Hash 函数和共享密钥的消息认证协议,它要求通信双方共享密钥 key、约定算法、对报文进行 Hash 运算,形成固定长度的认证码。通信双方通过认证码的校验来确定报文的合法性。
百度百科:https://baike.baidu.com/item/hmac/7307543?fr=aladdin
HMAC 的特点
- 抗篡改:攻击者即使截获了消息,若不知道密钥,就无法伪造正确的 HMAC。
- 防重放:结合时间戳或随机数(nonce)使用,可以防止重放攻击。
- 可用于 API 认证:HMAC 常用于 API 请求的身份认证,比如 AWS、支付宝等接口。
- 比数字签名快:HMAC 只依赖哈希函数,而数字签名(如 RSA 签名)需要额外的公私钥计算。
5.2 JavaScript实现HMAC
代码
var crypto = require('crypto-js')
function get_hmac1(str, key) {
return crypto.HmacSHA1(str, key).toString()
}
function get_hmac224(str, key) {
return crypto.HmacSHA224(str, key).toString()
}
function get_hmac256(str, key) {
return crypto.HmacSHA256(str, key).toString()
}
function get_hmac512(str, key) {
return crypto.HmacSHA512(str, key).toString()
}
var str = 'peng'
var key = 'askjdhjkas'
console.log(get_hmac1(str,key))
console.log(get_hmac224(str,key))
console.log(get_hmac256(str,key))
console.log(get_hmac512(str,key))

5.3Python实现HMAC
代码
key和str值一样,确定和js生成的一样
import hmac
import hashlib
def get_hmacsha1(key, str):
return hmac.new(key.encode('utf-8'), str.encode('utf-8'), hashlib.sha1).hexdigest()
def get_hmacsha224(key, str):
return hmac.new(key.encode('utf-8'), str.encode('utf-8'), hashlib.sha224).hexdigest()
def get_hmacsha256(key, str):
return hmac.new(key.encode('utf-8'), str.encode('utf-8'), hashlib.sha256).hexdigest()
def get_hmacsha512(key, str):
return hmac.new(key.encode('utf-8'), str.encode('utf-8'), hashlib.sha512).hexdigest()
str = 'peng'
key = 'askjdhjkas'
print(get_hmacsha1(key, str))
print(get_hmacsha224(key, str))
print(get_hmacsha256(key, str))
print(get_hmacsha512(key, str))

6.企查查网站逆向
6.1分析过程
登录后搜索小米

搜索后返回的没有找到api,返回的是一个页面
那就尝试点击分页
在请求头下找到了一个类似加密的键值对
https://www.qcc.com/api/search/searchMulti

右键复制(以cURL(base)格式复制)整个请求
curl 'https://www.qcc.com/api/search/searchMulti' \
-H 'accept: application/json, text/plain, */*' \
-H 'accept-language: zh-CN,zh;q=0.9' \
-H 'cache-control: no-cache' \
-H 'content-type: application/json' \
-H 'cookie: acw_tc=1a0c384a17408235448871640e0043676097a7e8a43ee701aa2dc819edc970; QCCSESSID=c88eeaa956741c981aeb5fe8a4; qcc_did=1ea4af44-65a0-4d83-932a-4ba76bc0bf83; tfstk=gBJtNMbkX20iXeWoIAG3n9vXrDnnxKKwsF-7nZbgGeLpV3zGG10NkBLX81b_Ic5vJnT-bi0wnlRer3wMIfW0HOWVh40oEYmwbtWb47X6iN-BYiihfECyG8WVh40h6LOrYt8rV0861HidmibffEs6Aw_FX-6f5saQOg_CltTfG9tC2gbffs1_ODIVRZ6fhEtINCEOol_YHQ1BjHk8I92bhpIO1Xx1R-sepGCOPh9Th-Z5X1QWfw3yy25FOn5v3oyAMhOyugT_5qQ2pH96NUg3sNORD3AvfAwCId-6Ns9SuStNINBBCQEbhHBOSEpv8P3dPd-BU91nF0KBLFxwpnqjhMYlRhJ1HYiPBO_1pMJm8R_vOI9G_tzskZJpAdOA4SpkeZw_raI01DnLgS51YplVGuHs0NSPvam3tSPVtMSdrDnLgS51YMQoxYV4g6jF.' \
-H 'da4728817277230574d7: 4870626981a425631fb457af4b1d6125bc76a10162a138f3bbc082d0c11c65bfccd34d3d8c29930d3aa122e519b3c1ea1c41d84003cd09b95c828e9fc06fb08e' \
-H 'origin: https://www.qcc.com' \
-H 'pragma: no-cache' \
-H 'priority: u=1, i' \
-H 'referer: https://www.qcc.com/web/search?key=%E5%B0%8F%E7%B1%B3' \
-H 'sec-ch-ua: "Not A(Brand";v="8", "Chromium";v="132", "Google Chrome";v="132"' \
-H 'sec-ch-ua-mobile: ?0' \
-H 'sec-ch-ua-platform: "Windows"' \
-H 'sec-fetch-dest: empty' \
-H 'sec-fetch-mode: cors' \
-H 'sec-fetch-site: same-origin' \
-H 'user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36' \
-H 'x-pid: fe2c13049497d88ff04a56fc39f9739e' \
-H 'x-requested-with: XMLHttpRequest' \
--data-raw '{"searchKey":"小米","pageIndex":2,"pageSize":20}'

接下来就要找到给请求头加密的地方
我这里直接尝试使用XHR/提取断点
/api/search/searchMulti

header肯定在发送请求前创建成功的,所以我们在调用堆栈中向之前代码单步调试

前面俩个堆栈方法中请求的header已经加密成了,接着就看到了异步代码,所以要在异步代码打上断点,继续单步调试

发现在这段代码结束后,请求头有了加密
看代码我们一开始也可以使用关键字定位,ctrl + shift + f搜索headers[
i.default = [function(e) {
var t, n;
return null !== (t = e.custom) && void 0 !== t && t.originConfig || (e.headers["X-Requested-With"] = "XMLHttpRequest",
null !== (n = e.custom) && void 0 !== n && n.functionName && (e.headers["x-function-name"] = encodeURIComponent(e.custom.functionName)),
window.pid && (e.headers["x-pid"] = window.pid),
e.withCredentials = !0,
(0,
a.default)(e)),
e
}

定位到是由(0,a.default)(e)进行加密的,继续跳转到实现

我们发现在这段代码中进行数据加密赋值
可以看到e.headers[i] = u,说明i是请求头键,u是请求头值
// 源代码
i.default = function(e) {
var t = e.url.replace(e.baseURL, "")
, n = a.default.stringify(e.params || {});
n && (t += (-1 === t.indexOf("?") ? "?" : a.default.options.delimiter || "&") + n),
t = t.toLowerCase();
var i = (0,
o.default)(t, e.data)
, u = (0,
r.default)(t, e.data, (0,
s.default)());
e.headers[i] = u
}

首先解析i,发现i的赋值(0, o.default)(t, e.data),跳转到 o.default实现
var i = (0, o.default)(t, e.data)

return (0, a.default)(t + n, (0, o.default)(t)).toLowerCase().substr(8, 20)发现此方法还有2个自定义参数a.default和o.default
这里只能一步一步继续看,我们按顺序继续跟踪o.default,因为会先执行里面的代码
然后我们重写这个方法
// 源代码
i.default = function() {
var e = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}
, t = (arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "/").toLowerCase()
, n = JSON.stringify(e).toLowerCase();
return (0,
a.default)(t + n, (0,
o.default)(t)).toLowerCase().substr(8, 20)
}
// 修改后
aa = function () {
var e = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}
, t = (arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "/").toLowerCase()
, n = JSON.stringify(e).toLowerCase();
return (0,
cc)(t + n, (0,
bb)(t)).toLowerCase().substr(8, 20)
}

跳转到o.default

这个方法有1个自定义的变量a,我们通过控制台输出,感觉他应该是一个固定变量
这个方法大部分是js方法,比较简单
重写这个方法
// 原代码
i.default = function() {
for (var e = (arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "/").toLowerCase(), t = e + e, n = "", i = 0; i < t.length; ++i) {
var o = t[i].charCodeAt() % a.default.n;
n += a.default.codes[o]
}
return n
}
// 修改后
bb = function () {
a = {
"n": 20,
"codes": {
0: 'W',
1: 'l',
2: 'k',
3: 'B',
4: 'Q',
5: 'g',
6: 'f',
7: 'i',
8: 'i',
9: 'r',
10: 'v',
11: '6',
12: 'A',
13: 'K',
14: 'N',
15: 'k',
16: '4',
17: 'L',
18: '1',
19: '8'
}
}
for (var e = (arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "/").toLowerCase(), t = e + e, n = "", i = 0; i < t.length; ++i) {
var o = t[i].charCodeAt() % a.n;
n += a.codes[o]
}
return n
}

上面方法完成后,我们接着单步调试回到 return (0,a.default)(t + n, (0, o.default)(t)).toLowerCase().substr(8, 20)
接着需要调试a.default

我们进入到a.default实现,打上断点,单步调试到此处,此处也是个方法跳转,接着跳转到实现
i.default = function(e, t) {
return (0,
a.default)(e, t).toString()
}

我们发现这段代码进行了HMAC加密,参数就是我们的请求地址(/api/search/searchmulti) + 请求参数({"searchkey":"小米","pageindex":1,"pagesize":20})
_createHmacHelper: function(t) {
return function(e, n) {
return new p.HMAC.init(t,n).finalize(e)
}
}

地址:https://toolgg.com/hmacsha512/
我们需要验证这个方法是否是固定的某种hmac算法,我们直接打开在线加解密的网站,进行HmacSHA512、HmacSHA1、HmacSHA224、HmacSHA256验证,只能一个个尝试,这里发现这个网站是使用的HmacSHA512算法

所以这个方法的意思就是:
(0, o.default)(t):对请求地址进行字符转换(0, a.default)(t + n, (0, o.default)(t)):请求地址进行字符转换后作为盐,在对请求地址 + 请求参数进行HMAC512加密

调试完 var i = (0, o.default)(t, e.data) ,
接着就是u = (0,r.default)(t, e.data, (0,s.default)());

接着调试s.default,跳转到实现

这个方法就是执行了js脚本,获取window.tid
ctrl + shift + f全局搜索window.tid
这个一眼就能看到最后一个就是赋值
var _default = _exports.default = function _default() {
var list = ["w", "i", "n", "d", "o", "w", ".", "t", "i", "d"];
return eval(list.join(""))
}

跳转到搜索,获取到 window.tid

window的值一般在首页都能搜索到,正常情况我们需要请求首页获取到该值,因为是本地测试,这里可以固定

s.default就是获取页面的 window.tid
接着调试 r.default,跳转到该实现

我们发现此方法有2个自定义方法a.default和o.default
那接着调试o.default,我们需要重写这个方法
cc是HmacSHA512加密
bb是进行字符转换
// 原代码
i.default = function() {
var e = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}
, t = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : ""
, n = (arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "/").toLowerCase()
, i = JSON.stringify(e).toLowerCase();
return (0,
a.default)(n + "pathString" + i + t, (0,
o.default)(n))
}
// 修改后
// cc是
ee = function () {
var e = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}
, t = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : ""
, n = (arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "/").toLowerCase()
, i = JSON.stringify(e).toLowerCase();
return (0,
cc)(n + "pathString" + i + t, (0,
bb)(n))
}

跳转到o.default

我们发现此方法就是对参数进行字符转换,刚才我们已经重写过了
这里需要固定a.default.codes变量,其他都是js方法

接着跳转到a.default实现

这里也是方法跳转,继续跳转到实现

发现这里也是进行HmacSHA512加密的地方,并且是规范的HmacSHA512
刚才我们通过在线加解密的网站验证了
我们可以通过crypto-js实现HmacSHA512
var crypto = require('crypto-js')
cc = function (text, key) {
return crypto.HmacSHA512(text, key).toString()
}
到这里调试完了,js逆向的代码也完成了,接着进行代码测试

6.2js逆向代码
var crypto = require('crypto-js')
aa = function () {
var e = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}
, t = (arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "/").toLowerCase()
, n = JSON.stringify(e).toLowerCase();
return (0,
cc)(t + n, (0,
bb)(t)).toLowerCase().substr(8, 20)
}
bb = function () {
a = {
"n": 20,
"codes": {
0: 'W',
1: 'l',
2: 'k',
3: 'B',
4: 'Q',
5: 'g',
6: 'f',
7: 'i',
8: 'i',
9: 'r',
10: 'v',
11: '6',
12: 'A',
13: 'K',
14: 'N',
15: 'k',
16: '4',
17: 'L',
18: '1',
19: '8'
}
}
for (var e = (arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "/").toLowerCase(), t = e + e, n = "", i = 0; i < t.length; ++i) {
var o = t[i].charCodeAt() % a.n;
n += a.codes[o]
}
return n
}
cc = function (text, key) {
return crypto.HmacSHA512(text, key).toString()
}
dd = function () {
// var list = ["w", "i", "n", "d", "o", "w", ".", "t", "i", "d"];
// return eval(list.join(""))
// window.tid
// <script>
// window.pid = 'abd354f89325103e1bf47f162fee26c0';
// window.tid = '026bf665b0abdeff61cb1b3c32fd6dd5'
// </script>
return '026bf665b0abdeff61cb1b3c32fd6dd5'
}
ee = function () {
var e = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}
, t = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : ""
, n = (arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "/").toLowerCase()
, i = JSON.stringify(e).toLowerCase();
return (0,
cc)(n + "pathString" + i + t, (0,
bb)(n))
}
get_hmacsha512_header = function (t, e) {
return {'key': aa(t, e), 'val': ee(t, e, dd())}
}
// // 测试代码
// var t = '/api/search/searchmulti',
// e = {"searchkey": "小米", "pageindex": 1, "pagesize": 20},
// key = '026bf665b0abdeff61cb1b3c32fd6dd5'
// console.log(aa(t,e))
// // u = (0, r.default)(t, e.data, (0, s.default)());
// // r.default('/api/search/searchmulti',{"searchkey": "小米", "pageindex": 1, "pagesize": 20},'026bf665b0abdeff61cb1b3c32fd6dd5')
// console.log(ee(t,e,dd()))
// console.log(ee(t,e,key))
//
// console.log(get_hmacsha512_header('/api/search/searchmulti',{"searchkey": "小米", "pageindex": 1, "pagesize": 20}))
6.3python调用代码
右键复制(以cURL(base)格式复制)整个请求

地址:https://www.spidertools.cn/#/curl2Request
这个网站可以快速帮我们转换headers

代码
主要是js逆向比较耗时,代码就是调用js生成加密headers,然后带上headers发送post请求
import json
import time
import execjs
import requests
class QiCCSpider:
def __init__(self):
self.headers = {
"accept": "application/json, text/plain, */*",
"accept-language": "zh-CN,zh;q=0.9",
"cache-control": "no-cache",
"content-type": "application/json",
"da4728817277230574d7": "4870626981a425631fb457af4b1d6125bc76a10162a138f3bbc082d0c11c65bfccd34d3d8c29930d3aa122e519b3c1ea1c41d84003cd09b95c828e9fc06fb08e",
"origin": "https://www.qcc.com",
"pragma": "no-cache",
"priority": "u=1, i",
"referer": "https://www.qcc.com/web/search?key=%E5%B0%8F%E7%B1%B3",
"sec-ch-ua": "\"Not A(Brand\";v=\"8\", \"Chromium\";v=\"132\", \"Google Chrome\";v=\"132\"",
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": "\"Windows\"",
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "same-origin",
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36",
"x-pid": "fe2c13049497d88ff04a56fc39f9739e",
"x-requested-with": "XMLHttpRequest"
}
self.cookies = {
"acw_tc": "1a0c384a17408235448871640e0043676097a7e8a43ee701aa2dc819edc970",
"QCCSESSID": "c88eeaa956741c981aeb5fe8a4",
"qcc_did": "1ea4af44-65a0-4d83-932a-4ba76bc0bf83",
"tfstk": "gBJtNMbkX20iXeWoIAG3n9vXrDnnxKKwsF-7nZbgGeLpV3zGG10NkBLX81b_Ic5vJnT-bi0wnlRer3wMIfW0HOWVh40oEYmwbtWb47X6iN-BYiihfECyG8WVh40h6LOrYt8rV0861HidmibffEs6Aw_FX-6f5saQOg_CltTfG9tC2gbffs1_ODIVRZ6fhEtINCEOol_YHQ1BjHk8I92bhpIO1Xx1R-sepGCOPh9Th-Z5X1QWfw3yy25FOn5v3oyAMhOyugT_5qQ2pH96NUg3sNORD3AvfAwCId-6Ns9SuStNINBBCQEbhHBOSEpv8P3dPd-BU91nF0KBLFxwpnqjhMYlRhJ1HYiPBO_1pMJm8R_vOI9G_tzskZJpAdOA4SpkeZw_raI01DnLgS51YplVGuHs0NSPvam3tSPVtMSdrDnLgS51YMQoxYV4g6jF."
}
self.url = 'https://www.qcc.com/api/search/searchMulti'
js_code = open('12.企查查.js', encoding='utf-8').read()
self.js = execjs.compile(js_code)
def get_data(self):
for i in range(1, 3):
# e = {"searchkey": "小米", "pageindex": i, "pagesize": 20}
e = {"searchKey": "小米", "pageIndex": i, "pageSize": 20}
js_result = self.js.call('get_hmacsha512_header', '/api/search/searchMulti', e)
self.headers[js_result['key']] = js_result['val']
print(js_result)
print(self.headers)
r = requests.post(self.url, headers=self.headers, cookies=self.cookies, json=e)
print(r.text)
time.sleep(1)
if __name__ == '__main__':
spider = QiCCSpider()
spider.get_data()

📌 创作不易,感谢支持!
每一篇内容都凝聚了心血与热情,如果我的内容对您有帮助,欢迎请我喝杯咖啡☕,您的支持是我持续分享的最大动力!

浙公网安备 33010602011771号