python编译执行js代码(pyexecjs)、补环境

pyexecjs是一个可以帮助我们运行js代码的一个第三方模块. 其使用是非常容易上手的.

但是它的运行是要依赖能运行js的第三方环境的. 这里我们选择用node作为我们运行js的位置.

1.1 安装Nodejs

  • 测试js代码

    node 1.js
    
  • python执行执行本地命令:node 1.js

    import os
    import subprocess
    
    # 根据自己的操作系统去修改(相当于python的sys.path,加载安装的模块)
    # 这不是你的node安装路径,是第三方包安装路径,输入:npm root -g
    os.environ["NODE_PATH"] = "/usr/local/lib/node_modules/"  
    
    signature = subprocess.getoutput('node 1.js')
    

2.2 安装pyexecjs

pip install pyexecjs

测试一下:

import execjs

print(execjs.get().name)  # Node.js (V8)

1.3 简单使用

import execjs

print(execjs.get().name)

# execjs.eval 可以直接运行js代码并得到结果
js = """
    "鲁班_王昭君_猴子_亚瑟_蔡文姬".split("_")
"""
res = execjs.eval(js)
print(res)

# execjs.compile(),  call()
# execjs.compile() 事先加载好一段js代码,
jj = execjs.compile("""
    function an(a, b){
        return a + b    
    }
""")
# call() 运行代码中的xxx函数. 后续的参数是xxx的参数
ret = jj.call("an", 10, 20)
print(ret)

windows中如果出现编码错误. 在引入execjs之前. 插入以下代码即可.

import subprocess
from functools import partial
subprocess.Popen = partial(subprocess.Popen, encoding='utf-8')

import execjs

完事儿. 你没有看错. execjs就这几个功能就够咱用的了.

1.4 游览器调试工具讲解

按钮从左往右
第一个: 释放掉当前断点debug. 程序继续向后运行. 直到结束或下一个断点。 (下一个断点处)
第二个: 运行下一步. 它的作用是会直接执行完这个函数,不显示执行细节。 (看当前行这个函数运行的结果是什么)
第三个: 它的作用和上面那个刚好相反。如果遇到一个函数,它进入函数内部一步一步地执去行,这样可以观察到执行过程。 (看看当前行的这个函数是怎么运行的)

1.5 补js第三方库环境

示例1

如逆向时遇到这种公开的第三方库(CryptoJS)。 可以直接用node中的npm来安装

设置镜像源

npm config set registry http://registry.npm.taobao.org 

使用npm安装js库

npm install crypto-js
var CryptoJS = require("crypto-js"); // 引入
function b(a, b) {
    // 抠到这种公开的第三方库。 可以直接用node中的npm来安装.
    var c = CryptoJS.enc.Utf8.parse(b)
      , d = CryptoJS.enc.Utf8.parse("0102030405060708")
      , e = CryptoJS.enc.Utf8.parse(a)
      , f = CryptoJS.AES.encrypt(e, c, {
        iv: d,
        mode: CryptoJS.mode.CBC
    });
    return f.toString()
}

示例2

npm install crypto
const crypto = require('crypto');

var t="_jsUyA02rwkOJ4enKX7c4dhd7CjvGkcKfbRx0BjNGW8lA7S2l8R3Ry5QLg9sMmKp72I4gQZHoGRX433rxXwjKmy5yFuVCe4HL1-8YeYQoyv5xBo29ruVPY2ApicRkT7O"

function data(t){
    var key='ydsecret://query/key/B*RGygVywfNBwpmBaZg*WT7SIOUP2T0C9WHMZN39j^DAdaZhAnxvGcCY6VYFwnHl'
    var iv='ydsecret://query/iv/C@lZe2YzHtZ2CYgaXKSVfsb7Y4QWHjITPPZ0nQp87fBeJ!Iv6v^6fvi2WN@bYpJ4'
    if (!t)
        return null;
    const a = Buffer.alloc(16, crypto.createHash("md5").update(key).digest())
              , r = Buffer.alloc(16, crypto.createHash("md5").update(iv).digest())
    console.log(a)
    console.log(r)
    const i = crypto.createDecipheriv("aes-128-cbc", a, r);
    console.log(i)
    let s = i.update(t, "base64", "utf-8");
    return s += i.final("utf-8"),
    s
}
console.log(data(t))

示例3 rsa

npm install node-jsencrypt
npm install jsencrypt  不维护了

var JSEncrypt = require("node-jsencrypt")
var encrypt = new JSEncrypt();
function getParams(bdata) {
        var c = Date.parse(new Date());
        var d = getUuid();
        // var c = 1694614752000;
        // var d = '6985dd00f9514f4cf5f88f8f09ea2f7e';
        var e = JSON.stringify(sort_ASCII(dataTojson(bdata || '{}')));
        // console.log(dataTojson(bdata || '{}'))
        newbdata = encrypt.encryptUnicodeLong(e);
        // var f = MD5(e + d + c);
        // console.log(f)
    return {timestamp:c,requestId:d,newbdata:newbdata,e:e}
    }
<html>
	<script src="https://cdn.bootcss.com/jsencrypt/3.0.0-beta.1/jsencrypt.js"></script>
    <script type="text/javascript">
        //公钥
        var PUBLIC_KEY = '-----BEGIN PUBLIC KEY-----MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALyBJ6kZ/VFJYTV3vOC07jqWIqgyvHulv6us/8wzlSBqQ2+eOTX7s5zKfXY40yZWDoCaIGk+tP/sc0D6dQzjaxECAwEAAQ==-----END PUBLIC KEY-----';
        //私钥
		var PRIVATE_KEY = '-----BEGIN PRIVATE KEY-----MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEAvIEnqRn9UUlhNXe84LTuOpYiqDK8e6W/q6z/zDOVIGpDb545NfuznMp9djjTJlYOgJogaT60/+xzQPp1DONrEQIDAQABAkEAu7DFsqQEDDnKJpiwYfUE9ySiIWNTNLJWZDN/Bu2dYIV4DO2A5aHZfMe48rga5BkoWq2LALlY3tqsOFTe3M6yoQIhAOSfSAU3H6jIOnlEiZabUrVGqiFLCb5Ut3Jz9NN+5p59AiEA0xQDMrxWBBJ9BYq6RRY4pXwa/MthX/8Hy+3GnvNw/yUCIG/3Ee578KVYakq5pih8KSVeVjO37C2qj60d3Ok3XPqBAiEAqGPvxTsAuBDz0kcBIPqASGzArumljkrLsoHHkakOfU0CIDuhxKQwHlXFDO79ppYAPcVO3bph672qGD84YUaHF+pQ-----END PRIVATE KEY-----';
		//使用公钥加密
        var encrypt = new JSEncrypt();//实例化加密对象
        encrypt.setPublicKey(PUBLIC_KEY);//设置公钥
        var encrypted = encrypt.encrypt('hello bobo!');//对指定数据进行加密
		alert(encrypted)
        //使用私钥解密
        var decrypt = new JSEncrypt();
        decrypt.setPrivateKey(PRIVATE_KEY);//设置私钥
        var uncrypted = decrypt.decrypt(encrypted);//解密
		alert(uncrypted);
    </script>
</html>

crypto 和 crypto-js 区别

crypto 和 crypto-js 是两个不同的库,用于不同的目的。
crypto 是 Node.js 的内置模块,用于提供加密和解密功能。它提供了一系列的加密算法,包括对称加密、哈希函数、数字签名、随机数生成等。你可以直接在 Node.js 环境中使用 crypto 模块,无需安装额外的依赖。它提供了对安全通信和数据存储的基本加密支持。

crypto-js 是一个独立的第三方 JavaScript 加密库,提供了多种加密算法的实现。它可以在浏览器和 Node.js 环境中使用。crypto-js 提供了对称加密、哈希函数、消息认证码等的实现,包括 AES、DES、SHA-256 等常见算法。相对于 Node.js 内置的 crypto 模块,crypto-js 提供了更多的加密算法选项,并且在浏览器端也可使用。

总结区别:
crypto 是 Node.js 内置的加密模块,而 crypto-js 是一个第三方 JavaScript 加密库。
crypto 提供了基本的加密功能,并且不需要额外安装依赖;crypto-js 提供了更丰富的加密算法实现,并可用于浏览器和 Node.js 环境,但需要通过 npm 安装。
crypto 适用于 Node.js 环境,而 crypto-js 可在浏览器和 Node.js 环境中使用。
crypto 提供的加密算法和功能相对较少,而 crypto-js 提供了更多的加密算法选项。

1.6 补游览器环境

环境准备:

  • node.js

  • jsdom(通过后端node+js代码实现伪造浏览器环境)

    npm install node-gyp@latest sudo npm explore -g npm -- npm i node-gyp@latest
    
    npm install jsdom -g
    

    注意:上述安装成功后已可以模拟浏览器环境,由于今天的头条他的内容。

    npm install canvas -g
    npm install -g canvas --canvas_binary_host_mirror=https://registry.npmmirror.com/-/binary/canvas/
    

如果执行出现错误,请去官方网站下载并安装最新的稳定版的node即可。

方式1

const jsdom = require("jsdom");
const {JSDOM} = jsdom;

const resourceLoader = new jsdom.ResourceLoader({
    userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.55 Safari/537.36",
});

const html = `<!DOCTYPE html><p>Hello world</p>`;


const dom = new JSDOM(html, {
    url: "https://www.toutiao.com",
    referrer: "https://example.com/",
    contentType: "text/html",
    resources: resourceLoader,
});

console.log(dom.window.location)
console.log(dom.window.navigator.userAgent)
console.log(dom.window.document.referrer)

方式2

const jsdom = require("jsdom");
const {JSDOM} = jsdom;

const resourceLoader = new jsdom.ResourceLoader({
    userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.55 Safari/537.36"
});

const html = `<!DOCTYPE html><p>Hello world</p>`;
const dom = new JSDOM(html, {
    url: "https://www.toutiao.com",
    referrer: "https://example.com/",
    contentType: "text/html",
    resources: resourceLoader,
});


//window = {}
window = global;

const params = {
    location: {
        hash: "",
        host: "www.toutiao.com",
        hostname: "www.toutiao.com",
        href: "https://www.toutiao.com",
        origin: "https://www.toutiao.com",
        pathname: "/",
        port: "",
        protocol: "https:",
        search: "",
    },
    navigator: {
        appCodeName: "Mozilla",
        appName: "Netscape",
        appVersion: "5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Safari/537.36",
        cookieEnabled: true,
        deviceMemory: 8,
        doNotTrack: null,
        hardwareConcurrency: 4,
        language: "zh-CN",
        languages: ["zh-CN", "zh"],
        maxTouchPoints: 0,
        onLine: true,
        platform: "MacIntel",
        product: "Gecko",
        productSub: "20030107",
        userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Safari/537.36",
        vendor: "Google Inc.",
        vendorSub: "",
        webdriver: false
    }
};

Object.assign(global,params);
document = dom.window.document;

//在下面如果你使用
location.href
navigator.appCodeName
window.location.href
window.appCodeName

注意:在nodejs中默认代码中会有一个global的关键字(全局变量)。

v1 = 123;
console.log(global);
global.v1 = 123
global.v2 = 123
global.navigator = {
	...
}
console.log(v1,v2);

navigator.userAgent

找加密入口的几种方法

1.直接搜索加密参数 
    搜索值的一部分 搜索加密参数的名字
2.调用栈往前寻找,边看scope,边看call stack 来找加密入口
  - 如果没有调用栈,可以看看提交表单时绑定的事件,来寻找加密位置
3.找url 不要找整个url,搜索?前面的url

1.7 实战案例(调试工具)

接下来. 我们来破解真正的百度翻译
简单流程:
1.分析url:真正的一句话的翻译其实它的url应该是:https://fanyi.baidu.com/v2transapi?from=en&to=zh
2.进入initiator,看js代码
3.找到发送ajax的请求,看data是如何生成的。
4.把js代码提取出来,用python调用js。

代码:

import requests
import execjs

f = open("baidu加密.js", mode="r", encoding='utf-8')
js = execjs.compile(f.read())


url = "https://fanyi.baidu.com/v2transapi?from=en&to=zh"
content = input("请输入一段英文:")
data = {
    "from": "en",
    "to": "zh",
    "query": content,
    "transtype": "realtime",
    "simple_means_flag": "3",
    "sign": js.call("e", content),
    "token": "c63d27ea65fdf259bf4d56b792e47b17",
    "domain": "common",
}
headers = {
    "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
    "Referer": "https://fanyi.baidu.com/",
    "Cookie": "REALTIME_TRANS_SWITCH=1; FANYI_WORD_SWITCH=1; HISTORY_SWITCH=1; SOUND_SPD_SWITCH=1; SOUND_PREFER_SWITCH=1; BIDUPSID=7214BF57BA799CC46A76979BF673523E; PSTM=1623064780; __yjs_duid=1_7946e25e70873bbe5515a663714cef991623067825398; BAIDUID=C434B9AC411BEFD0688E2DD206C8429A:FG=1; BDORZ=B490B5EBF6F3CD402E515D22BCDA1598; MCITY=-131%3A; BDUSS=kl4RWZySlNaNlRrdWNkSVRXYjYtNGkyUzFCZlhmeklhMDFtcjRLM01GdG4zMVZoRVFBQUFBJCQAAAAAAAAAAAEAAACh3e-019TDvczlwfnB-bjnAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGdSLmFnUi5hM; BDUSS_BFESS=kl4RWZySlNaNlRrdWNkSVRXYjYtNGkyUzFCZlhmeklhMDFtcjRLM01GdG4zMVZoRVFBQUFBJCQAAAAAAAAAAAEAAACh3e-019TDvczlwfnB-bjnAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGdSLmFnUi5hM; H_PS_PSSID=34438_34440_34380_34496_33848_34450_34092_34107_26350_34425_22160; delPer=0; PSINO=2; BA_HECTOR=a08k202181a52h208d1gj6e0m0q; BAIDUID_BFESS=DDAD1DC127ED72714BFB37825559ACDB:FG=1; Hm_lvt_64ecd82404c51e03dc91cb9e8c025574=1628330239,1628390196,1629451250,1630747372; Hm_lpvt_64ecd82404c51e03dc91cb9e8c025574=1630747372; ab_sr=1.0.1_ODBhYjIwYzRhMjk4NDNhZDYwYjRmZWZjM2QwY2E3MGNlMDRjYTI1ZjViODM2MDgxODk5NzJjNDFkZTAxYzc0OTVkYmNhYjZiMWMzZDFmNWFkN2QxMzAwMzZlZjhjYmE3ODkxZGRkNDJkNTY2N2M0NTQxODU5YmU4YTA1NGZjYTJkMDUzN2ZkMGVkMzlmOTU1M2ZlZTRhYWY4ZDQ5YTZmNTJjYmExYzk1ZTdiY2I5MTA4YjcyZDE3MWE1MTE5YjBj",
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36"
}

resp = requests.post(url, data=data, headers=headers)
print(resp.json())


posted @ 2023-02-22 17:06  hanfe1  阅读(4828)  评论(0编辑  收藏  举报