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())