案例-中国观鸟记录中心
网址: http://birdreport.cn/
抓包:只有一个请求:

看到这三个应该需要逆向


参数也是需要逆向的


两次请求发现requestId、sign 发生了变化,两次不一样

搜索requestId,找到一个关键字 eval

复制下来,放在console 中的小括号中:

可以看到运行的内容:

下面是eval运行后的内容:注意看到 ajaxSetup ,这是ajax的一个设置,是jquery提供的一个功能。

所以在启动器中,在ajax中可以找到调用上面的代码。

点击进去ajax,来到下面界面

在发送ajax之前有这样的内容:beforeSend.call 会执行之前设置ajax的内容

在这设置断点:

运行到断点出,然后看到这个函数

点进去就可以来到这里:

发送的请求参数:



可以看到这个md5函数是一个标准的md5:

解密:

点进去

来到解密函数:


python代码:
import subprocess
from functools import partial
subprocess.Popen = partial(subprocess.Popen, encoding="utf-8")
import execjs
import requests
import json
from urllib.parse import urlencode, quote
f = open("看鸟.js", mode='r', encoding="utf-8")
js_code = f.read()
f.close()
js = execjs.compile(js_code)
data = {
"city": "",
"ctime": "",
"district": "",
"endTime": "",
"limit": "20",
"mode": "0",
"outside_type": "0",
"page": "4",
"pointname": "",
"province": "青海省",
"serial_id": "",
"startTime": "",
"state": "",
"taxonid": "",
"taxonname": "",
"username": "",
}
# 直接把字典转化成 "city=&ctime=&district=&endTime="
encoded = urlencode(data)
print(encoded)
ret = js.call("get_headers", encoded)
print(ret)
# 发请求看结果.
url = "https://api.birdreport.cn/front/record/activity/search"
headers = ret['headers']
proxy = {
"http": "http://127.0.0.1:8888",
"https": "http://127.0.0.1:8888",
}
session = requests.session()
session.headers = headers
session.headers['User-Agent'] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36"
session.headers['Referer'] = "http://www.birdreport.cn/"
# 这个破东西坑了半天了....
session.headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8'
# 直接传数据. 即可.
resp = session.post(url, data=ret['data'], proxies=proxy, verify=False)
print(resp.request.headers)
print(resp.text)
看鸟.js
var JSEncrypt = require("node-jsencrypt");
var crypto = require("crypto");
function getUuid() {
var s = [];
var a = "0123456789abcdef";
for (var i = 0; i < 32; i++) {
s[i] = a.substr(Math.floor(Math.random() * 0x10), 1)
}
s[14] = "4";
s[19] = a.substr((s[19] & 0x3) | 0x8, 1);
s[8] = s[13] = s[18] = s[23];
var b = s.join("");
return b
}
function sort_ASCII(a) {
var b = new Array();
var c = 0;
for (var i in a) {
b[c] = i;
c++
}
var d = b.sort();
var e = {};
for (var i in d) {
e[d[i]] = a[d[i]]
}
return e
}
function dataTojson(a) {
var b = [];
var c = {};
b = a.split('&');
for (var i = 0; i < b.length; i++) {
if (b[i].indexOf('=') != -1) {
var d = b[i].split('=');
if (d.length == 2) {
c[d[0]] = d[1]
} else {
c[d[0]] = ""
}
} else {
c[b[i]] = ''
}
}
return c
}
var paramPublicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCvxXa98E1uWXnBzXkS2yHUfnBM6n3PCwLdfIox03T91joBvjtoDqiQ5x3tTOfpHs3LtiqMMEafls6b0YWtgB1dse1W5m+FpeusVkCOkQxB4SZDH6tuerIknnmB/Hsq5wgEkIvO5Pff9biig6AyoAkdWpSek/1/B7zYIepYY0lxKQIDAQAB";
var encrypt = new JSEncrypt();
encrypt.setPublicKey(paramPublicKey);
function get_headers(b) {
var c = Date.parse(new Date());
var d = getUuid();
var e = JSON.stringify(sort_ASCII(dataTojson(b || '{}')));
b = encrypt.encryptUnicodeLong(e); // 在node-jsencrypt里面没有.
//
var f = crypto.createHash("md5").update(e + d + c).digest('hex');
return {
"headers": {
timestamp: c +"",
requestId: d,
sign: f
},
"data": b
}
}
//
console.log(get_headers("city=&ctime=&district=&endTime=&limit=20&mode=0&outside_type=0&page=4&pointname=&province=%E9%9D%92%E6%B5%B7%E7%9C%81&serial_id=&startTime=&state=&taxonid=&taxonname=&username="))
// 'page=4&limit=20&taxonid=&startTime=&endTime=&province=%E9%9D%92%E6%B5%B7%E7%9C%81&city=&district=&pointname=&username=&serial_id=&ctime=&taxonname=&state=&mode=0&outside_type=0'
浙公网安备 33010602011771号