第8章 day08 PyExecJS介绍/微信公众平台案例
PyExecJS介绍
-
PyExecJS 是一个可以使用 Python 来模拟运行 JavaScript 的库。
- 使用该模块可以通过python程序调用执行js代码,获取js代码返回的结果!
- 注意事项:电脑必须安装好了nodejs开发环境上述模块才可以生效!
-
环境安装:
- pip install PyExecJS
-
使用步骤:
- 导包:
- import execjs
- 创建node对象:
- node = execjs.get()
- 编译即将被执行的js代码对应的文件,返回上下文对象ctx
- fp = open(filePath,encoding='utf-8')
- ctx = node.compile(fp.read())
- 生成要执行的js函数调用的字符串形式
- funName = 'getPwd("xxx")'
- 基于ctx调用eval函数,模拟执行funName表示的js函数
- result = ctx.eval(funName)
- 导包:
#1.导包
import execjs
#2.创建node对象
node = execjs.get()
#3.编译js文件返回上下文ctx对象(将js文件中的代码读取出来,被compile进行编译)
fp = open('test.js','r',encoding='utf-8')
ctx = node.compile(fp.read())
#4.使用上下文对象ctx调用eval函数执行js文件中的指定函数即可
result = ctx.eval('getPwd("123456")')
print(result)
//test.js
function getPwd(pwd){
return pwd;
}
微信公众平台案例
https://mp.weixin.qq.com/ :逆向登录密码的加密算法。
分析思路:
- 先通过抓包工具发现,密码是经过加密,并且发现密码的加密后的数据是32位,大概率是md5加密的!
- 发现加密后的数据是被pwd这个请求参数使用的。
- 需要全局搜索pwd或者pwd:,定位加密的环节在哪里
- 进行断点调试,定位加密算法。
实现方案1(大胆):
-
直接使用python的md5进行数据加密:
-
from hashlib import md5 pwd = '123456'; obj = md5() obj.update(pwd.encode("utf-8")) bs = obj.hexdigest() print(bs)
-
-
逆向网站js代码:
-
断点调试后,发现return P(t) 就是返回加密的内容。逆向P函数即可。
-
可以使用【发条】进行js代码调试
-
调试成功后的js代码:
-
g={}; function _(t, i) { var r = (t & 65535) + (i & 65535) , f = (t >> 16) + (i >> 16) + (r >> 16); return f << 16 | r & 65535 } function D(t, i) { return t << i | t >>> 32 - i } function R(t, i, r, f, T, O) { return _(D(_(_(i, t), _(f, O)), T), r) } function S(t, i, r, f, T, O, $) { return R(i & r | ~i & f, t, i, T, O, $) } function d(t, i, r, f, T, O, $) { return R(i & f | r & ~f, t, i, T, O, $) } function m(t, i, r, f, T, O, $) { return R(i ^ r ^ f, t, i, T, O, $) } function v(t, i, r, f, T, O, $) { return R(r ^ (i | ~f), t, i, T, O, $) } function o(t, i) { t[i >> 5] |= 128 << i % 32; t[(i + 64 >>> 9 << 4) + 14] = i; var r, f, T, O, $, s = 1732584193, c = -271733879, p = -1732584194, n = 271733878; for (r = 0; r < t.length; r += 16) { f = s; T = c; O = p; $ = n; s = S(s, c, p, n, t[r], 7, -680876936); n = S(n, s, c, p, t[r + 1], 12, -389564586); p = S(p, n, s, c, t[r + 2], 17, 606105819); c = S(c, p, n, s, t[r + 3], 22, -1044525330); s = S(s, c, p, n, t[r + 4], 7, -176418897); n = S(n, s, c, p, t[r + 5], 12, 1200080426); p = S(p, n, s, c, t[r + 6], 17, -1473231341); c = S(c, p, n, s, t[r + 7], 22, -45705983); s = S(s, c, p, n, t[r + 8], 7, 1770035416); n = S(n, s, c, p, t[r + 9], 12, -1958414417); p = S(p, n, s, c, t[r + 10], 17, -42063); c = S(c, p, n, s, t[r + 11], 22, -1990404162); s = S(s, c, p, n, t[r + 12], 7, 1804603682); n = S(n, s, c, p, t[r + 13], 12, -40341101); p = S(p, n, s, c, t[r + 14], 17, -1502002290); c = S(c, p, n, s, t[r + 15], 22, 1236535329); s = d(s, c, p, n, t[r + 1], 5, -165796510); n = d(n, s, c, p, t[r + 6], 9, -1069501632); p = d(p, n, s, c, t[r + 11], 14, 643717713); c = d(c, p, n, s, t[r], 20, -373897302); s = d(s, c, p, n, t[r + 5], 5, -701558691); n = d(n, s, c, p, t[r + 10], 9, 38016083); p = d(p, n, s, c, t[r + 15], 14, -660478335); c = d(c, p, n, s, t[r + 4], 20, -405537848); s = d(s, c, p, n, t[r + 9], 5, 568446438); n = d(n, s, c, p, t[r + 14], 9, -1019803690); p = d(p, n, s, c, t[r + 3], 14, -187363961); c = d(c, p, n, s, t[r + 8], 20, 1163531501); s = d(s, c, p, n, t[r + 13], 5, -1444681467); n = d(n, s, c, p, t[r + 2], 9, -51403784); p = d(p, n, s, c, t[r + 7], 14, 1735328473); c = d(c, p, n, s, t[r + 12], 20, -1926607734); s = m(s, c, p, n, t[r + 5], 4, -378558); n = m(n, s, c, p, t[r + 8], 11, -2022574463); p = m(p, n, s, c, t[r + 11], 16, 1839030562); c = m(c, p, n, s, t[r + 14], 23, -35309556); s = m(s, c, p, n, t[r + 1], 4, -1530992060); n = m(n, s, c, p, t[r + 4], 11, 1272893353); p = m(p, n, s, c, t[r + 7], 16, -155497632); c = m(c, p, n, s, t[r + 10], 23, -1094730640); s = m(s, c, p, n, t[r + 13], 4, 681279174); n = m(n, s, c, p, t[r], 11, -358537222); p = m(p, n, s, c, t[r + 3], 16, -722521979); c = m(c, p, n, s, t[r + 6], 23, 76029189); s = m(s, c, p, n, t[r + 9], 4, -640364487); n = m(n, s, c, p, t[r + 12], 11, -421815835); p = m(p, n, s, c, t[r + 15], 16, 530742520); c = m(c, p, n, s, t[r + 2], 23, -995338651); s = v(s, c, p, n, t[r], 6, -198630844); n = v(n, s, c, p, t[r + 7], 10, 1126891415); p = v(p, n, s, c, t[r + 14], 15, -1416354905); c = v(c, p, n, s, t[r + 5], 21, -57434055); s = v(s, c, p, n, t[r + 12], 6, 1700485571); n = v(n, s, c, p, t[r + 3], 10, -1894986606); p = v(p, n, s, c, t[r + 10], 15, -1051523); c = v(c, p, n, s, t[r + 1], 21, -2054922799); s = v(s, c, p, n, t[r + 8], 6, 1873313359); n = v(n, s, c, p, t[r + 15], 10, -30611744); p = v(p, n, s, c, t[r + 6], 15, -1560198380); c = v(c, p, n, s, t[r + 13], 21, 1309151649); s = v(s, c, p, n, t[r + 4], 6, -145523070); n = v(n, s, c, p, t[r + 11], 10, -1120210379); p = v(p, n, s, c, t[r + 2], 15, 718787259); c = v(c, p, n, s, t[r + 9], 21, -343485551); s = _(s, f); c = _(c, T); p = _(p, O); n = _(n, $) } return [s, c, p, n] } function u(t) { var i, r = ""; for (i = 0; i < t.length * 32; i += 8) { r += String.fromCharCode(t[i >> 5] >>> i % 32 & 255) } return r } function b(t) { var i, r = []; r[(t.length >> 2) - 1] = void 0; for (i = 0; i < r.length; i += 1) { r[i] = 0 } for (i = 0; i < t.length * 8; i += 8) { r[i >> 5] |= (t.charCodeAt(i / 8) & 255) << i % 32 } return r } function L(t) { return u(o(b(t), t.length * 8)) } function h(t, i) { var r, f = b(t), T = [], O = [], $; T[15] = O[15] = void 0; if (f.length > 16) { f = o(f, t.length * 8) } for (r = 0; r < 16; r += 1) { T[r] = f[r] ^ 909522486; O[r] = f[r] ^ 1549556828 } $ = o(T.concat(b(i)), 512 + i.length * 8); return u(o(O.concat($), 512 + 128)) } function y(t) { var i = "0123456789abcdef", r = "", f, T; for (T = 0; T < t.length; T += 1) { f = t.charCodeAt(T); r += i.charAt(f >>> 4 & 15) + i.charAt(f & 15) } return r } function E(t) { return unescape(encodeURIComponent(t)) } function I(t) { return L(E(t)) } function P(t) { return y(I(t)) } function B(t, i) { return h(E(t), E(i)) } function l(t, i) { return y(B(t, i)) } g.exports = function(t, i, r) { if (!i) { if (!r) { return P(t) } else { return I(t) } } if (!r) { return l(i, t) } else { return B(i, t) } }
-
-
python运行代码:
-
#1.导包 import execjs #2.创建node对象 node = execjs.get() #3.编译js文件返回上下文ctx对象(将js文件中的代码读取出来,被compile进行编译) fp = open('main.js','r',encoding='utf-8') ctx = node.compile(fp.read()) #4.使用上下文对象ctx调用eval函数执行js文件中的指定函数即可 result = ctx.eval('P("123456")') print(result)
-
-
一. JavaScript前置知识点
1. js中创建对象的方法
let a = {'name':'bobo'}; //方法1
function B(){this.name="bobo"};
let b = new B(); //方法2
console.log(a);
console.log(b);
2. 原型链
2.1 何为原型链
原型链是JavaScript中对象继承属性和方法的一种方式。具体介绍如下:
原型链是JavaScript中对象继承属性和方法的一种方式。当访问一个对象的属性或方法时,如果该对象本身没有这个属性或方法,它会通过原型链去它的原型对象中查找,如果原型对象也没有,会继续在其原型的原型中查找,这样逐级向上,直到找到属性或方法或者达到原型链的末端。
2.2 原型链相关概念
-
原型
-
概念:原型本身其实是一个function函数(构造函数),可以将其理解成Python中的class类。
-
创建一个原型:
function User(name,pwd){ this.userName = name; this.pwd = pwd; this.regist = function(){ console.log(this.name+"在注册") } } -
注意:
/* 如下代码是使用字面量方式创建对象时,直接使用花括号{}来定义对象的属性和方法。这种方式创建的对象是一个简单的键值对集合,没有原型链和构造函数。 */ let a = {'name':'bobo'}; /* 通过定义一个构造函数B(),然后使用new关键字来创建一个新的对象实例。这种方式创建的对象可以继承构造函数的原型属性和方法,从而实现面向对象编程的特性。 */ function B(){ this.name="bobo"; } let b = new B();
-
-
实例对象
-
概念:通过new关键字创建的对象(调用构造函数)称为实例对象。
-
创建实例对象:
let u1 = new User('jay','123'); let u2 = new User('tom','456');
-
-
原型对象
-
概念:原型对象用于存储所有实例对象共享的属性和方法,以减少每个实例对象重复存储相同属性和方法的开销。
-
原型对象存储所有实例对象共享的属性和方法
//类似于类属性 User.prototype.address = "BJ"; User.prototype.gender = "male"; //类似于类方法 User.prototype.login = function login(username, password){ console.log(`${username}在登录`); } //实例对象共享原型对象存储的内容 u1.login('jay','123'); u2.login('tom','456'); console.log(u1.address,u2.address,u1.gender,u2.gender); -
获取原型对象:
User.prototype; u1.__proto__; User.prototype === u1.__proto__ //true //可以通过原型名访问原型对象或者使用实例名访问原型对象
-
-
原型链
-
原型链是JavaScript中对象继承属性和方法的一种方式。具体介绍如下:
原型链是JavaScript中对象继承属性和方法的一种方式。当访问一个对象的属性或方法时,如果该对象本身没有这个属性或方法,它会通过原型链去它的原型对象中查找,如果原型对象也没有,会继续在其原型的原型中查找,这样逐级向上,直到找到属性或方法或者达到原型链的末端。原型对象本身也是一个对象,它也可以使用__proto__访问它的原型对象,类似于:
u1.__proto__.__proto__ -
原型链的成员访问:
- 实例对象可以访问其原型内的成员和其原型链上所有原型对象内的成员
User.toString()
-
-
浏览器环境navigator分析
- 思考:navigator对象的原型对象是谁?
- navigator.proto === Navigator(原型)
- navigator.proto === Navigator.prototype(原型对象)
- 思考:navigator对象的原型对象是谁?
3. Object对象常用成员
//判断对象类型typeof和Object.prototype.toString.call(Object原型对象)
console.log('数字1',typeof 1);
console.log("字符串1",typeof "1");
console.log('空对象{}',typeof {});
console.log('布尔true',typeof true);
console.log('空数组[]',typeof []);
console.log('null空',typeof null);
console.log('undefined',typeof undefined);
console.log('函数function (){}',typeof function (){});
//发现null和空数组[]类型都是object类型(无法区分具体类型)
console.log("=================================")
console.log(Object.prototype.toString.call(1));
console.log(Object.prototype.toString.call("1"));
console.log(Object.prototype.toString.call({}));
console.log(Object.prototype.toString.call(true));
console.log(Object.prototype.toString.call([]));
console.log(Object.prototype.toString.call(null));
console.log(Object.prototype.toString.call(undefined));
console.log(Object.prototype.toString.call(function () {}));
//创建新对象,设置其原型对象为window(在node环境下可能需要伪装浏览器环境下的对象)
a = Object.create(window)
a.__proto__ === window //true
//判断对象自身属性中是否具有指定的属性
function func(){
this.name="bobo";
this.getAge=function(){}
};
f = new func();
f.hasOwnProperty('name'); //true
f.hasOwnProperty('getAge'); //true
f.hasOwnProperty('toString'); //false
//获取指定对象上一个自有属性对应的属性描述符
Object.getOwnPropertyDescriptor(f,'name');
//获取指定对象上所有属性对应的属性描述符
Object.getOwnPropertyDescriptors(f);
/*
属性描述符是一组用于精确定义和描述对象属性的特性的集合(属性描述符也是一个对象)。通过属性描述符,开发者可以指定一个属性是否可被修改、删除、枚举或者通过特定的函数来获取和设置其值。
*/
//获取实例对象的原型对象
Object.getPrototypeOf(f);
Object.getPrototypeOf(f) === f.__proto__ ;//true
//设置一个指定的对象的原型(可以对一个已经存在的对象重新设置其原型对象)
Object.setPrototypeOf(f,Object.__proto__) //f对象的原型对象设置成了window的原型对象
//defineProperty直接在一个对象上定义一个新属性,然后可指定新属性的属性描述的,并返回此对象。
let User = {
"name":"小明",
}//创建一个User对象
//给对象添加两个成员
User.age = 10;
User["age"] = 20;
//给对象定义一个新属性且设置其属性描述符(属性描述符可分为:数据描述符和存取描述符)此时使用数据描述符。
//参数1:对象。参数2:属性名。参数3:属性描述的
Object.defineProperty(User, "height", {
enumerable:true, //该属性是否可遍历
configurable:true,//该属性是否可配置:决定该属性是否可以被删除或修改其属性描述符。
value:160, //属性的值
writable:false //该属性的值是否可以通过赋值运算符改变
});
//对象属性遍历,如果某个属性的文件描述符中的enumerable:false则无法遍历出该属性
for (const userKey in User) {
console.log(userKey);
}
//存取描述符
let Stu = {
"name":"小红",
}//创建一个Stu对象
let temp = null;//临时变量
//给Stu对象定义一个新属性score,且设置其属性描述符
Object.defineProperty(Stu, "score", {
enumerable:true,
configurable:true,
get:function (){// 当获取属性值是调用
console.log("正在获取值");
return temp;
},
set:function (value){// 当对属性进行赋值操作时调用
console.log("正在设置值");
temp = value;
}
});
console.log(User.score);
User.score = 100;
console.log(User.score);
/*
属性描述符注意事项:属性描述符分为两类:数据描述符和存取描述符。数据描述符包含value、writable、enumerable和configurable这些属性。存取描述符包含get、set、enumerable和configurable。两者不能混用,即一个描述符如果是数据描述符就不能包含get或set,反之亦然。
*/

浙公网安备 33010602011771号