js逆向:基于python、js的逆向加密与解密

1.js逆向的准备工作(查找解密加密的方法)

1.1 选择合适的触发事件,排除干扰请求

  • 想要爬取什么内容就选中哪个地方发起请求,排除其他请求的干扰
  • 就比如下图,需要爬取通知公告,就先清除网站的其他请求,然后再点击需要爬取的地方(这时候就默认发起请求)
    img

1.2 注意请求中的请求载荷(负载,就是需要的参数)

  • 在发起请求之后,先看一下Content-type(传送的数据是json格式,还是form表单格式),然后response中写那种格式
    img
    img
    img

1.3 请求和响应入口定位(方法)

1.3.1 关键字搜索

img

  • key关键字:portal-sign(请求解密中可以使用到)

  • 方法关键字:encrypt(加密)、decrypt(解密)

  • headers关键字

  • 拦截器关键字

      请求拦截器
      响应拦截器
        interceptors.request.use(f1)
        interceptors.request.use(f2)
        interceptors.response.use(f3)
        interceptors.response.use(f4)
    
        this.interceptors.response.forEach(function(e) {
               t.push(e.fulfilled, e.rejected)
           }); t.length; )
               n = n.then(t.shift(), t.shift());
           return n  
      路径关键字:
    

    img

  • 请求堆栈:主要是针对请求逆向

1.4 断点

  • 普通断点
  • XHR断点
  • 条件断点
  • 日志断点
    img

2.实战案例:公共资源交易平台

2.1 第一步:先模拟网站发起请求,获取数据

img

右键点击名称下面的圈的网址:复制它的cURL,到https://curlconverter.com/,粘贴它请求的代码
代码如下:
import requests

cookies = {
    'ASP.NET_SessionId': 'k4wbjl0uwixk5l4d4zygwjx0',
}

headers = {
    'Accept': 'application/json, text/plain, */*',
    'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
    'Cache-Control': 'no-cache',
    'Connection': 'keep-alive',
    'Content-Type': 'application/json;charset=UTF-8',
    'Origin': 'https://ggzyfw.fj.gov.cn',
    'Pragma': 'no-cache',
    'Referer': 'https://ggzyfw.fj.gov.cn/index/new/',
    'Sec-Fetch-Dest': 'empty',
    'Sec-Fetch-Mode': 'cors',
    'Sec-Fetch-Site': 'same-origin',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36 Edg/134.0.0.0',
    'portal-sign': '7147d1389bec4bc68f2e1617ee426713',
    'sec-ch-ua': '"Chromium";v="134", "Not:A-Brand";v="24", "Microsoft Edge";v="134"',
    'sec-ch-ua-mobile': '?0',
    'sec-ch-ua-platform': '"Windows"',
    # 'Cookie': 'ASP.NET_SessionId=k4wbjl0uwixk5l4d4zygwjx0',
}

json_data = {
    'pageSize': 5,
    'type': '12',
    'ts': 1742886819782,
}

response = requests.post('https://ggzyfw.fj.gov.cn/FwPortalApi/Article/PageList', cookies=cookies, headers=headers, json=json_data)
print(respnse.text)

2.2 第二步:获取数据成功,但是数据是加密的(我们需要破解数据),如下图

img

2.3 第三步:破解加密数据,这时候我们就需要进行关键字搜索,看看浏览器是怎样破解本地的数据的,我们可以仿照观察它使用了哪种算法进行加密的

2.3.1.搜索:decrypt(

  • 将搜索到的进行打断点,如果搜出来的很多,说明我们需要换其他关键字搜索(恰好我们搜索出来的刚好是)
  • 在图中可以看出使用的是AES算法,k是r["e"],iv是r["i"],我们就需要使用AES算法进行解密
    img

2.3.2 进行破解(代码和上面自己拼接)

img

代码如下:
b64_encrypt_data = response.json().get('Data')
# print(b64_encrypt_data)

import base64

from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad

# (1) 解码base64
encrypt_data = base64.b64decode(b64_encrypt_data)
print("encrypt_data:::",encrypt_data)

# (2) 解密:算法和什么钥匙
key = 'EB444973714E4A40876CE66BE45D5930'.encode()
iv = 'B5A8904209931867'.encode()
aes_obj = AES.new(key=key, mode=AES.MODE_CBC, iv=iv)

data = aes_obj.decrypt(encrypt_data)

data = unpad(data,16).decode()
print("data:::",data)

2.3.3 上述是使用python进行破解的,我们也可以使用js逆向进行破解

  • 和上述操作一样,进行断点,但是不同的是我们需要将解密的这一段复制过来,放到js文件中模拟它解码
    img

  • 放到js文件中进行调试(先运行代码,哪里不合适就去浏览器观察,缺什么就补什么,然后将Data搬过来进行测试)
    img

    代码如下:
    const crypto_js = require("crypto-js")
    
    // 数据解密
    function b(t) {
        var e = crypto_js.enc.Utf8.parse("EB444973714E4A40876CE66BE45D5930")
            , n = crypto_js.enc.Utf8.parse("B5A8904209931867")
            , a = crypto_js.AES.decrypt(t, e, {
            iv: n,
            mode: crypto_js.mode.CBC,
            padding: crypto_js.pad.Pkcs7
        });
        return a.toString(crypto_js.enc.Utf8)
    }
    
    // 测试代码
    t = ""  // 这里和我们上面获取的加密数据相同
    console.log(b(t))
    

2.3.4 js测试成功之后,我们需要在python文件中运行我们的js脚本文件(最终完成了解密)

  • 准备工作:
    node.js版本18
    python版本3.10以上,但不要使用最新版
    
    其次还需要导入以下:
    import subprocess
    from functools import partial
    subprocess.Popen = partial(subprocess.Popen, encoding="utf-8")
    import execjs
    
  • 在python中实现js解密
    代码如下:
    
    with open("007 js逆向解密、加密数据.js", encoding="utf8") as f:
        jsCode = f.read()
    js_compile = execjs.compile(jsCode)
    ret = js_compile.call("b", base64_encrypt_data)
    

2.4 模仿浏览器sign加密,实现载荷中的参数无论怎样改变,都可以获取到数据

img

2.4.1 关键字搜索 portal-sign

  • 找到先打断点
    img
  • 请求看验证断点,验证成功确实断在这里,然后悬浮鼠标点进函数里面
    img
  • 发现确实是加密的sign,最后可以验证一下,使用MD5进行加密的
    img

2.4.2 进行模仿加密,实现我们改载荷也能爬取数据

  • 将找到的代码,复制到我们创建的js文件中,进行调试
    img

    代码如下:
    
    // 数据加密
    
    function l(t, e) {
        return t.toString().toUpperCase() > e.toString().toUpperCase() ? 1 : t.toString().toUpperCase() == e.toString().toUpperCase() ? 0 : -1
    }
    
    function u(t) {
        for (var e = Object.keys(t).sort(l), n = "", a = 0; a < e.length; a++)
            if (void 0 !== t[e[a]])
                if (t[e[a]] && t[e[a]] instanceof Object || t[e[a]] instanceof Array) {
                    var i = JSON.stringify(t[e[a]]);
                    n += e[a] + i
                } else
                    n += e[a] + t[e[a]];
        return n
    }
    
    function d(t) {
        for (var e in t)
            "" !== t[e] && void 0 !== t[e] || delete t[e];
        var n = "B3978D054A72A7002063637CCDF6B2E5" + u(t);
        return crypto_js.MD5(n).toString()
    }
    
    // 测试js,sign加密
    data = {
        'pageNo': 1,
        'pageSize': 10,
        'total': 797,
        'type': '12',
        'timeType': '0',
        'ts': 1742800934952,
    }
    // console.log(d(data))
    
  • 将它放到我们的python中运行
    img

    代码如下:
    
    
    with open("007 js逆向解密、加密数据.js", encoding="utf8") as f:
        jsCode = f.read()
    js_compile = execjs.compile(jsCode)
    sign = js_compile.call("d", json_data)
    headers['portal-sign'] = sign
    

    3.爬取完整代码

    import time
    import subprocess
    from functools import partial
    
    subprocess.Popen = partial(subprocess.Popen, encoding="utf-8")
    
    import execjs
    
    import requests
    
    cookies = {
        'ASP.NET_SessionId': 'yw4wual11my4nd4pzpat0er2',
    }
    
    headers = {
        'Accept': 'application/json, text/plain, */*',
        'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
        'Cache-Control': 'no-cache',
        'Connection': 'keep-alive',
        'Content-Type': 'application/json;charset=UTF-8',
        'Origin': 'https://ggzyfw.fj.gov.cn',
        'Pragma': 'no-cache',
        'Referer': 'https://ggzyfw.fj.gov.cn/index/newList?type=12',
        'Sec-Fetch-Dest': 'empty',
        'Sec-Fetch-Mode': 'cors',
        'Sec-Fetch-Site': 'same-origin',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36 Edg/134.0.0.0',
        # 'portal-sign': '4b9c48b640dc79d393ee23c9be59849e',
        'sec-ch-ua': '"Chromium";v="134", "Not:A-Brand";v="24", "Microsoft Edge";v="134"',
        'sec-ch-ua-mobile': '?0',
        'sec-ch-ua-platform': '"Windows"',
        # 'Cookie': 'ASP.NET_SessionId=yw4wual11my4nd4pzpat0er2',
    }
    
    json_data = {
        'pageNo': 3,
        'pageSize': 10,
        'total': 797,
        'type': '12',
        'timeType': '0',
        'ts': int(time.time() * 1000),
    }
    # 基于js,sign加密
    with open("007 js逆向解密、加密数据.js", encoding="utf8") as f:
        jsCode = f.read()
    js_compile = execjs.compile(jsCode)
    sign = js_compile.call("d", json_data)
    headers['portal-sign'] = sign
    
    response = requests.post('https://ggzyfw.fj.gov.cn/FwPortalApi/Article/PageList', cookies=cookies, headers=headers,
                             json=json_data)
    
    
    
    
    base64_encrypt_data = response.json().get("Data")
    # print(base64_encrypt_data)
    
    # 基于JS逆向解密数据
    
    with open("007 js逆向解密、加密数据.js", encoding="utf8") as f:
        jsCode = f.read()
    js_compile = execjs.compile(jsCode)
    ret = js_compile.call("b", base64_encrypt_data)
    
    import json
    
    ret_table = json.loads(ret).get('Table')
    for i in ret_table:
        print(i)
    
    
posted @ 2025-03-25 16:22  tmars  阅读(1274)  评论(0)    收藏  举报