【猿人学WEB题目专解】猿人学第20题

🌈据说,看我文章时 关注、点赞、收藏帅哥美女们 心情都会不自觉的好起来。

前言:
🧡作者简介:大家好我是 user_from_future ,意思是 “ 来自未来的用户 ” ,寓意着未来的自己一定很棒~
✨个人主页:点我直达,在这里肯定能找到你想要的~
👍专栏介绍:猿人学WEB题目专解 ,提供猿人学WEB题目总计20题的解题思路与方法,如有讲述错误,请不吝赐教。

想看往期历史文章,可以浏览此博文: 历史文章目录,后续所有文章发布都会同步更新此博文~

人生苦短,我用python

题目网址

猿人学第20题

题目详情

在这里插入图片描述
界面是新的颜色,让我们计算 加和

题目思路

老样子,进入 request 函数,参数入口挺直观的:
在这里插入图片描述
打上断点,点击下一页,就找到了我们的核心函数:
在这里插入图片描述
看得出来,这次是引用的“加强版”的 wasm ,上一次简单版的 wasm 还是在第15题。
人懒了,先再像第6题一样试一次 RPC 吧。

使用 RPC 远程过程调用解决

上次说到,为什么会有想用这个的想法呢?原因有几个:

  1. 使用 RPC 远程过程调用很简单。
  2. 函数入口明确,可以直接调用出结果。
  3. 懒得逆向 / 逆向恐惧 / 不会逆向 等原因。
  4. 没有用过 RPC 远程过程调用,想尝试。

这次很明确,函数入口明确 + 懒得逆向。
window.sign 函数调用前,加断点断住,然后在控制台注入 RPC 框架代码:

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;
    try {
        var result=JSON.parse(requestJson)
    } catch (error) {
		console.log("catch error",requestJson);
        result = transjson(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, e) {
    this.send(action + atob("aGxeX14") + e);
}


function transjson(formdata){
    var regex = /"action":(?<actionName>.*?),/g
    var actionName = regex.exec(formdata).groups.actionName
    stringfystring =  formdata.match(/{..data..:.*..\w+..:\s...*?..}/g).pop()
    stringfystring= stringfystring.replace(/\\"/g,'"')
    paramstring = JSON.parse(stringfystring)
    tens = `{"action":`+ actionName + `,"param":{}}`
    tjson = JSON.parse(tens)
    tjson.param = paramstring
    return tjson
}

var demo = new Hlclient("ws://127.0.0.1:12080/ws?group=yrx&name=q20");

取消断点,继续运行即可。
单页 RPC 的Python代码:

index = 1
t = int(time.time()) * 1000
url = 'http://localhost:12080/execjs'
data = {
    'group': 'yrx',
    'name': "q20",
    'jscode': f'sign("{index}|{t}")'
}
sign = requests.post(url, data=data).json()['data']
url = f"https://match.yuanrenxue.cn/api/match/20?page={index}&sign={sign}&t={t}"
print(requests.get(url, headers=headers).json())

真是太轻松了,让我都不想处理 wasm 文件解决了~

正常处理 wasm 文件解决

首先,我们尝试向第15题一样,直接用 pywasm 导入 wasm ,没想到报错:
在这里插入图片描述
我们去搜一下又发现:
在这里插入图片描述
居然用万恶的 eval 来加载!
那先不管这个,我们来看看 sign 函数:
在这里插入图片描述
看到调用 wasm 时没有返回值,但最终是由另外一个函数返回的,现在看到几个数字,我们刷新或点下一页看看他会不会变化:
在这里插入图片描述
在这里插入图片描述
发现除了函数输入值 content 其他的所有数字都是定值!
再看看他返回的函数:
在这里插入图片描述
意思就是从指定内存获取数据,所以我们也可以通过这个函数获取 wasm 执行时的数据。
先回到 wasm 文件里。
在这里插入图片描述
在本地又不太好浏览,所以我们使用 wabtwasm 格式转换为 wat 格式:
在这里插入图片描述
这下才看的舒服,然后搜索 export 看看导出了哪些:
在这里插入图片描述
确认过眼神,sign 就是我们想要的函数,全局搜索 $sign ,配合浏览器断点调试:
在这里插入图片描述
在这里插入图片描述
我们发现这 wat 转出来就是浏览器的简化版。等到我们熟练驾驭 wasm 的时候再来看这文件吧,我们先去浏览器调试看值。
先贴一下刚才的两个值:r0 = 1114360, r1 = 32 ,用函数获取值就是 getStringFromWasm0(1114360, 32)
我们将所有有关 sign 的函数打个断点,看看他会跳转到哪里去,每跳一次,就更改到 sign 栈,然后执行函数获取值看看。
我们发现在这个函数之前,获取到的值都是那一串:
在这里插入图片描述
经过那个 call 就得到了我们的值:
在这里插入图片描述
这样我们就压缩了查找的范围,多这样找几次,我们就能获得结果了!
第二次找到的值变化范围:
在这里插入图片描述
很明显能发现,这个 sign 执行了 MD5 ,然后我们兴致冲冲的去执行 MD5 ,发现:window.sign('1|1682259720000') 得到 '0acdc2760793e6bc16dc58225b31f654' ,但我们使用 MD5 加密的结果却是:84c504783d8bc98d3160554f19b99241 ,难道这是魔改的 md5
算了,还是继续看变值吧:
在这里插入图片描述
在这里没有变化是我没想到的:
在这里插入图片描述
只能硬着头皮继续找下去了…
第三次值的变化:
在这里插入图片描述
执行完 call ,在这里用 32 的长度还报错了,往下试 31 可以:
在这里插入图片描述
可以看到后面跟了一串字符,我们刷新看看他变不变:
在这里插入图片描述
在这里插入图片描述
发现是一个固定值,我们先记录一下:D#uqGdcw41pWeNXm (不保证每个人的都一样)
然后把这新的值 MD5 加密一下:0acdc2760793e6bc16dc58225b31f654 ,和它的加密结果一模一样!

解题源码

import time
import hashlib
import requests
import jsonpath

headers = {
    'cookie': 'sessionid=6r3zqh6xc6lhl12enp6l07m7rasokbxo',
    'User-Agent': 'yuanrenxue.project'
}

value = 0
for index in range(1, 6):
    t = int(time.time()) * 1000
    # 使用 RPC 远程过程调用解决:var demo = new Hlclient("ws://127.0.0.1:12080/ws?group=yrx&name=q20");
    # url = 'http://localhost:12080/execjs'
    # data = {
    #     'group': 'yrx',
    #     'name': "q20",
    #     'jscode': f'sign("{index}|{t}")'
    # }
    # sign = requests.post(url, data=data).json()['data']
    # 正常逆向 WASM 解决
    sign = hashlib.md5(f'{index}|{t}D#uqGdcw41pWeNXm'.encode('utf-8')).hexdigest()
    url = f"https://match.yuanrenxue.cn/api/match/20?page={index}&sign={sign}&t={t}"
    # value += sum(v['value'] for v in requests.get(url, headers=headers).json()['data'])
    value += sum(jsonpath.jsonpath(requests.get(url, headers=headers).json(), '$..value'))
print(value)
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于您提到的错误TypeError: list indices must be integers or slices, not str,这是因为您在访问列表中的元素时使用了字符串作为索引,而列表的索引必须是整数或切片类型。解决这个错误的方法是使用整数或切片来访问列表中的元素。 关于您提到的猿人js逆向的问,我需要更多的信息才能为您提供具体的答案。对于爬虫编写,您可以使用Python的各种库(如Requests、BeautifulSoup、Scrapy等)来获取网页的内容,并进一步解析和处理。您可以使用这些库发送HTTP请求获取网页内容,然后使用解析库来提取您需要的数据。 爬虫编写的一般步骤如下: 1. 导入所需的库 2. 发送HTTP请求获取网页内容 3. 使用解析库解析网页内容 4. 提取所需的数据 5. 进行数据的进一步处理和存储 您可以根据具体的需求和网站的结构进行相应的编写和调试。如果您需要更具体的帮助,请提供更多的信息。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [Python:TypeError: list indices must be integers or slices, not str报错解决及原理](https://blog.csdn.net/hhd1988/article/details/128031602)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [Python BeautifulSoup [解决方法] TypeError: list indices must be integers or slices, not str](https://download.csdn.net/download/weixin_38590567/14871394)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值