Java_S 发表于 2021-1-15 20:58

Python反反爬之JS混淆---回溯

# 写在前面
Python反反爬系列

1.
2.
3. [访问逻辑---推心置腹]
4.

[解题代码Github](https://github.com/Java-S12138/yuanrenxue_python_spider)
[个人博客](https://syjun.vip)
## 题目
![]
题目网站,[点我去刷题]

**采集全部5页的彩票数据,计算全部中奖的总金额(包含一、二、三等奖)**

## 分析网页
老规矩,我们还是首先打开刷题网站,接着打开谷歌调试工具
查看【XHR】里面的内容
![]
可以发现通过Ajax的方式,返回了一串数据
对比网页的数字,不难发现,这些返回的数据,是页面的三等奖金额

但是,这道题让我们求的是一等奖,二等奖,三等奖的总金额
做了几道猿人学的题目,我们可以猜测,总金额可能会通过JS代码生成
这个问题,我们先留着,继续分析一下返回数据的这个URL

![]
通过观察,我们可以发现,URL中带了两个参数,一个【 m 】的加密参数,还有一个【 q 】的参数,【 q 】的参数值与时间戳类似
**所以说,要想正常访问,肯定要先算出【 m 】和【 q 】的值**

## m 和 q的值,从何而来
我们知道上面提到的请求是通过Ajax请求返回的,这里可以分享给大家一个小技巧
在谷歌浏览器的调试工具中,我们可以通过下图的方式,直接进入到AJax的代码部分
![]
![]
![]

来到这个页面,Ajax上面定义的一个数组,引起了我的注意,我们将它扣下来
```javascript
var list = {
    "page": window.page,
    "m": r(t, window.o),
    "q": window.i += window.o + '-' + t + "|",
};
```
看到这段代码,我相信大家已经大概明白了 m 和 q的值,从何而来

- **page**:页码,因为我们请求的第一页,所以在URL中省略了,但是从第二页开始page就会出现
- **m**:通过调用**r**函数,并传入,【t】和【window.o】参数,得到一串加密后的密文
- **q**:通过 += 的方式,可以累加得到一串字符串

我们截取一段 【q】的值分析一下,window.i和window.o已经 t 是什么

> q: 1-1610261917000|
通过对比我们可以发现

1. window.i就是这串值
2. window.o是1
3. t就是时间戳

但是,这个 += 符号有什么用呢?
我们多次请求一下第二页和第三页,你就明白啦

> q: 1-1610261917000|2-1610264287000|3-1610264288000|

这是我请求第一页,第二页,第三页后,【q】的值
这个时候,可能就有小伙伴会说,window.o就是页码的值

但是,当我在第三页回到第一页的时候,【q】的值是这样的

> q: 1-1610261917000|2-1610264287000|3-1610264288000|4-1610264345000|

所以说,window.o的值其实很简单,并不是页码的值,而是点击页面发起Ajax请求的次数罢了


----------
明白了【t】和【window.o】的含义,我们就明白了通过调用**r**函数传入的参数是什么了
现在我们知道了【q】值的生成过程,而【m】只知道一部分,所以我们的下一步就是寻找**r**函数

## 寻找**r**函数
我们在**r**函数出现的哪一行代码,打一个断点
![]
接着按CTRL+R,刷新一下页面
我们会发现代码卡在了769这一行,我们点击右上角的箭头继续往下运行
![]
这个时候,代码就卡在了**r**函数这一行,我们点击右上角如下图的这个按钮,就可以进入到包含**r**函数的JS文件中,这也是题目所提到的 【 **回溯** 】
![]
![]
就是这么简单,我们很顺利的找到了**r**函数,接着我们将代码扣下来分析一下

## 分析r函数

```javascript
function r(param1, param2) {
    if (window.o >= 6) {
      alert('不要戳这么多下,人家好痛嘛~');
      location.reload();
    }
    return z(param1, param2);
}
```
代码中,出现了一个if判断, 而判断中的内容就是,如果**Ajax请求**(也就是点击页面中页码的次数,当然首次进入页面是默认发起了一次请求的)**大于或者等于6次**的话,页面就会出现**如下图的弹窗**,紧接着执行**location.reload()函数**,而这个函数,我们在前面的题目中也碰到过,就是刷新整个页面,**window.o的值也会重置为1**
![]

接着将传入的参数,二次传递给**z**函数并执行
我们来看一下**z**函数中的代码
```javascript
function z(pwd, time) {
    var n = _n("jsencrypt");
    var g = (new n);
    var r = g.encode(pwd, time);
    return r;
}
```
这段代码的注意内容是:

- 实例化了jsencrypt对象
- 使用jsencrypt中的encode方法,进行了加密,并且返回,也就是【m】的值

jsencrypt就是一个基于rsa加解密的js库,反正就是一段操作,返回一段密文,感兴趣的同学可以自行百度,我这里就不展开讲了
我们就可以通过运行这个JS文件,从而得出m的值

到这里,相信大家已经明白了m 和 q的值,都是怎样产生的了

但是,在包含**r**函数的JS文件中,是有混淆过的代码的
大致浏览一下文件中的代码你就会发现这样三处混淆代码
![]
![]
![]

**所以说, 要想通过JS文件得出m的值,就需要先将混淆的代码翻译过来**

## 翻译混淆过的代码
通常像这种混淆过的代码,如果不是一个函数的话,我们是可以通过谷歌调试工具中的Console,运行出结果的
比如说这段混淆代码,其实就是JS中的一些运算
```javascript
[][(![] + [])[!+[] + !![] + !![]] + ([] + {})[+!![]] + (!![] + [])[+!![]] + (!![] + [])[+[]]][([] + {})[!+[] + !![] + !![] + !![] + !![]] + ([] + {})[+!![]] + ([][[]] + [])[+!![]] + (![] + [])[!+[] + !![] + !![]] + (!![] + [])[+[]] + (!![] + [])[+!![]] + ([][[]] + [])[+[]] + ([] + {})[!+[] + !![] + !![] + !![] + !![]] + (!![] + [])[+[]] + ([] + {})[+!![]] + (!![] + [])[+!![]]]((+!![] + []) + (!+[] + !![] + !![] + !![] + !![] + []) + (!+[] + !![] + !![] + !![] + !![] + !![] + !![] + []) + (+!![] + []) + (!+[] + !![] + !![] + !![] + !![] + []) + (+[] + []) + (!+[] + !![] + !![] + !![] + !![] + !![] + !![] + []) + (+[] + []))(!+[] + !![] + !![] + !![] + !![] + !![] + !![]) == ([][(![] + [])[!+[] + !![] + !![]] + ([] + {})[+!![]] + (!![] + [])[+!![]] + (!![] + [])[+[]]][([] + {})[!+[] + !![] + !![] + !![] + !![]] + ([] + {})[+!![]] + ([][[]] + [])[+!![]] + (![] + [])[!+[] + !![] + !![]] + (!![] + [])[+[]] + (!![] + [])[+!![]] + ([][[]] + [])[+[]] + ([] + {})[!+[] + !![] + !![] + !![] + !![]] + (!![] + [])[+[]] + ([] + {})[+!![]] + (!![] + [])[+!![]]]((+!![] + []) + (!+[] + !![] + !![] + !![] + !![] + !![] + []) + (!+[] + !![] + !![] + !![] + !![] + !![] + !![] + []) + (!+[] + !![] + !![] + !![] + !![] + !![] + !![] + []) + (!+[] + !![] + !![] + !![] + !![] + !![] + !![] + []) + (!+[] + !![] + []) + (+!![] + []) + (!+[] + !![] + !![] + !![] + !![] + []))(!+[] + !![] + !![] + !![] + !![] + !![]) & [][(![] + [])[!+[] + !![] + !![]] + ([] + {})[+!![]] + (!![] + [])[+!![]] + (!![] + [])[+[]]][([] + {})[!+[] + !![] + !![] + !![] + !![]] + ([] + {})[+!![]] + ([][[]] + [])[+!![]] + (![] + [])[!+[] + !![] + !![]] + (!![] + [])[+[]] + (!![] + [])[+!![]] + ([][[]] + [])[+[]] + ([] + {})[!+[] + !![] + !![] + !![] + !![]] + (!![] + [])[+[]] + ([] + {})[+!![]] + (!![] + [])[+!![]]]((+[] + []) + [][(![] + [])[!+[] + !![] + !![]] + ([] + {})[+!![]] + (!![] + [])[+!![]] + (!![] + [])[+[]]][([] + {})[!+[] + !![] + !![] + !![] + !![]] + ([] + {})[+!![]] + ([][[]] + [])[+!![]] + (![] + [])[!+[] + !![] + !![]] + (!![] + [])[+[]] + (!![] + [])[+!![]] + ([][[]] + [])[+[]] + ([] + {})[!+[] + !![] + !![] + !![] + !![]] + (!![] + [])[+[]] + ([] + {})[+!![]] + (!![] + [])[+!![]]]((!![] + [])[+!![]] + ([][[]] + [])[!+[] + !![] + !![]] + (!![] + [])[+[]] + ([][[]] + [])[+[]] + (!![] + [])[+!![]] + ([][[]] + [])[+!![]] + ([] + {})[!+[] + !![] + !![] + !![] + !![] + !![] + !![]] + ([][[]] + [])[+[]] + ([][[]] + [])[+!![]] + ([][[]] + [])[!+[] + !![] + !![]] + (![] + [])[!+[] + !![] + !![]] + ([] + {})[!+[] + !![] + !![] + !![] + !![]] + (+{} + [])[+!![]] + ([] + [][(![] + [])[!+[] + !![] + !![]] + ([] + {})[+!![]] + (!![] + [])[+!![]] + (!![] + [])[+[]]][([] + {})[!+[] + !![] + !![] + !![] + !![]] + ([] + {})[+!![]] + ([][[]] + [])[+!![]] + (![] + [])[!+[] + !![] + !![]] + (!![] + [])[+[]] + (!![] + [])[+!![]] + ([][[]] + [])[+[]] + ([] + {})[!+[] + !![] + !![] + !![] + !![]] + (!![] + [])[+[]] + ([] + {})[+!![]] + (!![] + [])[+!![]]]((!![] + [])[+!![]] + ([][[]] + [])[!+[] + !![] + !![]] + (!![] + [])[+[]] + ([][[]] + [])[+[]] + (!![] + [])[+!![]] + ([][[]] + [])[+!![]] + ([] + {})[!+[] + !![] + !![] + !![] + !![] + !![] + !![]] + (![] + [])[!+[] + !![]] + ([] + {})[+!![]] + ([] + {})[!+[] + !![] + !![] + !![] + !![]] + (+{} + [])[+!![]] + (!![] + [])[+[]] + ([][[]] + [])[!+[] + !![] + !![] + !![] + !![]] + ([] + {})[+!![]] + ([][[]] + [])[+!![]])(+!![]))[!+[] + !![] + !![]] + ([][[]] + [])[!+[] + !![] + !![]])(!+[] + !![] + !![] + !![] + !![])([][(![] + [])[!+[] + !![] + !![]] + ([] + {})[+!![]] + (!![] + [])[+!![]] + (!![] + [])[+[]]][([] + {})[!+[] + !![] + !![] + !![] + !![]] + ([] + {})[+!![]] + ([][[]] + [])[+!![]] + (![] + [])[!+[] + !![] + !![]] + (!![] + [])[+[]] + (!![] + [])[+!![]] + ([][[]] + [])[+[]] + ([] + {})[!+[] + !![] + !![] + !![] + !![]] + (!![] + [])[+[]] + ([] + {})[+!![]] + (!![] + [])[+!![]]]((!![] + [])[+!![]] + ([][[]] + [])[!+[] + !![] + !![]] + (!![] + [])[+[]] + ([][[]] + [])[+[]] + (!![] + [])[+!![]] + ([][[]] + [])[+!![]] + ([] + {})[!+[] + !![] + !![] + !![] + !![] + !![] + !![]] + ([][[]] + [])[!+[] + !![] + !![]] + (![] + [])[!+[] + !![] + !![]] + ([] + {})[!+[] + !![] + !![] + !![] + !![]] + (+{} + [])[+!![]] + ([] + [][(![] + [])[!+[] + !![] + !![]] + ([] + {})[+!![]] + (!![] + [])[+!![]] + (!![] + [])[+[]]][([] + {})[!+[] + !![] + !![] + !![] + !![]] + ([] + {})[+!![]] + ([][[]] + [])[+!![]] + (![] + [])[!+[] + !![] + !![]] + (!![] + [])[+[]] + (!![] + [])[+!![]] + ([][[]] + [])[+[]] + ([] + {})[!+[] + !![] + !![] + !![] + !![]] + (!![] + [])[+[]] + ([] + {})[+!![]] + (!![] + [])[+!![]]]((!![] + [])[+!![]] + ([][[]] + [])[!+[] + !![] + !![]] + (!![] + [])[+[]] + ([][[]] + [])[+[]] + (!![] + [])[+!![]] + ([][[]] + [])[+!![]] + ([] + {})[!+[] + !![] + !![] + !![] + !![] + !![] + !![]] + (![] + [])[!+[] + !![]] + ([] + {})[+!![]] + ([] + {})[!+[] + !![] + !![] + !![] + !![]] + (+{} + [])[+!![]] + (!![] + [])[+[]] + ([][[]] + [])[!+[] + !![] + !![] + !![] + !![]] + ([] + {})[+!![]] + ([][[]] + [])[+!![]])(+!![]))[!+[] + !![] + !![]] + ([][[]] + [])[!+[] + !![] + !![]])(!+[] + !![] + !![] + !![] + !![] + !![] + !![] + !![])(([] + {})[+[]])[+[]] + (!+[] + !![] + !![] + !![] + !![] + !![] + !![] + []) + (!+[] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + [])) + ([][[]] + [])[!+[] + !![]] + ([][[]] + [])[!+[] + !![] + !![]] + (+{} + [])[+!![]] + ([][[]] + [])[!+[] + !![]] + ([] + {})[!+[] + !![]] + ([][[]] + [])[!+[] + !![] + !![]] + ([][[]] + [])[!+[] + !![] + !![]] + ([][[]] + [])[!+[] + !![] + !![] + !![]] + ([] + {})[!+[] + !![] + !![] + !![] + !![]] + (+{} + [])[+!![]] + ([][[]] + [])[!+[] + !![] + !![] + !![]] + ([][[]] + [])[!+[] + !![] + !![]])(!+[] + !![] + !![]));
```
将这些代码输入到Console中,就可以得出结果
![]

在这道题目的三处混淆中,都可以通过这种方式翻译出来

而第一张图片的混淆,其实很有意思,看着也挺有意思的
它这种属于**JavaScript的表情包加密**,我们可以通过这个网站进行翻译[解密工具]

将需要解密的代码复制过去,然后点击aaencode解密,就可以得到结果【window.o = 1;】
![]
我这里就不放结果的截图,大家可以去试一试

还有一处混淆过的代码,你可以通过Console得出结果,我这里就不再赘述

全部翻译完成后,我们将结果与混淆的代码进行替换,接着道鬼鬼调试工具进行测试验证

## 验证加密结果
我们将处理过的代码粘贴到鬼鬼调试工具中
然后,在前面的地方,加一行代码 var window = this;
因为在代码中,很多地方用到了 window 变量,不声明的话,会报错
![]
在上面的截图中,可以发现我注释了一行代码 //window = {};
这行代码就是将window变为空,上面我也提到了,很多地方都需window,所以要将其注释

接着,我们加载全部代码,传入参数执行**r**函数,可以发现得到了我们想要的结果
![]

到目前为止,我们已经可以通过Python代码得到【m】和【q】的值了,但是还有一个问题我们还没有解决

## 求出中奖总金额
在文章开头,我们还留着一个问题

AJax返回的数据,是页面的三等奖金额
但是,这道题让我们求的是一等奖,二等奖,三等奖的总金额
所以,我们回到Ajax代码中(截取了部分代码)
如果你对Ajax的内容不是很熟悉的话,可以看看我这篇文章
在这篇文章中,我对ajax部分的代码解释得很详细,这里我就不多赘述
```javascript
$.ajax({
    url: window.url,
    dataType: "json",
    async: false,
    data: list,
    type: "GET",
    beforeSend: function (request) {},
    success: function (data) {
      if (window.page) {}
      else {
            window.page = 1
      }
      // 请求成功后返回的数据,也就是页面中三等奖的金额
      data = data.data;
      let html = '';
      let arg = 1;
      let puq = `<tr data-week="3"><td>date_twice</td><td>2020-10-date_value</td>caipiaohao<td>total_value</td><td>result_value1</td><td>result_value2</td><td>result_value3</td><td>0</td><td></td></tr>`;
      let arr_arg = ;
      // 通过循环三等奖的金额,进行一系列的操作,呈现出页面的各种数值
      // 我们可以不用详细的去分析,直接看下面的replace部分
      $.each(data, function (index, val) {
            let caipiao = `<td><span class="rq1">arg1</span><span class="rq1">arg2</span><span class="rq1">arg3</span><span class="rq1">arg4</span><span class="rq1">arg5</span><span class="rq1">arg6</span><span class="rq1">arg7</span></td><td><span class="bq1">arg8</span></td>`;
            let arr = ;
            for (let c = 1; c <= 8; c++) {
                caipiao = caipiao.replace('arg' + c, (Math.floor(((arr_arg << 2) / 5 + c) * c / 3) + 1) + arr)
            }
            // 这里的代码,主要是将页面的数值进行替换
            html += puq.replace('caipiaohao', caipiao)
                        .replace('date_twice', arg * window.page + 2020097)
                        .replace('date_value', '0' + window.page)
                        .replace('result_value3', val.value)
                        // total_value 指的就是页面中的 总销售额字段
                        // val.value 指的就是 三等奖金额
                        // 也就是说,总销售额,就是三等奖的金额乘以24
                        .replace('total_value', val.value * 24)
                        // result_value2 二等奖
                        .replace('result_value2', val.value * 8)
                        // result_value1 一等奖
                        .replace('result_value1', val.value * 15);
            arg += 1
      });
      $('.resbbp').text('').append(html)
    }
```
通过上述代码的注释,我们可以知道,每一行的总销售额,也就是我们所求的总金额,其实就是三等奖的金额乘以24

所以,我们就可以获取每页的三等奖金额总和,最后乘以24就可以得出这道题目的答案 ::aru:pouting::

## 解出答案
在写Python代码之前,我们还需要完成最后一个步骤
![]
我们知道想要正常请求URL拿到数据,需要三个参数(page,m,q)
而前面我们翻译完成的JS文件,返回的结果只有m的值,而没有返回时间戳
所以,我们只需要将**z**函数改下一下即可
```javascript
// 修改前
function z(pwd, time) {
    var n = _n("jsencrypt");
    var g = (new n);
    var r = g.encode(pwd, time);
    return r;
}

// 修改后
function z(pwd, time) {
    var n = _n("jsencrypt");
    var g = (new n);
    var r = g.encode(pwd, time);
    var answer_arr =
    return answer_arr;
}
```
现在,我们就可以愉快的写Python代码,爬取数据,解出答案啦
由于JS文件代码太多(2000多行),我就不粘贴出来,[点击我可以进行下载]

```python
# @BY   :Java_S
# @Time   :2021/1/10 13:36
# @Slogan :够坚定够努力大门自然会有人敲,别怕没人赏识就像三十岁的梵高

import time
import execjs
import requests


def get_cipher(timestamp, page):
    # 导入JS,读取需要的js文件
    with open(r'JS/js6.js', encoding='utf-8', mode='r') as f:
      JsData = f.read()
    # 加载js文件,使用call()函数执行,传入需要执行函数即可获取返回值
    = execjs.compile(JsData).call('get_cipher', timestamp, page)
    limit = f'{page}-' + str(timestamp) + '|'

    return cipher, limit


def get_data(page):
    cipher, limit = get_cipher(int(time.time()) * 1000, page)
    url = 'http://match.yuanrenxue.com/api/match/6'
    params = {
      'page': page,
      'm': cipher,
      'q': limit
    }
    headers = {
      'Host': 'match.yuanrenxue.com',
      'Referer': 'http://match.yuanrenxue.com/match/6',
      'User-Agent': 'yuanrenxue.project',
    }
    response = requests.get(url=url, headers=headers, params=params)
    answer = for i in response.json()['data']]
    print(f'第{page}页的三等奖:{answer}')

    return answer

if __name__ == '__main__':
    total = []
    for i in range(1,6):
      total += get_data(i)
    total = sum(total)*24
    print(f'五页中奖的总金额:{total}元')
```
![]


: https://www.52pojie.cn/thread-1337317-1-1.html
: https://www.52pojie.cn/thread-1339239-1-1.html
: https://www.52pojie.cn/thread-1341502-1-1.html
: https://www.52pojie.cn/thread-1346210-1-1.html
: https://syjun.vip/usr/uploads/2021/01/395464943.jpg
: http://match.yuanrenxue.com/match/6
: https://syjun.vip/usr/uploads/2021/01/3189750644.jpg
: https://syjun.vip/usr/uploads/2021/01/2761769185.jpg
: https://syjun.vip/usr/uploads/2021/01/2583982766.jpg
: https://syjun.vip/usr/uploads/2021/01/3763923002.jpg
: https://syjun.vip/usr/uploads/2021/01/3800050568.jpg
: https://syjun.vip/usr/uploads/2021/01/662541004.jpg
: https://syjun.vip/usr/uploads/2021/01/4128124389.jpg
: https://syjun.vip/usr/uploads/2021/01/3142550897.jpg
: https://syjun.vip/usr/uploads/2021/01/1103127448.jpg
: https://syjun.vip/usr/uploads/2021/01/986872791.jpg
: https://syjun.vip/usr/uploads/2021/01/1136954340.jpg
: https://syjun.vip/usr/uploads/2021/01/2274409932.jpg
: https://syjun.vip/usr/uploads/2021/01/1355107401.jpg
: https://syjun.vip/usr/uploads/2021/01/1035339501.jpg
: https://www.qtool.net/decode
: https://syjun.vip/usr/uploads/2021/01/1210912784.jpg
: https://syjun.vip/usr/uploads/2021/01/3094902137.jpg
: https://syjun.vip/usr/uploads/2021/01/859800304.jpg
: https://syjun.vip/archives/281.html
: https://syjun.vip/usr/uploads/2021/01/2761769185.jpg
: https://wwx.lanzoux.com/b01byvclg
: https://syjun.vip/usr/uploads/2021/01/1749758622.jpg

netspirit 发表于 2021-1-15 21:24

学爬虫的话js要学到什么程度啊?

ciker_li 发表于 2021-1-15 21:25

大神厉害!

肥猫警长 发表于 2021-1-15 21:34

{:301_973:}好想学啊!我想爬我们学校的题库

maoxingren 发表于 2021-1-15 21:42

Java_S 发表于 2021-1-15 22:43

netspirit 发表于 2021-1-15 21:24
学爬虫的话js要学到什么程度啊?

至少要看得懂,代码写的什么意思

netspirit 发表于 2021-1-15 22:44

Java_S 发表于 2021-1-15 22:43
至少要看得懂,代码写的什么意思

需要专门去学前端么?

正己 发表于 2021-1-16 00:25

好兄弟日穿猿人学{:17_1068:}

zhoujunxuan 发表于 2021-1-16 03:39

大佬,有没有碰过无法打开开发者工具的反爬虫机制,“www.vmgirls.com”这个网站你在加载完后会打不开开发者工具,如果想办法打开了这个网页会直接崩溃掉,如果在加载之前就开好开发者工具就会出现断点,直接暂停加载,如果debug的stepover也会不停的循环知道网页崩溃

jc021227 发表于 2021-1-16 08:27

膜拜大神,学习了!
页: [1] 2
查看完整版本: Python反反爬之JS混淆---回溯