关注它,不迷路。
本文章中所有内容仅供学习交流,不可用于任何商业用途和非法用途,否则后果自负,如有侵权,请联系作者立即删除!
一.目标地址
https://match.yuanrenxue.cn/match/2
二.代码还原
初次请求抓包,停止debugger位置:
往上跟堆栈,看到混淆代码,将整个混淆代码保存下来:
分析得知,这是典型的ob混淆,使用星球里的插件先还原字符串:
https://t.zsxq.com/shQFg
字符串解密替换后:
接下来就是后处理了,继续使用星球里的插件:
https://t.zsxq.com/G61wD
处理完毕后,发现更新了 cookie 值:
接下来就是删除垃圾代码,确保整个代码可以直接用起来。
三.分析和删除
最外层的自执行函数还原:
代码可以很简单:
ExpressionStatement(path)
{
let {parentPath,node} = path;
if (!parentPath.isProgram())
{
return;
}
let {expression} = path.node;
if (types.isCallExpression(expression) && types.isFunctionExpression(expression.callee))
{
path.replaceWithMultiple(expression.callee.body.body);
}
},
2.接着看到这个函数:
分析可以后得知,它做了两件事,qz进行了赋值,try语句走的是catch分支,因此整个函数其实就是返回 navigator["vendorSub"],浏览器上是"".所以,可以将它引用的地方全部替换成"",代码也很容易:
TryStatement(path) {
let { param, body } = path.node.handler;
if (body.body.length == 1 && types.isReturnStatement(body.body[0])) {
let functionParent = path.getFunctionParent();
let binding = functionParent.scope.getBinding(functionParent.node.id.name);
if (!binding) {
return;
}
for (let referPath of binding.referencePaths) {
let { parentPath } = referPath;
if (parentPath.isCallExpression()) {
parentPath.replaceWith(types.valueToNode(""));
}
}
functionParent.remove();
}
},
3.上一步看到了 qz 被赋值了,因此在它引用的地方:
代码会执行if分支,写个插件直接替换:
IfStatement(path) {
let { test, consequent, alternate } = path.node;
if (test.name == "qz") {
path.replaceWithMultiple(consequent.body);
}
},
4.删除与加密无关的函数调用,有两处,分别是:
和:
代码如下:
CallExpression(path) {
if (path.node.callee.name == "setInterval") {
path.remove();
return;
}
if (types.isMemberExpression(path.node.callee)) {
let { object, property } = path.node.callee;
if (types.isIdentifier(object, { "name": "location" }) && types.isStringLiteral(property, { "value": "reload" })) {
path.remove();
}
}
},
5.改造加密函数,使之可以直接调用。
改造前:
function _0x3e163b(_0x24b4ad, _0x12406a) {
document["cookie"] = "m" + "" + "=" + _0x59d4f4(_0x24b4ad) + "|" + _0x24b4ad + "; path=/";
}
改造后:
function _0x3e163b(_0x24b4ad, _0x12406a) {
cookie = "m" + "" + "=" + _0x59d4f4(_0x24b4ad) + "|" + _0x24b4ad + "; path=/";
return cookie;
}
插件代码:
AssignmentExpression(path) {
let { parentPath, node, scope } = path;
if (!parentPath.isExpressionStatement()) {
return;
}
let { left, operator, right } = node;
if (types.isMemberExpression(left)) {
let { object, property } = left;
if (types.isIdentifier(object, { "name": "document" }) && types.isStringLiteral(property, { "value": "cookie" })) {
path.node.left = types.Identifier(property.value);
parentPath.insertAfter(types.ReturnStatement(path.node.left));
}
}
},
经过上面的处理以后,整个混淆代码可以直接运行起来。
四.请求代码
分析得知,第一个实参是13位的时间戳,第二个参数没有用到,写下Python代码:
import time
import execjs
import requests
session = requests.Session()
session.headers = {
"User-Agent": "yuanrenxue.project",
}
url = "http://match.yuanrenxue.com/match/2"
r = session.get(url)
with open("2.js",'r') as fp:
jscode = fp.read()
ctx = execjs.compile(jscode)
timestamp = str(int(time.time()*1000))
cookie = ctx.call("_0x3e163b",timestamp)
session.cookies.set("m",cookie[2:])
sum = 0
for i in range(1,2):
api_url =f"http://match.yuanrenxue.com/api/match/2?page={i}"
r = session.get(api_url)
print (r.text)
data = r.json()
values = data["data"]
for value in values:
print (value)
sum += value["value"]
print (sum)
请求结果:
四.插件源码
完整源代码:
https://t.zsxq.com/kELKD
今天的分享就到这里,感谢阅读。
欢迎加入知识星球,学习更多AST和爬虫技巧。