补环境:vm2 transformer.js 源码分析

news2024/10/7 12:22:38

在补环境框架的文件夹里执行 vm2 文件能成功得到结果,但是将合并了环境和原 js 文件后的代码内容单独提取出来通过 vm2 调用却报错提示 SyntaxError: Use of internal vm2 state variable:

通过 transformer.js 源码,分析 VM2_INTERNAL_STATE_DO_NOT_USE_OR_PROGRAM_WILL_FAIL 和 makeNiceSyntaxError 都是什么:

const {Parser: AcornParser, isNewLine: acornIsNewLine, getLineInfo: acornGetLineInfo} = require('acorn');
const {full: acornWalkFull} = require('acorn-walk');

const INTERNAL_STATE_NAME = 'VM2_INTERNAL_STATE_DO_NOT_USE_OR_PROGRAM_WILL_FAIL';

该 js 文件的前两行引入了 acorn 和 acorn-walk,acorn 是一个小而快 JavaScript 解析器,熟知的还有 babel 和 eslint 等等,acorn-walk 包提供了遍历的能力,以下为 acorn 解析示例:  

AST 相关可阅读:【JavaScript 逆向】AST 技术反混淆 

console.log('Yy_Rose')

由上面代码可知 VM2_INTERNAL_STATE_DO_NOT_USE_OR_PROGRAM_WILL_FAIL 是一个字符串对象,赋值给了 INTERNAL_STATE_NAME,再看看 INTERNAL_STATE_NAME 在哪被调用了,搜索后总共有七个地方,与报错提示相关的在第 122 行,内容如下:

code: `${name}=${INTERNAL_STATE_NAME}.handleException(${name});`

先来看看初始扣下来的 js 文件中以下位置的代码内容:

然后再看看通过 vm2 合并环境后的 js 文件的 try catch 处,可以看出 VMScript 编译时自动添加了语句:

所以需要分析这部分代码的含义,是什么导致添加了这部分代码,且有什么用,代码如下:

acornWalkFull(ast, (node, state, type) => {
		if (type === 'Function') {
			if (node.async) hasAsync = true;
		}
		const nodeType = node.type;
		if (nodeType === 'CatchClause') {
			const param = node.param;
			if (param) {
				const name = assertType(param, 'Identifier').name;
				const cBody = assertType(node.body, 'BlockStatement');
				if (cBody.body.length > 0) {
					insertions.push({
						__proto__: null,
						pos: cBody.body[0].start,
						order: TO_LEFT,
						code: `${name}=${INTERNAL_STATE_NAME}.handleException(${name});`
					});
				}
			}
        } else if (nodeType === 'WithStatement') {...
        } else if (nodeType === 'Identifier') {...
        } else if (nodeType === 'ImportExpression') {...
        }
        ...
        ...
	});
  • acornWalkFull 是引用的 acorn-walk 包
  • ast:前面通过 acorn 的解析器 Parser 将 JavaScript 代码转换为了成了 AST(抽象语法树)
  • Identifier:标识符,指变量名称
  • BlockStatement:代码块语句,表示一些控制语句或特殊语句
  • catchClause:构造一个自定义的 catch 子句节点,作为 try 异常处理块的内容,param 用以表示 catch 后的参数,body 则表示 catch 后的执行语句,通常是一个块语句 
interface CatchClause <: Node {
    type: "CatchClause";
    param: Pattern;
    body: BlockStatement;
}

assertType 函数返回 node 节点,若节点为无效类型则抛出异常,类型断言:

function assertType(node, type) {
	if (!node) throw new Error(`None existent node expected '${type}'`);
	if (node.type !== type) throw new Error(`Invalid node type '${node.type}' expected '${type}'`);
	return node;
}

这里先判断 name 是否为 Identifier,获取了 catch 括号中的变量名称,然后判断 cBody 是否为 BlockStatement 代码块语句,这里为 try{}catch(){},insertions 为空数组,这里大底就是遍历了函数节点,当节点类型为 catchClause 时,在 try...catch... 代码块的 catch 部分开头添加了指定的内容,通过 handleException 处理异常,更改了 catch 处的代码,将整个 try 语句节点作为一个新的函数声明节点的子节点,用新生成的节点替换原有的函数声明节点。

抛出 makeNiceSyntaxError('Use of internal vm2 state variable' 异常处在第 155 行:

let internStateValiable = undefined;

if (internStateValiable) {
    throw makeNiceSyntaxError('Use of internal vm2 state variable', code, filename,             internStateValiable.start, {
		__proto__: null,
		start: internStateValiable.start,
		end: internStateValiable.end
	});
}

所以当通过 try 捕捉的参数未定义的时候,则会抛出此类异常及前文提到的 catch 处被更改的内容,INTERNAL_STATE_NAME 被调用,进一步导致报错 SyntaxError: Use of internal vm2 state variable,但是原本 js 文件的 try 处捕捉到异常时则执行 catch 后的内容,从以下可以看到,try 处赋值语句出现异常时,o[17] 被赋值为 0:

try {
    o[17] = e[t(608, "o#sx")](X[O][t(706, "YD8i")][v]()[c](e[t(525, "i5yU")]), -1) ? 0 : 1
} catch (t) {
    o[17] = 0
}

而 catch 处已经添加了 ${name}=${INTERNAL_STATE_NAME}.handleException(${name}); 的 js 文件会直接抛出异常,程序运行结束,所以不能直接将合并后的整个 js 文件内容复制出来使用,只能单独将合并后的环境拿出来,放在原始的 js 文件前面,再通过 vm2 调用执行,即可成功得到结果。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1316.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【韩顺平老师讲MySQL】函数和多表查询

文章目录P33.数学函数P34.日期函数P37.加密函数P38.流程控制函数P39.查询增强P40.分页查询P41.分组查询P42.多子句查询P43.多表查询笛卡尔积(重难点)P44.多表查询P45.自连接P46.多行子查询P33.数学函数 # 绝对值 SELECT ABS(-12) FROM DUAL;# 十进制转为二进制 SELECT BIN(10) …

【offer拿到手软系列】面试小贴士

​ 学习好一门语言贵在坚持——初识JavaScript&#x1f3f9;&#x1f481;‍♂️&#xff01; 首先&#xff1a; 博主是&#x1f466;一个帅气的boy&#xff0c;你可以叫我山鱼君 &#x1f5b1; ⌨个人主页&#xff1a;山鱼菌的个人主页 &#x1f496;&#x1f496;如果对你有帮…

vmlogin多登防关联浏览器中配置Geolocation定位插件的使用教程

Geolocation 接口是一个用来获取设备地理位置的可编程的对象&#xff0c;它可以让Web内容访问到设备的地理位置&#xff0c;这将允许Web应用基于用户的地理位置提供定制的信息。说实话&#xff1a;其实Geolocation 就是用来获取到当前设备的经纬度&#xff08;位置&#xff09;…

Zookeeper ---- Zookeeper集群操作

Zookeeper ---- Zookeeper集群操作1. 集群操作1. 集群规划2. 选举机制&#xff08;面试重点&#xff09;3. ZK集群启动停止脚本2. 客户端命令操作1. 命令行语法2. znode节点数据信息3. 节点类型&#xff08;持久/短暂/有序号/无序号&#xff09;4. 监听器原理5. 节点删除与查看…

2022年NPDP新版教材知识集锦--【第三章节】(1)

【新产品开发概论】 产品创新是“风险与回报”的过程 随着新产品的累积成本增加&#xff0c;产品的不确定性降低。成功率在很大程度上取决于企业采用的新产品开发实践和流程的质量。 【决策基本框架】 ⚫识别问题或机会 ⚫收集信息(信息来源&#xff1a;内部、外部、内外部…

iOS开发之Undefined symbol:_OBJC_CLASS_$_****

更新了Xcode14.0.1以后&#xff0c;项目突然曝出了此问题Undefined symbol:_OBJC_CLASS_$_****&#xff0c;因此记录一下&#xff0c;解决此问题的步骤&#xff1a; 第一步&#xff1a;首先在Build Phases中找到 Compile Sources&#xff0c;查看是否有对应的***.m文件&#x…

查找算法【二叉查找树】 - 二叉查找树的插入

查找算法【二叉查找树】 - 二叉查找树的插入 因为二叉查找树的中序遍历存在有序性&#xff0c;所以首先要查找待插入关键字的插入位置&#xff0c;当查找不成功时&#xff0c;再将待插入关键字作为新的叶子节点成为最后一个查找节点的左孩子或右孩子。 【算法步骤】 ① 若二…

vim编辑器使用和vim一键配置

1.vim的三种模式 开始之前&#xff0c;先简单说&#xff0c;vim并不是只有这三种模式。总的来说vim大概有12种模式&#xff0c;不同的版本可能也有一些具体的区别。今天我们先介绍三种常用的模式。 先用一张图来大概介绍三种模式之间的转换 命令模式&#xff08;Normal mod…

强化学习算法实践(一)——策略梯度算法

文章目录Reference1. REINFORCE1.1 Basic1.2 Code2. Improvement Tips2.1 Assign Suitable Credit2.2 Add a Baseline2.3 Advantage Function3. Actor-Critic(A2C)3.1 Basic3.2 Code策略梯度是一种基于策略的算法&#xff0c;相比于DQN一类的基于价值的算法&#xff0c;它会直接…

C语言分支与循环--循环篇(图片,动画演示),彻底搞定C语言循环

前言 &#x1f47b;作者&#xff1a;龟龟不断向前 &#x1f47b;简介&#xff1a;宁愿做一只不停跑的慢乌龟&#xff0c;也不想当一只三分钟热度的兔子。 &#x1f47b;专栏&#xff1a;C初阶知识点 &#x1f47b;工具分享&#xff1a; 刷题&#xff1a; 牛客网 leetcode笔记软…

jupyter怎么换环境?

1.为什么要换环境而不用使用默认环境&#xff1f; 在这之前我只知道&#xff0c;要pip安装很多环境包&#xff0c;来在程序中调用使用&#xff0c;但是在不同的项目中&#xff0c;环境总是相互矛盾&#xff0c;总会出现诸多版本问题。所以需要每个项目对应一个环境。conda默认…

2022第二届中国高校大数据竞赛A题(实时更新)

题目 制造业是国民经济的主体&#xff0c;近十年来&#xff0c;嫦娥探月、祝融探火、北斗组网&#xff0c;一大批重大标志性创新成果引领中国制造业不断攀上新高度。作为制造业的核心&#xff0c;机械设备在工业生产的各个环节都扮演着不可或缺的重要角色。但是&#xff0c;在…

【FTP工具】FileZila安装以及使用详解

一、FTP概念 安装FTP主要是为了传输文件&#xff0c;FTP是持久的&#xff0c;只有一次认证过程&#xff0c;传输多个文件都是使用同一个连接。因为FTP就是为远程文件交互而设计的&#xff0c;有些时候只是为了单纯做一个文件传输&#xff0c;往往搭建FTP服务更省时和节约成本。…

【每日刷题】之【Z字形变换】

✨✨hello&#xff0c;愿意点进来的小伙伴们&#xff0c;你们好呐&#xff01; &#x1f43b;&#x1f43b;系列专栏&#xff1a;【力扣刷题篇】 &#x1f432;&#x1f432;本篇内容&#xff1a; 每日刷题 &#x1f42f;&#x1f42f;作者简介:一名现大二的三非编程小白&#…

BI设计上篇 - 像设计师一样思考

形式服从功能。这句产品设计的箴言也适用于数据可视化。就数据可视化的形式和功能而言&#xff0c;我们首先考虑的是我们希望受众能用数据做什么&#xff08;功能&#xff09;&#xff0c;然后才是用可视化&#xff08;形式&#xff09;来简化这个过程。在本文中&#xff0c;我…

总结flutter玩转之-安卓view 承载flutter 的页面

1.假设你已经熟悉flutter 开发熟悉dart 语言 android 原生开发技能 一、在安卓原生项目添加代码 1.创建示例布局 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"…

【Linux修炼】6.gcc/g++及Makefile【工具篇】

每一个不曾起舞的日子&#xff0c;都是对生命的辜负。 Linux-gcc/g及Makefile本节目标程序的翻译过程1.程序的翻译过程2. 理解选项的含义3. 动态链接和静态链接Linux项目自动化构建工具-make/Makefile1. 背景2. “见见猪跑”3. makefile原理及语法3.1 Makefile原理3.2 Makefile…

pytorch初学笔记(二):TensorBoard之add_scale()的使用

目录 一、SummaryWriter类的介绍 1. 定义 2. SummaryWriter初始化 2.1 初始化 2.2 帮助文档给出的使用范例 2.3 常用方法 二、add_scale()方法介绍 1. 常用参数介绍 2. 绘制图形 2.1 安装tensorboard 2.2 对应代码 2.3 打开tensorboard窗口 2.3 注意事项 三、a…

kubernetes学习笔记

参考 Cloudman 老师的《每天5分钟玩转Kubernetes》&#xff0c;记录如何使用 Kubernetes &#xff0c;由于版本变化&#xff0c;一些命令也有相应的变化&#xff0c;本文对应 Kubernetes 1.25.3 5. 运行应用 010.123 用 Deployment 运行应用 原文使用kubectl run命令&#x…

JS(Dom对象的属性和方法)第十六课

Dom对象的属性和方法自定义的熟悉操作上面是今天博客要讲述的内容 一个案例回顾上次课讲的内容 下面是Html中的元素布局结构 <div>我是div审查元素<p>我是p标记的元素</p><span>我是span的元素信息</span></div><div class"one&…