爬取js加密和混淆的例子

爬取js加密和混淆的例子

url:https://www.aqistudy.cn/html/city_detail.html

分析:

1.点击不同气象指标的选项卡,发现没有相关的请求发送,说明当页面加载出来的时候,所有的气象数据已经加载完毕。

2.数据是否为动态加载

  • 数据是动态加载出来的

3.修改查询的条件(城市的切换,时间的修改),点击搜索按钮就会加载出新数据。

4.在抓包工具的XHR中捕获到了两个数据包

  • url一样

  • 都有一个d这样的请求参数

  • 两个数据包的请求参数d的数据值不同

  • d这个请求参数是经过加密且动态变化

处理动态变化且加密的请求参数d

  • 对请求参数d进行全局搜索(不可行)

  • 点击页面中的搜索按钮后,在抓包工具中就捕获到了那两个ajax请求的数据包

    • 点击按钮发起ajax请求,找按钮的点击事件(click)

    • 借助火狐浏览器的开发者工具进行按钮点击事件的定位

      • getData()js函数

  • 分析getData这个js函数的实现:目的就是为了找到ajax请求对应的js代码

    type=="HOUR":按照小时为时间单位进行查询并没有在该函数的实现中发现ajax请求对应的代码,但是发现了另外的两个函数调用getAQIData(),getWeatherData()

    分析getWeatherData();和getAQIData()这两个函数的定义,想要去找打ajax请求对应的代码:

    这两个函数实现的区别:
    
    - method变量赋值的字符串不一样
      - GETDETAIL
      - GETCITYWEATHER
    
    相同:
    - 都没有出现ajax请求对应的代码,但是发现了另一个函数的调用:
       getServerData(method,param,匿名函数,0.5)
           method:GETDETAIL或者GETCITYWEATHER
       	   param:字典,有四组键值对
           city:查询城市的名称
           type:HOUR
           startTime:查询开始的时间
           endTIme:查询结束的时间
    
      ![](https://img2018.cnblogs.com/blog/1732284/201912/1732284-20191206211407976-802530670.png)
    
    • 分析getServerData(method,param,匿名函数,0.5)这个函数的实现,还是为了找打ajax请求对应的代码:

      基于抓包工具的全局搜索才可以找到

    • 发现这个函数的实现代码看不懂,函数的实现好像是一组密文

      • 说明:网站对js函数的实现加密
      • JS混淆:对js函数的实现代码进行加密
      • JS反混淆:将加密的js代码解密成原文
      • 暴力破解:https://www.bm8.com.cn/jsConfusion/
    • 分析getServerData函数的实现:

      终于找到了ajax请求对应的代码
      
      - 参数d的构成:getParam(method, object)返回
        - method:method
        - object:param字典,四个键值分别是城市名称。type,起始时间,结束时间
      - 请求到的密文数据的解密方式:
        - decodeData(data):data参数就是响应的密文数据,返回值就是解密后的原文数据
      
      function getServerData(method, object, callback, period) {
              const key = hex_md5(method + JSON.stringify(object));
              const data = getDataFromLocalStorage(key, period);
              if (!data) {
                  # 在这里的getParam函数是将传入的参数弄成一个加密的字符串发送给服务器
                  var param = getParam(method, object);
                  $.ajax({
                      url: '../apinew/aqistudyapi.php',
                      data: {
                          d: param
                      },
                      type: "post",
                      success: function (data) {
                          # 服务器接收到数据进行解密
                          data = decodeData(data);
                          obj = JSON.parse(data);
                          if (obj.success) {
                              if (period > 0) {
                                  obj.result.time = new Date().getTime();
                                  localStorageUtil.save(key, obj.result)
                              }
                              callback(obj.result)
                          } else {
                              console.log(obj.errcode, obj.errmsg)
                          }
                      }
                  })
              } else {
                  callback(data)
              }
          }
      

JS逆向:

使用 PyExecJS 库来实现模拟JavaScript代码执行。

- 环境的安装:
  - pip install PyExecJS
  - 必须还要安装nodeJs的开发环境
  • 请求到加密的响应数据
  • 将加密的响应数据进行解密
  • 获取动态变化且加密的请求参数(d)
import execjs
import requests
headers = {
    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36'
}
node = execjs.get()
# 将解密后的js代码放到一个本地的文件中
file = 'test.js'

# 读取这个文件
ctx = node.compile(open(file,encoding='utf-8').read())

#将这五个变量作为getPostParamCode函数的参数
#这个字符串的不同获取的值不同也可以是 GETCITYWEATHER,
method = 'GETDETAIL' 

# 搜索的城市
city = '北京'

# 按照小时进行搜索
type = 'HOUR'

# 起始时间和结束时间
start_time = '2018-01-25 00:00:00'
end_time = '2018-01-25 23:00:00'

#模拟执行getPostParamCode函数
js = 'getPostParamCode("{0}", "{1}", "{2}", "{3}", "{4}")'.format(method, city, type, start_time, end_time)

# eval用来执行一个字符串表达式
params = ctx.eval(js)
# print(params)#请求参数d

url = 'https://www.aqistudy.cn/apinew/aqistudyapi.php'
data = {
    'd':params
}

#获取了加密的响应数据
response_code = requests.post(url=url,headers=headers,data=data).text
# response_code

#模拟执行decodeData函数对密文数据进行解密
js = 'decodeData("{0}")'.format(response_code)
page_text = ctx.eval(js)
print(page_text)

上面调用js代码中的getPostParamCode函数可以改写为:

function getPostParamCode(method, city, type, startTime, endTime){
    var param = {};
    param.city = city;
    param.type = type;
    param.startTime = startTime;
    param.endTime = endTime;
    # 然后调用执行getParam函数,对数据进行一个加密
    return getParam(method, param);
}
posted @ 2019-12-06 21:15  adrian-boy  阅读(353)  评论(0)    收藏  举报