news 2026/4/18 6:34:22

猿人学第三届-第二题-滑块缺口之涟漪 纯算

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
猿人学第三届-第二题-滑块缺口之涟漪 纯算

猿人学第三届-第二题-滑块缺口之涟漪

1. 网络包分析

1.1 目标API

https://match2025.yuanrenxue.cn/match2025/topic/2_captcha_jpg

1.2 关键载荷参数

  • 参数名:mmc
  • 作用: 这是我们需要还原的加密参数


2. JS代码解混淆

2.1 初始分析

通过启动器进入JS代码后,发现代码经过了严重混淆:

  • 变量名使用了大量隐藏字符(Unicode特殊字符)
  • 代码结构被打乱
  • 如果不解混淆,代码几乎无法阅读

2.2 解混淆工具

使用在线工具进行解混淆:

https://js-deobfuscator.ve

重要设置

  • ✅ 勾选"变量优化"
  • ✅ 点击"清理代码"按钮,移除无用代码

2.3 解混淆后的问题修复

第一个报错

解混淆后替换原JS代码,浏览器报错:

2:1015 Uncaught ReferenceError: yrx_ﱞﱞﱞﱞﱞﱞﱞﱞﱞ is not defined at 2:1015:13 at 2:1166:11 at 2:1181:11 (匿名) @ 2:1015 (匿名) @ 2:1166 (匿名) @ 2:1181

报错位置代码

{try{g=yrx_ﱞﱞﱞﱞﱞﱞﱞﱞﱞ(f,newTextEncoder().encode(Navigator.prototype.userAgent.call(navigator))+"_|_");}catch(a){g=yrx_ﱞﱞﱞﱞﱞﱞﱞﱞﱞ(f,newTextEncoder().encode(navigator.userAgent+Date.now("r")));}}

定位原始代码

搜索关键字TextEncoder,找到解混淆前的代码:

try{yrx_ﱞﱞﱞﱞﱞﱞﱞ=yrx_ﱞﱞﱞﱞﱞﱞﱞﱞﱞ(yrx_ﱞﱞﱞﱞﱞﱞ,(newTextEncoder)["encode"](Navigator["prototype"]["userAgent"]["call"](navigator))+"_|_")}catch(yrx_ﱞ){yrx_ﱞﱞﱞﱞﱞﱞﱞ=yrx_ﱞﱞﱞﱞﱞﱞﱞﱞﱞ(yrx_ﱞﱞﱞﱞﱞﱞ,(newTextEncoder)["encode"](navigator["userAgent"]+Date["now"]("r")))}yrx_ﱞﱞﱞﱞ-=6132+7*-122+-10*527

解决方案

通过对比解混淆前后的代码,发现函数定义在下方:

varyrx_ﱞﱞﱞﱞﱞﱞﱞﱞﱞ=function(yrx_ﱞﱞﱞﱞ,yrx_ﱞﱞﱞﱞﱞ){varyrx_ﱞﱞﱞﱞﱞﱞ=yrx_ﱞﱞ(this,(function(){returnyrx_ﱞﱞﱞﱞﱞﱞ["toString"]()["search"]("(((.+)+)+)"+"+$")["toString"]()["constructo"+"r"](yrx_ﱞﱞﱞﱞﱞﱞ)["search"]("(((.+)+)+)"+"+$")}));yrx_ﱞﱞﱞﱞﱞﱞ();varyrx_ﱞﱞﱞﱞﱞﱞﱞ=yrx_ﱞﱞﱞ(this,(function(){varyrx_ﱞ=function(){varyrx_ﱞ;try{yrx_ﱞ=Function("return (fu"+"nction() "+("{}.constru"+'ctor("retu'+'rn this")('+" )")+");")()}catch(yrx_ﱞﱞ){yrx_ﱞ=window}returnyrx_ﱞ}// ... 更多代码}));}

我们需要手动重命名这个函数。将其重命名为Getutf8arry

// 修改后的代码try{g=Getutf8arry(f,newTextEncoder().encode(Navigator.prototype.userAgent.call(navigator))+"_|_");}catch(a){g=Getutf8arry(f,newTextEncoder().encode(navigator.userAgent+Date.now("r")));}d-=8;

同时修改函数定义:

varGetutf8arry=functione(d,f){vari=a||27;for(;;){if(i<16){if(i<8){if(i<4){if(i<2){if(i<1){j[l]=255-l;i+=14;}else{// ... 更多代码}}}}}}}
第二个报错

再次测试后发现还有一个报错位置:

}elseif(c<11){e=document.getElementById("captchaCanvas");c-=3;}else{k=yrx_ﱞﱞﱞﱞﱞﱞﱞﱞﱞ(f,j);// 这里还有一个未重命名的调用c-=7;}

修改为

}elseif(c<11){e=document.getElementById("captchaCanvas");c-=3;}else{k=Getutf8arry(f,j);// 修改函数名c-=7;}

修改完成后,刷新页面,图片正常显示,说明解混淆已完成。


3. 加密逻辑分析

3.1 核心加密函数分析

从我们重命名的Getutf8arry函数入手,分析其返回值:

try{g=Getutf8arry(f,newTextEncoder().encode(Navigator.prototype.userAgent.call(navigator))+"_|_");}catch(a){g=Getutf8arry(f,newTextEncoder().encode(navigator.userAgent+Date.now("r")));}

关键发现

  1. try块是混淆陷阱new TextEncoder().encode(...) + "_|_"会报错,因为 Uint8Array 不能与字符串相加
  2. 真正的加密在catch块:实际执行的是navigator.userAgent + Date.now("r")
  3. 返回值g是一个长度为124的Uint8Array数组

这是典型的RC4 加密算法的特征。

3.2 加密参数还原

参数1:加密数据(data)
// 真正的加密数据生成newTextEncoder().encode(navigator.userAgent+Date.now("r"))

还原为函数:

/** * 生成加密所需的输入数据(UA + 时间戳) * @returns {Uint8Array} 输入数据的字节数组 */functiongenerateInputData(){// 获取浏览器的 UserAgentconstuserAgent='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36'// 获取当前时间戳consttimestamp=Date.now().toString();// 将UA和时间戳合并constcombinedString=userAgent+timestamp;// 转换为字节数组returnnewTextEncoder().encode(combinedString);}
参数2:加密密钥(key)

通过调试,将密钥f转换为字符串:

console.log(newTextDecoder().decode(f))// 输出: b31ac05816bb570d

发现是一个16位的随机字符串。向上查找代码,找到密钥生成逻辑:

if(d<12){if(d<10){if(d<9){e=Array.apply(null,Array(16)).map(function(){varb=a||0;for(;;){return"0123456789abcdef0123456789abcdef0123456789abcdef6789abcdef789abcdef6789abcdef".charAt(Math.floor(Math.random()*62));}}).join("");// ... 更多代码}}}

验证

"0123456789abcdef0123456789abcdef0123456789abcdef6789abcdef789abcdef6789abcdef".charAt(Math.floor(Math.random()*62));// 'd'"0123456789abcdef0123456789abcdef0123456789abcdef6789abcdef789abcdef6789abcdef".charAt(Math.floor(Math.random()*62));// 'e'"0123456789abcdef0123456789abcdef0123456789abcdef6789abcdef789abcdef6789abcdef".charAt(Math.floor(Math.random()*62));// 'f'

每次运行生成一个字符,Array(16)生成16个字符,与密钥长度一致:

'b31ac05816bb570d'.length// 16

还原为函数:

/** * 生成16位随机字符串作为加密密钥 * @returns {string} 16位随机字符串 */functiongenerateRandomKey(){constcharset="0123456789abcdef0123456789abcdef0123456789abcdef6789abcdef789abcdef6789abcdef";constkey=Array.apply(null,Array(16)).map(function(){returncharset.charAt(Math.floor(Math.random()*62));}).join("");returnkey;}

将密钥转换为 Uint8Array:

/** * 将密钥字符串转换为Uint8Array * @param {string} key - 密钥字符串 * @returns {Uint8Array} 字节数组 */functionkeyToByteArray(key){returnnewTextEncoder().encode(key);}

3.3 RC4加密算法还原

Getutf8arry函数复制到本地:

/** * RC4变种加密算法 * @param {Uint8Array} key - 加密密钥(16字节) * @param {Uint8Array} data - 待加密数据 * @returns {Uint8Array} 加密后的数据 */functionrc4Encrypt(key,data){vari=27;// 固定为27(通过单步调试确定)//此处省略自行复制}

重要修改

  • i = a || 27改为固定值i = 27(通过单步调试确定)

3.4 Token格式化

找到将加密数组转换为最终token的位置。全局搜索mmc

elseif(d<3){h.data={mmc:Array.from(g).map(function(b){varc=a||0;for(;;){returnb.toString(16).padStart(2,"0");}}).join("")+e};}

单步调试后验证:

h.data// {mmc: '6a014756a723eec83e1ff6bf8e0ad3e420df3c896f60768a70...543f677c3633be4ab9ab1c9dc1c72e7e3d3f3db51a0982988'}

还原为函数:

/** * 将加密结果转换为token格式 * @param {Uint8Array} encryptedData - 加密后的数据 * @param {string} key - 原始密钥 * @returns {object} 包含mmc字段的数据对象 */functionformatToken(encryptedData,key){constresult={data:{mmc:Array.from(encryptedData).map(function(byte){returnbyte.toString(16).padStart(2,"0");}).join("")+key}};returnresult;}

格式说明

  • 将每个字节转换为2位16进制字符串
  • 所有字节拼接后,追加原始密钥
  • 最终形成完整的mmc参数

4. 完整代码实现

constUSER_AGENT='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36'/** * 生成16位随机字符串作为加密密钥 * @returns {string} 16位随机字符串 */functiongenerateRandomKey(){constcharset="0123456789abcdef0123456789abcdef0123456789abcdef6789abcdef789abcdef6789abcdef";constkey=Array.apply(null,Array(16)).map(function(){returncharset.charAt(Math.floor(Math.random()*62));}).join("");returnkey;}/** * 将密钥字符串转换为Uint8Array * @param {string} key - 密钥字符串 * @returns {Uint8Array} 字节数组 */functionkeyToByteArray(key){returnnewTextEncoder().encode(key);}/** * 生成加密所需的输入数据(UA + 时间戳) * @returns {Uint8Array} 输入数据的字节数组 */functiongenerateInputData(){// 获取浏览器的 UserAgentconstuserAgent=typeofnavigator!=='undefined'?navigator.userAgent:USER_AGENT;// 获取当前时间戳consttimestamp=Date.now().toString();// 将UA和时间戳合并constcombinedString=userAgent+timestamp;// 转换为字节数组returnnewTextEncoder().encode(combinedString);}/** * RC4变种加密算法 * @param {Uint8Array} key - 加密密钥(16字节) * @param {Uint8Array} data - 待加密数据 * @returns {Uint8Array} 加密后的数据 */functionrc4Encrypt(key,data){// 此处省略具体实现,请从原始JS中复制完整的rc4Encrypt函数// 记得将 i = a || 27 改为 i = 27}/** * 将加密结果转换为token格式 * @param {Uint8Array} encryptedData - 加密后的数据 * @param {string} key - 原始密钥 * @returns {object} 包含mmc字段的数据对象 */functionformatToken(encryptedData,key){constresult={data:{mmc:Array.from(encryptedData).map(function(byte){returnbyte.toString(16).padStart(2,"0");}).join("")+key}};returnresult;}/** * 生成完整的加密token * @returns {string} 加密后的token字符串 */functiongenerateToken(){// 1. 生成随机密钥constkey=generateRandomKey();console.log("生成密钥:",key);// 2. 将密钥转换为字节数组constkeyBytes=keyToByteArray(key);console.log("密钥字节数组:",keyBytes);// 3. 生成输入数据(UA + 时间戳)constinputData=generateInputData();console.log("输入数据:",inputData);// 4. 执行RC4加密constencryptedData=rc4Encrypt(keyBytes,inputData);console.log("加密结果:",encryptedData);// 5. 格式化为最终tokenconsttokenData=formatToken(encryptedData,key);returntokenData.data.mmc;}// 使用示例consttoken=generateToken();console.log("最终Token:",token);

5. 总结

5.1 加密流程

  1. 生成随机密钥:16位随机字符串(从特定字符集中选择)
  2. 准备加密数据:UserAgent + 当前时间戳
  3. RC4加密:使用密钥对数据进行RC4变种加密
  4. 格式化输出:将加密结果转为16进制字符串,并追加原始密钥

5.2 关键技术点

  • 混淆陷阱:try块中的代码会报错,真正的逻辑在catch块
  • RC4算法:使用了RC4的变种实现
  • 状态机控制:通过变量i控制执行流程(固定为27)
  • Token格式:加密数据的16进制表示 + 原始密钥

5.3 注意事项

  • 时间戳必须与服务器时间同步
  • UserAgent必须与浏览器一致
  • 密钥每次请求都需要重新生成
  • 最终的mmc参数包含加密数据和密钥两部分
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/18 3:25:56

基于SpringBoot2+Vue2的线上艺术学习视频网站

线上艺术学习视频网站系统 演示视频 https://www.bilibili.com/video/BV1d3mgBrEz2/ 角色 管理员 教师 学生 技术 Spring Boot、MyBatis-Plus、MySQL、Vue 核心功能 本系统是一个线上艺术学习视频网站&#xff0c;核心价值在于提供一个集课程学习、艺术作品分享、社区交…

作者头像 李华
网站建设 2026/4/18 3:26:02

2025最新的电子实验记录本软件,引领科研数字化变革的智能中枢

在生命科学、生物医药、材料化学等前沿科研领域&#xff0c;每一次实验、每一组数据都是推动科学进步的基石。长久以来&#xff0c;研究人员依赖纸质实验记录本&#xff0c;不仅面临字迹潦草、本册易损、检索困难等困扰&#xff0c;更在数据整合、团队协作和合规审计上步履维艰…

作者头像 李华
网站建设 2026/4/17 22:13:39

docker启动mysql及部分命令回顾

一、创建mysql 1、docker run --name mysql8.0-container -e MYSQL_ROOT_PASSWORDmy-secret-pw -d -p 3306:3306 mysql:8.0参数解释&#xff1a; --name mysql8.0-container&#xff1a;指定容器的名称为mysql8.0-container。 -e MYSQL_ROOT_PASSWORDmy-secret-pw&#xff1a;设…

作者头像 李华
网站建设 2026/4/18 0:32:15

终极HTML压缩指南:如何用minify-html让你的网页加载速度翻倍

终极HTML压缩指南&#xff1a;如何用minify-html让你的网页加载速度翻倍 【免费下载链接】minify-html Extremely fast and smart HTML JS CSS minifier, available for Rust, Deno, Java, Node.js, Python, Ruby, and WASM 项目地址: https://gitcode.com/gh_mirrors/mi/m…

作者头像 李华