爬虫&逆向--Day08--加密算法

一、V8引擎

1.1、V8引擎

我们知道,js是一种可以直接运行在浏览器中的脚本语言。那么为什么浏览器可以直接运行js脚本程序呢?原因就在于浏览器中内置了“V8”引擎。

什么是V8引擎?

V8引擎是一款专门解释和执行JavaScript代码的虚拟机。任何程序只要集成了V8引擎,就可以执行JavaScript代码。浏览器集成了V8引擎,可以执行JavaScript代码;

1.2、Node.js

由于浏览器内部集成了V8引擎,因此js程序可以直接运行在浏览器中。那么,如果想要在浏览器外部运行js代码可以吗?

试想一下,如果我们想在自己电脑上运行Python代码,是不是必须事先要装好Pyhon的运行环境(Python解释器)呢。同样,如果我们想在自己电脑上运行js程序的话,也要事先装好js的运行环境。那么这个执行js程序的运行环境就是“Node.js”。

什么是Node.js?

Node.js是一个基于Chrome V8引擎的JavaScript运行时环境,它使得JavaScript能够在浏览器外部运行。Node.js的出现将JavaScript从浏览器中解放出来。

1.3、Node.js环境安装

1、下载Node.js 打开官网下载链接:https://nodejs.org/zh-cn/

2、安装

下载完成后,双击“node-v12.16.1-x64.msi”,开始安装Node.js ①点击【Next】按钮 ②勾选复选框(I accept the…),点击【Next】按钮

一直【next】就完了,然后【install】安装,安装完后点击【Finish】按钮完成安装

安装成功后简单一下测试安装是否成功:

在键盘按下【win+R】键,输入cmd,然后回车,打开cmd窗口

3、环境变量配置

 

4、pycharm配置node环境

  1. 打开PyCharm,点击菜单栏中的“File” > “Settings”(对于Mac用户,是“PyCharm” > “Preferences”)。

  2. 在弹出的设置窗口中,选择“Languages & Frameworks” > “Node.js and NPM”。

  3. 在“Node Interpreter”字段中,点击右侧的“…”按钮,然后选择您安装Node.js的路径。这通常是在您的系统路径下的“node”可执行文件。

  4. 确认设置无误后,点击“OK”保存配置。

 【Node.js安装方式参考:爬虫&逆向--Day06--Javascript基础入门 

二、base64编码

2.1、base64是什么

Base64编码,是由64个字符组成编码集:26个大写字母A~Z,26个小写字母a~z,10个数字0~9,符号“+”与符号“/”。Base64编码的基本思路是将原始数据的三个字节拆分转化为四个字节,然后根据Base64的对应表,得到对应的编码数据。

当原始数据凑不够三个字节时,编码结果中会使用额外的符号“=”来表示这种情况。

2.2、base64原理

每一个base64的字符会对应有一个索引值(0-63)

将you进行base64编码过程如下:

小于3个字符为一组的编码方式如:

ASCII:

2.3、base64测试

base64编码示例:

import base64

# 将原始数据转化为二进制/字节数据
data = "you".encode("utf-8")
print(data)                             # b'you'

# 把字节转化成b64
bs = base64.b64encode(data).decode()
print(bs)                               # eW91

bs = "yo".encode("utf-8")
# 把字节转化成b64
print(base64.b64encode(bs).decode())    # eW8=

# 猜测结果
bs = "y".encode("utf-8")
# 把字节转化成b64
print(base64.b64encode(bs).decode())    # eQ==
"""
1、需要先将原始数据转化为二进制/字节数据
2、在把二进制字节数据转化为base64
"""

base64解码示例:

注意, base64编码处理后的字符串长度. 一定是4的倍数(因为Base64编码的基本思路是将原始数据的三个字节拆分转化为四个字节). 如果在网页上看到有些密文的b64长度不是4的倍数. 会报错

import base64

s = "eW91"
ret = base64.b64decode(s)
print(ret)  # 正确        b'you'

s = "eW91eQ=="
ret = base64.b64decode(s)
print(ret)  # 正确        b'youy'

s = "eW91eQ"
ret = base64.b64decode(s)
print(ret)  # 报错,s不是4的倍数   编码的时候不够4的倍数可以补0,解码不够4的倍数直接报错


"""
错误提示:binascii.Error: Incorrect padding
输入的base64编码字符串必须符合base64的padding规则。
我理解这是因为字符串的长度不是 4 的倍数,这是 base64 编码文本的要求。
"""

如果不是4的倍数如何处理呢?解决思路. 使用=填充为4的倍数即可

s = "eW91eQ"
# 填充为4的倍数  不够4的倍数,就填充=
s += ("=" * (4 - len(s) % 4))
print("填充后", s)     # 填充后 eW91eQ==
ret = base64.b64decode(s).decode()
print(ret)          # youy

base64 编码的优点:

  • 算法是编码,不是压缩,编码后只会增加字节数(一般是比之前的多1/3,比如之前是3, 编码后是4)

  • 算法简单,基本不影响效率

  • 算法可逆,解码很方便,不用于私密传输。

三、JS常见的加密方式:MD5加密、DES/AES加密、RSA加密

  • 加密在前端开发和爬虫中是经常遇见的。掌握了加密、解密算法也是你从一个编程小白到大神级别质的一个飞跃。且加密算法的熟练和剖析也是很有助于帮助我们实现高效的js逆向。下述只把我们常用的加密方法进行总结。不去深究加密的具体实现方式。

  • 常见的加密算法基本分为这几类,

    • 线性散列算法(签名算法)MD5

    • 对称性加密算法 AES DES

    • 非对称性加密算法 RSA

3.1、MD5加密(不可逆)

  • MD5是一种被广泛使用的线性散列算法,可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整的一致性。且MD5加密之后产生的是一个固定长度(32位或16位)的数据。

    • 结论:一旦看到了一个长度为32位的密文数据,该数据极有可能是通过md5算法进行的加密!

  • 解密:

    • 常规讲MD5是不存在解密的。但是理论上MD5是可以进行反向暴力破解的。暴力破解的大致原理就是用很多不同的数据进行加密后跟已有的加密数据进行对比,由此来寻找规律。理论上只要数据量足够庞大MD5是可以被破解的。但是要注意,破解MD5是需要考虑破解的成本(时间和机器性能)。假设破解当前的MD5密码需要目前计算能力最优秀的计算机工作100年才能破解完成。那么当前的MD5密码就是安全的。

  • 增加破解成本的方法(方法很多,这里只说我常用的)。

    • 使用一段无意义且随机的私匙进行MD5加密会生成一个加密串,我们暂且称之为串1

    • 将要加密的的数据跟串1拼接,再进行一次MD5,这时会生成串2

    • 将串2再次进行MD5加密,这时生成的串3就是我们加密后的数据。

  • 我们在注册账号时的密码一般都是用的MD5加密。

  • 代码实操:

    • Python版本:

  • from hashlib import md5
    
    # 1、创建一个加密对象
    obj = md5()
    # 2、把明文放到加密对象当中
    text = "hahahaha"  # 明文数据
    obj.update(text.encode("utf-8"))
    # 3、开始加密
    bs = obj.hexdigest()
    print(bs)  # 4f0b36a34946153c358f8b243428a1eb
    • JS版本:下载安装crypto-js(npm install crypto-js)
  • // 导入加密算法库  除了md5还有其他的加密算法
    var CryptoJS = require('crypto-js');
    // 原始数据
    var data = 'hahahaha';
    // 生成MD5摘要
    var md5Digest = CryptoJS.MD5(data).toString();
    
    console.log(md5Digest);  // 4f0b36a34946153c358f8b243428a1eb
    • 上述代码的核心关键字:md5

    • 特性是只能加密不能解密

    • npm install crypto-js  导入方式

3.2、DES/AES加密(可逆)

  • DES全称为Data Encryption Standard,即数据加密标准,是一种使用密钥加密的算法。该加密算法是一种对称加密方式,其加密运算、解密运算需要使用的是同样的密钥(一组字符串)即可。

  • 注意:

    • 现在用AES这个标准来替代原先的DES。

    • AES和DES的区别:

      • 加密后密文长度的不同:

        • DES加密后密文长度是8的整数倍

        • AES加密后密文长度是16的整数倍

      • 应用场景的不同:

        • 企业级开发使用DES足够安全

        • 如果要求高使用AES

  • DES算法的入口参数有三个:

    • Key、Data、Mode,padding、iv。

      • Key为DES算法的工作密钥;

      • Data为要被加密或被解密的数据;

      • Mode为DES的工作模式。最常用的模式就是 CBC 模式和 ECB模式

        • ECB:是一种基础的加密方式,密文被分割成分组长度相等的块(不足补齐),然后单独一个个加密,一个个输出组成密文。

        • CBC:是一种循环模式,前一个分组的密文和当前分组的明文异或后再加密,这样做的目的是增强破解难度。

      • padding为填充模式,如果加密后密文长度如果达不到指定整数倍(8个字节、16个字节),填充对应字符

      • iv:参数中的iv主要用于CBC模式,确保即使加密相同的明文,每次产生的密文也不相同,增强加密的安全性。iv通常是一个16字节的随机字符串。这个字符串在解密时也需要用到,因此需要妥善保存。

  • Python版本:

    • 环境安装:
    • pip install pycryptodome     pip是python中导入,npm是js导入
    • 加密代码:
    • from Crypto.Cipher import AES
      from Crypto.Util.Padding import pad
      import base64
      
      key = '0123456789abcdef'.encode()       # 秘钥: 必须16字节  【需要保密】
      iv = b'abcdabcdabcdabcd'                # 偏移量:16位/字节(字节类型) 随便写,16位就行  【需要保密】
      text = 'hahahaha is a monkey!'          # 加密内容
      # 设置加密内容的长度填充(位数为16的整数倍)
      text = pad(text.encode(), 16)           # 这里写了16,就一定是生成的16的整数倍
      # 创建加密对象
      aes = AES.new(key, AES.MODE_CBC, iv)    # 创建一个aes对象
      
      en_text = aes.encrypt(text)             # 加密明文
      print("aes加密数据:::", en_text)         # 返回二进制类型数据
      # aes加密数据::: b'v)\x90C\x9f\xa6\xae1\xa8\xc7*{\xf2\xa4(\xb8\x0f\xa6\xed\xa1\xf1\xc4\xe9\xe9G\xfdU:O\x1dK\x19'
      
      # 二进制密文转换成字符串格式
      en_text = base64.b64encode(en_text).decode()  # 将返回的字节型数据转进行base64编码
      print(en_text)
      # dimQQ5+mrjGoxyp78qQouA+m7aHxxOnpR/1VOk8dSxk=
    • 解密代码:
    • from Crypto.Cipher import AES
      import base64
      from Crypto.Util.Padding import unpad
      
      key = '0123456789abcdef'.encode()
      iv = b'abcdabcdabcdabcd'
      # 需要解密的文本
      text = 'dimQQ5+mrjGoxyp78qQouA+m7aHxxOnpR/1VOk8dSxk='.encode()
      
      # 将密文数据转换为二进制类型
      ecrypted_base64 = base64.b64decode(text)
      print("aes解密数据-二进制数据:::", ecrypted_base64)
      # aes解密数据-二进制数据::: b'v)\x90C\x9f\xa6\xae1\xa8\xc7*{\xf2\xa4(\xb8\x0f\xa6\xed\xa1\xf1\xc4\xe9\xe9G\xfdU:O\x1dK\x19'
      
      aes = AES.new(key, AES.MODE_CBC, iv)
      source = aes.decrypt(ecrypted_base64)  # 解密
      # 未填充数据
      print("aes解密数据:::", source.decode())
      # aes解密数据::: hahahaha is a monkey!
      # 取消填充数据
      print("aes解密数据:::", unpad(source, 16).decode())
      # aes解密数据::: hahahaha is a monkey!
  • JS版本
    • 加密
  • const CryptoJS = require("crypto-js")
    
    // 密钥(128位,16字节)   parse转换为二进制
    var key = CryptoJS.enc.Utf8.parse('0123456789abcdef');
    
    // 初始化向量(IV)(128位,16字节)
    var iv = CryptoJS.enc.Utf8.parse('abcdabcdabcdabcd');
    
    // 待加密的数据
    var plaintext = 'hahahaha is a monkey!';
    
    // 进行AES-128加密,使用CBC模式和PKCS7填充  获取加密对象进行加密
    var encrypted = CryptoJS.AES.encrypt(plaintext, key, {
        iv: iv,
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7
    });
    
    // 获取加密后的密文
    var ciphertext = encrypted.toString();
    
    console.log(ciphertext);  // dimQQ5+mrjGoxyp78qQouA+m7aHxxOnpR/1VOk8dSxk=
    • 解密
  • const CryptoJS = require("crypto-js")
    
    // 密钥(128位,16字节)
    var key = CryptoJS.enc.Utf8.parse('0123456789abcdef');
    
    // 初始化向量(IV)(128位,16字节)
    var iv = CryptoJS.enc.Utf8.parse('abcdabcdabcdabcd');
    
    // 密文数据
    var encrypText = 'dimQQ5+mrjGoxyp78qQouA+m7aHxxOnpR/1VOk8dSxk=';
    
    // 进行加密,使用CBC模式和PKCS7填充
    var decrypted = CryptoJS.AES.decrypt(encrypText, key, {
        iv: iv,
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7
    });
    
    // 解密
    var plaintext = decrypted.toString(CryptoJS.enc.Utf8);
    
    console.log(plaintext);  // hahahaha is a monkey!
  • 上述代码的关键字:

    • AES,DES

    • encrypt(用于加密的函数名),decrypt(用于解密的函数名)

    • xxxkey:秘钥一般是单独生成的,一定不会傻到明文的写在代码中!

3.3、RSA加密(可逆)

  • RSA加密:

    • RSA加密算法是一种非对称加密算法。在公开密钥加密和电子商业中RSA被广泛使用。

  • 非对称加密算法:

    • 非对称加密算法需要两个密钥:

      • 公开密钥(publickey:简称公钥)

      • 私有密钥(privatekey:简称私钥)

      • 公钥与私钥是一对,如果用公钥对数据进行加密,只有用对应的私钥才能解密。因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。

  • 注意:

    • 使用时都是使用公匙加密使用私匙解密。公匙可以公开,私匙自己保留。

    • 算法强度复杂、安全性依赖于算法与密钥但是由于其算法复杂,而使得加密解密速度没有对称加密解密的速度快。

  • 使用流程和场景介绍

    • 通过公匙加密,使用私匙解密。私匙是通过公匙计算生成的。假设ABC三方之间相互要进行加密通信。大家相互之间使用公匙进行信息加密,信息读取时使用各自对应的私匙进行信息解密

    • 用户输入的支付密码会通过RSA加密

  • 公钥私钥生成方式:

  • 环境安装:npm install jsencrypt

JS代码示例:

window = globalThis;

const JSEncrypt = require('jsencrypt');

// 公钥
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 hahaha');//对指定数据进行加密
console.log(encrypted);
// p19MI6MdWWb4a3Dft93YGng96EYM4ETZbAZAKk0UkqOeIava+TNU6vIMkUrOIpY9uozlHF4X1XtFxPJVszGLpA==


//使用私钥解密
var decrypt = new JSEncrypt();
decrypt.setPrivateKey(PRIVATE_KEY);//设置私钥
var uncrypted = decrypt.decrypt(encrypted);//解密
console.log(uncrypted);
// hello hahaha

Python代码示例:

1.创建公钥和私钥

from Crypto.PublicKey import RSA

# 通过相关算法生成唯一秘钥
rsakey = RSA.generate(1024)
# 将秘钥保存到文件中
with open("rsa.public.pem", mode="wb") as f:
    f.write(rsakey.publickey().exportKey())

with open("rsa.private.pem", mode="wb") as f:
    f.write(rsakey.exportKey())

2.加密算法实现

from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
import base64

# 加密
data = "我喜欢你"
with open("rsa.public.pem", mode="r") as f:
    pk = f.read()  # 读取公钥
    rsa_pk = RSA.importKey(pk)  # 把公钥作用在我们的RSA中
    # 基于公钥创建加密对象
    rsa = PKCS1_v1_5.new(rsa_pk)

    result = rsa.encrypt(data.encode("utf-8"))
    # 处理成b64方便传输
    b64_result = base64.b64encode(result).decode("utf-8")
    print(b64_result)
# d/lw4ekJMfUAgpuYY8PxjNmvT5NutxGdREjK9ltg14wHqwXVR55L92Ny5Yq+JAIBID9OLUYYkgAywpjoBwU1wCB35y1Qlderm+yHiyfIb4/DoMyWQpfvHHIf4S3mcSigVm7miDZlIrWFWBET6eerw9wytE/iMtS2/iAKuMyT86k=

3.解密算法实现

from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
import base64

data = 'd/lw4ekJMfUAgpuYY8PxjNmvT5NutxGdREjK9ltg14wHqwXVR55L92Ny5Yq+JAIBID9OLUYYkgAywpjoBwU1wCB35y1Qlderm+yHiyfIb4/DoMyWQpfvHHIf4S3mcSigVm7miDZlIrWFWBET6eerw9wytE/iMtS2/iAKuMyT86k='
# 解密
with open("rsa.private.pem", mode="r") as f:
    prikey = f.read()
    rsa_pk = RSA.importKey(prikey)
    # 创建解密对象
    rsa = PKCS1_v1_5.new(rsa_pk)
    result = rsa.decrypt(base64.b64decode(data), None)
    print("rsa解密数据:::", result.decode("utf-8"))  # rsa解密数据::: 我喜欢你
  • 上述代码提取关键字:

    • RSA

    • setPublicKey(设置公钥)

    • setPrivateKey(设置私钥)

    • encrypt,decrypt

四、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)

// PyExecJS.js
function get_pwd(text) {
    window = globalThis;

    const JSEncrypt = require('jsencrypt');


    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(text);//对指定数据进行加密
    return encrypted;

}
# PyExecJS.py

# 1.导包
import execjs

# 2.创建node对象
node = execjs.get()
# 3.编译js文件返回上下文ctx对象(将js文件中的代码读取出来,被compile进行编译)
fp = open('PyExecJS.js', 'r', encoding='utf-8')

ctx = node.compile(fp.read())
# 4.使用上下文对象ctx调用eval函数执行js文件中的指定函数即可
result = ctx.eval('get_pwd("123456")')
print(result)
# anaPjw2Mf4S91gE6NkMC/t3uXuDSgvBhcTtqlxWJBR9q6p86T1UeWQIzkbJ5LaXiWiaqINhT2ToG+hj92MQIKg==

 五、微信公众平台案例

https://mp.weixin.qq.com/ :逆向登录密码的加密算法。

分析思路:

  • 先通过抓包工具发现,密码是经过加密,并且发现密码的加密后的数据是32位,大概率是md5加密的!

  • 发现加密后的数据是被pwd这个请求参数使用的。

  • 需要全局搜索pwd或者pwd:,定位加密的环节在哪里

  • 进行断点调试,定位加密算法。

实现方案1(大胆):

  • 直接使用python的md5进行数据加密:

from hashlib import md5

pwd = '1234567890'
obj = md5()
obj.update(pwd.encode("utf-8"))

bs = obj.hexdigest()
print(bs)
# e807f1fcf82d132f9bb018ca6738a19f
"""
看到加密数据是32的,大胆猜测是MD5进行的加密,所以使用Python代码编写MD5加密进行对数据加密,
对比加密后的数据,发现数据显示一直,所以判断该网站的密码加密算法是MD5
正常在发起请求的时候,既然已经知道是MD5加密,我们只需要编写MD5加密脚本进行加密,然后再把加密后的数据赋值给pwd即可
现在不是需要学习逆向是什么,如何改写前端代码,所以我们需要知道那段代码是对密码进行的加密
"""

逆向网站js代码:

  • 断点调试后,发现return P(t) 就是返回加密的内容。逆向P函数即可。

  • 可以使用【发条】进行js代码调试

  • 调试成功后的js代码:

function _(n, u) {
    var i = (n & 65535) + (u & 65535),
        b = (n >> 16) + (u >> 16) + (i >> 16);
    return b << 16 | i & 65535
}

function E(n, u) {
    return n << u | n >>> 32 - u
}

function w(n, u, i, b, S, j) {
    return _(E(_(_(u, n), _(b, j)), S), i)
}

function C(n, u, i, b, S, j, F) {
    return w(u & i | ~u & b, n, u, S, j, F)
}

function d(n, u, i, b, S, j, F) {
    return w(u & b | i & ~b, n, u, S, j, F)
}

function l(n, u, i, b, S, j, F) {
    return w(u ^ i ^ b, n, u, S, j, F)
}

function p(n, u, i, b, S, j, F) {
    return w(i ^ (u | ~b), n, u, S, j, F)
}

function f(n, u) {
    n[u >> 5] |= 128 << u % 32;
    n[(u + 64 >>> 9 << 4) + 14] = u;
    var i, b, S, j, F, s = 1732584193,
        o = -271733879,
        a = -1732584194,
        t = 271733878;
    for (i = 0; i < n.length; i += 16) {
        b = s;
        S = o;
        j = a;
        F = t;
        s = C(s, o, a, t, n[i], 7, -680876936);
        t = C(t, s, o, a, n[i + 1], 12, -389564586);
        a = C(a, t, s, o, n[i + 2], 17, 606105819);
        o = C(o, a, t, s, n[i + 3], 22, -1044525330);
        s = C(s, o, a, t, n[i + 4], 7, -176418897);
        t = C(t, s, o, a, n[i + 5], 12, 1200080426);
        a = C(a, t, s, o, n[i + 6], 17, -1473231341);
        o = C(o, a, t, s, n[i + 7], 22, -45705983);
        s = C(s, o, a, t, n[i + 8], 7, 1770035416);
        t = C(t, s, o, a, n[i + 9], 12, -1958414417);
        a = C(a, t, s, o, n[i + 10], 17, -42063);
        o = C(o, a, t, s, n[i + 11], 22, -1990404162);
        s = C(s, o, a, t, n[i + 12], 7, 1804603682);
        t = C(t, s, o, a, n[i + 13], 12, -40341101);
        a = C(a, t, s, o, n[i + 14], 17, -1502002290);
        o = C(o, a, t, s, n[i + 15], 22, 1236535329);
        s = d(s, o, a, t, n[i + 1], 5, -165796510);
        t = d(t, s, o, a, n[i + 6], 9, -1069501632);
        a = d(a, t, s, o, n[i + 11], 14, 643717713);
        o = d(o, a, t, s, n[i], 20, -373897302);
        s = d(s, o, a, t, n[i + 5], 5, -701558691);
        t = d(t, s, o, a, n[i + 10], 9, 38016083);
        a = d(a, t, s, o, n[i + 15], 14, -660478335);
        o = d(o, a, t, s, n[i + 4], 20, -405537848);
        s = d(s, o, a, t, n[i + 9], 5, 568446438);
        t = d(t, s, o, a, n[i + 14], 9, -1019803690);
        a = d(a, t, s, o, n[i + 3], 14, -187363961);
        o = d(o, a, t, s, n[i + 8], 20, 1163531501);
        s = d(s, o, a, t, n[i + 13], 5, -1444681467);
        t = d(t, s, o, a, n[i + 2], 9, -51403784);
        a = d(a, t, s, o, n[i + 7], 14, 1735328473);
        o = d(o, a, t, s, n[i + 12], 20, -1926607734);
        s = l(s, o, a, t, n[i + 5], 4, -378558);
        t = l(t, s, o, a, n[i + 8], 11, -2022574463);
        a = l(a, t, s, o, n[i + 11], 16, 1839030562);
        o = l(o, a, t, s, n[i + 14], 23, -35309556);
        s = l(s, o, a, t, n[i + 1], 4, -1530992060);
        t = l(t, s, o, a, n[i + 4], 11, 1272893353);
        a = l(a, t, s, o, n[i + 7], 16, -155497632);
        o = l(o, a, t, s, n[i + 10], 23, -1094730640);
        s = l(s, o, a, t, n[i + 13], 4, 681279174);
        t = l(t, s, o, a, n[i], 11, -358537222);
        a = l(a, t, s, o, n[i + 3], 16, -722521979);
        o = l(o, a, t, s, n[i + 6], 23, 76029189);
        s = l(s, o, a, t, n[i + 9], 4, -640364487);
        t = l(t, s, o, a, n[i + 12], 11, -421815835);
        a = l(a, t, s, o, n[i + 15], 16, 530742520);
        o = l(o, a, t, s, n[i + 2], 23, -995338651);
        s = p(s, o, a, t, n[i], 6, -198630844);
        t = p(t, s, o, a, n[i + 7], 10, 1126891415);
        a = p(a, t, s, o, n[i + 14], 15, -1416354905);
        o = p(o, a, t, s, n[i + 5], 21, -57434055);
        s = p(s, o, a, t, n[i + 12], 6, 1700485571);
        t = p(t, s, o, a, n[i + 3], 10, -1894986606);
        a = p(a, t, s, o, n[i + 10], 15, -1051523);
        o = p(o, a, t, s, n[i + 1], 21, -2054922799);
        s = p(s, o, a, t, n[i + 8], 6, 1873313359);
        t = p(t, s, o, a, n[i + 15], 10, -30611744);
        a = p(a, t, s, o, n[i + 6], 15, -1560198380);
        o = p(o, a, t, s, n[i + 13], 21, 1309151649);
        s = p(s, o, a, t, n[i + 4], 6, -145523070);
        t = p(t, s, o, a, n[i + 11], 10, -1120210379);
        a = p(a, t, s, o, n[i + 2], 15, 718787259);
        o = p(o, a, t, s, n[i + 9], 21, -343485551);
        s = _(s, b);
        o = _(o, S);
        a = _(a, j);
        t = _(t, F)
    }
    return [s, o, a, t]
}

function L(n) {
    var u, i = "";
    for (u = 0; u < n.length * 32; u += 8) {
        i += String.fromCharCode(n[u >> 5] >>> u % 32 & 255)
    }
    return i
}

function y(n) {
    var u, i = [];
    i[(n.length >> 2) - 1] = void 0;
    for (u = 0; u < i.length; u += 1) {
        i[u] = 0
    }
    for (u = 0; u < n.length * 8; u += 8) {
        i[u >> 5] |= (n.charCodeAt(u / 8) & 255) << u % 32
    }
    return i
}

function $(n) {
    return L(f(y(n), n.length * 8))
}

function q(n, u) {
    var i, b = y(n),
        S = [],
        j = [],
        F;
    S[15] = j[15] = void 0;
    if (b.length > 16) {
        b = f(b, n.length * 8)
    }
    for (i = 0; i < 16; i += 1) {
        S[i] = b[i] ^ 909522486;
        j[i] = b[i] ^ 1549556828
    }
    F = f(S.concat(y(u)), 512 + u.length * 8);
    return L(f(j.concat(F), 512 + 128))
}

function z(n) {
    var u = "0123456789abcdef",
        i = "",
        b, S;
    for (S = 0; S < n.length; S += 1) {
        b = n.charCodeAt(S);
        i += u.charAt(b >>> 4 & 15) + u.charAt(b & 15)
    }
    return i
}

function Q(n) {
    return unescape(encodeURIComponent(n))
}

function B(n) {
    return $(Q(n))
}

function x(n) {
    return z(B(n))
}

function M(n, u) {
    return q(Q(n), Q(u))
}

function R(n, u) {
    return z(M(n, u))
}

function get_pwd(n, u, i) {
    if (!u) {
        if (!i) {
            return x(n)
        } else {
            return B(n)
        }
    }
    if (!i) {
        return R(u, n)
    } else {
        return M(u, n)
    }
}

python运行代码:

# 1.导包
import execjs

# 2.创建node对象
node = execjs.get()
# 3.编译js文件返回上下文ctx对象(将js文件中的代码读取出来,被compile进行编译)
fp = open('案例.js', 'r', encoding='utf-8')
ctx = node.compile(fp.read())
# 4.使用上下文对象ctx调用eval函数执行js文件中的指定函数即可
result = ctx.eval('get_pwd("1234567890")')
print(result)

分析1、

 分析2、

 分析3、

 分析4、点击该处,即可跳转到对应的方法处

 分析5、在发条工具中,调用函数的时候,点击:计算表达式

发条工具下载链接:通过网盘分享的文件:JS-ED_1.9.exe

链接: https://pan.baidu.com/s/1bK1CrNF68waktsUizwFJ7w?pwd=ypjs 提取码: ypjs

 分析6、发条工具的调试功能,也可以借助PyCharm来完成,创建一个JS文件用来调试js代码,再创建一个python文件用于调用js代码

 

posted @ 2025-07-04 16:03  L遇上J  阅读(92)  评论(0)    收藏  举报