爬虫攻守道 - 猿人学第20题 - 殊途同归

news2024/11/13 9:34:34

写在开头

  • 这题也是,自己搞顶多追踪到wasm代码,然后就走不下去了。找了2个参考方案,自己做的过程中还又遇到些新的问题,下面做个记录。
  • 解法1参考文章
  • 解法2参考文章

解法1:追根溯源

  • 在 JS 代码中追踪到 Payload 赋值位置

  • 追踪 Sign 函数,调用的 wasm 代码。这里需要记录一下 var55 和 var56 的值

  • 回到 JS 代码,选中 getStringFromWasm0(r0, r1) 部分,可以看到最终的 sign 已经生成。此时在 console 端口中输入 getStringFromWasm0(1114192, 31) —— 1114192和31 是 var55 和 var56 的值,1个代表内存地址,1个代表偏移量,表示从这个地址取这个长度的字符 —— 可以看到后面加了1串固定的字符串,也就是传说中的 md5 的盐?

  •  到这里也就明白了,sign函数是以 页码,时间戳作为输入,然后加上了固定字符串(盐),拼接后做了 md5 加密。下面是Python 实现代码
# !/usr/bin/env python3
# _*_ coding:utf-8 _*_
"""
@File               : match_20_normal.py
@Project            : S044_YuanRenXue
@CreateTime         : 2023/4/15 18:00
@Author             : biaobro
@Software           : PyCharm
@Last Modify Time   : 2023/4/15 18:00 
@Version            : 1.0
@Description        : None
"""
from urllib.parse import urlencode
import hashlib
import requests
import time

"""
关键的JS代码,得到Payload
t = Date.parse(new Date());
var list = {
    "page": window.page,
    "sign": window.sign(window.page + '|' + t.toString()),
    "t": t,
};
"""


def get_sign(page, ts):
    sign = hashlib.md5((str(page) + "|" + str(ts) + 'D#uqGdcw41pWeNXm').encode()).hexdigest()
    return sign

all_total = 0
for page in range(1, 6):
    ts = int(time.time()) * 1000
    payload = {
        'page': page,
        'sign': get_sign(page, ts),
        't': ts
    }
    url = "https://match.yuanrenxue.cn/api/match/20?" + urlencode(payload)
    print(url)

    headers = {
        'user-agent': 'yuanrenxue.project',
        'cookie': 'sessionid=ntkvbzoagc6tpauaugwk3b0jdrdbuba9'
    }
    resp = requests.get(url, headers=headers)
    # print(resp.text)

    datas = resp.json()['data']
    print(datas)

    p_total = 0
    for data in datas:
        p_total = p_total + data['value']

    all_total = all_total + p_total

print(all_total)

解法2:举重若轻

  • 这个解法不明白原理,但结合Git 作者给的 Demo 和 参考文章,还是照猫画虎搞出来了。Git 作者提供的代码,无法直接获取字典对象。参考文章提供的代码也需要稍微调整。
  • 这个解法需要准备2个东西,1个是在浏览器 Console 跑的JS代码,1个是 Git 作者提供的 Win Exe 程序。
    • 启动Exe 程序,建议在文件夹中右键选择“在终端中代开”,然后敲入 win64-localhost.exe 运行。
    • 打开浏览器找到第20题页面打开,在Console 端口中输入以下 JS 代码,然后回车
function Hlclient(wsURL) {
    this.wsURL = wsURL;
    this.handlers = {};
    this.socket = {};
    if (!wsURL) {
        throw new Error('wsURL can not be empty!!')
    }
    this.connect()
    this.handlers["_execjs"]=function (resolve,param){
        var res=eval(param)
        if (!res){
            resolve("没有返回值")
        }else{
            resolve(res)
        }

    }
}

Hlclient.prototype.connect = function () {
    console.log('begin of connect to wsURL: ' + this.wsURL);
    var _this = this;
    try {
        this.socket["ySocket"] = new WebSocket(this.wsURL);
        this.socket["ySocket"].onmessage = function (e) {
            try{
                let blob=e.data
                blob.text().then(data =>{
                    _this.handlerRequest(data);
                })
            }catch{
                console.log("not blob")
                _this.handlerRequest(blob)
            }

        }
    } catch (e) {
        console.log("connection failed,reconnect after 10s");
        setTimeout(function () {
            _this.connect()
        }, 10000)
    }
    this.socket["ySocket"].onclose = function () {
        console.log("connection failed,reconnect after 10s");
        setTimeout(function () {
            _this.connect()
        }, 10000)
    }

};
Hlclient.prototype.send = function (msg) {
    this.socket["ySocket"].send(msg)
}

Hlclient.prototype.regAction = function (func_name, func) {
    if (typeof func_name !== 'string') {
        throw new Error("an func_name must be string");
    }
    if (typeof func !== 'function') {
        throw new Error("must be function");
    }
    console.log("register func_name: " + func_name);
    this.handlers[func_name] = func;
    return true

}

//收到消息后这里处理,
Hlclient.prototype.handlerRequest = function (requestJson) {
    var _this = this;
    var result=JSON.parse(requestJson);
    //console.log(result)
    if (!result['action']) {
        this.sendResult('','need request param {action}');
        return
    }
    var action=result["action"]
    var theHandler = this.handlers[action];
    if (!theHandler){
        this.sendResult(action,'action not found');
        return
    }
    try {
        if (!result["param"]){
            theHandler(function (response) {
                _this.sendResult(action, response);
            })
        }else{
            var param=result["param"]
            try {
                param=JSON.parse(param)
            }catch (e){
                console.log("")
            }
            theHandler(function (response) {
                _this.sendResult(action, response);
            },param)
        }

    } catch (e) {
        console.log("error: " + e);
        _this.sendResult(action+e);
    }
}



Hlclient.prototype.sendResult = function (action, response) {
    var responseJson;
    if (typeof response == 'string') {
        try {
            responseJson = JSON.parse(response);
        } catch (e) {
            responseJson = {};
            responseJson['data'] = response;
        }
    } else if (typeof response == 'object') {
        responseJson = response;
    } else {
        responseJson = {};
        responseJson['data'] = response;
    }
    if (Array.isArray(responseJson)) {
        responseJson = {
            data: responseJson,
            code: 0
        }
    }

    if (responseJson['code']) {
        responseJson['code'] = 0;
    } else if (responseJson['status']) {
        responseJson['status'] = 0;
    } else {
        responseJson['status'] = 0;
    }
    var responseText = JSON.stringify(responseJson);
    this.send(action + atob("aGxeX14") + responseText);
}

// 上面是用于建立环境的源码
// 注入环境后连接通信
// var demo = new Hlclient("ws://127.0.0.1:12080/ws?group=zzz&name=hlg");

// 连接通信
var client = new Hlclient("ws://127.0.0.1:12080/ws?group=match20&name=yuanrenxue");

// demo_001
// 注册一个方法 第一个参数hello为方法名,
// 第二个参数为函数,resolve里面的值是想要的值(发送到服务器的)
client.regAction("hello1", function (resolve) {
    //这样每次调用就会返回“好困啊+随机整数”
    var Js_sjz = "好困啊"+parseInt(Math.random()*1000);
    resolve(Js_sjz);
})
// 访问接口,获得js端的返回值
// http://localhost:12080/go?group=zzz&name=hlg&action=hello

// demo_002
//写一个传入字符串,返回base64值的接口(调用内置函数btoa)
client.regAction("hello2", function (resolve,param) {
    //这样添加了一个param参数,http接口带上它,这里就能获得
    var base666 = btoa(param)
    resolve(base666);
})

// demo_003
//假设有一个函数 需要传递两个参数
function hlg(User,Status){
    return User+"说:"+Status;
}

client.regAction("hello3", function (resolve,param) {
    //这里还是param参数 param里面的key 是先这里写,但到时候传接口就必须对应的上
    res=hlg(param["user"],param["status"])
    resolve(res);
})
// url = "http://localhost:12080/go"

// 第二个参数为函数,resolve里面的值是想要的值(发送到服务器的)
// param是可传参参数,可以忽略
client.regAction("ShiGuang", function (resolve, param) {
    t = Date.parse(new Date());
    var list = {
        "page": String(param),
        "sign": window.sign(String(param) + '|' + t.toString()),
        "t": t,
    }
    resolve(list)
})
  • 准备好环境后,就可以写Python 代码进行请求了。以下是 Python 代码
# !/usr/bin/env python3
# _*_ coding:utf-8 _*_
"""
@File               : match_20_jsrpc.py
@Project            : S044_YuanRenXue
@CreateTime         : 2023/4/15 23:06
@Author             : biaobro
@Software           : PyCharm
@Last Modify Time   : 2023/4/15 23:06 
@Version            : 1.0
@Description        : None
"""
import ast
import requests


def get_params(page):
    params = {
        "group": "match20",
        "name": "yuanrenxue",
        "action": "ShiGuang",
        "param": str(page)
    }
    try:
        res = requests.post("http://localhost:12080/go", params=params)
        res = res.json()
        print(res)

        # 这个写法是把
        # '{"page":"1","sign":"df47c82c991462661cfc3642369039a3","t":1681818656000,"status":0}'
        # 转换成
        # {'page': '1', 'sign': 'df47c82c991462661cfc3642369039a3', 't': 1681818656000, 'status': 0}
        # 否则直接按json 或 字典方式是读不出来的
        params = ast.literal_eval(res.get("data"))
        print(params)
        return params
    except:
        return False


get_params(1)

  • 运行结果。现在拿到了 sign,再获取页面上的数据就不是问题了。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/432362.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

漂亮实用的15个脑图模板,你知道哪些是AI做的吗?

对于很多第一次接触到思维导图的朋友,看到软件的时候往往找不到方向,不知道如何创作? 今天大家的好助手来了。 一是有大量的思维导图模板,大家看着模板做,慢慢就会做了。 二是ProcessOn 思维导图已经可以用AI 做思维…

鏖战大模型,未必能拯救商汤

在不被资本市场看好的质疑声中,商汤科技于近日跟风推出了自己的大模型产品,而且还直接打造了一个大模型超市,声称包括CV(计算机视觉)、NLP(​​​​​​​自然语言处理)、AIGC(人工智…

新电脑如何增加c盘空间

刚到手的台式机,发现C盘只分配了 100G 空间,对于我来说是不太够的(安装的软件太多,即使是一点点数据,几年就达到100G了)。对于经常不选择软件安装路径,全部都装在C盘的人,也是不够的…

【致敬未来的攻城狮计划】— 连续打卡第五天:Keil配置使用(使用 RASC 生成 Keil 工程)

系列文章目录 1.连续打卡第一天:提前对CPK_RA2E1是瑞萨RA系列开发板的初体验,了解一下 2.开发环境的选择和调试(从零开始,加油) 3.欲速则不达,今天是对RA2E1 基础知识的补充学习。 4.e2 studio 使用教程 文…

8万字智慧旅游景区信息化建设方案word

本资料来源公开网络,仅供个人学习,请勿商用,如有侵权请联系删除。 1.1. 整体建设框架 XXXXXX智慧景区旅游建设对于全面整合景区旅游资源,提升景区旅游产业发展能级,进一步增强景区旅游业的核心竞争力具有十分重要的支…

拷贝、原型原型链

浅拷贝 将原对象或原数组的引用直接赋给新对象,新数组 新对象只是对原对象的一个引用,而不复制对象本身。新旧对象还是共享同一块内存 如果属性是一个基本数据类型,拷贝的就是基本数据类型的值 如果属性是引用类型,拷贝的是内…

Oracle的学习心得和知识总结(二十)|Oracle数据库Real Application Testing之DBMS_SQLTUNE包技术详解

目录结构 注:提前言明 本文借鉴了以下博主、书籍或网站的内容,其列表如下: 1、参考书籍:《Oracle Database SQL Language Reference》 2、参考书籍:《PostgreSQL中文手册》 3、EDB Postgres Advanced Server User Gui…

SRv6项目实践(二):基本的P4框架

1.数据包头的定义 在实现SRv6之前,有很多的工作需要做,首先先阅读一下p4的代码总体框架,数据包的包头格式一共有如下这些,我们需要把他们的协议逐一完善 struct parsed_headers_t {cpu_out_header_t cpu_out;cpu_in_header_t cpu_in;ethern…

PostgreSQL环境搭建和主备构建

目录 1 Windows 上安装 PostgreSQL2 docker安装PostgreSQL2.1 检索当前镜像2.2. 拉取当前镜像2.3 创建挂载文件夹2.4 启动镜像2.5 查看日志2.7 查看进程2.8 使用连接 3 postgresql主从主备搭建3.1 安装好网络源(主1.11、从1.12)3.2 安装postgresql&#…

(数字图像处理MATLAB+Python)第五章图像增强-第二节:基于直方图修正的图像增强

文章目录 一:灰度直方图(1)定义(2)程序(3)性质 二:直方图修正法理论三:直方图均衡化(1)直方图均衡化变换函数T(r)的求解(2&#xff09…

设计模式-创建型模式之简单工厂模式( Simple Factory Pattern )

1.创建型模式简介创建型模式(Creational Pattern)对类的实例化过程进行了抽象,能够将软件模块中对象的创建和对象的使用分离。为了使软件的结构更加清晰,外界对于这些对象只需要知道它们共同的接口,而不清楚其具体的实现细节,使整…

HCIP之MPLS中的LDP协议

LDP协议 LDP协议 --- 标签分发协议 MPLS控制层面需要完成的工作主要就是分配标签和传递标签。分配标签的前提是本地路由表中得先存在标签,传递标签的前提也是得先具备路由基础。所以,LDP想要正常工作,则需要IGP作为基础。 LDP协议主要需要完…

信号处理流程

1.降噪处理 我们在录制音频数据的同时,大量噪声都会掺杂进来,不同环境和情境下产生的噪声也不尽相同,噪声信号中的无规则波纹信息影响了声学信号所固有的声学特性,使得待分析的声音信号质量下降,并且噪声对声音识别系统…

02-数据库连接池+lombok工具

数据库连接池 概念: 数据库连接池是个容器,负责分配、管理数据库连接(Connection) 它允许应用程序重复使用一个现有的数据库连接,而不是重新建立一个 释放空闲时间超过最大空闲时间的连接,来避免因为没有释…

【硬件外设使用】——UART

【硬件外设使用】——UART UART基本概念UART通信协议UART使用方法pyb.uartmachine.uart UART 可用的传感器 UART基本概念 UART全称为Universal Asynchronous Receiver/Transmitter,是通过异步(Asynchronous)方式传输数据的一个串行通信协议。…

C6678开发概述与Sys/bios基本使用

C6678开发概述 参考开发环境标记及术语创建sys/bios自定义平台运行第一个sys/bios程序Clock模块使用Demo 参考 TMS320C6678 Multicore Fixed and Floating-Point Digital Signal Processor Datasheet TMS320C66x DSP CorePac User Guide 官方手册 创龙6678开发教程 开发环境 …

使用 ChatGPT 改善 Android 开发效率的 7 个案例~

翻译 修改自 https://proandroiddev.com/chatgpt-for-android-developers-1c3c1ecc6440,原作者:Rafa Araujo ChatGPT 是由 OpenAI 公司创造的自然语言处理工具,对那些想要提高技能的软件开发人员来说,它绝对是不容错过的重要利器…

日撸 Java 三百行day32

文章目录 说明day32 图的连通性检测1.思路1.1矩阵表示1.2.矩阵相乘1.3结合矩阵运算思考图的连通性。 2.代码 说明 闵老师的文章链接: 日撸 Java 三百行(总述)_minfanphd的博客-CSDN博客 自己也把手敲的代码放在了github上维护:ht…

Linux下安装navicat

1.在https://www.navicat.com.cn/download/navicat-premium下载navicat安装包 2.在终端执行命令 给navicat16-premium-cs.AppImage赋予可执行的权限 chmod x navicat16-premium-cs.AppImage 启动Navicat16 ./navicat16-premium-cs.AppImage 3.点击连接——mysql——输入连…

java单机秒杀扛1万并发方案和代码

我们先来看普通的加锁加事务秒杀性能, 说明: 1.这里的秒杀业务执行一次耗时100毫秒 2.电脑配置16g内存 4核8线程 cpu i7 7代,数据库连接池max20 RequestMapping("/purchase2")public ResultJson purchase2( Long productId){int userId new Random().nextInt(10…