【困难】 猿人学web第一届 第18题 jsvmp 洞察先机

news2024/11/16 10:54:05

文章目录

  • 数据接口分析
  • 还原加密参数
  • 插桩调试
  • 分析日志
    • 插桩补充
  • python 代码

数据接口分析

数据接口 https://match.yuanrenxue.cn/match/18data
在这里插入图片描述

请求参数
{page: 页码, t: 时间戳, v: 加密值}在这里插入图片描述
请求第一页不需要携带 t, v 参数
在这里插入图片描述

cookie
只需要携带 sessionid
在这里插入图片描述

只要 还原加密字段 v

还原加密参数

查看数据接口对应的 request 栈
在这里插入图片描述
下断点,点击页码请求数据,会在对应的位置断住
在这里插入图片描述
断住后单步执行到, xml.open 方法是被重写过的,跟进去
在这里插入图片描述
代码是压缩成一行的
拿到本地格式化再折叠
可以很明显的看到是一个自执行函数
这个自执行函数传入的参数就是这个 vmp 对应的指令
在这里插入图片描述

继续跟栈,可以找到这个 vmp 对应的解释器
在这里插入图片描述
将断点放到最后一行
在这里插入图片描述
单步进去,这个函数就是对应的解释器
在这里插入图片描述

解决 vmp 最有效的办法就是插桩看日志,根据日志的信息 进行合理的猜测 / 还原

插桩调试

插桩应该插在:
运行了方法,同时使用变量接收的位置 xxx = xxx(xxx, xxx) 或 xxx.apply(xxx, [xxx])
又或者是 return 语句后面 进行了计算操作 xxx1 + xxx2 (运算操作)

在这个解释器有很多符合这两个特征的地方
这里只插关键的位置

搜索 27 == __U
这个 return语句后进行了运算操作在这里插入图片描述
这里是三元表达式,如果想知道进行了什么运算操作的花可以将这里的 三元表达式还原成 if
插入条件断点
在这里插入图片描述
这里的代码是用 ast 还原后再重新生成的 (ast 真方便 /dog)
对应的代码 ↓

if(33==(v_=vv_)){console.log(27,"V_ instanceof y_;",V_,y_,V_ instanceof y_)V_ instanceof y_;}else{if(23==v_){console.log(27,"V_ in y_;",V_,y_,V_ in y_)V_ in y_;}else{if(19==v_){console.log(27,"V_ + y_;",V_,y_,V_+y_)V_+y_;}else{if(46==v_){console.log(27,"V_ - y_;",V_,y_,V_-y_)V_-y_;}else{if(14==v_){console.log(27,"V_ / y_;",V_,y_,V_/y_)V_/y_;}else{if(31==v_){console.log(27,"V_ * y_;",V_,y_,V_*y_)V_*y_;}else{if(32==v_){console.log(27,"_y_(V_, y_);",V_,y_,_y_(V_,y_))_y_(V_,y_);}else{if(27==v_){console.log(27,"V_ % y_;",V_,y_,V_%y_)V_%y_;}else{if(25==v_){console.log(27,"V_ < y_;",V_,y_,V_<y_)V_<y_;}else{if(2==v_){console.log(27,"V_ <= y_;",V_,y_,V_<=y_)V_<=y_;}else{if(16==v_){console.log(27,"V_ > y_;",V_,y_,V_>y_)V_>y_;}else{if(42==v_){console.log(27,"V_ >= y_;",V_,y_,V_>=y_)V_>=y_;}else{if(40==v_){console.log(27,"V_ & y_;",V_,y_,V_&y_)V_&y_;}else{if(39==v_){console.log(27,"V_ != y_;",V_,y_,V_!=y_)V_!=y_;}else{if(21==v_){console.log(27,"V_ !== y_;",V_,y_,V_!==y_)V_!==y_;}else{if(47==v_){console.log(27,"V_ | y_;",V_,y_,V_|y_)V_|y_;}else{if(50==v_){console.log(27,"V_ ^ y_;",V_,y_,V_^y_)V_^y_;}else{if(26==v_){console.log(27,"V_ == y_;",V_,y_,V_==y_)V_==y_;}else{if(37==v_){console.log(27,"V_ === y_;",V_,y_,V_===y_)V_===y_;}else{if(8==v_){console.log(27,"V_ << y_;",V_,y_,V_<<y_)V_<<y_;}else{if(18==v_){console.log(27,"V_ >> y_;",V_,y_,V_>>y_)V_>>y_;}else{if(1==v_){console.log(27,"V_ >>> y_;",V_,y_,V_>>>y_)V_>>>y_;}else{console.log(27,"void 0;",V_,y_,void 0)void 0;}}}}}}}}}}}}}}}}}}}}}};false

搜索 48 == __U
这个 return 语句后面执行了 apply 方法在这里插入图片描述
插入条件断点
在这里插入图片描述
对应的代码 ↓

if(__V(_, ___(u_), 0, 0, _u__).name){
    console.log(48, __V(_, ___(u_), 0, 0, _u__).name, 'apply', y__(____));
}else{
    console.log(48, 'function(){}', 'apply', y__(____));
};false

搜索 32 == __U
这个 return 语句后面执行了 apply 方法在这里插入图片描述
插入条件断点
在这里插入图片描述
对应的代码↓

if(yU_ instanceof Function){
    console.log(32, yU_.name, yU_[_v].name, ...__)
}else{
    console.log(32, yU_, yU_[_v].name, ...__)
};false

其实还少了两个地方的桩没有插,后面有补充,最好补上
在 目录 日志分析下的 插桩补充目录,点击跳转过去即可

分析日志

插好桩以后,点击页码进行请求 会生成对应的日志(第1, 5页不会进行加密)
生成日志后,将日志保存到本地在这里插入图片描述
在出现密文后的日志全部删除,不需要分析在这里插入图片描述
这里就是生成的密文,和请求字段的密文是一致在这里插入图片描述在这里插入图片描述

替换掉无意义的内容
在这里插入图片描述
在这里插入图片描述

从头开始分析(这里只分析关键信息)

这一段指令集的目的是生成 鼠标轨迹数组
在页面一直滑动会一直生成这几段日志
在这里插入图片描述
910为鼠标在页面上 x 轴的位置
226 为鼠标在页面上 y 轴的位置
滑动鼠标,那么两个坐标的值会与 m 相加 (move)
按下鼠标左键,那么两个坐标的值会与 d 相加 (down)
抬起鼠标左键,那么两个坐标的值会与 u 相加 (up)
在对应数组的后面执行了 shift 方法
那么这个数组的值就为
[‘912m226’, ‘911m226’, ‘910m226’, ‘910d226’, ‘910u226’]

这段指令是判断你是否点击了第一页或第五页(第一页和第五页不执行后续的加密逻辑)
在这里插入图片描述
其实…这个和还原加密没有关系 /dog(不皮了,后面只分析和加密相关的日志)

执行了 Date.now()方法获取 时间戳
将这个 时间戳 除以 1000
使用 parseInt 将这个时间戳转化为 整数
生成了 t 参数(请求参数的 t 字段)
在这里插入图片描述

使用 toString(16) 将这个数值转化为 十六进制字符串(‘66d9f991’)
将获取的十六进制字符串再相加(‘66d9f991’ + ‘66d9f991’)
使用 slice 方法取索引为 从 0 开始,从 16 结束的字符(‘66d9f99166d9f991’.slice(0,16))
结果为 ‘66d9f99166d9f991’
在这里插入图片描述
验证
在这里插入图片描述

获取页码与 “|” 相加 (2 + “|”)
获取了轨迹数组并转化为字符串 ([…].toString())
将前面的操作得到的结果再一起相加 (2 + “|” + […].toString())
‘2|912m226,911m226,910m226,910d226,910u226’
在这里插入图片描述

这两个操作分别将上面生成的两个参数进行了解码,是接下来用于加密用的在这里插入图片描述在这里插入图片描述
对应 nodejs 的操作
Crypto.enc.Latin1.parse(‘66d9f99166d9f991’)
Crypto.enc.Latin1.parse(‘2|912m226,911m226,910m226,910d226,910u226’)

全局搜索 encrpyt
查看搜索到的第一个 encrypt
在这里插入图片描述
加密方式是 AES 加密,加密时需要传入 密文,密钥,iv向量
对应着传入的 3 个参数,可以看打印 32 日志的输出方式在这里插入图片描述

先来查看密文
是 Crypto.enc.Latin1.parse(‘2|912m226,911m226,910m226,910d226,910u226’) 的结果在这里插入图片描述
在这里插入图片描述

再来查看密钥
是 Crypto.enc.Latin1.parse(‘66d9f99166d9f991’) 的结果
在这里插入图片描述
在这里插入图片描述

iv 的值与密钥的值一致

接下来加密验证下结果是否一样
在这里插入图片描述

Crypto = require('crypto-js')
let text = Crypto.AES.encrypt(Crypto.enc.Latin1.parse('2|912m226,911m226,910m226,910d226,910u226'), Crypto.enc.Latin1.parse('66d9f99166d9f991'), {
    iv: Crypto.enc.Latin1.parse('66d9f99166d9f991'),  // iv 向量
    // 下面的参数可以填也可以不填,加密模式默认为 cbc, 填充方式默认为 pkcs7
    // mode: Crypto.mode.CBC, // 加密模式
    // padding: Crypto.pad.Pkcs7, // 填充方式
})
console.log(text.toString())

得到的结果与浏览器的一致
在这里插入图片描述
在这里插入图片描述

插桩补充

插桩的点其实有问题,比如为什么我知道是 AES 加密,为什么我知道哪个是 key,哪个是 iv
其实少插了两处桩

全局搜索 18 == _U
插入日志点
18, v_
, V__在这里插入图片描述
对应的日志在这里插入图片描述
这就是我为什么知道 密文,密钥 和 iv 的原因

还有一处地方插桩后是可以看得到 字符串 AES 的,但是我忘记在哪里了,这也是我为什么是 AES 加密 Latin1解码的原因,感兴趣的可以自己插桩找找

分析验证完之后 就可以编写 python 代码

python 代码

首先获取 2,3,4,5 页对应的鼠标轨迹数组,将最后两个参数中的 m 替换成 d 和 u 即可
第2页:[‘905m206’, ‘905m207’, ‘905m208’, ‘905d209’, ‘905u211’]
第3页:[‘950m203’, ‘950m204’, ‘950m206’, ‘950d208’, ‘950u210’]
第4页:[‘1004m209’, ‘1004m208’, ‘1004m207’, ‘1004d208’, ‘1004u209’]
第5页:[‘1052m197’, ‘1052m199’, ‘1052m200’, ‘1051d201’, ‘1051u203’]

js代码

Crypto = require('crypto-js')
function sdk(page){
    let slideArr;
    switch (page){
        case 2:
            slideArr = ['905m206', '905m207', '905m208', '905d209', '905u211']
            break;
        case 3:
            slideArr = ['950m203', '950m204', '950m206', '950d208', '950u210']
            break;
        case 4:
            slideArr = ['1004m209', '1004m208', '1004m207', '1004d208', '1004u209']
            break;
        case 5:
            slideArr = ['1052m197', '1052m199', '1052m200', '1051d201', '1051u203']
            break;
    }
    let encryptStr = Crypto.enc.Latin1.parse(page + "|" + slideArr.toString())
    let timeStrap = parseInt(Date.now() / 1000)
    let key_iv = Crypto.enc.Latin1.parse(timeStrap.toString(16) + timeStrap.toString(16));
    let v = Crypto.AES.encrypt(encryptStr, key_iv, {
        iv: key_iv,
        mode: Crypto.mode.CBC, // 加密模式
        padding: Crypto.pad.Pkcs7, // 填充方式
    }).toString()
    return {
        'page': page,
        't': timeStrap,
        'v': v
    }
}

python 代码

import time

import requests
import execjs

headers = {
    "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36"
}
cookies = {
    "sessionid": "你的sessionId",
}


def call_js(file_name, func_name, *args):
    with open(file_name, mode='r', encoding='utf-8') as f:
        js_code = execjs.compile(f.read())
    return js_code.call(func_name, *args)


def get_match18(page_):
    url = "https://match.yuanrenxue.cn/match/18data"
    params = {}
    if page_ > 1:
        params = call_js('18.js', 'sdk', page_)
    else:
        params['page'] = page_
    response = requests.get(url, headers=headers, cookies=cookies, params=params)
    print(response.json()['data'])
    return response.json()['data']


if __name__ == '__main__':
    nums = 0
    for page in range(1, 6):
        nums_list = get_match18(page)
        for num in nums_list:
            nums += num['value']
        print('page: ', page, 'nums: ', nums)

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

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

相关文章

深入理解Java反射技术及其应用

什么是反射技术&#xff1f; Java反射机制是一种强大的特性&#xff0c;它允许程序在运行时动态加载类并获取类或对象的属性和方法。其核心在于JVM通过获得class对象进行反编译&#xff0c;从而获取对象的各种信息。 反射机制的基本特点 动态性 Java是一种先编译后运行的语言…

【电子通识】规格书上的%FS和%RD具体指什么?

在仪器仪表类的手册上&#xff0c;常见的精度表达规格显示方式&#xff1a;%FS 和%RD 究竟如何解读呢&#xff1f; 术语解说 %RD(Reading)&#xff1a;用于表示对比显示值(读值)存在多少(%)的误差 %FS(Full Scale)&#xff1a;用于表示对比全量程存在多少(%)的误差 %SP(Set Poi…

基于vue框架的城市体育运动交流平台15s43(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。

系统程序文件列表 项目功能&#xff1a;用户,赛事类型,近期赛事,比赛报名,器材类型,器材信息,自由约战,运动队伍 开题报告内容 基于Vue框架的城市体育运动交流平台开题报告 一、项目背景与意义 随着城市化进程的加速和居民健康意识的提升&#xff0c;城市体育运动已成为现代…

思维导图神器!四款高效工具助你职场逆袭

在如今这个信息爆炸的时代&#xff0c;如何高效地整理和呈现思维&#xff0c;成为了一个重要的能力&#xff1b;思维导图作为一种有效的思维工具&#xff0c;被广泛应用于工作、学习和生活中&#xff1b;今天&#xff0c;我将为大家介绍四款常用的思维导图软件并分享一下它们的…

win10任务栏透明如何调整?——详解Windows任务栏设置与优化技巧

在这个数字化时代&#xff0c;电脑已经成为我们日常办公和生活中的。关于win10任务栏透明的设置方法&#xff0c;身边很多同事都在咨询。 本文就来简单介绍下关于电脑任务栏个性化设置的方法&#xff0c;毕竟任务栏影响着用户体验。这时&#xff0c;一款优秀的任务栏优化工具就…

模拟实现string类: clear函数、流提取(<<)和流插入(>>)运算符重载、>、<、==、<=、>=、!=的运算符重载、赋值运算符(=)重载等的介绍

文章目录 前言一、 clear函数二、流提取(<<)和流插入(>>)运算符重载三、 >、<、、<、>、!的运算符重载四、赋值运算符&#xff08;&#xff09;重载总结 前言 模拟实现string类: clear函数、流提取(<<)和流插入(>>)运算符重载、>、<…

[论文笔记]ChatQA: Surpassing GPT-4 on Conversational QA and RAG

引言 今天来看一下上篇论文笔记中反复介绍的 ChatQA: Surpassing GPT-4 on Conversational QA and RAG。 为了简单&#xff0c;下文中以翻译的口吻记录&#xff0c;比如替换"作者"为"我们"。 我们介绍了 ChatQA&#xff0c;这是一个模型套件&#xff0c;一…

机器学习和深度学习的常见概念总结(面试用,多原创图和公式)

目录 使用说明一、未分类损失函数&#xff08;Loss Function&#xff09;1. **损失函数的作用**2. **常见的损失函数**2.1. **均方误差&#xff08;MSE, Mean Squared Error&#xff09;**2.2. **均方根误差&#xff08;RMSE, Root Mean Squared Error&#xff09;**2.3. **平均…

1. 运动控制指令概要(omron 机器自动化控制器)

机器自动化控制器——第一章 运动控制指令概要 1-1 运动控制指令PLCopen运动控制用功能块运动控制指令概要▶ 运动控制指令的种类▶ 状态变化▶ 运动控制指令的启动和状态▶ 异常处理▶ 执行运动控制指令时输入变量的变更(指令重启)▶ 通过选择缓存模式执行指令多重启动▶ 通过…

四川锦程消费金融有限责任公司2024年(第一批次)催收机构选型入库采购公告

四川锦程消费金融有限责任公司2024年&#xff08;第一批次&#xff09;催收机构选型入库采购公告 根据需要&#xff0c; 四川锦程消费金融有限责任公司决定对外公 开选型采购催收代理合作的催收机构&#xff0c;欢迎符合条件的催收 机构参与采购。具体公告如下&#xff1a; 一…

Redisson分布式锁实现及原理详解

随着技术快速发展&#xff0c;数据规模增大&#xff0c;分布式系统越来越普及&#xff0c;一个应用往往会部署在多台机器上&#xff08;多节点&#xff09;&#xff0c;在有些场景中&#xff0c;为了保证数据不重复&#xff0c;要求在同一时刻&#xff0c;同一任务只在一个节点…

Makefile中的override

若对变量进行赋值一部分需要由命令行&#xff08;注意命令行只能使用/:/进行赋值&#xff0c;不能使用&#xff1f;进行赋值&#xff09;输入完成&#xff0c;一部分需要写在Makefile文件里&#xff0c;Makefile规则默认会让命令行的赋值覆盖文件里的赋值。要想解决这个问题&am…

【源码+文档+调试讲解】高校研招信息共享系统

摘 要 近年来&#xff0c;科技飞速发展&#xff0c;在经济全球化的背景之下&#xff0c;互联网技术将进一步提高社会综合发展的效率和速度&#xff0c;互联网技术也会涉及到各个领域&#xff0c;而高校研招信息共享系统在网络背景下有着无法忽视的作用。信息管理系统的开发是…

log4j靶场,反弹shell

1.用vulhub靶场搭建&#xff0c;首先进入目录CVE-2021-44228中&#xff0c;docker启动命令 2.发现端口是8983&#xff0c;浏览器访问http://172.16.1.18:8983/ 3.用dnslog平台检测dns回显&#xff0c;看看有没有漏洞存在 4.反弹shell到kali&#xff08;ip为172.16.1.18&#xf…

【白话Spring】三级缓存

快速导航 一、Spring的三级缓存是什么&#xff1f;三级缓存SpringBean 的生命周期&#xff1a;BeanFactory关于Bean初始化注释&#xff1a;分析&#xff1a;Bean的创建过程&#xff1a;Bean的销毁过程&#xff1a; Spring Bean创建的核心逻辑&#xff1a; 二、Spring的三级缓存…

CentOS7 使用yum报错:[Errno 14] HTTP Error 404 - Not Found 正在尝试其它镜像。

CentOS7 使用yum报错&#xff1a;[Errno 14] HTTP Error 404 - Not Found 正在尝试其它镜像。 CentOS镜像下载、VM虚拟机下载 下载地址&#xff1a;www.macfxb.cn 一、问题描述 安装完CentOS7 后 使用yum报错 如下图 二、解决方案 1.查看自己的系统架构 我的是aarch64 uname …

【MySQL】查询语句之inner、left、right、full join 的区别

前言&#xff1a; INNER JOIN 和 OUTER JOIN 是SQL中常用的两种连接方式&#xff0c;用于从两表活多表中提取相关的数据。两者区别主要在于返回的 结果集 如何处理 匹配 与 不匹配 的行。 目录 1、INNER JOIN 2、OUTER JOIN 3、总结 1、INNER JOIN 称为内连接&#xff0c;只…

ComfyUI-AdvancedLivePortrait:实时编辑人脸让图像动起来

经常使用Stable Diffiusion的朋友都知道&#xff0c;webUI和comfyUI底层都是Stable Diffiusion&#xff0c;但是它们的显示界面有非常大的区别&#xff1a;webUI界面简洁&#xff0c;新手比较容易上手&#xff1b;而ComfyUI 是采用基于节点的图形界面&#xff0c;通过连接不同的…

面向 NetworkX 用户的加速生产就绪型图形分析

目录 借助 NetworkX 轻松进行图形分析 使用 cuGraph 加速图形分析 使用 ArangoDB 进行生产就绪型图形分析 借助 cuGraph 和 ArangoDB 实现 GPU 加速分析 实施示例 测试环境 下载数据 创建 NetworkX 图形 在不使用 ArangoDB 的情况下运行 cuGraph 算法 将 NetworkX 图…

【Qt 即时通讯项目】登录验证码是如何做到的呢

文章目录 1. 登录注册功能验证码实现2. 验证码生成的流程3. 细节部分 1. 登录注册功能验证码实现 &#x1f427;①目的&#xff1a;引入验证码&#xff0c;目的是用来避免程序被其它程序暴力破解的方式找到密码。 2. 验证码生成的流程 ①&#x1f34e;首先通过Qt的QRandomGen…