[2021.7]猿人学 | 爬虫攻防大赛 | 第二题

本文探讨了动态cookie的抓包分析和加密机制,通过谷歌抓包和Fiddler4工具,揭示了动态cookie的生成过程,并利用Python实现了解密和爬虫策略。重点在于理解_0x6a787a和相关函数的作用,以及如何编写脚本来处理加密后的cookie值。
摘要由CSDN通过智能技术生成

1.cookie作用

Cookie相当于你浏览Web站点时,相对于这个站点的身份证号,如果说身份证号错误,肯定是不能正常访问这个站点的;这也是这次题目的考察内容

动态cookie,每过一段时间 ,就会重新加载cookie来重置页面,通过这种方式,达到反爬虫的效果,只有破解掉动态cookie的生成过程,才可以通过爬虫进行正常爬取

2.谷歌抓包分析

由于是动态Cookie,为了避免其他Cookie的影响,所以使用浏览器的无痕模式进行调试,按f12并选中【Preserve log】
【Preserve log】:保留请求日志,跳转页面的时候勾选上,可以看到跳转前的请求(可以让我看到更详细的请求)

这里抓包时依然要禁用debugger
在这里插入图片描述
这里分析抓到的包,第一个2是没有 返回任何数据的
并且谷歌也无法查看response
如下图所示:
在这里插入图片描述
在这里插入图片描述
第二个2的请求,是携带了cookie,并且也是请求到了有关的数据,如下图所示:
在这里插入图片描述
在这里插入图片描述
后面第三个2的XHR请求中,存在传输的数据,并且同样是携带了cookie的:
在这里插入图片描述
接下来,我们就来分析动态cookie的加载过程

3.cookie变换代码分析

既然谷歌抓包无法有效进行分析,那我们就用fiddler4,进行抓包分析,fiddler4是一款非常强大的抓包工具,可以配置抓取app的数据包,也可以抓取PC端的数据包,关于fiddler4的使用和配置,这里就不详细介绍了,自行百度即可。
使用fiddler4进行抓包,发现第一条/match/2的请求,原本在谷歌中无法查看的响应,在这里可以看到,可以发现,这是一段JS代码,这里,我们猜测这是进行动态cookie加密的代码(因为下一条/match/2紧接着获取了cookie,而且第一条的响应中也没有set-cookie)
在这里插入图片描述
我们对它进行解混淆后,复制到JS调试工具中进行分析(这里我使用的是pycharm分析,控制台进行测试)
在这里插入图片描述
这里代码量比较长,我们只首先关键的生成cookie的部分
在这里插入图片描述
在这里插入图片描述
与生成的cookie对比一下,发现"m" 和 “=” 之间应该是空字符串,但是这里还需要注意的是,这个函数可能通过eval执行其他操作,这里对_0x6a787a()函数进行简单分析
上代码:

 function _0x6a787a(_0x5cd4c7, _0x24c494) {
    var _0x1289d2 = _0x4c58de(this, function () {
      var _0x55f098 = function () {
        var _0x55df77 = _0x55f098["constructor"]("return /\" + this + \"/")()["compile"]("^([^ ]+( +[^ ]+)+)+[^ ]}");

        return !_0x55df77["test"](_0x1289d2);
      };

      return _0x55f098();
    });

    _0x1289d2();

    (function () {
      _0x3878a0(this, function () {
        var _0x261244 = new RegExp("function *\\( *\\)");

        var _0x17ca1d = new RegExp("\\+\\+ *(?:[a-zA-Z_$][0-9a-zA-Z_$]*)", "i");

        var _0x305294 = $dbsm_0x1f5ac5("init");

        if (!_0x261244["test"](_0x305294 + "chain") || !_0x17ca1d["test"](_0x305294 + "input")) {
          _0x305294("0");
        } else {
          $dbsm_0x1f5ac5();
        }
      })();
    })();

    _0x5d5fb0();

    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(_0x55525f(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 (_0x2455d3) {
      return navigator["vendorSub"];
    }
  }

分析以上代码,执行了_0x1289d2()函数以及_0x5d5fb0(),这两个函数并且包含了eval(_0x55525f(qz))这段代码

我们先来看_0x1289d2()函数,放到控制台去执行
在这里插入图片描述
发现这个东西,跟加密没什么关系,先pass掉,记住有这样的东西
然后再来看_0x5d5fb0()这个函数

  function _0x5d5fb0(_0x107682, _0x4d361d) {
    if (_0x4d361d) {
      return _0xfb1f8b(_0x107682);
    }

    return _0x4c0128(_0x107682);
  }

  function _0x55525f(_0x350007, _0x2fd05c) {
    let _0x3aca5d = "";

    for (let _0xa9a63 = 0; _0xa9a63 < _0x350007["length"]; _0xa9a63++) {
      _0x3aca5d += String["fromCharCode"](_0x350007[_0xa9a63]);
    }

    return _0x3aca5d;
  }

这个函数是需要传入参数的,没有参数估计也没什么用,我们先控制台运行一下试试:
在这里插入图片描述
最后就是这个特殊的eval(_0x55525f(qz))函数,我们来执行一下看看是否对结果cookie值有影响
在这里插入图片描述
好吧,只是一串字符串,仅此而已。
看剩下的其他代码:

    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 (_0x2455d3) {
      return navigator["vendorSub"];
    }

try…catch 这个语法,我相信稍微学了点编程的同学,都知道是什么意思,我这里也不再阐述,不懂的同学可以问问百度
try里面的内容还是有点意思,直接进来就报错
我为什么这么说呢,是因为,global这个变量根本就没有定义,所有会直接报错,进入catch里面,虽然说传入了变量,但是在下面的代码并没有引用,可以不管
最后,直接return navigator[“vendorSub”]

接下来,我们可以来删除无用函数,简化改变cookie的代码

  function _0x83032f(_0x297bfd, _0x281a82) {
    document["cookie"] = "m" + "=" + _0x53fd82(_0x297bfd) + "|" + _0x297bfd + "; path=/";
    location["reload"]();
  }

这样来看,很明显,加密是通过_0x53fd82(_0x297bfd)函数进行处理的,
在这里插入图片描述
接着分析_0x53fd82(_0x297bfd)函数,_0x297bfd是传入的参数,是由执行函数中_0x334d50()生成的,而 _0x53fd82()是一串很长的三元运算符,分析这个三元运算符,在执行函数时只给_0x3e4e6a传入了时间参数,其他的都是null值,因此直接跳入_0x5cd03d(_0x3e4e6a)来执行
_0x53fd82()代码如下所示:

  function _0x53fd82(_0x3e4e6a, _0x31d569, _0x124094) {
    _0x6a787a();
	# 这里只执行_0x5cd03d(_0x3e4e6a) ,这里有一些三元运算符的计算技巧
    return _0x31d569 ? _0x124094 ? _0x4c0128(_0x31d569, _0x3e4e6a) : y(_0x31d569, _0x3e4e6a) : _0x124094 ? _0x554afd(_0x3e4e6a) : _0x5cd03d(_0x3e4e6a);
  }

_0x334d50()代码如下所示:

  function _0x334d50(_0x53a223, _0xc9f38e) {
    return Date["parse"](new Date());
  }

然后又发现_0x5cd03d()函数依然调用了方法,调用的方法又调用了别的方法,我这里直接pass掉,直接放到控制台去运行调试。这里建议使用调试工具(博主正在找,找到给大家分享),将以上没用的代码进行删除,自定义一个get_m_value函数用来去到加密的值,如下所示:

# 这里是原来三元运算符的代码
function _0x53fd82(_0x3e4e6a, _0x31d569, _0x124094) {
    return _0x5cd03d(_0x3e4e6a);
}
# 这是取到加密值
function _0x83032f(_0x297bfd, _0x281a82) {
    return "m" + "=" + _0x53fd82(_0x297bfd) + "|" + _0x297bfd;
}
# 使用函数去调用代码
function get_m_value(){
    return _0x83032f(_0x334d50()); 
}

我们看一下做题时的时间字符串:
在这里插入图片描述
把这个值复制后,放入修改后的代码中,进行加密验证,看看加密字符串有没有问题
#在这里插入图片描述

4.编写脚本

接下来就可以愉快的敲python代码了
代码如下:

import requests
import execjs
import time

def get_res(page_num,parm):
    url = 'http://match.yuanrenxue.com/api/match/2?page={}'.format(page_num)
    headers = {
        'Host': 'match.yuanrenxue.com',
        'Referer': 'http://match.yuanrenxue.com/match/2',
        'User-Agent': 'yuanrenxue.project',
        'X-Requested-With': 'XMLHttpRequest',
        'Cookie': parm
    }
    response = requests.get(url=url,headers=headers)
    print(response.content.decode())
    return response.json()

def calculate_m_value():
    with open('22.js',mode='r',encoding='utf-8') as f:
        JsData = f.read()
    cookie_value = execjs.compile(JsData).call('get_m_value')
    return cookie_value

if __name__ == '__main__':
    sum_ = 0
    for page_num in range(1,6):
        print(page_num)
        time.sleep(1)
        cookie_value = calculate_m_value()
        res = get_res(page_num,cookie_value)
        for i in res['data']:
            sum_ +=i['value']
    print(sum_)


在这里插入图片描述
结果如下:
在这里插入图片描述

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

代码魔法师!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值