该文章只是用于逆向学习,不得以商用或者是破坏他人利益的目的进行使用。如有侵权请联系作者。
网站链接:
bse64
aHR0cHM6Ly9nZ3p5ZncuZnVqaWFuLmdvdi5jbi9idXNpbmVzcy9saXN0Lw==
分析环节
进入网站 进行翻页请求时我们会发现改请求时ajax请求。
这里,我们可以直接看一下请求参数和返回结果,以及表头携带。
请求参数
请求参数中不存在加密
返回数据
data被加密了
请求头
请求头中存在一个加密参数
此时我们换页,查看改参数是否改变
发生改变,所以我们现在需要做的就是先找到请求头中的 portal-sign的加密位置。
由于数据加密的这个过程中我们并不知道再那个文件中,应为返回数据的话是已经得到加密头了,所以这里我们采用搜索关键字的方法来进行快速定位。这也是为什么我不直接使用xhr断点找加密的原因。
搜索关键词portal-sign
找到关键字,点击进入该js文件
打个断点待会好调试
现在我们已经找到加密的位置了,根据名字可以直接确定,这就是加密的赋值操作,现在开始调试,找到加密函数。
执行一步的时候我们发现他出现到这里了,结合上面的f.getsign(e)可以确定,这个过程是正确的
那么,我们先不扣代码,先走一步看看,执行到这里的时候我们需要看一下这些参数是什么
控制台输出一下r["a"]
这个值先记录一下
输出l(t),我们可以确定的是,l(t)是一个加密的过程
并且我们看参数t是一个对象
中间的ts是一个时间戳,带有请求的一些参数,这个先不管
现在继续进入,进入下图文件中。我们发现这个过程是创建了一个Md5对象并且调用了update方法,所以我们已经可以知道这个结果了,以防万一,我们直接跳过调试观察一下。可以验证个参数就是一个通过md5加密的一个过程,你现在可以采用md5加密验证也可以直接扣下来这段代码,我们使用平台是可以直接知道,这个加密就是MD5加密的一个过程,但是为了锻炼我的扣代码能力,我选择了硬扣。如果你不想查看这个过程的话,可以直接略过。
js扣代码环节
根据我们上边的一些记录我们现在需要做的是,刷新网页,重新打开浏览器,执行一遍这个过程,看看有哪些是固定的。
可以确定r["a"]是没有改变,我们直接搜索这个值看一下有没有
存在,所以现在我们就知道这个过程了,他是将一个请求头t当作参数传递给d在d函数中,通过一个常量和一个加密后的数据进行拼接,然后使用MD5进行加密。
现在开始着手扣第一步代码,得到加密后的n
我喜欢使用html来验证js代码是否完整,所以这里我使用的html讲解
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
function s(t, e) {
return t.toString().toUpperCase() > e.toString().toUpperCase() ? 1 : t.toString().toUpperCase() == e.toString().toUpperCase() ? 0 : -1
}
function l(t) {
for (var e = Object.keys(t).sort(s), n = "", a = 0; a < e.length; a++)
if (void 0 !== t[e[a]])
if (t[e[a]] && t[e[a]]instanceof Object || t[e[a]]instanceof Array) {
var i = JSON.stringify(t[e[a]]);
n += e[a] + i
} else
n += e[a] + t[e[a]];
return n
}
function d(t) {
for (var e in t)
"" !== t[e] && void 0 !== t[e] || delete t[e];
var n = "B3978D054A72A7002063637CCDF6B2E5" + l(t);
console.log(n)
return u(n).toLocaleLowerCase()
}
t = {
"ts": 1702288385369,
"type": "12",
"IS_IMPORT": 1,
"pageSize": 3
}
d(t)
</script>
</body>
</html>
出现的错误是因为没有找到u(n),我们可以发现已经出现拼接好的n了,那么我们可以确定的是,代码已经成功了一步。
现在开始着手MD5加密环节
进入之后,会返回一个new对象,所以直接将u(n)部分替换
替换的代码
function d(t) {
for (var e in t)
"" !== t[e] && void 0 !== t[e] || delete t[e];
var n = "B3978D054A72A7002063637CCDF6B2E5" + l(t);
console.log(n)
return new Md5(!0).update(n)[t]()
接下来就i是把整个md5扣下来了
联立前面的代码,我们可以直接放到html中,观察。
这边md5我就不单独放出来了,不然我写着是真的卡
出现错误:找不到这个blocks,那么开始在代码中找这个定义
还顺带找到了buffers,直接拷贝到文件中。
出现错误
直接在浏览器中打印,是一个ture
直接填写,然后在代码中替换。
现在又出现缺少
我们发现是创建函数出了问题,里面少了一个参数t,直接根据提示,发现是一个字符串,在代码中补全。
现在缺少了一个EXTRA
开始找位置,然后补全,在这个位置,直接复制下来
继续找
找到,然后复制下来。
现在没有报错,我们试一下结果对不对。。
完美解决,所以此时我们已经得到了这个正确的js代码,只需要将参数中的ts更改成当前的请求时间戳就行,
这里贴上html代码,你只需要把js部分复制修改即可
1
我们来处理一下此时的python请求,先把第一步确定好。
第一步请求的python代码
import requests
import execjs
ts = int(execjs.compile(open('D:/桌面/pythoncode/new.js', 'r', encoding='utf-8').read()).call('gettime'))
json_data = {
'pageNo': 1,
'pageSize': 40,
'total': 5770,
'AREACODE': '',
'M_PROJECT_TYPE': '',
'KIND': 'GCJS',
'GGTYPE': '1',
'PROTYPE': '',
'timeType': '6',
'BeginTime': '2022-07-18 00:00:00',
'EndTime': '2023-01-18 23:59:59',
'createTime': [],
'ts': ts,
}
sign = str(execjs.compile(open('D:/桌面/pythoncode/new.js', 'r', encoding='utf-8').read()).call('main',json_data))
print(sign)
headers = {
'Accept': 'application/json, text/plain, */*',
'Accept-Language': 'zh-CN,zh;q=0.9,zh-TW;q=0.8,en;q=0.7',
'Connection': 'keep-alive',
'Content-Type': 'application/json;charset=UTF-8',
'Origin': 'https://ggzyfw.fujian.gov.cn',
'Referer': 'https://ggzyfw.fujian.gov.cn/business/list/',
'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/108.0.0.0 Safari/537.36',
'portal-sign': sign,
'sec-ch-ua': '"Not?A_Brand";v="8", "Chromium";v="108", "Google Chrome";v="108"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"Windows"',
}
response = requests.post('https://ggzyfw.fujian.gov.cn/FwPortalApi/Trade/TradeInfo', headers=headers, json=json_data).json()
print(response)
得到请求头加密参数
HEX_CHARS = "0123456789abcdef".split("")
EXTRA = [128, 32768, 8388608, -2147483648]
var buffer = new ArrayBuffer(68);
buffer8 = new Uint8Array(buffer),
blocks = new Uint32Array(buffer)
function Md5(t) {
if (t)
blocks[0] = blocks[16] = blocks[1] = blocks[2] = blocks[3] = blocks[4] = blocks[5] = blocks[6] = blocks[7] = blocks[8] = blocks[9] = blocks[10] = blocks[11] = blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0,
this.blocks = blocks,
this.buffer8 = buffer8;
else if (true) {
var n = new ArrayBuffer(68);
this.buffer8 = new Uint8Array(n),
this.blocks = new Uint32Array(n)
} else
this.blocks = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
this.h0 = this.h1 = this.h2 = this.h3 = this.start = this.bytes = this.hBytes = 0,
this.finalized = this.hashed = !1,
this.first = !0
}
Md5.prototype.update = function (t) {
if (!this.finalized) {
var n, e = typeof t;
if ("string" !== e) {
if ("object" !== e)
throw ERROR;
if (null === t)
throw ERROR;
if (true && t.constructor === ArrayBuffer)
t = new Uint8Array(t);
else if (!Array.isArray(t) && (!true || !ArrayBuffer.isView(t)))
throw ERROR;
n = !0
}
var r, i, o = 0, c = t.length, A = this.blocks, a = this.buffer8;
while (o < c) {
if (this.hashed && (this.hashed = !1,
A[0] = A[16],
A[16] = A[1] = A[2] = A[3] = A[4] = A[5] = A[6] = A[7] = A[8] = A[9] = A[10] = A[11] = A[12] = A[13] = A[14] = A[15] = 0),
n)
if (true)
for (i = this.start; o < c && i < 64; ++o)
a[i++] = t[o];
else
for (i = this.start; o < c && i < 64; ++o)
A[i >> 2] |= t[o] << SHIFT[3 & i++];
else if (true)
for (i = this.start; o < c && i < 64; ++o)
r = t.charCodeAt(o),
r < 128 ? a[i++] = r : r < 2048 ? (a[i++] = 192 | r >> 6,
a[i++] = 128 | 63 & r) : r < 55296 || r >= 57344 ? (a[i++] = 224 | r >> 12,
a[i++] = 128 | r >> 6 & 63,
a[i++] = 128 | 63 & r) : (r = 65536 + ((1023 & r) << 10 | 1023 & t.charCodeAt(++o)),
a[i++] = 240 | r >> 18,
a[i++] = 128 | r >> 12 & 63,
a[i++] = 128 | r >> 6 & 63,
a[i++] = 128 | 63 & r);
else
for (i = this.start; o < c && i < 64; ++o)
r = t.charCodeAt(o),
r < 128 ? A[i >> 2] |= r << SHIFT[3 & i++] : r < 2048 ? (A[i >> 2] |= (192 | r >> 6) << SHIFT[3 & i++],
A[i >> 2] |= (128 | 63 & r) << SHIFT[3 & i++]) : r < 55296 || r >= 57344 ? (A[i >> 2] |= (224 | r >> 12) << SHIFT[3 & i++],
A[i >> 2] |= (128 | r >> 6 & 63) << SHIFT[3 & i++],
A[i >> 2] |= (128 | 63 & r) << SHIFT[3 & i++]) : (r = 65536 + ((1023 & r) << 10 | 1023 & t.charCodeAt(++o)),
A[i >> 2] |= (240 | r >> 18) << SHIFT[3 & i++],
A[i >> 2] |= (128 | r >> 12 & 63) << SHIFT[3 & i++],
A[i >> 2] |= (128 | r >> 6 & 63) << SHIFT[3 & i++],
A[i >> 2] |= (128 | 63 & r) << SHIFT[3 & i++]);
this.lastByteIndex = i,
this.bytes += i - this.start,
i >= 64 ? (this.start = i - 64,
this.hash(),
this.hashed = !0) : this.start = i
}
return this.bytes > 4294967295 && (this.hBytes += this.bytes / 4294967296 << 0,
this.bytes = this.bytes % 4294967296),
this
}
}
,
Md5.prototype.finalize = function () {
if (!this.finalized) {
this.finalized = !0;
var t = this.blocks
, n = this.lastByteIndex;
t[n >> 2] |= EXTRA[3 & n],
n >= 56 && (this.hashed || this.hash(),
t[0] = t[16],
t[16] = t[1] = t[2] = t[3] = t[4] = t[5] = t[6] = t[7] = t[8] = t[9] = t[10] = t[11] = t[12] = t[13] = t[14] = t[15] = 0),
t[14] = this.bytes << 3,
t[15] = this.hBytes << 3 | this.bytes >>> 29,
this.hash()
}
}
,
Md5.prototype.hash = function () {
var t, n, e, r, i, o, c = this.blocks;
this.first ? (t = c[0] - 680876937,
t = (t << 7 | t >>> 25) - 271733879 << 0,
r = (-1732584194 ^ 2004318071 & t) + c[1] - 117830708,
r = (r << 12 | r >>> 20) + t << 0,
e = (-271733879 ^ r & (-271733879 ^ t)) + c[2] - 1126478375,
e = (e << 17 | e >>> 15) + r << 0,
n = (t ^ e & (r ^ t)) + c[3] - 1316259209,
n = (n << 22 | n >>> 10) + e << 0) : (t = this.h0,
n = this.h1,
e = this.h2,
r = this.h3,
t += (r ^ n & (e ^ r)) + c[0] - 680876936,
t = (t << 7 | t >>> 25) + n << 0,
r += (e ^ t & (n ^ e)) + c[1] - 389564586,
r = (r << 12 | r >>> 20) + t << 0,
e += (n ^ r & (t ^ n)) + c[2] + 606105819,
e = (e << 17 | e >>> 15) + r << 0,
n += (t ^ e & (r ^ t)) + c[3] - 1044525330,
n = (n << 22 | n >>> 10) + e << 0),
t += (r ^ n & (e ^ r)) + c[4] - 176418897,
t = (t << 7 | t >>> 25) + n << 0,
r += (e ^ t & (n ^ e)) + c[5] + 1200080426,
r = (r << 12 | r >>> 20) + t << 0,
e += (n ^ r & (t ^ n)) + c[6] - 1473231341,
e = (e << 17 | e >>> 15) + r << 0,
n += (t ^ e & (r ^ t)) + c[7] - 45705983,
n = (n << 22 | n >>> 10) + e << 0,
t += (r ^ n & (e ^ r)) + c[8] + 1770035416,
t = (t << 7 | t >>> 25) + n << 0,
r += (e ^ t & (n ^ e)) + c[9] - 1958414417,
r = (r << 12 | r >>> 20) + t << 0,
e += (n ^ r & (t ^ n)) + c[10] - 42063,
e = (e << 17 | e >>> 15) + r << 0,
n += (t ^ e & (r ^ t)) + c[11] - 1990404162,
n = (n << 22 | n >>> 10) + e << 0,
t += (r ^ n & (e ^ r)) + c[12] + 1804603682,
t = (t << 7 | t >>> 25) + n << 0,
r += (e ^ t & (n ^ e)) + c[13] - 40341101,
r = (r << 12 | r >>> 20) + t << 0,
e += (n ^ r & (t ^ n)) + c[14] - 1502002290,
e = (e << 17 | e >>> 15) + r << 0,
n += (t ^ e & (r ^ t)) + c[15] + 1236535329,
n = (n << 22 | n >>> 10) + e << 0,
t += (e ^ r & (n ^ e)) + c[1] - 165796510,
t = (t << 5 | t >>> 27) + n << 0,
r += (n ^ e & (t ^ n)) + c[6] - 1069501632,
r = (r << 9 | r >>> 23) + t << 0,
e += (t ^ n & (r ^ t)) + c[11] + 643717713,
e = (e << 14 | e >>> 18) + r << 0,
n += (r ^ t & (e ^ r)) + c[0] - 373897302,
n = (n << 20 | n >>> 12) + e << 0,
t += (e ^ r & (n ^ e)) + c[5] - 701558691,
t = (t << 5 | t >>> 27) + n << 0,
r += (n ^ e & (t ^ n)) + c[10] + 38016083,
r = (r << 9 | r >>> 23) + t << 0,
e += (t ^ n & (r ^ t)) + c[15] - 660478335,
e = (e << 14 | e >>> 18) + r << 0,
n += (r ^ t & (e ^ r)) + c[4] - 405537848,
n = (n << 20 | n >>> 12) + e << 0,
t += (e ^ r & (n ^ e)) + c[9] + 568446438,
t = (t << 5 | t >>> 27) + n << 0,
r += (n ^ e & (t ^ n)) + c[14] - 1019803690,
r = (r << 9 | r >>> 23) + t << 0,
e += (t ^ n & (r ^ t)) + c[3] - 187363961,
e = (e << 14 | e >>> 18) + r << 0,
n += (r ^ t & (e ^ r)) + c[8] + 1163531501,
n = (n << 20 | n >>> 12) + e << 0,
t += (e ^ r & (n ^ e)) + c[13] - 1444681467,
t = (t << 5 | t >>> 27) + n << 0,
r += (n ^ e & (t ^ n)) + c[2] - 51403784,
r = (r << 9 | r >>> 23) + t << 0,
e += (t ^ n & (r ^ t)) + c[7] + 1735328473,
e = (e << 14 | e >>> 18) + r << 0,
n += (r ^ t & (e ^ r)) + c[12] - 1926607734,
n = (n << 20 | n >>> 12) + e << 0,
i = n ^ e,
t += (i ^ r) + c[5] - 378558,
t = (t << 4 | t >>> 28) + n << 0,
r += (i ^ t) + c[8] - 2022574463,
r = (r << 11 | r >>> 21) + t << 0,
o = r ^ t,
e += (o ^ n) + c[11] + 1839030562,
e = (e << 16 | e >>> 16) + r << 0,
n += (o ^ e) + c[14] - 35309556,
n = (n << 23 | n >>> 9) + e << 0,
i = n ^ e,
t += (i ^ r) + c[1] - 1530992060,
t = (t << 4 | t >>> 28) + n << 0,
r += (i ^ t) + c[4] + 1272893353,
r = (r << 11 | r >>> 21) + t << 0,
o = r ^ t,
e += (o ^ n) + c[7] - 155497632,
e = (e << 16 | e >>> 16) + r << 0,
n += (o ^ e) + c[10] - 1094730640,
n = (n << 23 | n >>> 9) + e << 0,
i = n ^ e,
t += (i ^ r) + c[13] + 681279174,
t = (t << 4 | t >>> 28) + n << 0,
r += (i ^ t) + c[0] - 358537222,
r = (r << 11 | r >>> 21) + t << 0,
o = r ^ t,
e += (o ^ n) + c[3] - 722521979,
e = (e << 16 | e >>> 16) + r << 0,
n += (o ^ e) + c[6] + 76029189,
n = (n << 23 | n >>> 9) + e << 0,
i = n ^ e,
t += (i ^ r) + c[9] - 640364487,
t = (t << 4 | t >>> 28) + n << 0,
r += (i ^ t) + c[12] - 421815835,
r = (r << 11 | r >>> 21) + t << 0,
o = r ^ t,
e += (o ^ n) + c[15] + 530742520,
e = (e << 16 | e >>> 16) + r << 0,
n += (o ^ e) + c[2] - 995338651,
n = (n << 23 | n >>> 9) + e << 0,
t += (e ^ (n | ~r)) + c[0] - 198630844,
t = (t << 6 | t >>> 26) + n << 0,
r += (n ^ (t | ~e)) + c[7] + 1126891415,
r = (r << 10 | r >>> 22) + t << 0,
e += (t ^ (r | ~n)) + c[14] - 1416354905,
e = (e << 15 | e >>> 17) + r << 0,
n += (r ^ (e | ~t)) + c[5] - 57434055,
n = (n << 21 | n >>> 11) + e << 0,
t += (e ^ (n | ~r)) + c[12] + 1700485571,
t = (t << 6 | t >>> 26) + n << 0,
r += (n ^ (t | ~e)) + c[3] - 1894986606,
r = (r << 10 | r >>> 22) + t << 0,
e += (t ^ (r | ~n)) + c[10] - 1051523,
e = (e << 15 | e >>> 17) + r << 0,
n += (r ^ (e | ~t)) + c[1] - 2054922799,
n = (n << 21 | n >>> 11) + e << 0,
t += (e ^ (n | ~r)) + c[8] + 1873313359,
t = (t << 6 | t >>> 26) + n << 0,
r += (n ^ (t | ~e)) + c[15] - 30611744,
r = (r << 10 | r >>> 22) + t << 0,
e += (t ^ (r | ~n)) + c[6] - 1560198380,
e = (e << 15 | e >>> 17) + r << 0,
n += (r ^ (e | ~t)) + c[13] + 1309151649,
n = (n << 21 | n >>> 11) + e << 0,
t += (e ^ (n | ~r)) + c[4] - 145523070,
t = (t << 6 | t >>> 26) + n << 0,
r += (n ^ (t | ~e)) + c[11] - 1120210379,
r = (r << 10 | r >>> 22) + t << 0,
e += (t ^ (r | ~n)) + c[2] + 718787259,
e = (e << 15 | e >>> 17) + r << 0,
n += (r ^ (e | ~t)) + c[9] - 343485551,
n = (n << 21 | n >>> 11) + e << 0,
this.first ? (this.h0 = t + 1732584193 << 0,
this.h1 = n - 271733879 << 0,
this.h2 = e - 1732584194 << 0,
this.h3 = r + 271733878 << 0,
this.first = !1) : (this.h0 = this.h0 + t << 0,
this.h1 = this.h1 + n << 0,
this.h2 = this.h2 + e << 0,
this.h3 = this.h3 + r << 0)
}
,
Md5.prototype.hex = function () {
this.finalize();
var t = this.h0
, n = this.h1
, e = this.h2
, r = this.h3;
return HEX_CHARS[t >> 4 & 15] + HEX_CHARS[15 & t] + HEX_CHARS[t >> 12 & 15] + HEX_CHARS[t >> 8 & 15] + HEX_CHARS[t >> 20 & 15] + HEX_CHARS[t >> 16 & 15] + HEX_CHARS[t >> 28 & 15] + HEX_CHARS[t >> 24 & 15] + HEX_CHARS[n >> 4 & 15] + HEX_CHARS[15 & n] + HEX_CHARS[n >> 12 & 15] + HEX_CHARS[n >> 8 & 15] + HEX_CHARS[n >> 20 & 15] + HEX_CHARS[n >> 16 & 15] + HEX_CHARS[n >> 28 & 15] + HEX_CHARS[n >> 24 & 15] + HEX_CHARS[e >> 4 & 15] + HEX_CHARS[15 & e] + HEX_CHARS[e >> 12 & 15] + HEX_CHARS[e >> 8 & 15] + HEX_CHARS[e >> 20 & 15] + HEX_CHARS[e >> 16 & 15] + HEX_CHARS[e >> 28 & 15] + HEX_CHARS[e >> 24 & 15] + HEX_CHARS[r >> 4 & 15] + HEX_CHARS[15 & r] + HEX_CHARS[r >> 12 & 15] + HEX_CHARS[r >> 8 & 15] + HEX_CHARS[r >> 20 & 15] + HEX_CHARS[r >> 16 & 15] + HEX_CHARS[r >> 28 & 15] + HEX_CHARS[r >> 24 & 15]
}
,
Md5.prototype.toString = Md5.prototype.hex,
Md5.prototype.digest = function () {
this.finalize();
var t = this.h0
, n = this.h1
, e = this.h2
, r = this.h3;
return [255 & t, t >> 8 & 255, t >> 16 & 255, t >> 24 & 255, 255 & n, n >> 8 & 255, n >> 16 & 255, n >> 24 & 255, 255 & e, e >> 8 & 255, e >> 16 & 255, e >> 24 & 255, 255 & r, r >> 8 & 255, r >> 16 & 255, r >> 24 & 255]
}
,
Md5.prototype.array = Md5.prototype.digest,
Md5.prototype.arrayBuffer = function () {
this.finalize();
var t = new ArrayBuffer(16)
, n = new Uint32Array(t);
return n[0] = this.h0,
n[1] = this.h1,
n[2] = this.h2,
n[3] = this.h3,
t
}
,
Md5.prototype.buffer = Md5.prototype.arrayBuffer,
Md5.prototype.base64 = function () {
for (var t, n, e, r = "", i = this.array(), o = 0; o < 15;)
t = i[o++],
n = i[o++],
e = i[o++],
r += BASE64_ENCODE_CHAR[t >>> 2] + BASE64_ENCODE_CHAR[63 & (t << 4 | n >>> 4)] + BASE64_ENCODE_CHAR[63 & (n << 2 | e >>> 6)] + BASE64_ENCODE_CHAR[63 & e];
return t = i[o],
r += BASE64_ENCODE_CHAR[t >>> 2] + BASE64_ENCODE_CHAR[t << 4 & 63] + "==",
r
}
function s(t, e) {
return t.toString().toUpperCase() > e.toString().toUpperCase() ? 1 : t.toString().toUpperCase() == e.toString().toUpperCase() ? 0 : -1
}
function l(t) {
for (var e = Object.keys(t).sort(s), n = "", a = 0; a < e.length; a++)
if (void 0 !== t[e[a]])
if (t[e[a]] && t[e[a]] instanceof Object || t[e[a]] instanceof Array) {
var i = JSON.stringify(t[e[a]]);
n += e[a] + i
} else
n += e[a] + t[e[a]];
return n
}
function d(t) {
for (var e in t)
"" !== t[e] && void 0 !== t[e] || delete t[e];
var n = "B3978D054A72A7002063637CCDF6B2E5" + l(t);
return new Md5(!0).update(n)['hex']()
}
function gettime(){
d1 = ((new Date).getTime())
return d1
}
function main(dictData) {
return d(dictData)
}
准备解决得到的加密数据。
这个纯靠经验,直接搜索,decrypt(),这个东西是js的一种解密的密钥
出现两个,我们现在先看第一个。
打断点调试
执行到这个位置的时候,我们输出一下a.tostring(),主要还是t的数据格式格式跟返回的data太像了
发现,这个结果是我们需要的数据
直接复制这段函数,使用crypto-js,来模拟一下检查是不是aes的(名字中存在)
将缺少的参数补上,这里还是控制台输出r["e"] r["j"]
返回参数解密
const Crypto = require('crypto-js')
var c = 'EB444973714E4A40876CE66BE45D5930'
var b = 'B5A8904209931867'
function decrypt(t) {
var e = Crypto.enc.Utf8.parse(c)
, n = Crypto.enc.Utf8.parse(b)
, a = Crypto.AES.decrypt(t, e, {
iv: n,
mode: Crypto.mode.CBC,
padding: Crypto.pad.Pkcs7
});
return a.toString(Crypto.enc.Utf8)
}
我们可以发现返回值符合预期结果,所以这个js文件处理加密的数据是正确的
最终的py代码
import requests
import execjs
ts = int(execjs.compile(open('D:\桌面\pythoncode\得到加密参数.js', 'r', encoding='utf-8').read()).call('gettime'))
json_data = {
'pageNo': 1,
'pageSize': 40,
'total': 5770,
'AREACODE': '',
'M_PROJECT_TYPE': '',
'KIND': 'GCJS',
'GGTYPE': '1',
'PROTYPE': '',
'timeType': '6',
'BeginTime': '2022-07-18 00:00:00',
'EndTime': '2023-01-18 23:59:59',
'createTime': [],
'ts': ts,
}
sign = str(execjs.compile(open('D:\桌面\pythoncode\得到加密参数.js', 'r', encoding='utf-8').read()).call('main',json_data))
print(sign)
headers = {
'Accept': 'application/json, text/plain, */*',
'Accept-Language': 'zh-CN,zh;q=0.9,zh-TW;q=0.8,en;q=0.7',
'Connection': 'keep-alive',
'Content-Type': 'application/json;charset=UTF-8',
'Origin': 'https://ggzyfw.fujian.gov.cn',
'Referer': 'https://ggzyfw.fujian.gov.cn/business/list/',
'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/108.0.0.0 Safari/537.36',
'portal-sign': sign,
'sec-ch-ua': '"Not?A_Brand";v="8", "Chromium";v="108", "Google Chrome";v="108"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"Windows"',
}
response = requests.post('https://ggzyfw.fujian.gov.cn/FwPortalApi/Trade/TradeInfo', headers=headers, json=json_data).json()
data = response["Data"]
ctx = execjs.compile(open('D:\桌面\pythoncode\解密得到的数据.js', 'r', encoding='utf-8').read()).call('decrypt', data)
print(ctx)
效果展示
批量下载只需要修改参数即可,留个赞!