Skip to content

Commit f1011fd

Browse files
committed
Fix #88
1 parent df3d954 commit f1011fd

File tree

2 files changed

+114
-0
lines changed

2 files changed

+114
-0
lines changed

src/transforms/stack.ts

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { walk } from "../traverse";
66
import {
77
AssignmentExpression,
88
BinaryExpression,
9+
CallExpression,
910
ExpressionStatement,
1011
Identifier,
1112
IfStatement,
@@ -18,6 +19,7 @@ import {
1819
} from "../util/gen";
1920
import { getIdentifierInfo } from "../util/identifiers";
2021
import {
22+
computeFunctionLength,
2123
getBlockBody,
2224
getDefiningContext,
2325
getReferencingContexts,
@@ -28,10 +30,14 @@ import {
2830
} from "../util/insert";
2931
import { chance, choice, getRandomInteger } from "../util/random";
3032
import Transform from "./transform";
33+
import { noRenameVariablePrefix } from "../constants";
34+
import { FunctionLengthTemplate } from "../templates/functionLength";
3135

3236
export default class Stack extends Transform {
3337
mangledExpressionsMade: number;
3438

39+
functionLengthName: string;
40+
3541
constructor(o) {
3642
super(o, ObfuscateOrder.Stack);
3743

@@ -111,8 +117,14 @@ export default class Stack extends Transform {
111117
});
112118

113119
var startingSize = subscripts.size;
120+
var isIllegal = false;
114121

115122
walk(object.body, [object, ...parents], (o, p) => {
123+
if (o.type === "Identifier" && o.name === "arguments") {
124+
isIllegal = true;
125+
return "EXIT";
126+
}
127+
116128
if (o.type == "Identifier") {
117129
var info = getIdentifierInfo(o, p);
118130
if (!info.spec.isReferenced || info.spec.isExported) {
@@ -128,6 +140,10 @@ export default class Stack extends Transform {
128140
illegal.add(o.name);
129141
}
130142

143+
if (o.name.startsWith(noRenameVariablePrefix)) {
144+
illegal.add(o.name);
145+
}
146+
131147
if (
132148
info.isClauseParameter ||
133149
info.isFunctionParameter ||
@@ -200,6 +216,8 @@ export default class Stack extends Transform {
200216
}
201217
});
202218

219+
if (isIllegal) return;
220+
203221
illegal.forEach((name) => {
204222
defined.delete(name);
205223
referenced.delete(name);
@@ -467,6 +485,9 @@ export default class Stack extends Transform {
467485
object.body.body.splice(parseInt(index) + i, 0, rotateNodes[index]);
468486
});
469487

488+
// Preserve function.length property
489+
var originalFunctionLength = computeFunctionLength(object.params);
490+
470491
// Set the params for this function to be the stack array
471492
object.params = [RestElement(Identifier(stackName))];
472493

@@ -475,6 +496,47 @@ export default class Stack extends Transform {
475496
object.body,
476497
Template(`${stackName}["length"] = ${startingSize}`).single()
477498
);
499+
500+
if (originalFunctionLength !== 0) {
501+
if (!this.functionLengthName) {
502+
this.functionLengthName = this.getPlaceholder();
503+
prepend(
504+
parents[parents.length - 1] || object,
505+
FunctionLengthTemplate.single({ name: this.functionLengthName })
506+
);
507+
}
508+
509+
if (object.type === "FunctionDeclaration") {
510+
var body = parents[0];
511+
if (Array.isArray(body)) {
512+
var index = body.indexOf(object);
513+
514+
body.splice(
515+
index,
516+
0,
517+
ExpressionStatement(
518+
CallExpression(Identifier(this.functionLengthName), [
519+
Identifier(object.id.name),
520+
Literal(originalFunctionLength),
521+
])
522+
)
523+
);
524+
}
525+
} else {
526+
ok(
527+
object.type === "FunctionExpression" ||
528+
object.type === "ArrowFunctionExpression"
529+
);
530+
531+
this.replace(
532+
object,
533+
CallExpression(Identifier(this.functionLengthName), [
534+
{ ...object },
535+
Literal(originalFunctionLength),
536+
])
537+
);
538+
}
539+
}
478540
};
479541
}
480542
}

test/transforms/stack.test.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -519,3 +519,55 @@ test("Variant #16: Function with 'this'", async () => {
519519

520520
expect(TEST_OUTPUT).toStrictEqual(true);
521521
});
522+
523+
// https://github.com/MichaelXF/js-confuser/issues/88
524+
test("Variant #17: Syncing arguments parameter", async () => {
525+
var output = await JsConfuser(
526+
`
527+
var TEST_OUTPUT;
528+
529+
function syncingArguments(parameter) {
530+
arguments[0] = "Correct Value";
531+
TEST_OUTPUT = parameter;
532+
}
533+
534+
syncingArguments("Incorrect Value");
535+
`,
536+
{ target: "node", stack: true }
537+
);
538+
539+
function evalNoStrictMode(evalCode) {
540+
var fn = new Function(evalCode + ";return TEST_OUTPUT");
541+
return fn();
542+
}
543+
544+
var TEST_OUTPUT = evalNoStrictMode(output);
545+
546+
expect(TEST_OUTPUT).toStrictEqual("Correct Value");
547+
});
548+
549+
test("Variant #18: Preserve function.length property", async () => {
550+
var output = await JsConfuser(
551+
`
552+
function oneParameter(a){
553+
var _ = 1;
554+
};
555+
var twoParameters = function(a,b){
556+
var _ = 1;
557+
};
558+
var myObject = {
559+
threeParameters(a,b,c){
560+
var _ = 1;
561+
}
562+
}
563+
564+
TEST_OUTPUT = oneParameter.length + twoParameters.length + myObject.threeParameters.length;
565+
`,
566+
{ target: "node", stack: true }
567+
);
568+
569+
var TEST_OUTPUT;
570+
eval(output);
571+
572+
expect(TEST_OUTPUT).toStrictEqual(6);
573+
});

0 commit comments

Comments
 (0)