JS逆向基础
一、什么是JS逆向?
我们在网站进行账号登录的时候对网页源进行抓包就会发现我们输入的密码在后台会显示为一串由字母或数字等符号,这就是经过加密呈现的一段加密文字,而分析这些接口的加密算法并实现模拟调用的过程就叫做「逆向」。
逆向对于爬虫说是一个永远绕不开的话题,而我们所做的解密工作,通过解密步骤得到密码的过程,称为JS逆向。
我们将通过一个简单的案例来讲解JS的分析思路。
二、接口抓包
首先我们先点击网站的的登陆页面,打开网站的控制台,点击1(网络),再点击2(fetch/XHR),然后再点击3(清空信息),我们在进行输入(4)账号密码和验证码,为了教学,故意输错密码,点击登录,控制台跳出6(登陆包),在其中可以获取Signature(7)
点击1,在点击2,即可出现搜索页面(3),我们将Signature输入,即可获取Signature在网页源代码中的生成函数
可知3即为需要逆向分析的数据
三、逆向分析
U.Signature = Object(f.a)(U, M, l.j ? l.g : l.c);
按照下图操作获取Object(f.a)函数和U,M,和 l.j ? l.g : l.c的值
将代码复制到js文件中,运行代码报错,提示找不到f函数,将代码中相关函数全部复制
源码
js
l = {
key: cryptoJs.enc.Utf8.parse("fX@VyCQVvpdj8RCa"),
iv: cryptoJs.enc.Utf8.parse(function (t) {
for (var e = "", i = 0; i < t.length - 1; i += 2) {
var n = parseInt(t[i] + "" + t[i + 1], 16);
e += String.fromCharCode(n)
}
return e
}("00000000000000000000000000000000"))
}
, v = function (data) {
return function (data) {
return cryptoJs.AES.encrypt(data, l.key, {
iv: l.iv,
mode: cryptoJs.mode.CBC,
padding: cryptoJs.pad.Pkcs7
}).toString()
}(data)
}
, d = function (data) {
return cryptoJs.MD5(data).toString()
}
, f = function (t) {
var e = "";
return Object.keys(t).sort().forEach((function (n) {
e += n + ("object" === typeof (t[n]) ? JSON.stringify(t[n], (function (t, e) {
return "number" == typeof e && (e = String(e)),
e
}
)).replace(/\//g, "\\/") : t[n])
}
)),
e
}
h = function (t) {
var data = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}
, e = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : "a75846eb4ac490420ac63db46d2a03bf"
, n = e + f(data) + f(t) + e;
return n = d(n),
n = v(n)
}
U = {
"App-Ver": "",
"Os-Ver": "",
"Device-Ver": "",
"Imei": "",
"Access-Token": "",
"Timestemp": 1700571511,
"NonceStr": "170057151176dni",
"App-Id": "4ac490420ac63db4",
"Device-Os": "web"
};
let L = {
"username": "qweqweqeqweqwe",
"password": "qweqweqweqweqwe",
"code": "65xv",
"hdn_refer": "https://www.epwk.com/"
};
C = 'a75846eb4ac490420ac63db46d2a03bf'
console.log(h(U, L, C))
又报错
导入crypto-js库替换o函数
const cryptoJs = require("crypto-js")
js
const cryptoJs = require("crypto-js")
l = {
key: cryptoJs.enc.Utf8.parse("fX@VyCQVvpdj8RCa"),
iv: cryptoJs.enc.Utf8.parse(function (t) {
for (var e = "", i = 0; i < t.length - 1; i += 2) {
var n = parseInt(t[i] + "" + t[i + 1], 16);
e += String.fromCharCode(n)
}
return e
}("00000000000000000000000000000000"))
}
, v = function (data) {
return function (data) {
return cryptoJs.AES.encrypt(data, l.key, {
iv: l.iv,
mode: cryptoJs.mode.CBC,
padding: cryptoJs.pad.Pkcs7
}).toString()
}(data)
}
, d = function (data) {
return cryptoJs.MD5(data).toString()
}
, f = function (t) {
var e = "";
return Object.keys(t).sort().forEach((function (n) {
e += n + ("object" === typeof (t[n]) ? JSON.stringify(t[n], (function (t, e) {
return "number" == typeof e && (e = String(e)),
e
}
)).replace(/\//g, "\\/") : t[n])
}
)),
e
}
h = function (t) {
var data = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}
, e = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : "a75846eb4ac490420ac63db46d2a03bf"
, n = e + f(data) + f(t) + e;
return n = d(n),
n = v(n)
}
U = {
"App-Ver": "",
"Os-Ver": "",
"Device-Ver": "",
"Imei": "",
"Access-Token": "",
"Timestemp": 1700571511,
"NonceStr": "170057151176dni",
"App-Id": "4ac490420ac63db4",
"Device-Os": "web"
};
let L = {
"username": "qweqweqeqweqwe",
"password": "qweqweqweqweqwe",
"code": "65xv",
"hdn_refer": "https://www.epwk.com/"
};
C = 'a75846eb4ac490420ac63db46d2a03bf'
console.log(h(U, L, C))
运行又报错,替换r.a函数,
"object" === typeof (t[n])
最后代码运行出Signature
最后将js代码转成python,再与爬虫相结合最后写出代码
python
import requests
cookies = {
'Hm_lvt_387b8f4fdb89d4ea233922bdc6466394': '1698224816,1699438386,1700570522',
'PHPSESSID': 'ca8646d868cd69a35397b2a42dba42d0e7a8f02b',
'time_diff': '0',
'XDEBUG_SESSION': 'XDEBUG_ECLIPSE',
'adbanner_city': '%E5%8C%97%E4%BA%AC%E5%B8%82',
'banners_show_cookie_ip': '221.216.142.177',
'login_referer': 'https%3A%2F%2Fwww.epwk.com%2F',
'Hm_lpvt_387b8f4fdb89d4ea233922bdc6466394': '1700570526',
'login_fail_need_graphics': '0',
}
headers = {
'Accept': 'application/json, text/plain, */*',
'Accept-Language': 'zh-CN,zh;q=0.9',
'Access-Token': '',
'App-Id': '4ac490420ac63db4',
'App-Ver': '',
'CHOST': 'www.epwk.com',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
'Content-Type': 'application/x-www-form-urlencoded',
# 'Cookie': 'Hm_lvt_387b8f4fdb89d4ea233922bdc6466394=1698224816,1699438386,1700570522; PHPSESSID=ca8646d868cd69a35397b2a42dba42d0e7a8f02b; time_diff=0; XDEBUG_SESSION=XDEBUG_ECLIPSE; adbanner_city=%E5%8C%97%E4%BA%AC%E5%B8%82; banners_show_cookie_ip=221.216.142.177; login_referer=https%3A%2F%2Fwww.epwk.com%2F; Hm_lpvt_387b8f4fdb89d4ea233922bdc6466394=1700570526; login_fail_need_graphics=0',
'Device-Os': 'web',
'Device-Ver': '',
'Imei': '',
'NonceStr': '1700570738pdcom',
'Origin': 'https://www.epwk.com',
'Os-Ver': '',
'Pragma': 'no-cache',
'Referer': 'https://www.epwk.com/login.html',
'Sec-Fetch-Dest': 'empty',
'Sec-Fetch-Mode': 'cors',
'Sec-Fetch-Site': 'same-origin',
'Signature': 'Ks5z+mbEmnNOLXsZKuOq84sn8ATLQmZxN9RmH1Gi4yuPWQWo+GYbhylLq4jxFy3F',
'Timestemp': '1700570738',
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36',
'sec-ch-ua': '"Google Chrome";v="119", "Chromium";v="119", "Not?A_Brand";v="24"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"macOS"',
}
data = {
'username': 'qweqweqeqweqwe',
'password': 'qweqweqweqweqwe',
'code': 'aaaa',
'hdn_refer': 'https://www.epwk.com/',
}
response = requests.post('https://www.epwk.com/api/epwk/v1/user/login', cookies=cookies, headers=headers, data=data)
print(response.text)