缘起

应星友要求,写下此文,哎,有钱能使鬼推磨。

实战地址:

http://match.yuanrenxue.com/match/2

抓包分析

由于谷歌浏览器某些请求不会显示,建议使用火狐浏览器来抓包分析。

这是一个典型的cookie反爬,最后一个红框处是数据接口。如果不看题目,有经验的人一眼就能看出来。

第一次请求,返回的是一段js代码:

第二次请求的是同一地址,这时候带上了cookie:

根据经验,第二次请求的cookie,肯定是第一次请求计算的,因为第一次请求结果中并没有直接设置cookie。

注意记录此时的 cookie 值:

m : "9c8b2ba4362ff5a7023d8db7041dcd04|1603517539000"

|后面明显是个时间戳

AST化简代码,静态分析

将第一次请求的js代码保存为encode.js,去掉 script标签。

保存后,使用一键解ob混淆工具还原代码,命令:

node decode_obfuscator.js encode.js

打开保存后的结果 decode_result.js,代码很短,一下就看到了 cookie设置的地方:

是在 _0x721154 这个函数里设置的,后面直接就调用了,实参是 函数 _0x5015e3 ,它的返回值是一个 时间戳,也就是 |后面的值

把 _0x721154 这个函数改造一下,去掉DOM相关的操作,让它直接返回结果:

function _0x721154(_0x1243f6, _0x167ea5) {return "m" + _0x3445fe() + "=" + _0x531a93(_0x1243f6) + "|" + _0x1243f6 + "; path=/";}

现在实参明确了,返回结果也明确了,先来看 _0x3445fe 这个函数

去除垃圾代码

_0x3445fe 这个函数 定义如下:

function _0x3445fe(_0x22e65, _0x533ac1) {var _0x537cb8 = 0;var _0x385b2c = _0x2d77f8(this, function () {var _0x245ea0 = function () {var _0x56862a = _0x245ea0["constructor"]("return /\" + this + \"/")()["compile"]("^([^ ]+( +[^ ]+)+)+[^ ]}");return !_0x56862a["test"](_0x385b2c);};return _0x245ea0();});_0x385b2c();_0x449be1();qz = [10, 99, 111, 110, 115, 111, 108, 101, 32, 61, 32, 110, 101, 119, 32, 79, 98, 106, 101, 99, 116, 40, 41, 10, 99, 111, 110, 115, 111, 108, 101, 46, 108, 111, 103, 32, 61, 32, 102, 117, 110, 99, 116, 105, 111, 110, 32, 40, 115, 41, 32, 123, 10, 32, 32, 32, 32, 119, 104, 105, 108, 101, 32, 40, 49, 41, 123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 102, 111, 114, 40, 105, 61, 48, 59, 105, 60, 49, 49, 48, 48, 48, 48, 48, 59, 105, 43, 43, 41, 123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 104, 105, 115, 116, 111, 114, 121, 46, 112, 117, 115, 104, 83, 116, 97, 116, 101, 40, 48, 44, 48, 44, 105, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 125, 10, 32, 32, 32, 32, 125, 10, 10, 125, 10, 99, 111, 110, 115, 111, 108, 101, 46, 116, 111, 83, 116, 114, 105, 110, 103, 32, 61, 32, 39, 91, 111, 98, 106, 101, 99, 116, 32, 79, 98, 106, 101, 99, 116, 93, 39, 10, 99, 111, 110, 115, 111, 108, 101, 46, 108, 111, 103, 46, 116, 111, 83, 116, 114, 105, 110, 103, 32, 61, 32, 39, 402, 32, 116, 111, 83, 116, 114, 105, 110, 103, 40, 41, 32, 123, 32, 91, 110, 97, 116, 105, 118, 101, 32, 99, 111, 100, 101, 93, 32, 125, 39, 10];eval(_0x19be63(qz));try {if (global) {console["log"]("\u4EBA\u751F\u82E6\u77ED\uFF0C\u4F55\u5FC5python\uFF1F");} else {while (1) {console["log"]("\u4EBA\u751F\u82E6\u77ED\uFF0C\u4F55\u5FC5python\uFF1F");debugger;}}} catch (_0x1d08b1) {return navigator["vendorSub"];}}

来看 _0x385b2c 这个函数:

var _0x385b2c = _0x2d77f8(this, function () {var _0x245ea0 = function () {var _0x56862a = _0x245ea0["constructor"]("return /\" + this + \"/")()["compile"]("^([^ ]+( +[^ ]+)+)+[^ ]}");return !_0x56862a["test"](_0x385b2c);};return _0x245ea0();});_0x385b2c();

这个函数在声明之后马上就执行了,没有实参,虽然有返回值,但是并没有赋值给其他变量。 再看函数体,没有对任何全局变量进行操作,因此,可以直接进行删除!

按照这个思路,后面的 _0x449be1(); 调用同样可以删除,没啥用。

再看 try语句:

    try {if (global) {console["log"]("\u4EBA\u751F\u82E6\u77ED\uFF0C\u4F55\u5FC5python\uFF1F");} else {while (1) {console["log"]("\u4EBA\u751F\u82E6\u77ED\uFF0C\u4F55\u5FC5python\uFF1F");debugger;}}} catch (_0x1d08b1) {return navigator["vendorSub"];}

浏览器环境没有 global 这个对象,那就会执行 catch语句,返回了:

navigator["vendorSub"]

这个值,直接在控制台运行得出它是一个空值。因此,直接替换成这样就好:

return "";

这样就清爽多了:

function _0x3445fe(_0x22e65, _0x533ac1) {var _0x537cb8 = 0;qz = [10, 99, 111, 110, 115, 111, 108, 101, 32, 61, 32, 110, 101, 119, 32, 79, 98, 106, 101, 99, 116, 40, 41, 10, 99, 111, 110, 115, 111, 108, 101, 46, 108, 111, 103, 32, 61, 32, 102, 117, 110, 99, 116, 105, 111, 110, 32, 40, 115, 41, 32, 123, 10, 32, 32, 32, 32, 119, 104, 105, 108, 101, 32, 40, 49, 41, 123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 102, 111, 114, 40, 105, 61, 48, 59, 105, 60, 49, 49, 48, 48, 48, 48, 48, 59, 105, 43, 43, 41, 123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 104, 105, 115, 116, 111, 114, 121, 46, 112, 117, 115, 104, 83, 116, 97, 116, 101, 40, 48, 44, 48, 44, 105, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 125, 10, 32, 32, 32, 32, 125, 10, 10, 125, 10, 99, 111, 110, 115, 111, 108, 101, 46, 116, 111, 83, 116, 114, 105, 110, 103, 32, 61, 32, 39, 91, 111, 98, 106, 101, 99, 116, 32, 79, 98, 106, 101, 99, 116, 93, 39, 10, 99, 111, 110, 115, 111, 108, 101, 46, 108, 111, 103, 46, 116, 111, 83, 116, 114, 105, 110, 103, 32, 61, 32, 39, 402, 32, 116, 111, 83, 116, 114, 105, 110, 103, 40, 41, 32, 123, 32, 91, 110, 97, 116, 105, 118, 101, 32, 99, 111, 100, 101, 93, 32, 125, 39, 10];eval(_0x19be63(qz));return "";}

这个函数后面是一个 定时器语句,因为后面有调用 _0x3445fe 这个函数,因此这行调用也可以删除:

setInterval(_0x3445fe(), 500);

定你妹呀!

运行得到结果

好了,经过上面的操作,似乎可以运行了。注意加打印并传入实参,方便比对结果:

console.log(_0x721154("1603517539000"));

将上面的代码添加到自执行函数的最好一行,运行报错:

报错位置在 _0x3445fe 函数的 下面代码处:

eval(_0x19be63(qz));

有个history,估计也是dom相关的,先屏蔽掉,再运行:

不报错了,比对之前的cookie值,一模一样。

这就出结果了,简直不要太简单。完!

AST反混淆实战:猿人学爬虫比赛第二题详细题解相关推荐

  1. JS逆向:猿人学爬虫比赛第九题详细题解

    实战地址 http://match.yuanrenxue.com/match/9 抓包分析 地址栏输入 地址,按下F12并回车,浏览器停在这里: 不用理会它,点击下图所示的按钮: 按下F8,让浏览器继 ...

  2. AST反混淆实战-高级难度

    Ast实战:反混淆解析高级难度ob混淆网站 https://obfuscator.io/ 一.混淆demo生成 二.混淆demo说明 步骤相同-不在冗余 详情参考:AST反混淆实战-中等难度 http ...

  3. AST反混淆实战-经典ob混淆

    Ast实战:反混淆解析经典ob混淆 一.混淆demo获取 ob混淆源码 来自猿人学14题 https://match.yuanrenxue.com/api/match/14/m demo.js //为 ...

  4. AST反混淆实战-中等难度

    Ast实战:反混淆解析中等难度ob混淆网站 https://obfuscator.io/ 一.混淆demo生成 二.混淆demo生成 三.混淆demo整理 demo.js //TODO 这里对混淆de ...

  5. webpack打包后引用cdn的js_JS逆向:Webpack打包后的代码怎么搞?猿人学爬虫比赛第十六题详细题解...

    实战地址 http://match.yuanrenxue.com/match/16 抓包分析 地址栏输入 地址,按下F12并回车,发现数据在这里: 查看cookie,无加密相关的字段.请求的接口倒是有 ...

  6. JS逆向:猿人学爬虫比赛第五题详细题解(下)

    上篇文章,我们已经找到了加密的地方,关键代码是这样的: _$Ww = _$Tk["enc"]["Utf8"]["parse"](window ...

  7. js逆向系列之猿人学爬虫第17题-天杀的http2.0

    文章目录 1. 目标网站 2. 抓包分析 3. 编码测试 1. 目标网站 网址: https://match.yuanrenxue.com/match/17 2. 抓包分析 这道题目,叫天杀的http ...

  8. js逆向系列之猿人学爬虫第13题

    文章目录 1. 目标网址 2. 抓包分析 3. 编码测试 1. 目标网址 目标网站:猿人学web第13题 2. 抓包分析 浏览器打开无痕模式,看第一页数据包: 两个名叫13的包,第二个有数据,是请求了 ...

  9. [007]爬虫系列 | 猿人学爬虫攻防大赛 | 第二题: js 混淆 - 动态Cookie

    一.题目 链接: <猿人学爬虫攻防大赛 | 第二题: js 混淆 - 动态Cookie> 二.分析 按照以往习惯,我们先按F12打开控制台,Network抓包,勾选preserve log ...

最新文章

  1. html弹窗赋值给查询框,bootstrap模态框动态赋值, ajax异步请求数据后给id为queryInfo的模态框赋值并弹出模态框(JS)...
  2. 兼容ie8 rgba()用法
  3. floyd 判圈算法 UVa 11549 计算器谜题
  4. 什么是 MultiRaft ?
  5. 【离散数学】集合的包含排斥原理
  6. Bluetooth handsfree 和 headset 区别
  7. 制作自己的特色PE----Mr.Zhang
  8. 洛谷P1313 计算系数【快速幂+dp】
  9. SocketDataHandler ConcurrentAsyncQueue Server/Client
  10. python 读取excel太慢_实用技巧——Python实现从Excel读取数据并绘制成图像
  11. 二、十进制数字快速转换为16进制字符
  12. java struts 拦截器_java框架篇---struts实现拦截器
  13. Java中list==null与list.size( )==0的区别
  14. windows7修改或删除曾经保存的远程桌面连接的密码
  15. 华为5大设计师讲述HarmonyOS UX设计背后的故事
  16. 笔试题:输入0123456789对应输出“一二三四五六七八九”
  17. 163VIP邮箱登录入口有哪些?VIP163邮箱怎么登陆?
  18. ios项目中调用百度地图iphone版与百度地图HDipad版的坑
  19. MIC的常见问题分析
  20. 沪深A股分析数据龙虎榜信息API接口(JSON标准格式,Get请求方式)

热门文章

  1. Allegro通孔焊盘制作
  2. 快的买大黄蜂是福是祸?
  3. 实验7 Wireshark网络安全检测
  4. JAVA学习者从入门到精通
  5. Latex 调整行距
  6. R语言ECM误差修正模型、均衡修正模型、受限VECM、协整检验、单位根检验即期利率市场数据
  7. LINK : fatal error LNK1168: cannot open Debug/xxx.exe for writing
  8. 音视频开发进阶|第七讲:分辨率与帧率·上篇
  9. 大数据与JS实现2014巴西世界杯冠军预测图
  10. 猿创征文|我的前端学习之旅【来自一名大四老学长的真情流露】