https://www.mps.gov.cn/n2254098/n4904352/index.html

直接访问的话,返回的是一段js代码,主要是对cookie进行赋值

直接复制出来,到控制台执行

执行的结果先不管,我们这次逆向的目标,主要是cookies中两个值的生成

其中,__jsluid_s 是第一次请求的时候服务器返回的

__jsl_clearance_s 会不会是第一次返回的那段js执行后的结果呢?对比一下:

1
2
3
4
5
# 执行结果
__jsl_clearance_s=1654493484.607|-1|eU3CZr0IIIZOWUJfz3vNntOeewo%3D

# cookies
__jsl_clearance_s=1654493484.979|0|70p4p0lk5rF59kkzj6oslUuf8Qk%3D

看来不是,如果那么简单我也不会写这篇博客了 😬

还是看一下抓包,第二次请求的时候也返回了一段js

注意到开头是一段大数组,很明显的ob混淆的特诊,先解一下混淆:

复制结果放到浏览器执行,跳到代码最后:

可以确定,就是最后的go函数,对cookie进行了修改,那就先进入函数内部加密逻辑理清

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function _0x3ee693() {
var window_userAgent = window.navigator.userAgent;
var _0x459673 = ["Phantom"];
for (var index = 0; index < _0x459673["length"]; index++) {
if (window_userAgent.indexOf(_0x459673[index]) != -1) {
return true;
}
}
if (window.callPhantom || window._phantom || window.Headless || window.navigator.webdriver || window.navigator.__driver_evaluate || window.navigator.__webdriver_evaluate) {
return true;
}
}
;
if (_0x3ee693()) {
return;
}

这里主要是检测是否使用了 phantom 和 webdriver的,直接不管跳过

最重要的是后面这一句,对cookie进行了修改

1
document.cookie = _0x463d2c.tn + "=" + _0x59651f[0] + ";Max-age=" + _0x463d2c.vt + "; path = /";

分析一下,_0x463d2c 是开头传入的那一个大字典,所以 tn 和 vt 的值都可以确定

_0x59651f[0] 则是由下面的代码生成:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var date = new Date();
function _0x14f692(_0x59297c, _0x117587) {
var _length = _0x463d2c.chars.length;
for (var index = 0; index < _length; index++) {
for (var index = 0; index < _length; index++) {
var _0x428069 = _0x117587[0] + _0x463d2c.chars.substr(index, 1) + _0x463d2c.chars.substr(index, 1) + _0x117587[1];
if (hash(_0x428069) == _0x59297c) {
return [
_0x428069,
new Date() - date
];
}
}
}
}
;
var _0x59651f = _0x14f692(_0x463d2c.ct, _0x463d2c.bts);

这一段好像没什么好讲的,就是传入 ct bts两个参数给 _0x14f692函数,然后拿到返回结果,由两个地方需要注意:

  • substr(start, length) 主要用来截取子字符串,比如

    1
    2
    3
    4
    "cxs".substr(1, 2)
    >>> 'xs'
    "cxs".substr(0, 2)
    >>> 'cx'
  • if (hash(_0x428069) == _0x59297c) 中 hash函数已经在字典中指定了哈希算法,这里的话就是 sha256,不过每次返回都是不同的,经过多次测算,网站总共使用了三种哈希算法:md5 sha1 和 sha256

代码整理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
import json
import re

from urllib.parse import urljoin
import execjs
import js2py
import requests
from hashlib import md5, sha1, sha256

session = requests.session()
default_headers = {
"Accept-Language": "zh-CN,zh;q=0.9",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36",
"Accept-Encoding": "gzip, deflate, br",
}
session.headers.update(default_headers)


def go(params):
chars = params["chars"]
if params["ha"] == "md5":
hash_md = md5
elif params["ha"] == "sha1":
hash_md = sha1
elif params["ha"] == "sha256":
hash_md = sha256

def _0x179e62(bts, ct):
char_len = len(chars)
for i in range(char_len):
for j in range(char_len):
_0x3b8d5f = bts[0] + chars[i] + chars[j] + bts[1]
hash_val = hash_md(bytes(_0x3b8d5f, encoding="utf-8")).hexdigest()
if hash_val == ct:
return _0x3b8d5f

_0x3d9242 = _0x179e62(params["bts"], params["ct"])
return _0x3d9242


def get_jsl_cl1(html_text):
js_script1 = re.search(r"cookie=(.+);location", html_text).group(1)
# jsl_cl = js2py.eval_js(js_script1)
jsl_cl = execjs.eval(js_script1)
jsl_cl_s = re.search("_s=(.+?);", jsl_cl).group(1)
return jsl_cl_s


def get_jsl_cl2(html_text):
params_txt = re.search(r";go\((.+?)\)</script>", html_text).group(1)
params = json.loads(params_txt)
jsl_cl_s = go(params)
return jsl_cl_s


def main():
url = "https://www.mps.gov.cn/n2254098/n4904352/index.html"
html1 = session.get(url).text
jsl_cl_s = get_jsl_cl1(html1)
session.cookies.update({"__jsl_clearance_s": jsl_cl_s})
html2 = session.get(url).text
jsl_cl_s = get_jsl_cl2(html2)
session.cookies.update({"__jsl_clearance_s": jsl_cl_s})
print(session.get(url).content.decode())


if __name__ == "__main__":
main()