vmp简单实现以及快手sig3源码解析
一、什么是vmp?
vmp全称虚拟机保护(Virtual Machine Protection),是一种用于软件保护和防逆向工程的技术,主要通过使用虚拟机来执行代码,以保护源代码、降低代码可读性、提升逆向/抄袭难度。
二、基础vm
这里只结合代码来看代码混淆层面的vm实现,不深入讲语言应用层面的复杂虚拟机(jvm、Dalvik等)。
原代码:
var a = 15;
var b = 18;
var c = a + b;
console.log(c);
栈式虚拟机
栈式虚拟机是一种使用栈(stack)来管理操作数(operand)和中间结果(ir)的虚拟机架构。所有的操作都基于栈进行,指令通过栈来传递操作数。
栈式虚拟机的设计使其指令集非常简洁,因为所有操作都隐含地使用栈顶元素作为操作数。
使用栈来存储和操作数据。
指令通过栈来传递操作数。
优点是指令集简洁,容易实现。
缺点是指令间的数据传递需要通过栈,效率可能较低。
使用栈式虚拟机实现原代码如下:
function stack_vmp_main(op_list){
var start_ip = 0;
var ret;
var stack = [];
for (;!ret;){
op = op_list[start_ip++];
ret = run_zhiling(op, op_list, stack);
}
function run_zhiling(op, op_list, stack){
switch(op){
case 0:
stack.push(op_list[start_ip++])
break
case 1:
stack.push(stack.pop() + stack.pop())
break
case 2:
console.log(stack.pop())
break
case 3:
return true
}
}
}
stack_vmp_main([0,15,0,18,1,2,3]);
可以看到,栈式虚拟机的指令集简单易懂,很容易看出vm是如何实现以及各指令的作用。
寄存器式虚拟机
寄存器式虚拟机通过寄存器(register)来管理操作数和中间结果。寄存器是一组高速存储单元,操作数在这些寄存器之间传递和操作,避免了频繁的内存访问。与栈式虚拟机相比,寄存器式虚拟机的指令集更为复杂,因为每条指令都需要指定操作数所在的寄存器位置。
寄存器式虚拟机的优缺点:
优点:寄存器之间的操作通常比栈操作更高效,减少了指令的数量。
缺点:指令集更复杂,实现难度较大。
使用寄存器式虚拟机实现原代码如下:
function register_vmp_main(op_list){
var start_ip = 0;
var ret;
var linshi;
for (;!ret;){
op = op_list[start_ip++];
ret = run_zhiling(op, op_list);
}
function run_zhiling(op, op_list){
switch(op){
case 0:
linshi = new Array(op_list[start_ip++])
break
case 1:
linshi[op_list[start_ip++]] = void 0;
break
case 2:
linshi[op_list[start_ip++]] = op_list[start_ip++];
break
case 3:
linshi[op_list[start_ip++]] = linshi[op_list[start_ip++]] + linshi[op_list[start_ip++]];
break;
case 4:
console.log(linshi[op_list[start_ip++]]);
break;
case 5:
return true
}
}
}
register_vmp_main([0,255,1,0,1,1,1,2,2,0,15,2,1,18,3,2,0,1,4,2,5])
由于js中array长度可变以及变量即插即用的特性,指令0(初始化寄存器)和指令1(初始化变量)大部分情况下可以省去,但是通常不会简化掉这些指令,因为批量初始化可以更方便后续的寻址引用。
vm扩展
以上两种虚拟机基本为所有vm的基础,衍生出的堆式虚拟机、中间语言虚拟机、栈帧式虚拟机等复杂的虚拟机都是将它们改进/结合而来。
这里拿中间语言式虚拟机举例:
中间语言式虚拟机
顾名思义,使用一种语言运行另一种语言的code即为中间语言(Intermediate Language)式虚拟机,比如wasm。它具有平台独立性和跨语言互操作性,使得编译后的代码可以在多个平台上运行。同时,由于执行过程中加入了额外的抽象语言,性能方面也会受到较大的损耗。
我们反混淆中常用到的AST便可以理解为中间语言,babel的generate就是这门中间语言的反汇编,而parser.parse则可以理解为增加了一层中间语言vmp的混淆
使用栈式虚拟机来实现IL虚拟机实现原代码如下:
// ast版
function il_vmp_main(ast_tree) {
function get_op_list(node, il_zhiling) {
if (!il_zhiling) {
il_zhiling = []
}
switch (node.type) {
case 'Program':
node.body.forEach(statement => get_op_list(statement, il_zhiling));
break;
case 'VariableDeclaration':
node.declarations.forEach(declarator => get_op_list(declarator, il_zhiling));
break;
case 'VariableDeclarator':
il_zhiling.push({ op: 'DECLARE', name: node.id.name });
get_op_list(node.init, il_zhiling);
il_zhiling.push({ op: 'STORE', name: node.id.name });
break;
case 'Literal':
il_zhiling.push({ op: 'PUSH', value: node.value });
break;
case 'Identifier':
il_zhiling.push({ op: 'LOAD', name: node.name });
break;
case 'BinaryExpression':
get_op_list(node.left, il_zhiling);
get_op_list(node.right, il_zhiling);
il_zhiling.push({ op: 'ADD' });
break;
case 'ExpressionStatement':
get_op_list(node.expression, il_zhiling);
break;
case 'CallExpression':
node.arguments.forEach(arg => get_op_list(arg, il_zhiling));
il_zhiling.push({ op: 'CALL', callee: node.callee.property.name });
break;
default:
throw new Error(`Unsupported node type: ${node.type}`);
}
return il_zhiling;
}
function run_zhiling(il_zhiling) {
const stack = [];
const variables = {};
for (let ip = 0; ip < il_zhiling.length; ip++) {
const instr = il_zhiling[ip];
switch (instr.op) {
case 'DECLARE':
variables[instr.name] = 0;
break;
case 'PUSH':
stack.push(instr.value);
break;
case 'STORE':
variables[instr.name] = stack.pop();
break;
case 'LOAD':
stack.push(variables[instr.name]);
break;
case 'ADD':
stack.push(stack.pop() + stack.pop());
break;
case 'CALL':
if (instr.callee === 'log') {
console.log(stack.pop());
} else {
throw new Error(`Unsupported function call: ${instr.callee}`);
}
break;
default:
throw new Error(`Unsupported operation: ${instr.op}`);
}
}
}
il_zhiling_list = get_op_list(ast_tree);
run_zhiling(il_zhiling_list);
}
ast = {
"type": "Program",
"body": [
{
"type": "VariableDeclaration",
"declarations": [
{
"type": "VariableDeclarator",
"id": { "type": "Identifier", "name": "a" },
"init": { "type": "Literal", "value": 15, "raw": "15" }
}
],
"kind": "var"
},
{
"type": "VariableDeclaration",
"declarations": [
{
"type": "VariableDeclarator",
"id": { "type": "Identifier", "name": "b" },
"init": { "type": "Literal", "value": 18, "raw": "18" }
}
],
"kind": "var"
},
{
"type": "VariableDeclaration",
"declarations": [
{
"type": "VariableDeclarator",
"id": { "type": "Identifier", "name": "c" },
"init": {
"type": "BinaryExpression",
"operator": "+",
"left": { "type": "Identifier", "name": "a" },
"right": { "type": "Identifier", "name": "b" }
}
}
],
"kind": "var"
},
{
"type": "ExpressionStatement",
"expression": {
"type": "CallExpression",
"callee": { "type": "MemberExpression", "object": { "type": "Identifier", "name": "console" }, "property": { "type": "Identifier", "name": "log" } },
"arguments": [{ "type": "Identifier", "name": "c" }]
}
}
]
}
il_vmp_main(ast);
将get_op_list的结果单独提取出来,便可以看做一套自己的汇编语言:
// 自定义版
il_list = [
{
op: "DECLARE",
name: "a",
},
{
op: "PUSH",
value: 15,
},
{
op: "STORE",
name: "a",
},
{
op: "DECLARE",
name: "b",
},
{
op: "PUSH",
value: 18,
},
{
op: "STORE",
name: "b",
},
{
op: "DECLARE",
name: "c",
},
{
op: "LOAD",
name: "a",
},
{
op: "LOAD",
name: "b",
},
{
op: "ADD",
},
{
op: "STORE",
name: "c",
},
{
op: "LOAD",
name: "c",
},
{
op: "CALL",
callee: "log",
},
]
function il2_vmp_main(il_zhiling){
const stack = [];
const variables = {};
for (let ip = 0; ip < il_zhiling.length; ip++) {
const instr = il_zhiling[ip];
switch (instr.op) {
case 'DECLARE':
variables[instr.name] = 0;
break;
case 'PUSH':
stack.push(instr.value);
break;
case 'STORE':
variables[instr.name] = stack.pop();
break;
case 'LOAD':
stack.push(variables[instr.name]);
break;
case 'ADD':
stack.push(stack.pop() + stack.pop());
break;
case 'CALL':
if (instr.callee === 'log') {
console.log(stack.pop());
} else {
throw new Error(`Unsupported function call: ${instr.callee}`);
}
break;
default:
throw new Error(`Unsupported operation: ${instr.op}`);
}
}
}
il2_vmp_main(il_list)
IL虚拟机实例demo:http://43.153.41.76:8602/
(需要注意的是,拿寄存器式虚拟机也可实现IL的运行,并不局限于栈式虚拟机)
三、几个vmp分析
腾讯tdc
略,栈式虚拟机的经典。
快手sig3
快手创作者平台和h5部分接口sig3签名,js如下:
https://s2-111422.kwimgs.com/kos/nlav111422/h5-share/assets/index-CkeXlguR.js
vmp核心代码
!function(e, n) {
"object" === ("undefined" == typeof exports ? "undefined" : Rr(exports)) && "object" === ("undefined" == typeof module ? "undefined" : Rr(module)) ? module.exports = n() : "function" == typeof define && define.amd ? define([], n) : "object" === ("undefined" == typeof exports ? "undefined" : Rr(exports)) ? exports.Jose = n() : e.Jose = n()
}(window, (function() {
return t = {},
e.m = n = [function(e, n) {
(function() {
var e = Object.create
, t = Array.isArray;
n.prototypeOf = function(e) {
return e.constructor.prototype
}
,
n.create = e,
n.hasProp = function(e, n) {
return Object.prototype.hasOwnProperty.call(e, n)
}
,
n.isArray = t,
n.defProp = function(e, n, t) {
return Object.defineProperty(e, n, t)
}
}
).call(this)
}
, function(e, n) {
(function() {
function e(e) {
this.elements = e,
this.index = 0
}
e.prototype.next = function() {
if (this.index >= this.elements.length)
throw new Error("array over");
return this.elements[this.index++]
}
,
n.ArrayIterator = e
}
).call(this)
}
, function(e, n, t) {
function o(e) {
return (o = "function" == typeof Symbol && "symbol" === Rr(Symbol.iterator) ? function(e) {
return void 0 === e ? "undefined" : Rr(e)
}
: function(e) {
return e && "function" == typeof Symbol && e.constructor === Symbol && e !== Symbol.prototype ? "symbol" : void 0 === e ? "undefined" : Rr(e)
}
)(e)
}
(function() {
var e = {}.hasOwnProperty
, a = t(0).isArray
, r = (i.prototype.run = function() {
for (var e = this.callStack[this.depth], n = e.error; 0 <= this.depth && e && !this.paused; )
if ((e = n ? this.unwind(n) : e).run(),
(n = e.error)instanceof Error && this.injectStackTrace(n),
e.done()) {
if (e.guards.length) {
var t = e.guards.pop();
if (t.finalizer) {
e.ip = t.finalizer,
e.exitIp = t.end,
e.paused = !1;
continue
}
}
!e.construct || "object" !== (t = o(this.rv)) && "function" !== t && (this.rv = e.scope.get(0)),
(e = this.popFrame()) && !n && (e.evalStack.push(this.rv),
this.rv = void 0)
} else
n = (e = this.callStack[this.depth]).error;
if (this.timedOut() && (n = new Error(this),
this.injectStackTrace(n)),
n)
throw n
}
,
i.prototype.unwind = function(e) {
for (var n = this.callStack[this.depth]; n; ) {
n.error = e;
var t = n.ip - 1
, o = n.guards.length;
if (o && (o = n.guards[o - 1]).start <= t && t <= o.end) {
if (null !== o.handler)
if (t <= o.handler)
n.evalStack.push(e),
n.error = null,
n.ip = o.handler;
else {
if (!(o.finalizer && n.ip <= o.finalizer)) {
n = this.popFrame();
continue
}
n.ip = o.finalizer
}
else
n.ip = o.finalizer;
return n.paused = !1,
n
}
n = this.popFrame()
}
throw e
}
,
i.prototype.injectStackTrace = function(e) {
var n, t, o = void 0, r = void 0, i = void 0, s = void 0, l = void 0, c = [], u = 0;
for (this.depth > this.maxTraceDepth && (u = this.depth - this.maxTraceDepth),
r = i = n = this.depth,
t = u; n <= t ? i <= t : t <= i; r = n <= t ? ++i : --i)
"<anonymous>" === (s = (o = this.callStack[r]).script.name) && o.fname && (s = o.fname),
c.push({
at: {
name: s,
filename: o.script.filename
},
line: o.line,
column: o.column
});
if (e.trace) {
for (l = e.trace; a(l[l.length - 1]); )
l = l[l.length - 1];
l.push(c)
} else
e.trace = c;
return e.stack = e.toString()
}
,
i.prototype.pushFrame = function(e, n, t, o, a, r, i) {
if (null == r && (r = "<anonymous>"),
null == i && (i = !1),
this.checkCallStack())
return (t = new p(t,e.localNames,e.localLength)).set(0, n),
i = new s(this,e,t,this.realm,r,i),
a && i.evalStack.push(a),
o && i.evalStack.push(o),
this.callStack[++this.depth] = i
}
,
i.prototype.checkCallStack = function() {
return this.depth !== this.maxDepth || (this.callStack[this.depth].error = new Error("maximum call stack size exceeded"),
this.pause(),
!1)
}
,
i.prototype.popFrame = function() {
var e = this.callStack[--this.depth];
return e && (e.paused = !1),
e
}
,
i.prototype.pause = function() {
return this.paused = this.callStack[this.depth].paused = !0
}
,
i.prototype.resume = function(e) {
if (this.timeout = null != e ? e : -1,
this.paused = !1,
this.callStack[this.depth].paused = !1,
this.run(),
!this.paused)
return this.rexp
}
,
i.prototype.timedOut = function() {
return 0 === this.timeout
}
,
i.prototype.send = function(e) {
return this.callStack[this.depth].evalStack.push(e)
}
,
i.prototype.done = function() {
return -1 === this.depth
}
,
i);
function i(e, n) {
this.realm = e,
this.timeout = null != n ? n : -1,
this.maxDepth = 1e3,
this.maxTraceDepth = 50,
this.callStack = [],
this.evalStack = null,
this.depth = -1,
this.yielded = this.rv = void 0,
this.paused = !1,
this.r1 = this.r2 = this.r3 = null,
this.rexp = null
}
var s = (l.prototype.run = function() {
for (var e = this.script.instructions; this.ip !== this.exitIp && !this.paused && 0 !== this.fiber.timeout; )
this.fiber.timeout--,
e[this.ip++].exec(this, this.evalStack, this.scope, this.realm);
0 === this.fiber.timeout && (this.paused = this.fiber.paused = !0);
var n = this.evalStack.len();
if (!this.paused && !this.error && 0 !== n)
throw new Error("Evaluation stack has " + n + " items after execution")
}
,
l.prototype.done = function() {
return this.ip === this.exitIp
}
,
l.prototype.setLine = function(e) {
this.line = e
}
,
l.prototype.setColumn = function(e) {
this.column = e
}
,
l);
function l(e, n, t, o, a, r) {
this.fiber = e,
this.script = n,
this.scope = t,
this.realm = o,
this.fname = a,
this.construct = null != r && r,
this.evalStack = new c(this.script.stackSize,this.fiber),
this.ip = 0,
this.exitIp = this.script.instructions.length,
this.paused = !1,
this.finalizer = null,
this.guards = [],
this.rv = void 0,
this.line = this.column = -1
}
var c = (u.prototype.push = function(e) {
if (this.idx === this.array.length)
throw new Error("maximum evaluation stack size exceeded");
return this.array[this.idx++] = e
}
,
u.prototype.pop = function() {
return this.array[--this.idx]
}
,
u.prototype.top = function() {
return this.array[this.idx - 1]
}
,
u.prototype.len = function() {
return this.idx
}
,
u.prototype.clear = function() {
return this.idx = 0
}
,
u);
function u(e, n) {
this.fiber = n,
this.array = new Array(e),
this.idx = 0
}
var p = (d.prototype.get = function(e) {
return this.data[e]
}
,
d.prototype.set = function(e, n) {
return this.data[e] = n
}
,
d.prototype.name = function(n) {
var t = void 0
, o = this.names;
for (t in o)
if (e.call(o, t) && o[t] === n)
return parseInt(t);
return -1
}
,
d);
function d(e, n, t) {
this.parent = e,
this.names = n,
this.data = new Array(t)
}
var h = (f.prototype.get = function(e) {
return this.object[e]
}
,
f.prototype.set = function(e, n) {
return this.object[e] = n
}
,
f.prototype.has = function(e) {
return e in this.object
}
,
f);
function f(e, n) {
this.parent = e,
this.object = n
}
n.Fiber = r,
n.Scope = p,
n.WithScope = h
}
).call(this)
}
, function(e, n, t) {
(t = new (t(4))).eval('["<script>",0,[[76,1]č77,5572Ĕ[2ēĕėĠď5ċ,falseĝ24Ē,nullĝ16]ĝĀĂĄĆĈĊāanonymousĉčĤ,28ħĩīĝ3ČČ4Ĝčģ7ĥ2ėĨĪĬčŕĦ4ģśŝđŠœţŖ,40ĶĝŜŎĥūŢ[ŤČ39ŲĕŝįŷŔŮ38žō23őšƃĦ37ƇŴ22ƋŬŹƄ5Ƒŝ1ƕŸź,3ŧųŝČƂŭƎűŚƣĒ9ƝƍČ2ŽƪſĒŐƦƗĦŏƚĒşŒƞŮŞƻķƮƧưĸƳō1ŶƾƯŵǂƁnjDžŎ4ǂƊƷƟƉǂƔǗǀƢƴ1ƜǜƹƩ[ŨĒƥǑƸČ1ƲǥƫƭǢǫƆLjŴƶǩƟ1ƐǴĥƽƌǒķƻŪǷŮNJƻNjǾǪĒǔǻůDŽȉ13ƻǖȃĦ1řǮƴǛȔǫǞljȎǸǤǦǨȈƟǭģ2ȣƖ7ŖĭƭǫĭLJȉȑŚȱĐĒųėǙčƱĦǭȫ,"$encode"ȸĒȳĞȮƠĶŧȡɌ1ȋĞǺǥȵė3ȱȼŻƙĕČɁɃĄyćɉġǎȻɎɓɑĶɓɕǁȴɊ4ǭɝůǤȿɁɇɤɦɊƅȭƎɐĶɒĶɰɗȀɨĚųƜǤƟɕʈďėȫʋȷǒɟɘɊ8ɸƜȗƟȱʐĖǧɗȿǬ5609ǹ7ɌʡǠdzďČ-NJɴ54Ű5śĢŕųʱɛ6ʩ335ȾĢŦʼ,9ŏ89ęĐɊNJśŻ26ʿˌ9ɸĢ6ˑ,ʲŦǹ6ȫʨˏʫˇȨ4ʵĚƏȗʭ8ɕȿʲ99ˋŞɴśįʯʭ˲ˇ10ʶ0Ȗ˔ʬȹˢɠĒƓŕǠ0ʵɊƓɸČ96ˋʧ88˫ȹʻ̅ɔ˿̑9ˁʣȹˆ̙ŕ85ʚ˃˄ŵ˫ǫ3ƱƏ8˂̖Ŏ6ʬǫʿŘʥɱʑŎ7ˮǫ06Ʊ64˭ˮ˷ųįʝŮʇəŎ̝˻ȱƟʯʠȹƓ̽ĒǠ̳5Į0˸͔˂˻ˋ9ʶ̡̼̺͕ȵŻ˽̝Ɖ47ʹŎ2ʊ̅żğ0ʨ˩̌˓˸̏˚˲̳ͮ7ͻĒ5͜9ȫ˱̂Ͱˋ˥˧ɛ˂̼͝Ŏŕ̎Ŏ8ȫĐ̬ğ̌ơ˛ɛĮƅ˼ʚΜƓˇơ̊˲ŰͯƉ̬ˇʧěͱŞΒ̪ͬȊͺ8ǬΗΜ5̴Ƭͱ0ƅγɛ͖ğ̀π̿̕ΜŜ˥˚̓̔˼ΊƉ8ͨƠĮ̕Ɠ̥˘Γ·Φ̯μ˗Ϊ̌ŰŰƓ͕Ėˮ̠Ǭύ43ͭψϣƱή˽ʚĐƺɨΠȾČĖ0ͱ˃̯ϣɴ˻Įʩ΅Ȗ̱Įʧ˻ę΅θʿЉͭ˛Ǭ̐̿ɴϔϣ̕˥ęŘȨ̔Б͎̅ŏğ̯ϮЃϹ΅υˌƱ̐ʚγʸʗȿ̬ϑȐˠΫ͚ϕˁɛĚ1ˋзƏΦ̥˧ŏͮз̓˻Ȑˉ˕ϒęˁ̕Ŧˋбȹʦ˔̳πȨѓŵˇḚ̇˱Ȗ̥̌Ȗ͢Ŝʫěѣ˱˻ż˚Ϙʩ̌˚ΕķˌнƏͶѲΛ̙˲ї˼ʸѲέТʪϾ͙ϛ˓ϮʦˌʧрϹ6̋Тʫϵ˃ѻͦ˔бưωŕĮǠѲˎͳͱ·̣ѹҏκͳϯĚ͂ĖΫʿюʸʧҐθ̟̻̄ʰƠʧ0̰ʚϪ̻ȨˇŰ͢м˗̨Şơ˥ŜŘˁʶ̼̌˛ϮϾŞʫҽŞҀ̅΅̶ϔ͓̻˚ή˃̿̊ʦӍͮˇ̔ż·ΗҴβ˛ˌθżмӍѱ̢ƓϘФ̌ʚεNJѸϾ̿ϒӮ˻̼ѩ7Ӆѐ˻ˌę̀ϧӷ͟ТϾŦϵȅϹ˭ϕϧџ˽͚ӷͲҷƉѯ͚ŘӔϔĮŏϮҫԡԄӈʦӓнӪˋΕ̬˽ҺɔԩϹ˗Ξ̬͚ͫ˺ĕį͂ǍΥɲʉнƆĺāăąćŋ"rĊĎȨ,truŸȿǤɶȧ͐ǀĶϕȧɎՙǍɓȵđģŐϛԱʀưɾнʀʜɌĮİ"jɧȉȗӛˁ՞ƹɾϳɪİȐĭįƜ"dմʎ՜ɾءէŰխ,ɗ˓ʃɮˇ"slicɈĭĥɡ֕֗֙ʖևɨɛչŗɾսČћ˂ɵƭƜɔրŎɀpօŮʟ͌˪թ,ַʓսʜɰցɀDմʡɛʯȼ֮կ׀փִť̺֡ƅѴɾѝֽ֎Ȱ֑Śν֖֔֘մͱĦך֞֩ׄˌֹҽż֏Ɏ֪Сɍվֱֿ"ֳǍֶɳϊĕʌǍ͋ɳԒҷϛŦկɎɜ͌ёˇՒՔչʜ׆͈ɀbעוՂ̺ӐʔʍŮ͒ɛʔ֤,ʯɌ҉ǒؘɳ4ɜ֭ůֹ؞ĝؠȉآɨ˧ȵʜɳґƜկɜĝˠ̆ȝʡ͖ͭ˼ؖȽפė̓ذɏخ˭֍ضĭظʺɓɳ̐˻ҥȏȡ͌ʸӹɊ΅˫صׇْ٘نǥɭטʅזčثտŚʆقĘϬ֨ˈ٘ҖȿƷʡʸתİϸĞ؍"؏بŔتɌ͑٪μȕϛμҙȎٳӇהٷհƔٺםɎة٥ٿؗځ˧ֹٵČڒ[ثڀؒٳˠŔƊ"DatɈċĭƊڅԙţڣڥڧĊȡʄ̅ײarīםĥւpڷڹ٘ˤ̙ͶǤؤۀʣȩՕėęئڌٹٻ٭ڛڝڕڟۊҧďƜɰڑٽړǍح̺ʧśƜʗɶےڔĦ۟ʡѯټɨ˚إվȧgؐҞەֺĮֹ۵ښۜڜۧۼ۶ј۬۠ڌئ˼ְւsؐ۩ė͂ȗۥɊ̳ڃŻחǥΊ͙ʔɜڻıijĵؒ˔̲ܗӖȏն͌́۹̱ҐۚʁŚڴ۠ӢؑĞܛIJĴȮĹčĝܵlܜĴܾܽ"nŀaŀtŀڨ"oŀvŀfŀcŀuŀՍĺȐŵʱʜĔˋč"ŀʵ˧ŀstڷtupRłdomݐňn݇ɀ˿ۃؿŀۃۃݣuݑɀerݕܺکݞļՉĿɀ܊ŌՐ؇ՕȬ٭ՠǒբųդܑ̼ۗނȉʏܦԼۻِٟ۪ה̘ٸձkؐʗӛΈ֓lɃgthڐĦۤ͌ͮѥتҽΘֹޱ״٪ʫ˛ـϼˁژɊʫڇ"ުnެޮ٤̺ͤ˻ĝ̥ظŐΣɨŜ֬ĦҴѨߋȻֹ̀ȱμ߃Կ٭ɗߢߖڡТęߑ̱ŜܓܲʡŜʏ١ܖ٣ȻߖۅߥĶնʗͥƟʇĶަظđϯࠅֺ̨ĖۯČہޜߚӤ٭ߴܕ٧ǥ٩۶Ԃק߃̤ى۱ձxմǔĝܻܝ݀ࠧՌŀ݃ɀ݅ɀݲ"֟[Ĕϯށ࠲ޗՇĽՊŀ۳މČދ֊۹ߌƟޑĕޓɨθɫʙ܇ޠޤǍޙʙٰލȉަ̯͌νֺ٪ϟߠʙҎҷ߆ޫޭޯ֥ߝߑʯ̑Ęҽ̤ࠌࡇسɶɰࡘ˃Лʗڭޜʗ؟ۿĘޜʟ߾تģʞƇģܠՁ[ܠثʡϔћԢࡷظǤعӝčܠࠏҠࡺت࡛ࡗʙθߏ٭ࡻپǍࢡࡇࠝࢥࢢۇŵࡸ͉ް٪˗یࢲࡇޛٞѢȻݏتܹ࠶[ܼࠧࣂࠩɀࠫ"࠭"݇ࠤ̻࠵ĔǤ࠸ޅՋݏ࠽ՑՓތޗࡂƄפࡆ̺ˉʬǒࡒɨˉߘܔࣥ߁̅ǤܰࢌكϛѶֹΊˌνʐߒ࢙ȹ͌ЕؕࠈٷʡҌ؛Ɋ·ڇӛ̐ܫࣨǥܮɹtoSՒi߈ںձऌऎąऑࢧࣣࢍҽ̝˸رङ۶ѽࠛ٥ࢿࠥܿࣂࣄՍࣆմĔǹݞݷݷ0ब࠷ބľՋքࣕ࣫ࡁࡨސࣝʕ̺˼ͱЄΒؿࡻڣकऐ࠼ڳ֒ڵfrݭChڷCɆ࠱מւॏ॑॓rॕɇࡦٟࡼա٪ϑϕࡣ߈ࡥࣲߌʭԘӀت͌˼ͭ˥घޘ।̿ۤɎҽ˼ߩش؝९ˏӡڢɀMڦޮޗࡌ߶ڵ֘ilऒւঋࢨॶ࢝ޖ࡛ɨ˼ՖƑĢͷ߂ঘʨڙࡾčࣷࢌŐњˏঙ͇ޗʭॻঠुॱŚߵࠖ֯߸।ʮࡀءঝ͗ҿۑপࢋٞʯদǬॺNJࢵঘNJεߤڜћǠ߫ীৌԛȿɕڗৌࡡɶɓऊɡcड़फ़eA࣋Ȼܛ"ৡ॔ॖ׃Ģķ˛۸٥ॅʪরমԵҷКৼ͖߿Ίʮ՝ॴমঢ়ࠕי৪ढ़৬০ܳձৣ৭প˗͏تৄͯȖࠐˏОήਁਞۺܐঘğνਡुğڇȗࢎ৯ਉܭ्ࡢɀਵɇਔਥ٬ҷʯчথਚͬ৶ĢԝਠتƉࣧॾਥͥৗੈਆࢎईਮ̆Җउਲ਼ɹਹਏक़ਸৢਸ਼ߑਚȐइੌڊਝৌռࢁߌۺঈশ࠘ʘ੫੦͒ࢃ٥ࢅ۔Șǥࠄ࢙đόƵਃʨੋʇڜߙࢇࢌđߧઍƬॺͱי߇߉ॠيਥߟהॅ҈८٥ਂਞ˔ࢤڜɕȥ।ŏٮਥ৽ਾਥচժયڇ҂ਪوڮঃঅڲਊ֓powऒڎઽિॿਥॽજĖॳ٥ּ࢞ૅٗોડ׆੮ɯĭ߹ुԹ֍ॅոતˏ̬੦̬ਅঘΚĞૡۺˁસࡥইয়ɀflooހਐख़৮ɋਜৃૡ͜ӌ૨˿ߜҺણଅਪѬ٭૬٨।ϯণ̨ϻ੧৻ʭ˂ӏƱɴˠƱࢰૡ։છଥؾߐ૨ড়ૡżଋॺˁॸĦଐ٠ࠗଔ۶еੋȱࠣ࠵नࠦऩ݄݆݈ࠪŀɀݍ࣌ʮ࣎ऴՈशŀֳहࣗޜޏȲפȯގࣛڟࣞଝচįࢠ।Ř०ક३٭ઘȏগुʶǍষʭʶ߯ୱ୳৻ߡࡪŐЎˏ˧࡛࢈Ћގؤࡉİৄ֎ਚͭੋ୳࢝ॺؽ४ऽ૫ࠒୖஆʿଈ੯ܮୱ̹ӛɔਈ՟ަઇࠀȄઌஂઁؚઁ୭̔୰ઌ୳ਖஅˉੇথNJଘ΅ஏʸৱପु΅ণঘ΅ଳ֮ɵݮˏٴ۹ூȿɗଌʭаଈࣾǫ߿ॺԟ॰͚ஈ֮،ձૃĢچࡡʤଽ࣪௯΄Ͼ௲ொٝଭਲ٢ଓসʵࢮŘ̐͢ěצொثூͥɶަ߷௺[ࡹੱହੳ୭ఎŚநઉઋƇ࢚ʗܠɔॅʦεϛNJரࡳଡ଼ࠍ।ҋણॼఱࠁఴঔெ̼णఘڞఝЁͳࢣࠓలપౄ௰ஷҷலొȄٔϝӗଳࡧూȄŧ॰ʧ͖ౠౝȕܥˏ˚˛ҴķҶహ౦̫।χ୕Ǹவ˙ূ౩৲৹ɕŐঘ̳ȕਃ۹మ͂ࢵ֮֏AࠢಅॲގಈЧୖਚҐࢺु͂ௌŎࡎƠঃಏ౩࣭ಢܫʜଽಅ࢘ఠಚࡶࢬۓȕʭଢ૪્ࢹɜy૾ķૉଏ౩৸ɶ౬̑ॅˠಜįैಡǿ܌Ē̑ಙǸࡄಚణ̆͢ಇ୰౩ࢸɎଘˡ۹ௗਃȫεఊଡତǿౖঘͮ੧દͮઅ۞।ě߯՚ઊ̹౬۹ਿ೧੩ৗଠఌଣ߬̀ণ࢈ఢழథLjࢊܠơॅ̼ଚమԁుʭŜஈళǹسഇఋଢటࡹഠࡕബഢاంਖ਼ఄସఆ్ƼѪ̙ˣಸॹ५ĢĖೲ೦഻ఉഈഩ೭ुĐࢮਚĐೲࠔఃউവɖటȿ̱ǹਰഽഠೡۨੑƵْധ೫ഊথൖԄΕޜൎളಳĢθюˏЏഞ॰̕ǭнȺ೬ഋঘӿేඁਣ൙ଶ൏ఛശண˭ӏ൳ଯട൰ଌۄਃԔӀൾൣఙൖ̯ϕॺХుடਲ਼൮।ϔ͖ϔരࡴ൳స՟ģൺϔଚ೪ഉപගಮҷඨԛ౯ජഴඤ̔ࢮ൶ࢫ൪ാƵ՟ਭඖ̅ඳെुПή൳ߕහലੰඊ॰ʩΕ౬˗ಃඑƬࠖॢঘІനൿˏ˗ڇෝଊ൭ੲணͣ۹ʏǿʏࠃదđࢍౘु̝߯थčୀधࠦࣅ݂ୄɀୈ"ݍݐݒŀiŀআ߆ݣ࠻ŀքୋޖࣀ࣏ĝ࣑फ؈ऻܬౄୖో౨ࡅी˹দɶൖ̐രɌ΅෬պ෦ॼв഼ุอଌੀఙදฆࣁୁ์ܿࠩୋƜย࠹ކ"಼ศࣘୗࡃिਚ˱ਬ෬ก˹൘վۤٹ݃̌ͶӹϒͶೲఀְڎথঈൕЉ˿߯ಃ֮ױఙ؟๊จܽୂୋƊ๒࣐व࠺ɀಎ๘୕ࣚฬईʠୟ̃ඏ৹ఓࡊϹҺٵफປ՝Ϋͪͦ˽ದ΄ຢฌߑദưћњণະ௪ຬࢻກմએାࣀຆࠨૹभຊ࣌ຌຎ"િຑสะດٟຖิ̃ెҷӪ͜ॽڍຣພʤγʨ໗ຸޢົޟޜϒؿΦߑ࣬ຄ๋࣌ฉ݁ແ୍̆๔Ջݮ़໊໎գ໐ŎȖऄӪȖෟޝȹȖڃມູ̌ȐࣵӅеຨʡਦ؊ຮ༒ນ༌ǧຯࢾຈށȖฤຍ๕MՎĞ࠾໋ຓ༁ೕʤༀֆڟా༷༼Ůࢩďທ༅ச༡ཆคා༘˟ຨϹǹ༊േຼํງชपฌࠬळ༬༮ໆ๕S༲ފ༵ห༸ीཀʠ༿՟ోགྷȶΫ୩πుഫ͔౮ຝͦğནϒਦు༘ਫଈࡹཔ༨བເୃཛୋįཞރའՋճছཧཁอեভȹఋ়ࣼ۶ଣͅޗഷ࡚́ࡑঽ́ࢮ१ખຨྙണ୲ྞஒආ༘Ө૪౾ͰҴΔӔ;ຨ֓ੜૺ৫ਏƟིɚͶɾͶѥٷ̃ྼԳଈׄҺν˦ஊٌં࿐ࠏఔڇę́ࡩֺًࣸࠂ֢͜ര֪໕ˇ˩ଌಫعపիமǥॵLj࢈ַɔৎęׄ࿘ɚ্ّർེƠாّਘի౯ငચଷਜ਼࿉৩ဘ૾ơדҷूȗܣಱף۶ơӲԜཏʥဆဌޛໟتǭܣׄȨГࣾɚཱུ௹ံଃ̙ਭ̨г˛֧ඛջ୶ǫ္ϖլಯƓ၃ဳջർȿ၄ྈͯΚ՝၊̬ޡ֢Ɖৎဣ၆֢н੦Ȧײʼnߊ১ȍၨsၪఝબ࿙Ԝ౻ငြဇਜʤ၀ၢိҶၼΒΝ֪߯͘ි٥၁̅ၕဤၗȖးႂ༆ုơ̹ၔၡੁ࿐ޜၦਗ਼ɡpၩऒڣ႟ၮմʐࢊၻࢀʤႚ࿙၍ႭνଽဴၗঁဿႂΨ႓̿၃႗่࿐༠ೢဖ႞Ⴀ֚ױႣၯႦշӼႹჀඈיယბ٪Ʊුර༽ઐַΠŮၞࡢ୧ၯɶɵཬܲၗͱרͱ༊ߦŞէƱ྾ջ൩ჩළ؞ैएऑႝॐm॒࿈ॗ২ग़ᄆလॠۦဨ˓ჸడྪઌࢊࡡࢊභׄ̈܃ɕࢊ໘ᄞҶȠ٪ˁࢋ૯"Eݿ૽ࣙګųĝܸྊྌวࣈݽେݔմ[নޖʲΖēĔ˲यໄཟŀׂྖࡕཫॣ༄ӋȾഷˁ̑სࢶླƠָڵყગోΡ႓ƅ߯ჳߓˈၗѮᅦྲྀ൚ɚʹ֍հւݓᄐᅗŰϕখঽϯɡᅠ܃ྱౌၗŦ଼ֈఙුׄΎಶɚ˧ೆჼϮࢅჿखोჁᄄज़ᄈယᄋᄇय़ుᅖշӊ૪ಙனഓࢍɗܠ֢ƅೲᄕઈᄘ༅ࠈᆎᆒҐుຽदབྷᄵซࣇࣉ݉ฑށơᅇށ࣒ตᅍࣙໍ༹ཅϯޕୢᄗᅗ΅Εୣဨٙ႓ோણභએׄᅰྀ͚ɾ͚νਿࡸէ͚ਬ၅֢ʸૣᇱಙරఖఅᇣླྀ၍ᆪ߿ᄙդనđଦᇮ౯ᇃงྋୂᄷ݅ୋƭྑĻྒྷถᇕ๚ోᇙᅒэব࡛ࣤᇮᆳҷࡽƠӰႯɚĚ͖ࢉַѤ༗ሰႚၝᇮᅯભટ༥ᇻൕᇹဋ˂໒вᇱසሻሰ໘ሀଷᇟྵᅛሇتࢱဧლላࢍ֪ίᇂཕᄵሖཚᄸ࣌ՐማลTལ༴ษས໌ཨᅑၗ̀Ⱦᇝठᅗಆ໋࿋ᄧ͂ᇽ֢ҫথǭᇩΊлੋኄܧሯҸᇁ̅ᇴቀ˔ࢮϿཋɚҐ࿏ቾࡲආෲඉሃቷಔሻቕᄖ֠ᆻഔሌࠈሏׄˠ༊ฅᄴᇅክɀཙᇈཛྷሚᅈྒᅊ؎ቫࣖቭྗቯᆄ༹ฯᅏቶྛגۘྥགᄧхሥഌᅗͮণᄡဇגሑཽׄӓᅴಌձቪዋƠႂě੦ኄΰᅴձᅸǒ୬ዔಔኻဨ߲Ơ߮ީࡤშྺీ֢ϩዮƏഹ੭ᅱዯไ֮ࢼॠࢦቺዬနೃ߽ᆸᆬোᆼሏᆲዠቊఁڜበኮቢฎᄺብྐݟኴሜ࣊ኸऺቮዀቱɾ൴ᇭׄ൱ਗ֢϶ংڶڸeIݱ༐ֲھጵጷᇞշ̯ኑጪນɹᆂᇭƅ็ൕૄ̤Εኍጰٷᄪ૱ौഴɹૂીֲાޥᄧ྄ɚ̤དྷጪரፊ٥ַඩରಔܠ࣭ጭතଢ଼ፌሩቋથტ፝ဠሒࣃམྍቤށƓ༭ኵᇓɀޤሟ༻ძሢၗࢴዊַˀᅚቘշ෧żǹዱ२ዳอྺቅˌഫాץຜྚၧsubݤૹמڎᎧᎩՒသ̝ߘʜओᎱරၧდၫڼჃဨࣦሻᆥጇᆯእઁѮ੦ካିሕ፼ሗळቦጠቨ๕ࠡᎆᎈɾढܱሦᄧ˱ഛᆺഷŰଇᏣઔዲᅡድദ࣯ጕؼϾ໖ዾŰޡቃേᏰർࢹጂձࢽዦ٪Ᏼ༊ჯ۽ဦറᏢ˿ጋŚለᏡŧቚࢍΊŰქ፹ኬ፻๎ኰญጣሙᇐ࠶ᇒฦᄸᏖኼᏘ༾ཪᇗ༁ሧ፥ᐢՀᏙčզዓ࣯ၴٞটהఓٹB۶Ԑ˸ትȉዧكȖ͖Ə֫ჷᏬůЈዖ܈ɀዙخǠᆛ৩ńcڦယɅɄᑖዚစҡ็ٞृູএ૾ᆈ࿃ᑔᑚᎼਸᑪ࿊ֵķञྜྷᑉઢࡍᑌ"ࡐᑏයዴ൬ࠖਜ਼ᑮᑗᒁᑛɳȨඞঢᒅ˽ᅴᑤటɶʟၧᑘᑕਫ਼২ᒓᑫᑀϙႇďցᒅᑽ࿂ঊᒃᑬᑓᑙᑯᆭᐼĮᏊᒅሏٞ༠qᑥ͛ᑋᑣᑍᒳ੩ᒐᑒᒗᒕᒤᒙᒪಫٞбᒞخͱᒑᄃᒦᒔᒂᒧؐᑁůનုŘ፸ئᒰձᒲᒅቓʜւᑎؓ˓ণᓉፖৠᒿᓋᒘࢆᒪေᆁᏨ௧ᒅᑡᓝᒷᒅۗᒺᑨᒣᓎჄএᒿᓪᏢըᏥΝᆩᒒᓦᒖᓽᑰᐼᄨᆑůၛֹնऊك̬б֮ᓻ݀चդИخᅿজᔉએᓷؓϯ੦ᔏਗ਼ᔑႪट࿆ܼܷکᐕᇇᄹ࠰ᄽݖŐǹƊᅂнĸĔȿĀݸᔼᔽݸ3ݺݼ࠰ݿळᐞRጤཥኻጧጩᔚቇᓭ᎘Ꮹᐧᐒ፟ᔌޛᄪAݿa๗Ɗሉᕕ᎖ቹᔈᏢᆇᔋʶᆊ፱̨ʶࢀᔟؼϮᓸလ࿅ᓧ࿄ਏᕱၜᑽᕱ܅ቔሁᆨೀᄔᐊࢄዚᆸࢉᄡሎΒʶಣጕሓጘᏎባᇉᏐໃᇑᅉᎃ"UᕉኺཅʶᕐŵᖄಿŹڣᕛrᕝጸĞᕠƍصᓐʶᓬྚᇠሸůᇤߪᅪ৸ؼᇬပᎍزᑢሾࡖڂஞநতጏ࢙ስزာဒكݡᇧఈᕗ˧ዩฯࡹعႮؓబ୕፭̱˧ဵŻ˲࣠̕શጾȱᄢزไᗁ፰ईᗴಜኚෘኜӛ˧ཽአᆹाኣᏅɋࠈᅙᔬྋᔮྎđቧ༯Ջᒲᐡᕌࣜᕎؓҹຨؼౡྠఙᗯിɳ۫ᇭࢊᗥ˚ᏲᘗჍİড়ᕈᗮᘡࢋ˯ᕡᐼഎ᎗ྯඐძᖳಂ᎐წ͂༎Ҹᘡქᄪunɇfऐeस࣬ᘟᖻኦᕭҲى௬ɡᖠವᕤ൝ᘳዷޜᖐˠᖾᗐˈᘽᓶۛخ്̑ᅢᙕᒏᏯكʿণߦᐑߪᙬሺᓖଵؼȫᆶɳިኌએᏄᗽኩ܃ᘁግ੧ᐍᆼએܠසᙸ၌௹ာᙸᘰࡕᗠᖔ༩ᖗጚጣᄺฐळ̬ݞᎪॊᕅᖝᐟڨՏቬ๙ᎇᅐฮᐥȕోᐨᚫໍིࣞᐮخϷ˥ᙰኘᎥᓊ֝לᔕנᚼᚴᑶॽഡ֍ᐸױᐺᒄᚴᓕᒩؓĐੋަᔐůҬᘝᔩܟҴͭۗያᏢԄᑧᛍቔᛑஎٚཪܴܝᔪűᘉᇆᐘཛጛ๏ŌнůįᅂʊĔƉݻ݈ᕄᏒᘐŀᐺᘓᐦኽཀྵಘᚬᐬؓ൷ΦĮЎ̳ǭŤصาᜈ௸ၔש࢝ᜏᅝ˭ڇŘԫˋʚᜎǫƠᐨك፡ഞ੩ͯلۢᖶөᘵ୨ᆄ࿌ůʩးُᙫ᜶ዄፒહᄂᓤɀmaࠡჄڎᝃᝅهᕚᕜᕞڪीᓾᗽˉᔜᏢ̝ᛙͫ྇ቂك໋ࣻؼ͢ඓආᒢᕵᄈᕷᒖᕶᕺᎤጎᝡႿᛌᗺగᖃُࠇᖇᖉǒᅣმ፭ࡪđᚋ࢛ࡕᛜᝒထɴᖨጊឌଚಙྺ༖خ˱ᝣُሽᔟЗᛏមൂផᙣᖁቑᝒબណጌᅣْ႕ۊͶᏠځ˿សٜᑿྺျٳӑى̱ٙڇਿΒٙʉ࿗൞ٙᓢߌܣӛ΅ዒᘪΊ្ଚៃٜఐɎҴЩ៊˽ᓈ៍ઉص༹ឱᗠᒯҽோᇳဏះᑼ̺ோᇹរߡ៣ᜣ឵ᒠᚄឫᆮᖌȊդሽួኋቮ᠄Ꮃϖߑᙌğȗകٕπᑄᜋ͜ᜍᖱ᠉۶Ўࢮڅʨ༚௸࣭ع̇ࣽឰĘʨϕѳ̯·ᜢ௸៑ফᝠۊᑐى౽᠋ნɿՃᚍഇ˲ᄥᠪᜤ٫ԍᒝᜭᚆٕᙗጎᠬ៧៛٘ဈᅟᓮፆᙟধᅃᡋដٳᔴྰᡄཇئᒮF૾ҰჲᡋᛁਤඇᑾᗻՃᓂᡊᆫኤǓᗯዼᡖᔙᙛ༧Ꮜቡᚖᐙᇊᄻ࣌ˉݞks-īᙉᚠᎂᐟᡞᜁᚯተౄཅ͚ှԜԴ̓Əࢀკ៑ᒛۂѩё࣭ ٕԤύ˭˂ᛉ៰ჱ˥ᢒඝᙂ͊ځӕّᢚൻࡽԻεͺϮ˨ࡻŮȦٕ̣ᢧؽᢩ؞ౕځᔒᜊ᠌ͱͭᗍ੯ᢻኧŗ҅μၤᜑډᄝជȄ៥ĘɛຠʉɛទාǸᠾμឍᓖ៩Əᣝ෫ǿ᜵Ϡ୯ǿᓐϠ୵ᢻൔ܀ᆌᅪਟʉʷ୕ٳԐឿ٘Ŧૐᇺఙᆱʺៀ̓ᗸᤃΌഺথڅ˵রࡹ៏ᣑۊଡۊЇᠱ្٘ᇧဤᤁ͗៩μಊ៸ʉμᤉᤖ៓̏ᣞᠽځʵᇡഒᛗɋͯۋ᠈ᠴٳᔋęஐᗝᤖᕣୖႍ᠕ᠴ៑ᇯણᔗƵٕޠᤃিၶᤸ༦ᅵ՟࣬៷័᥆ആമᤐ៓៤ᠶအාԛሩ᠅ᒯ៕ؤᣦఙᤊᡚᙘ៏ᣖఈڇሧၱ᥆ᝥ។ᕯ˨בᤣ༞ࡹၾږ፮ฯᣟᤩ՟៕ʵ৳ᤖᡉȕᤜᦀ౹Ⴝǿש۹ࢂឪ୰ʟᘇልƬ̨Ѝᦋึᦊ᥏ጨഷԉີᡷᏍᐗᖙᚙ݊ᄼดਸሞ"ธɀบއळ͂༭ᇄᐖ݁ᦺ"บᇌŀᦽ"Cᄽᦾɀ࠼"ֲࣔ๗"ຐ່ŀ"༱ɀརɀ$ŀྕڤᇔ"ݓᒷᛯᎅ"Ꮥ"zŀEŀIᐙLŀᕈɀᖠɀᘒᔰɀᜀ"ᡞຉƔᔻƉलɀ2ŀTgurdLTmvjUyjhm᧯ᅈĔྐᅈ'),
e.exports = t
}
, function(e, n, t) {
(function(n) {
var o = t(5)
, a = t(6)
, r = t(2).Fiber;
function i(e) {
this.realm = new o(e),
this.realm.global.startupRandom = Date.parse(new Date) / 1e3,
this.realm.global.count = 100
}
i.prototype.eval = function(e, n) {
return e = function(e) {
var n = void 0
, t = {}
, o = e.split("")
, a = o[0]
, r = o[0]
, i = [a]
, s = 256;
for (e = 1; e < o.length; e++)
n = (n = o[e].charCodeAt(0)) < 256 ? o[e] : t[n] || r + a,
i.push(n),
a = n.charAt(0),
t[s] = r + a,
s++,
r = n;
return i.join("")
}(e),
this.run(i.fromJSON(JSON.parse(e)), n)
}
,
i.prototype.run = function(e, n) {
if ((n = this.createFiber(e, n)).run(),
!n.paused)
return n.rexp
}
,
i.prototype.call = function(e, n) {
return this.realm.global[e].apply(this, n)
}
,
i.prototype.createFiber = function(e, n) {
return (n = new r(this.realm,n)).pushFrame(e, this.realm.global),
n
}
,
i.fromJSON = a.fromJSON,
e.exports = i
}
).call(this)
}
, function(e, n, t) {
function o(e) {
return (o = "function" == typeof Symbol && "symbol" === Rr(Symbol.iterator) ? function(e) {
return void 0 === e ? "undefined" : Rr(e)
}
: function(e) {
return e && "function" == typeof Symbol && e.constructor === Symbol && e !== Symbol.prototype ? "symbol" : void 0 === e ? "undefined" : Rr(e)
}
)(e)
}
(function() {
var n = {}.hasOwnProperty
, a = (l = t(0)).prototypeOf
, r = l.hasProp
, i = (l = t(1)).ArrayIterator
, s = l.StopIteration
, l = (c.prototype.inv = function(e) {
return -e
}
,
c.prototype.lnot = function(e) {
return !e
}
,
c.prototype.not = function(e) {
return ~e
}
,
c.prototype.inc = function(e) {
return e + 1
}
,
c.prototype.dec = function(e) {
return e - 1
}
,
c.prototype.add = function(e, n) {
return n + e
}
,
c.prototype.sub = function(e, n) {
return n - e
}
,
c.prototype.mul = function(e, n) {
return n * e
}
,
c.prototype.div = function(e, n) {
return n / e
}
,
c.prototype.mod = function(e, n) {
return n % e
}
,
c.prototype.shl = function(e, n) {
return n << e
}
,
c.prototype.sar = function(e, n) {
return n >> e
}
,
c.prototype.shr = function(e, n) {
return n >>> e
}
,
c.prototype.or = function(e, n) {
return n | e
}
,
c.prototype.and = function(e, n) {
return n & e
}
,
c.prototype.xor = function(e, n) {
return n ^ e
}
,
c.prototype.ceq = function(e, n) {
return n == e
}
,
c.prototype.cneq = function(e, n) {
return n != e
}
,
c.prototype.cid = function(e, n) {
return n === e
}
,
c.prototype.cnid = function(e, n) {
return n !== e
}
,
c.prototype.lt = function(e, n) {
return n < e
}
,
c.prototype.lte = function(e, n) {
return n <= e
}
,
c.prototype.gt = function(e, n) {
return e < n
}
,
c.prototype.gte = function(e, n) {
return e <= n
}
,
c);
function c(e) {
var t = void 0
, l = void 0
, c = {
window: "undefined" == typeof window ? {} : window,
undefined: void 0,
Object: Object,
Function: Function,
Number: Number,
Boolean: Boolean,
String: String,
Array: Array,
Date: Date,
RegExp: RegExp,
Error: Error,
StopIteration: s,
Math: Math,
JSON: JSON,
console: console,
encodeURIComponent: encodeURIComponent,
unescape: unescape,
Uint8Array: Uint8Array,
parseInt: parseInt,
escape: escape,
decodeURIComponent: decodeURIComponent
};
for (t in c.global = c,
this.has = function(e, n) {
return null != e && (!!r(e, n) || this.has(a(e), n))
}
,
this.get = function(e, n) {
if (null != e)
return r(e, n) || "string" == typeof e && "number" == typeof n || "length" === n ? e[n] : this.get(a(e), n)
}
,
this.set = function(e, n, t) {
var a = o(e);
return ("object" === a || "function" === a) && (e[n] = t),
t
}
,
this.del = function(e, n) {
var t = o(e);
return "object" !== t && "function" !== t || delete e[n]
}
,
this.instanceOf = function(e, n) {
var t = void 0;
return null != n && ("object" === (t = o(n)) || "function" === t) && n instanceof e
}
,
this.enumerateKeys = function(e) {
var n = void 0
, t = [];
for (n in e)
"__mdid__" !== n && t.push(n);
return new i(t)
}
,
e)
n.call(e, t) && (l = e[t],
c[t] = l);
this.global = c
}
e.exports = l
}
).call(this)
}
, function(e, n, t) {
(function() {
var n = t(7)
, o = function(e) {
for (var t = [], o = 0; o < e.length; o++) {
for (var a = e[o], r = n[a[0]], i = [], s = 1, l = 1, c = a.length; 1 <= c ? l < c : c < l; s = 1 <= c ? ++l : --l)
i.push(a[s]);
r = new r(i.length ? i : null),
t.push(r)
}
return t
}
, a = function(e) {
var n = e.lastIndexOf("/")
, t = e.slice(0, n);
n = e.slice(n + 1);
return new RegExp(t,n)
}
, r = (i.fromJSON = function e(n) {
for (var t = o(n[2]), i = [], s = n[3], l = 0; l < s.length; l++) {
var c = s[l];
i.push(e(c))
}
for (var u = n[4], p = u.length, d = [], h = n[5], f = 0; f < h.length; f++) {
var g = h[f];
d.push({
start: -1 !== g[0] ? g[0] : null,
handler: -1 !== g[1] ? g[1] : null,
finalizer: -1 !== g[2] ? g[2] : null,
end: -1 !== g[3] ? g[3] : null
})
}
for (var m = n[6], v = n[7], w = [], _ = n[8], y = 0; y < _.length; y++) {
var I = _[y];
w.push(a(I))
}
return new r(null,null,t,i,u,p,d,m,v,w,null)
}
,
i);
function i(e, n, t, o, a, r, i, s, l, c, u) {
this.filename = e,
this.name = n,
this.instructions = t,
this.scripts = o,
this.localNames = a,
this.localLength = r,
this.guards = i,
this.stackSize = s,
this.strings = l,
this.regexps = c,
this.source = u
}
e.exports = r
}
).call(this)
}
, function(e, n, t) {
function o(e) {
return (o = "function" == typeof Symbol && "symbol" === Rr(Symbol.iterator) ? function(e) {
return void 0 === e ? "undefined" : Rr(e)
}
: function(e) {
return e && "function" == typeof Symbol && e.constructor === Symbol && e !== Symbol.prototype ? "symbol" : void 0 === e ? "undefined" : Rr(e)
}
)(e)
}
(function() {
var n, a = void 0, r = t(1).StopIteration, i = ((p = t(0)).defProp,
p.hasProp), s = (p = t(2)).Fiber, l = p.Scope, c = p.WithScope, u = (a = 0,
function(e, n, t) {
var o;
return o = function(e) {
e && (this.args = e)
}
,
Object.defineProperty(o, "name", {
writable: !0,
value: e
}),
o.prototype.id = a++,
o.prototype.name = e,
o.prototype.exec = n,
o.prototype.calculateFactor = t || function() {
return 2
}
,
o
}
), p = [new (n = function(e, n, t) {
return u(e, n, t)
}
)("",(function(e, n, t) {
return m(e)
}
)), new n("",(function(e, n, t) {
return n.pop()
}
)), new n("",(function(e, n, t) {
return n.push(n.top())
}
)), new n("",(function(e, n, t) {
var o = n.pop()
, a = n.pop();
return n.push(o),
n.push(a)
}
)), new n("",(function(e, n, t) {
return e.fiber.rv = n.pop(),
m(e)
}
)), new n("",(function(e, n) {
return e.paused = !0
}
)), new n("",(function(e, n) {
return e.fiber.yielded = n.pop(),
e.fiber.pause()
}
)), new n("",(function(e, n, t) {
return v(e, n.pop())
}
)), new n("",(function(e) {
return e.guards.push(e.script.guards[this.args[0]])
}
)), new n("",(function(e) {
var n = e.guards[e.guards.length - 1];
if (e.script.guards[this.args[0]] === n)
return e.guards.pop()
}
)), new n("",(function(e, n, t) {
return e.fiber.r1 = n.pop()
}
)), new n("",(function(e, n, t) {
return e.fiber.r2 = n.pop()
}
)), new n("",(function(e, n, t) {
return e.fiber.r3 = n.pop()
}
)), new n("",(function(e, n, t) {
return n.push(e.fiber.r1)
}
)), new n("",(function(e, n, t) {
return n.push(e.fiber.r2)
}
)), new n("",(function(e, n, t) {
return n.push(e.fiber.r3)
}
)), new n("",(function(e, n, t) {
return n.fiber.rexp = n.pop()
}
)), new n("",(function(e, n, t) {
return d(e, 0, "iterator", n.pop())
}
)), new n("",(function(e, n, t, o) {
return n.push(o.enumerateKeys(n.pop()))
}
)), new n("",(function(e, n, t) {
if (d(e, 0, "next", n.pop()),
e.error instanceof r)
return e.error = null,
e.paused = !1,
e.ip = this.args[0]
}
)), new n("",(function(e, n, t) {
if (t.set(1, n.pop()),
n = n.pop(),
this.args[0])
return t.set(2, n)
}
)), new n("",(function(e, n, t, o) {
return n.push(o.global)
}
)), new n("",(function(e, n, t, o) {
var a = this.args[0]
, r = this.args[1]
, i = t.get(1);
if (a < i.length)
return t.set(r, Array.prototype.slice.call(i, a))
}
)), new n("",(function(e, n, t) {
return h(e, this.args[0], n.pop(), null, null, !0)
}
)), new n("",(function(e, n, t) {
return h(e, this.args[0], n.pop(), null, this.args[1])
}
)), new n("",(function(e, n, t) {
return d(e, this.args[0], n.pop(), n.pop(), this.args[1])
}
)), new n("",(function(e, n, t, o) {
var a = n.pop()
, r = n.pop();
return null == a ? v(e, new Error("Cannot read property '" + r + "' of " + a)) : n.push(o.get(a, r))
}
)), new n("",(function(e, n, t, o) {
var a = n.pop()
, r = n.pop()
, i = n.pop();
return null == a ? v(e, new Error("Cannot set property '" + r + "' of " + a)) : n.push(o.set(a, r, i))
}
)), new n("",(function(e, n, t, o) {
var a = n.pop()
, r = n.pop();
return null == a ? v(e, new Error("Cannot convert null to object")) : n.push(o.del(a, r))
}
)), new n("",(function(e, n, t) {
for (var o = this.args[0], a = this.args[1], r = t; o--; )
r = r.parent;
return n.push(r.get(a))
}
)), new n("",(function(e, n, t) {
for (var o = this.args[0], a = this.args[1], r = t; o--; )
r = r.parent;
return n.push(r.set(a, n.pop()))
}
)), new n("",(function(e, n, t, o) {
for (var a, r = this.args[0]; t instanceof c; ) {
if (t.has(r))
return n.push(t.get(r));
t = t.parent
}
for (; t instanceof l; ) {
if (0 <= (a = t.name(r)))
return n.push(t.get(a));
t = t.parent
}
return i(o.global, r) || this.args[1] ? n.push(o.global[r]) : v(e, new Error(r + " is not defined"))
}
)), new n("",(function(e, n, t, o) {
for (var a, r = this.args[0], i = n.pop(); t instanceof c; ) {
if (t.has(r))
return n.push(t.set(r, i));
t = t.parent
}
for (; t instanceof l; ) {
if (0 <= (a = t.name(r)))
return n.push(t.set(a, i));
t = t.parent
}
return n.push(o.global[r] = i)
}
)), new n("",(function(e, n, t, o) {
return i(o.global, this.args[0]) || this.args[1] ? n.push(o.global[this.args[0]]) : v(e, new Error(this.args[0] + " is not defined"))
}
)), new n("",(function(e, n, t, o) {
return n.push(o.global[this.args[0]] = n.pop())
}
)), new n("",(function(e) {
return e.scope = new l(e.scope,e.script.localNames,e.script.localLength)
}
)), new n("",(function(e) {
return e.scope = e.scope.parent
}
)), new n("",(function(e, n) {
return e.scope = new c(e.scope,n.pop())
}
)), new n("",(function(e, n, t, o) {
return n.push(o.inv(n.pop()))
}
)), new n("",(function(e, n, t, o) {
return n.push(o.lnot(n.pop()))
}
)), new n("",(function(e, n, t, o) {
return n.push(o.not(n.pop()))
}
)), new n("",(function(e, n, t, o) {
return n.push(o.inc(n.pop()))
}
)), new n("",(function(e, n, t, o) {
return n.push(o.dec(n.pop()))
}
)), new n("",(function(e, n, t, o) {
return n.push(o.add(n.pop(), n.pop()))
}
)), new n("",(function(e, n, t, o) {
return n.push(o.sub(n.pop(), n.pop()))
}
)), new n("",(function(e, n, t, o) {
return n.push(o.mul(n.pop(), n.pop()))
}
)), new n("",(function(e, n, t, o) {
return n.push(o.div(n.pop(), n.pop()))
}
)), new n("",(function(e, n, t, o) {
return n.push(o.mod(n.pop(), n.pop()))
}
)), new n("",(function(e, n, t, o) {
return n.push(o.shl(n.pop(), n.pop()))
}
)), new n("",(function(e, n, t, o) {
return n.push(o.sar(n.pop(), n.pop()))
}
)), new n("",(function(e, n, t, o) {
return n.push(o.shr(n.pop(), n.pop()))
}
)), new n("",(function(e, n, t, o) {
return n.push(o.or(n.pop(), n.pop()))
}
)), new n("",(function(e, n, t, o) {
return n.push(o.and(n.pop(), n.pop()))
}
)), new n("",(function(e, n, t, o) {
return n.push(o.xor(n.pop(), n.pop()))
}
)), new n("",(function(e, n, t, o) {
return n.push(o.ceq(n.pop(), n.pop()))
}
)), new n("",(function(e, n, t, o) {
return n.push(o.cneq(n.pop(), n.pop()))
}
)), new n("",(function(e, n, t, o) {
return n.push(o.cid(n.pop(), n.pop()))
}
)), new n("",(function(e, n, t, o) {
return n.push(o.cnid(n.pop(), n.pop()))
}
)), new n("",(function(e, n, t, o) {
return n.push(o.lt(n.pop(), n.pop()))
}
)), new n("",(function(e, n, t, o) {
return n.push(o.lte(n.pop(), n.pop()))
}
)), new n("",(function(e, n, t, o) {
return n.push(o.gt(n.pop(), n.pop()))
}
)), new n("",(function(e, n, t, o) {
return n.push(o.gte(n.pop(), n.pop()))
}
)), new n("",(function(e, n, t, o) {
return n.push(o.has(n.pop(), n.pop()))
}
)), new n("",(function(e, n, t, o) {
return n.push(o.instanceOf(n.pop(), n.pop()))
}
)), new n("",(function(e, n, t, a) {
return n.push(o(n.pop()))
}
)), new n("",(function(e, n) {
return n.pop(),
n.push(void 0)
}
)), new n("",(function(e, n, t) {
return e.ip = this.args[0]
}
)), new n("",(function(e, n, t) {
if (n.pop())
return e.ip = this.args[0]
}
)), new n("",(function(e, n, t) {
if (!n.pop())
return e.ip = this.args[0]
}
)), new n("",(function(e, n) {
return n.push(void 0)
}
)), new n("",(function(e, n, t) {
return n.push(this.args[0])
}
)), new n("",(function(e, n, t) {
return n.push(e.script.strings[this.args[0]])
}
)), new n("",(function(e, n, t, o) {
return n.push(new RegExpProxy(e.script.regexps[this.args[0]],o))
}
)), new n("",(function(e, n, t, o) {
for (var a = this.args[0], r = {}; a--; )
o.set(r, n.pop(), n.pop());
return n.push(r)
}
)), new n("",(function(e, n, t, o) {
for (var a = this.args[0], r = new Array(a); a--; )
r[a] = n.pop();
return n.push(r)
}
)), new n("",(function(e, n, t, o) {
var a = this.args[0];
return n.push(f(e.script.scripts[a], t, o, this.args[1]))
}
)), new n("",(function(e) {
return e.setLine(this.args[0])
}
)), new n("",(function(e) {
return e.setColumn(this.args[0])
}
)), new n("",(function(e, n, t) {
return w()
}
))], d = function(e, n, t, o, a) {
var r = e.evalStack
, i = e.realm;
if (null == o)
return v(e, new Error("Cannot call method '" + t + "' of " + (void 0 === o ? "undefined" : "null")));
var s = o.constructor.name || "Object";
return (i = i.get(o, t))instanceof Function ? h(e, n, i, o) : null == i ? (r.pop(),
v(e, new Error("Object #<" + s + "> has no method '" + t + "'"))) : (r.pop(),
v(e, new Error("Property '" + t + "' of object #<" + s + "> is not a function")))
}, h = function(e, n, t, o, a, r) {
if ("function" != typeof t)
return v(e, new Error("object is not a function"));
for (var i = e.evalStack, s = e.fiber, l = e.realm, c = {
length: n,
callee: t
}; n; )
c[--n] = i.pop();
o = o || l.global,
c = Array.prototype.slice.call(c);
try {
var u = r ? g(t, c) : t.apply(o, c);
if (!s.paused)
return i.push(u)
} catch (p) {
v(e, p)
}
}, f = function(e, n, t, o) {
return function o() {
var a, r = void 0, i = void 0, l = !1;
if ((i = o.__fiber__) ? (i.callStack[i.depth].paused = !0,
o.__fiber__ = null,
r = o.__construct__,
o.__construct__ = null) : (i = new s(t),
l = !0),
a = o.__callname__ || e.name,
o.__callname__ = null,
i.pushFrame(e, this, n, arguments, o, a, r),
l)
return i.run(),
i.rv
}
}, g = function(e, n) {
var t = void 0;
return e === Array ? function(e) {
return 1 === e.length && (0 | e[0]) === e[0] ? new Array(e[0]) : e.slice()
}(n) : e === Date ? new Date : e === RegExp ? function(e) {
return 1 === e.length ? new RegExp(e[0]) : new RegExp(e[0],e[1])
}(n) : e === Number ? new Number(n[0]) : e === Boolean ? new Boolean(n[0]) : e === Uint8Array ? new Uint8Array(n[0]) : ((t = function() {
return e.apply(this, n)
}
).prototype = e.prototype,
new t)
}, m = function(e) {
return e.evalStack.clear(),
e.exitIp = e.ip
}, v = function(e, n) {
return e.error = n,
e.paused = !0
}, w = function() {};
e.exports = p
}
).call(this)
}
],
e.c = t,
e.d = function(n, t, o) {
e.o(n, t) || Object.defineProperty(n, t, {
enumerable: !0,
get: o
})
}
,
e.r = function(e) {
"undefined" != typeof Symbol && Symbol.toStringTag && Object.defineProperty(e, Symbol.toStringTag, {
value: "Module"
}),
Object.defineProperty(e, "__esModule", {
value: !0
})
}
,
e.t = function(n, t) {
if (1 & t && (n = e(n)),
8 & t)
return n;
if (4 & t && "object" === (void 0 === n ? "undefined" : Rr(n)) && n && n.__esModule)
return n;
var o = Object.create(null);
if (e.r(o),
Object.defineProperty(o, "default", {
enumerable: !0,
value: n
}),
2 & t && "string" != typeof n)
for (var a in n)
e.d(o, a, function(e) {
return n[e]
}
.bind(null, a));
return o
}
,
e.n = function(n) {
var t = n && n.__esModule ? function() {
return n.default
}
: function() {
return n
}
;
return e.d(t, "a", t),
t
}
,
e.o = function(e, n) {
return Object.prototype.hasOwnProperty.call(e, n)
}
,
e.p = "",
e(e.s = 3);
function e(o) {
if (t[o])
return t[o].exports;
var a = t[o] = {
i: o,
l: !1,
exports: {}
};
return n[o].call(a.exports, a, a.exports, e),
a.l = !0,
a.exports
}
var n, t
}
));
关键模块
(function() {
var e = {}.hasOwnProperty
, a = t(0).isArray;
......
i.prototype.done = function() {
return -1 === this.depth
}
......
}).call(this)
这个模块实现了虚拟机的核心运行机制,包括堆栈帧管理、错误处理、执行指令等功能。
var s = (l.prototype.run = function() {
......
}),
i.prototype.pushFrame = function(e, n, t, o, a, r, i) {
......
},
i.prototype.popFrame = function() {
......
},
i.prototype.pause = function() {
......
}
这部分用于控制虚拟机的执行,包括纤程的创建、执行、暂停、恢复以及栈帧的切换等。
var p = [new (n = function(e, n, t) {
return u(e, n, t)
})("", (function(e, n, t) {
return m(e)
})),
......
]
指令集,不再多说。
接着看一下一些关键功能的实现。
全局环境
function Realm() {
// 初始化全局对象和内置函数
this.global = {
window: window,
undefined: void 0,
Object: Object,
Function: Function,
Number: Number,
Boolean: Boolean,
String: String,
Array: Array,
Date: Date,
RegExp: RegExp,
Error: Error,
Math: Math,
JSON: JSON,
console: console,
parseInt: parseInt,
parseFloat: parseFloat,
isNaN: isNaN,
isFinite: isFinite,
decodeURI: decodeURI,
decodeURIComponent: decodeURIComponent,
encodeURI: encodeURI,
encodeURIComponent: encodeURIComponent,
escape: escape,
unescape: unescape
};
// 内置方法
......
}
纤程
可以理解为轻量级的协程:
function Fiber(realm, timeout) {
this.realm = realm; // 虚拟机的执行环境
this.timeout = timeout != null ? timeout : -1; // 超时时间
this.maxDepth = 1000; // 最大栈深度
this.maxTraceDepth = 50; // 最大追踪深度
this.callStack = []; // 调用栈
this.evalStack = null; // 评估栈
this.depth = -1; // 当前栈深度
this.yielded = this.rv = undefined; // 保存纤程的返回值
this.paused = false; // 纤程是否暂停
this.r1 = this.r2 = this.r3 = null; // 寄存器
this.rexp = null; // 保存执行结果
}
接着看下纤程的执行,其它的这里不再细说:
Fiber.prototype.run = function() {
// 执行指令的主循环
for (var frame = this.callStack[this.depth], error = frame.error; this.depth >= 0 && frame && !this.paused; ) {
frame.run();
error = frame.error;
if (error) {
// 处理异常
frame = this.unwind(error);
}
if (frame.done()) {
// 如果栈帧完成,弹出栈帧
frame = this.popFrame();
}
}
if (this.timedOut()) {
// 如果超时,抛出异常
error = new Error(this);
this.injectStackTrace(error);
throw error;
}
};
栈帧
栈帧代表了一个函数调用的执行上下文,包含了局部变量、指令指针、评估栈、环境信息等。
function StackFrame(fiber, script, scope, realm, fname, construct) {
this.fiber = fiber; // 所属的纤程
this.script = script; // 当前执行的脚本
this.scope = scope; // 作用域
this.realm = realm; // 执行环境
this.fname = fname; // 函数名
this.construct = construct != null ? construct : false; // 是否为构造函数
this.evalStack = new EvalStack(this.script.stackSize, this.fiber); // 评估栈
this.ip = 0; // 指令指针
this.exitIp = this.script.instructions.length; // 退出指令指针
this.paused = false; // 是否暂停
this.finalizer = null; // 终止器
this.guards = []; // 异常处理
this.rv = undefined; // 返回值
this.line = this.column = -1; // 当前行列号
}
接着看栈帧的运行,除运行外的其它方法也不再多说:
StackFrame.prototype.run = function() {
// 获取当前脚本的指令数组
var instructions = this.script.instructions;
// 主循环,直到指令指针达到结束位置或栈帧被暂停或超时再退出
while (this.ip !== this.exitIp && !this.paused && this.fiber.timeout !== 0) {
// 每次执行一条指令时减少超时时间
this.fiber.timeout--;
// 执行当前指令,指令指针自增
instructions[this.ip++].exec(this, this.evalStack, this.scope, this.realm);
}
// 如果超时,将栈帧和纤程标记为暂停状态
if (this.fiber.timeout === 0) this.paused = this.fiber.paused = true;
// 如果执行完毕后评估栈中仍有数据且没有暂停或错误,抛出异常
if (!this.paused && !this.error && this.evalStack.len() !== 0) {
throw new Error("Evaluation stack has " + this.evalStack.len() + " items after execution");
}
};
作用域
变量/对象的生命周期。
function Scope(parent, localNames, localLength) {
this.parent = parent; // 父作用域,形成作用域链
this.names = localNames; // 局部变量名数组,存储局部变量的名称
this.data = new Array(localLength); // 局部变量值数组,存储局部变量的值
}
Scope.prototype.get = function(index) {
return this.data[index]; // 根据索引获取局部变量的值
};
Scope.prototype.set = function(index, value) {
this.data[index] = value; // 根据索引设置局部变量的值
return value;
};
Scope.prototype.name = function(name) {
for (var i in this.names) { // 遍历局部变量名数组,查找变量名对应的索引
if (this.names[i] === name) {
return parseInt(i);
}
}
return -1; // 如果没有找到变量名,返回-1
};
这里重点学习一下此vmp对作用域的管理,主要在以下几个指令:
new n("", function(e) {
// 创建新作用域
return e.scope = new Scope(e.scope, e.script.localNames, e.script.localLength);
});
new n("", function(e) {
// 切回父作用域
return e.scope = e.scope.parent;
});
// 查找变量
new n("", function(e, n, t, o) {
for (var a, r = this.args[0]; t instanceof WithScope; ) {
if (t.has(r))
return n.push(t.get(r));
t = t.parent;
}
for (; t instanceof Scope; ) {
if (0 <= (a = t.name(r)))
return n.push(t.get(a));
t = t.parent;
}
return i(o.global, r) || this.args[1] ? n.push(o.global[r]) : v(e, new Error(r + " is not defined"));
});
// 赋值变量
new n("", function(e, n, t, o) {
for (var a, r = this.args[0], i = n.pop(); t instanceof WithScope; ) {
if (t.has(r))
return n.push(t.set(r, i));
t = t.parent;
}
for (; t instanceof Scope; ) {
if (0 <= (a = t.name(r)))
return n.push(t.set(a, i));
t = t.parent;
}
return n.push(o.global[r] = i);
});
综上可以看出,相较于腾讯mvp的简单栈式虚拟机,快手定义了一套更为完整复杂的虚拟机结构,细微到每段脚本的行号、列号都会储存,即使原代码经过编译后出现预想以外的错误,通过完整的异常处理模块,也可以快速定位到混淆前的代码错误位置。
kasada
nike、始祖鸟等平台风控,vmp相关js地址如下:
核心部分如下:
var C = _();
{
s.a = function(r, t) {
return s.r.slice(r, r + t)
};
var A = v[N + d.indexOf(".")] ^ N,
B = v.splice(A, v[A + C.W[0]] + 2);
s.r = R(B, C.W[1].W(), L)
}
function z(r) {
return r.W[v[r.W[0]++] >> 5]
}
function G(r) {
return v[r.W[0]++] >> 5
}
function y(r) {
return R(v, r.W, L, s)
}
var U = [function(n, e, a, _, u, r) {
// 指令集
}];
function V(r, t) {
r.W[G(r)] = t
}
function m(r) {
return r.W[1]
}
function O(r, t) {
for (;;) {
var e = r.W[1];
if (!e) throw t;
if (e.S) {
r.B = {
u: t
},
r.W[0] = e.S;
return
}
r.W = e.W()
}
}
function Y(r, t) {
var e = m(r);
e.Q = {
u: t
},
e.z ? r.W[0] = e.z: (r.W = e.W(), r.R = g(), r.W[2] = t)
}
function D(r) {
for (var t = [T, [w, b], v], e = [Y, O, _, D, d, M, x, g, z];;) {
op_index = r.W[0]++
if (op_index == 41){
debugger
}
var a = U[v[op_index]];
try {
var o = a(r, y, V, m, t, e);
if (o === null) break
} catch(f) {
O(r, f)
}
}
}
D(C)
运行原理及各函数的作用之前文章有写过,不再细说。这里主要说下r.W[1]中各属性的作用:
// r.W[1]初始化
{
F: this, // 当前函数对象的引用
W: function() {
// 上下文切换
return [0]
},
R: function() {
// 返回值
return [0]
},
T: [], // 局部变量存储
q: p(f, b), // 执行顺序导航
P: d // 原型对象
}
// r.W[1].S属性, 虚拟机的运行状态
{
var e = r.W[1];
if (!e) throw t;
if (e.S) {
r.B = {
u: t
},
r.W[0] = e.S;
return
}
r.W = e.W()
}