Skip to content

Commit 48663b3

Browse files
committed
split code
1 parent cc97a64 commit 48663b3

File tree

13 files changed

+1890
-1708
lines changed

13 files changed

+1890
-1708
lines changed

src/plugin/jsconfuser.js

Lines changed: 25 additions & 1708 deletions
Large diffs are not rendered by default.

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
Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
const safeFunc = require('../../utility/safe-func')
2+
const safeGetLiteral = safeFunc.safeGetLiteral
3+
const safeGetName = safeFunc.safeGetName
4+
const safeReplace = safeFunc.safeReplace
5+
6+
function checkControlVar(path) {
7+
const parent = path.parentPath
8+
if (path.key !== 'right' || !parent.isAssignmentExpression()) {
9+
return false
10+
}
11+
const var_path = parent.get('left')
12+
const var_name = var_path.node?.name
13+
if (!var_name) {
14+
return false
15+
}
16+
let root_path = parent.parentPath
17+
if (root_path.isExpressionStatement) {
18+
root_path = root_path.parentPath
19+
}
20+
const binding = parent.scope.getBinding(var_name)
21+
for (const ref of binding.referencePaths) {
22+
if (ref === var_path) {
23+
continue
24+
}
25+
let cur = ref
26+
let valid = false
27+
while (cur && cur !== root_path) {
28+
if (cur.isSwitchCase() || cur === path) {
29+
valid = true
30+
break
31+
}
32+
cur = cur.parentPath
33+
}
34+
if (!valid) {
35+
return false
36+
}
37+
if (ref.key === 'object') {
38+
const prop = ref.parentPath.get('property')
39+
if (!prop.isLiteral() && !prop.isIdentifier()) {
40+
return false
41+
}
42+
continue
43+
}
44+
if (ref.key === 'right') {
45+
const left = ref.parentPath.get('left')
46+
if (!left.isMemberExpression()) {
47+
return false
48+
}
49+
const obj = safeGetName(left.get('object'))
50+
if (obj !== var_name) {
51+
return false
52+
}
53+
continue
54+
}
55+
}
56+
return true
57+
}
58+
59+
/**
60+
* Process the constant properties in the controlVar
61+
*
62+
* Template:
63+
* ```javascript
64+
* controlVar = {
65+
* // strings
66+
* key_string: 'StringLiteral',
67+
* // numbers
68+
* key_number: 'NumericLiteral',
69+
* }
70+
* ```
71+
*
72+
* Some kinds of deadCode may in inserted to the fake chunks:
73+
*
74+
* ```javascript
75+
* controlVar = false
76+
* controlVar = undefined
77+
* controlVar[randomControlKey] = undefined
78+
* delete controlVar[randomControlKey]
79+
* ```
80+
*/
81+
const deControlFlowFlatteningStateless = {
82+
ObjectExpression(path) {
83+
if (!checkControlVar(path)) {
84+
return
85+
}
86+
const parent = path.parentPath
87+
const var_name = parent.get('left').node?.name
88+
console.log(`[ControlFlowFlattening] parse stateless in obj: ${var_name}`)
89+
const props = {}
90+
const prop_num = path.node.properties.length
91+
for (let i = 0; i < prop_num; ++i) {
92+
const prop = path.get(`properties.${i}`)
93+
const key = safeGetName(prop.get('key'))
94+
const value = safeGetLiteral(prop.get('value'))
95+
if (!key || !value) {
96+
continue
97+
}
98+
props[key] = value
99+
}
100+
const binding = parent.scope.getBinding(var_name)
101+
for (const ref of binding.referencePaths) {
102+
if (ref.key !== 'object') {
103+
continue
104+
}
105+
const prop = safeGetName(ref.parentPath.get('property'))
106+
if (!prop) {
107+
continue
108+
}
109+
if (!Object.prototype.hasOwnProperty.call(props, prop)) {
110+
continue
111+
}
112+
const upper = ref.parentPath
113+
if (upper.key === 'left' && upper.parentPath.isAssignmentExpression()) {
114+
// this is in the fake chunk
115+
ref.parentPath.parentPath.remove()
116+
continue
117+
}
118+
safeReplace(ref.parentPath, props[prop])
119+
}
120+
binding.scope.crawl()
121+
},
122+
}
123+
124+
/**
125+
*
126+
* Template:
127+
* ```javascript
128+
* flaggedLabels = {
129+
* currentLabel: { flagKey: 'xxx', flagValue : 'true or false' }
130+
* }
131+
* labelToStates[chunk[i].label] = stateValues: [] => caseStates[i]
132+
* initStateValues = labelToStates[startLabel]
133+
* endState
134+
* chunks = [
135+
* {
136+
* body: [
137+
* {
138+
* type: "GotoStatement",
139+
* label: "END_LABEL",
140+
* }
141+
* ],
142+
* }
143+
* {
144+
* label: "END_LABEL",
145+
* body: [],
146+
* }
147+
* ]
148+
* while (stateVars) {
149+
* switch (stateVars) {
150+
* // fake assignment expression
151+
* case fake_assignment: {
152+
* stateVar = 'rand'
153+
* // 'GotoStatement label'
154+
* }
155+
* // clone chunks
156+
* case fake_clone: {
157+
* // contain a real chunk
158+
* }
159+
* // fake jumps
160+
* case real_1: {
161+
* if (false) {
162+
* // 'GotoStatement label'
163+
* }
164+
* // follow with real statements
165+
* }
166+
* }
167+
* }
168+
* The key may exist in its parent's map
169+
* ```
170+
*/
171+
const deControlFlowFlatteningState = {
172+
ObjectExpression(path) {
173+
if (!checkControlVar(path)) {
174+
return
175+
}
176+
},
177+
}
178+
179+
module.exports = {
180+
deControlFlowFlatteningStateless,
181+
deControlFlowFlatteningState,
182+
}

0 commit comments

Comments
 (0)