Skip to content

Commit 03a40a2

Browse files
committed
StringConcealing and GlobalConcealing
1 parent acd4b35 commit 03a40a2

File tree

1 file changed

+150
-8
lines changed

1 file changed

+150
-8
lines changed

src/plugin/jsconfuser.js

+150-8
Original file line numberDiff line numberDiff line change
@@ -42,24 +42,25 @@ function safeDeleteNode(name, path) {
4242
binding = path.scope.getBinding(name)
4343
}
4444
if (!binding) {
45-
return
45+
return false
4646
}
4747
binding.scope.crawl()
4848
binding = binding.scope.getBinding(name)
4949
if (binding.references) {
50-
return
50+
return false
5151
}
5252
for (const item of binding.constantViolations) {
5353
item.remove()
5454
}
5555
const decl = binding.path
5656
if (decl.removed) {
57-
return
57+
return true
5858
}
5959
if (!decl.isVariableDeclarator() && !decl.isFunctionDeclaration()) {
60-
return
60+
return true
6161
}
6262
binding.path.remove()
63+
return true
6364
}
6465

6566
function deAntiToolingCheckFunc(path) {
@@ -845,9 +846,6 @@ function insertDepItemVar(deps, name, path) {
845846
*/
846847
function findGlobalFn(path) {
847848
const glo_fn_name = path.node.id?.name
848-
if (path.parentPath.getFunctionParent()) {
849-
return null
850-
}
851849
if (!glo_fn_name) {
852850
return null
853851
}
@@ -1197,7 +1195,10 @@ const deStringConcealing = {
11971195
FunctionDeclaration(path) {
11981196
const obj = findGlobalFn(path)
11991197
if (!obj) {
1200-
return
1198+
return null
1199+
}
1200+
if (obj.glo_fn_path.parentPath.getFunctionParent()) {
1201+
return null
12011202
}
12021203
findGlobalFnRef(obj)
12031204
if (!findBufferToString(obj)) {
@@ -1239,6 +1240,26 @@ function tryStringConcealingPlace(path) {
12391240
}
12401241

12411242
const deStringConcealingPlace = {
1243+
StringLiteral(path) {
1244+
if (path.key !== 'right' || !path.parentPath.isAssignmentExpression()) {
1245+
return
1246+
}
1247+
const name = safeGetName(path.parentPath.get('left'))
1248+
if (!name) {
1249+
return
1250+
}
1251+
const binding = path.scope.getBinding(name)
1252+
if (binding.constantViolations.length !== 1) {
1253+
return
1254+
}
1255+
for (const ref of binding.referencePaths) {
1256+
if (ref.node.start < path.node.start) {
1257+
continue
1258+
}
1259+
ref.replaceWith(path.node)
1260+
}
1261+
safeDeleteNode(name, path.parentPath)
1262+
},
12421263
ArrayExpression(path) {
12431264
let valid = true
12441265
if (path.node.elements.length === 0) {
@@ -1414,6 +1435,125 @@ const deOpaquePredicates = {
14141435
},
14151436
}
14161437

1438+
function findGlobalVar(glo_name, glo_path) {
1439+
let tmp_path = glo_path.parentPath.getFunctionParent()
1440+
if (
1441+
!tmp_path ||
1442+
!tmp_path.parentPath.isMemberExpression() ||
1443+
!tmp_path.parentPath.parentPath.isCallExpression()
1444+
) {
1445+
return null
1446+
}
1447+
const tmp_body = tmp_path.node.body.body
1448+
tmp_path = tmp_path.parentPath.parentPath
1449+
const ret_node = tmp_body[tmp_body.length - 1]
1450+
if (
1451+
!t.isReturnStatement(ret_node) ||
1452+
!t.isAssignmentExpression(ret_node.argument)
1453+
) {
1454+
return null
1455+
}
1456+
const code = generator(ret_node.argument.right).code
1457+
const template = `${glo_name}call(this)`
1458+
if (!checkPattern(code, template)) {
1459+
return null
1460+
}
1461+
const glo_var = ret_node.argument.left.name
1462+
const binding = glo_path.scope.getBinding(glo_var)
1463+
for (const ref of binding.referencePaths) {
1464+
if (
1465+
!ref.parentPath.isMemberExpression() ||
1466+
!ref.parentPath.parentPath.isReturnStatement()
1467+
) {
1468+
continue
1469+
}
1470+
const func_path = ref.getFunctionParent()
1471+
const func_name = func_path.node.id.name
1472+
return {
1473+
glo_var: glo_var,
1474+
tmp_path: tmp_path,
1475+
glo_fn_name: func_name,
1476+
glo_fn_path: func_path,
1477+
}
1478+
}
1479+
return null
1480+
}
1481+
1482+
function getGlobalConcealingNames(glo_fn_path) {
1483+
const obj = {}
1484+
glo_fn_path.traverse({
1485+
SwitchCase(path) {
1486+
const key = parseInt(generator(path.node.test).code)
1487+
let consequent = path.node.consequent[0]
1488+
if (t.isReturnStatement(consequent)) {
1489+
obj[key] = consequent.argument.property.value
1490+
} else {
1491+
if (t.isExpressionStatement(consequent)) {
1492+
consequent = consequent.expression
1493+
}
1494+
obj[key] = consequent.right.left.value
1495+
}
1496+
},
1497+
})
1498+
return obj
1499+
}
1500+
1501+
/**
1502+
* Hide the global vars found by module GlobalAnalysis
1503+
*
1504+
* Template:
1505+
* ```javascript
1506+
* // Add to head:
1507+
* var globalVar, tempVar = function () {
1508+
* getGlobalVariableFnName = createGetGlobalTemplate()
1509+
* return globalVar = getGlobalVariableFnName.call(this)
1510+
* }["call"]()
1511+
* // Add to foot:
1512+
* function globalFn (indexParamName) {
1513+
* var returnName
1514+
* switch (indexParamName) {
1515+
* case state_x: {
1516+
* return globalVar[name]
1517+
* }
1518+
* case state_y: {
1519+
* returnName = name || globalVar[name]
1520+
* break
1521+
* }
1522+
* }
1523+
* return globalVar[returnName]
1524+
* }
1525+
* // References:
1526+
* // name -> globalFn(state)
1527+
* ```
1528+
*/
1529+
const deGlobalConcealing = {
1530+
FunctionDeclaration(path) {
1531+
const glo_obj = findGlobalFn(path)
1532+
if (!glo_obj) {
1533+
return null
1534+
}
1535+
const obj = findGlobalVar(glo_obj.glo_fn_name, glo_obj.glo_fn_path)
1536+
if (!obj) {
1537+
return null
1538+
}
1539+
console.log(`[GlobalConcealing] globalVar: ${obj.glo_var}`)
1540+
const glo_vars = getGlobalConcealingNames(obj.glo_fn_path)
1541+
console.log(`[GlobalConcealing] globalFn: ${obj.glo_fn_name}`)
1542+
let binding = obj.glo_fn_path.parentPath.scope.getBinding(obj.glo_fn_name)
1543+
for (const ref of binding.referencePaths) {
1544+
const repl_path = ref.parentPath
1545+
if (ref.key !== 'callee' || !repl_path.isCallExpression()) {
1546+
continue
1547+
}
1548+
const key = parseInt(generator(repl_path.node.arguments[0]).code)
1549+
repl_path.replaceWith(t.identifier(glo_vars[key]))
1550+
}
1551+
if (safeDeleteNode(obj.glo_fn_name, obj.glo_fn_path)) {
1552+
obj.tmp_path.remove()
1553+
}
1554+
},
1555+
}
1556+
14171557
module.exports = function (code) {
14181558
let ast
14191559
try {
@@ -1442,6 +1582,8 @@ module.exports = function (code) {
14421582
traverse(ast, deOpaquePredicates)
14431583
traverse(ast, calculateConstantExp)
14441584
traverse(ast, pruneIfBranch)
1585+
// GlobalConcealing
1586+
traverse(ast, deGlobalConcealing)
14451587
code = generator(ast, {
14461588
comments: false,
14471589
jsescOption: { minimal: true },

0 commit comments

Comments
 (0)