Skip to content

Commit 3cbed50

Browse files
committed
split code (+17 squashed commits)
Squashed commits: [cc97a64] Stack update [799dd70] ControlFlowFlattening part1 [fefcebc] StringConcealing [cfd3688] StringConcealing and GlobalConcealing [4fb343d] StringConcealing and OpaquePredicates [d5b5d5a] OpaquePredicates prepare [7a606fe] StringSplitting [37170a3] Stack update [40f5fb1] StringConcealing main [862f40c] Stack update [465eed6] StringConcealing prepare [8cb190a] Stack update [6ae5e14] StringCompression [8f5c6fa] DuplicateLiteralsRemoval [b1b2f50] Stack functionLengthName [61f7001] Minify arrowFunctionName [11408a6] AntiTooling
1 parent 9e0a60b commit 3cbed50

File tree

14 files changed

+1928
-0
lines changed

14 files changed

+1928
-0
lines changed

src/main.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import fs from 'fs'
22
import PluginCommon from './plugin/common.js'
33
import PluginJjencode from './plugin/jjencode.js'
4+
import PluginJsconfuser from './plugin/jsconfuser.js'
45
import PluginSojson from './plugin/sojson.js'
56
import PluginSojsonV7 from './plugin/sojsonv7.js'
67
import PluginObfuscator from './plugin/obfuscator.js'
@@ -41,6 +42,8 @@ const main = () => {
4142
code = PluginAwsc(sourceCode)
4243
} else if (type === 'jjencode') {
4344
code = PluginJjencode(sourceCode)
45+
} else if (type === 'jsconfuser') {
46+
code = PluginJsconfuser(sourceCode)
4447
} else {
4548
code = PluginCommon(sourceCode)
4649
}

src/plugin/jsconfuser.js

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
const { parse } = require('@babel/parser')
2+
const generator = require('@babel/generator').default
3+
const traverse = require('@babel/traverse').default
4+
5+
const calculateConstantExp = require('../visitor/calculate-constant-exp')
6+
const pruneIfBranch = require('../visitor/prune-if-branch')
7+
const jcAntiTooling = require('../visitor/jsconfuser/anti-tooling')
8+
const jcControlFlow = require('../visitor/jsconfuser/control-flow')
9+
const jcDuplicateLiteral = require('../visitor/jsconfuser/duplicate-literal')
10+
const jcGlobalConcealing = require('../visitor/jsconfuser/global-concealing')
11+
const jcMinifyInit = require('../visitor/jsconfuser/minify')
12+
const jcOpaquePredicates = require('../visitor/jsconfuser/opaque-predicates')
13+
const jcStackInit = require('../visitor/jsconfuser/stack')
14+
const jcStringCompression = require('../visitor/jsconfuser/string-compression')
15+
const jcStringConceal = require('../visitor/jsconfuser/string-concealing')
16+
17+
module.exports = function (code) {
18+
let ast
19+
try {
20+
ast = parse(code, { errorRecovery: true })
21+
} catch (e) {
22+
console.error(`Cannot parse code: ${e.reasonCode}`)
23+
return null
24+
}
25+
// AntiTooling
26+
traverse(ast, jcAntiTooling)
27+
// Minify
28+
const jcMinify = jcMinifyInit()
29+
traverse(ast, jcMinify.deMinifyArrow)
30+
// DuplicateLiteralsRemoval
31+
traverse(ast, jcDuplicateLiteral)
32+
// Stack
33+
const jcStack = jcStackInit(jcMinify.arrowFunc)
34+
traverse(ast, jcStack.deStackFuncLen)
35+
traverse(ast, jcStack.deStackFuncOther)
36+
// StringCompression
37+
traverse(ast, jcStringCompression)
38+
// StringConcealing
39+
traverse(ast, jcStringConceal.deStringConcealing)
40+
traverse(ast, jcStringConceal.deStringConcealingPlace)
41+
// StringSplitting
42+
traverse(ast, calculateConstantExp)
43+
// Stack (run again)
44+
traverse(ast, jcStack.deStackFuncOther)
45+
// OpaquePredicates
46+
traverse(ast, jcOpaquePredicates)
47+
traverse(ast, calculateConstantExp)
48+
traverse(ast, pruneIfBranch)
49+
// GlobalConcealing
50+
traverse(ast, jcGlobalConcealing)
51+
// ControlFlowFlattening
52+
traverse(ast, jcControlFlow.deControlFlowFlatteningStateless)
53+
traverse(ast, calculateConstantExp)
54+
// ExpressionObfuscation
55+
code = generator(ast, {
56+
comments: false,
57+
jsescOption: { minimal: true },
58+
}).code
59+
return code
60+
}

src/utility/check-func.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
function checkPattern(code, pattern) {
2+
let i = 0
3+
let j = 0
4+
while (i < code.length && j < pattern.length) {
5+
if (code[i] == pattern[j]) {
6+
++j
7+
}
8+
++i
9+
}
10+
return j == pattern.length
11+
}
12+
13+
module.exports = {
14+
checkPattern,
15+
}

src/utility/safe-func.js

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
const t = require('@babel/types')
2+
3+
function safeDeleteNode(name, path) {
4+
let binding
5+
if (path.isFunctionDeclaration()) {
6+
binding = path.parentPath.scope.getBinding(name)
7+
} else {
8+
binding = path.scope.getBinding(name)
9+
}
10+
if (!binding) {
11+
return false
12+
}
13+
binding.scope.crawl()
14+
binding = binding.scope.getBinding(name)
15+
if (binding.references) {
16+
return false
17+
}
18+
for (const item of binding.constantViolations) {
19+
item.remove()
20+
}
21+
const decl = binding.path
22+
if (decl.removed) {
23+
return true
24+
}
25+
if (!decl.isVariableDeclarator() && !decl.isFunctionDeclaration()) {
26+
return true
27+
}
28+
binding.path.remove()
29+
return true
30+
}
31+
32+
function safeGetLiteral(path) {
33+
if (path.isUnaryExpression()) {
34+
if (path.node.operator === '-' && path.get('argument').isNumericLiteral()) {
35+
return -1 * path.get('argument').node.value
36+
}
37+
return null
38+
}
39+
if (path.isLiteral()) {
40+
return path.node.value
41+
}
42+
return null
43+
}
44+
45+
function safeGetName(path) {
46+
if (path.isIdentifier()) {
47+
return path.node.name
48+
}
49+
if (path.isLiteral()) {
50+
return path.node.value
51+
}
52+
return null
53+
}
54+
55+
function safeReplace(path, value) {
56+
if (typeof value === 'string') {
57+
path.replaceWith(t.stringLiteral(value))
58+
return
59+
}
60+
if (typeof value === 'number') {
61+
path.replaceWith(t.numericLiteral(value))
62+
return
63+
}
64+
path.replaceWithSourceString(value)
65+
}
66+
67+
module.exports = {
68+
safeDeleteNode,
69+
safeGetLiteral,
70+
safeGetName,
71+
safeReplace,
72+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
const t = require('@babel/types')
2+
3+
function deAntiToolingCheckFunc(path) {
4+
if (path.node.params.length) {
5+
return false
6+
}
7+
const body = path.node.body
8+
if (!t.isBlockStatement(body)) {
9+
return false
10+
}
11+
if (body.body.length) {
12+
return false
13+
}
14+
return true
15+
}
16+
17+
function deAntiToolingExtract(path, func_name) {
18+
let binding = path.scope.getBinding(func_name)
19+
for (let ref of binding.referencePaths) {
20+
if (!ref.parentPath.isCallExpression() || !ref.key === 'callee') {
21+
continue
22+
}
23+
const call = ref.parentPath
24+
if (!call.listKey === 'body') {
25+
continue
26+
}
27+
for (let node of call.node.arguments) {
28+
call.insertBefore(node)
29+
}
30+
call.remove()
31+
}
32+
binding.scope.crawl()
33+
binding = path.scope.getBinding(func_name)
34+
if (binding.references === 0) {
35+
path.remove()
36+
}
37+
}
38+
39+
const deAntiTooling = {
40+
FunctionDeclaration(path) {
41+
const func_name = path.node.id?.name
42+
if (!func_name) {
43+
return
44+
}
45+
if (!deAntiToolingCheckFunc(path)) {
46+
return
47+
}
48+
console.log(`AntiTooling Func Name: ${func_name}`)
49+
deAntiToolingExtract(path, func_name)
50+
},
51+
}
52+
53+
module.exports = deAntiTooling

0 commit comments

Comments
 (0)