• 爬取js加密和混淆的例子


    作业讲解:js逆向

    概述

    url:https://nyloner.cn/proxy
    
    需求:将这个网页中的代理ip和端口号进行爬取
    难点:
    	动态变化的请求参数
    	js加密
    	需要js逆向
    

    分析

    • 爬取的数据是动态加载

    • 并且我们进行了抓包工具的全局搜索,没有查找到结果

      • 意味着:爬取的数据从服务端请求到的是加密的密文数据
    • 页面每10s刷新一次,刷新后发现数据更新,但是浏览器地址栏的url没有变,说明加载出的数据是由ajax请求到的。

      • 动态加载出来的数据是由ajax请求到的,并且请求到的数据为加密数据
    • 定位到ajax数据包,从中可以看到url和动态变化的请求参数和加密的响应数据

    • 将ajax请求到的密文数据捕获

      • 动态地获取动态变化的请求参数

      • 基于抓包工具进行了动态变化请求参数token的全局搜索,定位到了token的源头,就是如下js代码:

        var token = md5(String(page) + String(num) + String(timestamp));
        
      • 对密文数据进行解密

        • 通过解析找到了解密的js函数:decode_str(encode_str)
      • 查找encode_str的实现:

        • js逆向:将js代码转换成python代码。开发环境只能执行python代码

    答案

    动态参数解析

    # 我们抓包看到 token是加密生成 则把它进行加密
    var token = md5(String(page) + String(num) + String(timestamp));
    # 进行加密
    def getToken():
        page = str(1)
        num = str(15)
        t = str(int(time.time()))
        md5 = hashlib.md5()
        md5.update((page+num+t).encode('utf-8'))
        token = md5.hexdigest()
        return token
    

    网页源码js

    # 动态参数加密
    function get_proxy_ip(page, num, click_btn) {
        var timestamp = Date.parse(new Date());
        timestamp = timestamp / 1000;
        # token的加密
        var token = md5(String(page) + String(num) + String(timestamp));
        # ajax 请求 类似这样的url:https://nyloner.cn/proxy?page=1&num=15&token=26c8bc7&t=1575
        $.get('../proxy?page=' + page + '&num=' + num + '&token=' + token + '&t=' + timestamp, function (result) {
            # 判断 是否为True 
            if (result.status === 'true') {
                var setHtml = "";
                $("#ip-list").html(setHtml);
                var encode_str = result.list;
                # decode_str 是解密函数
                var items = str_to_json(decode_str(encode_str));
                for (var index = 0; index < items.length; ++index) {
                    item = items[index];
                    setHtml += "<tr>
    <td>" + (index + 1) + "</td>
    ";
                    setHtml += "<td>" + item.ip.toString() + "</td>
    ";
                    setHtml += "<td>" + item.port.toString() + "</td>
    ";
                    setHtml += "<td>" + item.time.toString() + "</td>
    </tr>
    ";
                }
                $("#ip-list").html(setHtml);
                if (click_btn === 'next') {
                    document.getElementById("last-page").disabled = false;
                    if (items.length < 15) {
                        document.getElementById("next-page").disabled = true;
                    }
                } else {
                    document.getElementById("next-page").disabled = false;
                    if (page === 1) {
                        document.getElementById("last-page").disabled = true;
                    }
                }
    
            }
        });
    }
    
    

    获取token 向url发请求获取加密的数据

    import time
    import hashlib
    import requests
    import base64
    #js逆向之后的结果
    def decode_str(scHZjLUh1):
        #解密成字符串
        scHZjLUh1 = base64.decodestring(scHZjLUh1.encode())
        key = 'nyloner'
        lenth = len(key)
        code = ''
        sch_lenth = len(scHZjLUh1)
        for i in range(sch_lenth):
            coeFYlqUm2 = i % lenth
            #chr(0-255)返回对应编码的字符
            #ord(a-z)返回编码数值
            code += chr(scHZjLUh1[i] ^ ord(key[coeFYlqUm2]))
        code = base64.decodestring(code.encode())
        code = code.decode('utf-8')
        code
    #     return code
    

    将加密的数据进行解析

    token = getToken()
    url = 'https://nyloner.cn/proxy'
    param = {
        'num':'15',
        'page':'1',
        't':str(int(time.time())),
        'token':token
        
    }
    
    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',
        'Cookie':'sessionid=2cj1fd0hpbv64qrxe6xckek8tu3uad4m'
    }
    code = requests.get(url,headers=headers,params=param).json().get('list')
    str_code = decode_str(code)
    str_code
    

    js加密,混淆

    需求概述

    url:https://www.aqistudy.cn/html/city_detail.html
    获取该url的数据
    

    需求分析

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

    • 2.数据是否为动态加载

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

    • 4.在抓包工具的xhr中获取到了两个数据包

      • url一样
      • 都有一个d这样的请求参数
      • 两个数据包的请求参数d的数据值不同
      • d这个请求参数是经过加密且动态变化
    • 处理动态变化且加密的请求参数d

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

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

        • 点击按钮发起ajax请求,找按钮的点击事件(click)
        • 借助火狐浏览器的开发者工具进行按钮点击时间的定位
          • getDate()js函数
      • 分析getDate这个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:查询结束的时间
                      • 分析getServerDate(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参数就是响应的密文数据,返回值就是解密后的原文数据

                      • 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()
    file = 'test.js'
    ctx = node.compile(open(file,encoding='utf-8').read())
    
    #如何五个变量会作为getPostParamCode的参数
    method = 'GETDETAIL'#GETCITYWEATHER
    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)
    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)
    
  • 相关阅读:
    Java笔记(2)
    java笔记(1) java环境
    黑马javaSE内部编程题10道
    Openblas编译Android NDK库的步骤
    Android layout的横竖屏处理
    会议整理
    概率论总结
    数据分析推荐书籍
    操作系统(蒲晓蓉)7
    运筹学整理笔记1
  • 原文地址:https://www.cnblogs.com/zhangdadayou/p/11999969.html
Copyright © 2020-2023  润新知