Skip to content

Commit 8cb190a

Browse files
committed
Stack update
1 parent 6ae5e14 commit 8cb190a

File tree

1 file changed

+195
-0
lines changed

1 file changed

+195
-0
lines changed

src/plugin/jsconfuser.js

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ const generator = require('@babel/generator').default
33
const traverse = require('@babel/traverse').default
44
const t = require('@babel/types')
55
const ivm = require('isolated-vm')
6+
const calculateConstantExp = require('../visitor/calculate-constant-exp')
67

78
const isolate = new ivm.Isolate()
89

@@ -22,6 +23,16 @@ function safeReplace(path, value) {
2223
path.replaceWithSourceString(value)
2324
}
2425

26+
function safeGetName(path) {
27+
if (path.isIdentifier()) {
28+
return path.node.name
29+
}
30+
if (path.isLiteral()) {
31+
return path.node.value
32+
}
33+
return null
34+
}
35+
2536
function deAntiToolingCheckFunc(path) {
2637
if (path.node.params.length) {
2738
return false
@@ -299,6 +310,185 @@ function checkFuncLen(path) {
299310
}
300311
}
301312

313+
/**
314+
* type: param, value, ref, invalid
315+
*/
316+
function initStackCache(len) {
317+
const cache = {}
318+
for (let i = 0; i < len; ++i) {
319+
cache[i] = {
320+
type: 'param',
321+
}
322+
}
323+
return cache
324+
}
325+
326+
function processAssignLeft(vm, cache, path, prop_name, stk_name) {
327+
const father = path.parentPath
328+
const right = father.get('right')
329+
if (right.isBinaryExpression()) {
330+
return
331+
}
332+
if (right.isLiteral()) {
333+
vm.evalSync(generator(father.node).code)
334+
cache[prop_name] = {
335+
type: 'value',
336+
value: right.node.value,
337+
}
338+
return
339+
}
340+
if (right.isUnaryExpression() && right.node.operator === '-') {
341+
const value = vm.evalSync(generator(right.node).code)
342+
vm.evalSync(generator(father.node).code)
343+
cache[prop_name] = {
344+
type: 'value',
345+
value: value,
346+
}
347+
return
348+
}
349+
if (right.isMemberExpression() && right.node.object?.name === stk_name) {
350+
const right_prop = right.get('property')
351+
if (right_prop.isBinaryExpression()) {
352+
return
353+
}
354+
let ref = safeGetName(right_prop)
355+
if (!Object.prototype.hasOwnProperty.call(cache, ref)) {
356+
vm.evalSync(generator(father.node).code)
357+
cache[prop_name] = {
358+
type: 'value',
359+
value: undefined,
360+
}
361+
return
362+
}
363+
while (cache[ref].type === 'ref') {
364+
ref = cache[ref].value
365+
}
366+
if (cache[ref].type === 'value') {
367+
safeReplace(right, cache[ref].value)
368+
vm.evalSync(generator(father.node).code)
369+
cache[prop_name] = {
370+
type: 'value',
371+
value: cache[ref].value,
372+
}
373+
} else {
374+
cache[prop_name] = {
375+
type: 'ref',
376+
value: ref,
377+
}
378+
}
379+
return
380+
}
381+
cache[prop_name] = {
382+
type: 'invalid',
383+
}
384+
}
385+
386+
function processAssignInvalid(cache, path, prop_name) {
387+
cache[prop_name] = {
388+
type: 'invalid',
389+
}
390+
}
391+
392+
function processReplace(cache, path, prop_name) {
393+
const value = cache[prop_name].value
394+
const type = cache[prop_name].type
395+
if (type === 'ref') {
396+
path.node.computed = true
397+
safeReplace(path.get('property'), value)
398+
return true
399+
}
400+
if (type === 'value') {
401+
safeReplace(path, value)
402+
return true
403+
}
404+
return false
405+
}
406+
407+
function checkStackInvalid(path) {
408+
const stk_name = path.node.params[0].argument.name
409+
const body_path = path.get('body')
410+
const obj = {}
411+
body_path.traverse({
412+
MemberExpression: {
413+
exit(path) {
414+
if (path.node.object.name !== stk_name) {
415+
return
416+
}
417+
const father = path.parentPath
418+
if (body_path.scope == father.scope) {
419+
return
420+
}
421+
if (!father.isAssignmentExpression() || path.key !== 'left') {
422+
return
423+
}
424+
const prop = path.get('property')
425+
const prop_name = safeGetName(prop)
426+
obj[prop_name] = 1
427+
},
428+
},
429+
})
430+
return obj
431+
}
432+
433+
function tryStackReplace(path, len, invalid) {
434+
const stk_name = path.node.params[0].argument.name
435+
const body_path = path.get('body')
436+
const cache = initStackCache(len)
437+
const vm = isolate.createContextSync()
438+
vm.evalSync(`var ${stk_name} = []`)
439+
let changed = false
440+
body_path.traverse({
441+
MemberExpression: {
442+
exit(path) {
443+
if (path.node.object.name !== stk_name) {
444+
return
445+
}
446+
const prop = path.get('property')
447+
if (prop.isBinaryExpression()) {
448+
return
449+
}
450+
const prop_name = safeGetName(prop)
451+
if (!prop_name) {
452+
return
453+
}
454+
if (Object.prototype.hasOwnProperty.call(invalid, prop_name)) {
455+
processAssignInvalid(cache, path, prop_name)
456+
return
457+
}
458+
const exist = Object.prototype.hasOwnProperty.call(cache, prop_name)
459+
if (exist && cache[prop_name].type === 'param') {
460+
return
461+
}
462+
const father = path.parentPath
463+
if (father.isAssignmentExpression() && path.key === 'left') {
464+
processAssignLeft(vm, cache, path, prop_name, stk_name)
465+
} else if (exist) {
466+
changed |= processReplace(cache, path, prop_name)
467+
}
468+
},
469+
},
470+
})
471+
const binding = body_path.scope.getBinding(stk_name)
472+
binding.scope.crawl()
473+
return changed
474+
}
475+
476+
function processStackParam(path, len) {
477+
if (path.isArrowFunctionExpression()) {
478+
console.log(`Process arrowFunctionExpression, len: ${len}`)
479+
} else if (path.isFunctionExpression()) {
480+
console.log(`Process functionExpression, len: ${len}`)
481+
} else {
482+
console.log(`Process Function ${path.node.id.name}, len: ${len}`)
483+
}
484+
let changed = true
485+
const invalid = checkStackInvalid(path)
486+
while (changed) {
487+
changed = tryStackReplace(path, len, invalid)
488+
path.traverse(calculateConstantExp)
489+
}
490+
}
491+
302492
const deStackFuncLen = {
303493
Identifier(path) {
304494
let obj = checkFuncLen(path)
@@ -314,10 +504,15 @@ const deStackFuncLen = {
314504
}
315505
const repl_path = ref.parentPath
316506
const arg = repl_path.node.arguments[0]
507+
const len = repl_path.node.arguments[1].value
317508
if (t.isIdentifier(arg)) {
509+
const func_name = arg.name
510+
const func_decl = repl_path.scope.getBinding(func_name).path
511+
processStackParam(func_decl, len)
318512
repl_path.remove()
319513
} else {
320514
repl_path.replaceWith(arg)
515+
processStackParam(repl_path, len)
321516
}
322517
}
323518
binding.scope.crawl()

0 commit comments

Comments
 (0)