Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1.7.1 #109

Merged
merged 7 commits into from
Jul 23, 2023
Merged

1.7.1 #109

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,22 @@
# `1.7.1`
Updates

- Fixed [#107](https://github.com/MichaelXF/js-confuser/issues/107)
- - RGF and Integrity clash issue fixed

- Fixed [#106](https://github.com/MichaelXF/js-confuser/issues/106)
- - Object Extraction to properly handle `const` objects

- Fixed [#105](https://github.com/MichaelXF/js-confuser/issues/105)
- - Duplicate Literals Removal updated to not cause this error

- Fixed [#103](https://github.com/MichaelXF/js-confuser/issues/103)
- - Dispatcher will no longer apply to these types of functions to prevent this error

- Added documentation page for [ES5](https://github.com/MichaelXF/js-confuser/blob/master/docs/ES5.md)

- Rollup Plugin created: https://github.com/ayecue/rollup-js-confuser (Thanks @ayecue !)

# `1.7.0`
Updates

Expand Down
2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -737,7 +737,6 @@ function iVQoGQD(...iVQoGQD){
stringSplitting: 0.75,

// Use at own risk
eval: false,
rgf: false
}
```
Expand Down Expand Up @@ -828,7 +827,6 @@ These features are experimental or a security concern.
```js
{
target: "node",
eval: true, // (security concern)
rgf: true, // (security concern)

// set to false for web-related scripts
Expand Down
2 changes: 1 addition & 1 deletion docs/ControlFlowFlattening.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ while (mJMdMhJ + A1Nyvv + xDwpOk6 != 83) {
}
```

As seen in the example, your code will bee wrapped in a large, complicated switch statement. The makes the behavior of your program very hard to understand and is resistent to deobfuscators. This comes with a large performance reduction.
As seen in the example, your code will be wrapped in a large, complicated switch statement. The makes the behavior of your program very hard to understand and is resistent to deobfuscators. This comes with a large performance reduction.

## Flattening Control Structures

Expand Down
197 changes: 197 additions & 0 deletions docs/ES5.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
## `ES5`

The ES5 option converts most ES6+ features into ES5 compatible code.

Option name: `es5`

Option values: `true/false`

Note: Does not cover all cases such as Promises or Generator functions. Use [Babel](https://babel.dev/).

The ES5 option is intended to undo any ES6 feature the obfuscator adds to your code. If you input ES5 code, and enable the `es5` option, you can be guaranteed to have ES5 compatible output.

## Example

```js
// Input
function print(...messages){
console.log(...messages); // The spread operator (...)
// was introduced in ES6!
}

print("Hello", "World"); // "Hello World"

// Output
var __p_2580918143;
function print() {
var __p_7607361496;
var messages, __p_2591841272 = (__p_7607361496 = Array.prototype.slice.call(arguments), messages = __p_7607361496.slice(0));
(__p_2580918143 = console).log.apply(__p_2580918143, [].concat(Array.prototype.slice.call(messages)));
}
print('Hello', 'World'); // "Hello World"
```

## Polyfill Array Methods

When the ES5 option is enabled, array method polyfills will be injected to the top of your script.

```js
if (!Array.prototype.forEach) {
Array.prototype.forEach = function forEach(callback, thisArg) {
if (typeof callback !== 'function') {
throw new TypeError(callback + ' is not a function');
}
var array = this;
thisArg = thisArg || this;
for (var i = 0, l = array.length; i !== l; ++i) {
callback.call(thisArg, array[i], i, array);
}
};
}
```

## Destructuring

The ES5 option supports transpiling the destructuring patterns.

```js
// Input
var {userName, email} = { userName: "John", email: "[email protected]" };

// Output
var __p_7467473759;
var userName, email, __p_4755992742 = (__p_7467473759 = {
userName: 'John',
email: '[email protected]'
}, userName = __p_7467473759.userName, email = __p_7467473759.email);
```

## Spread Operator

The ES5 option supports transpiling the spread operator.

```js
// Input
array.push(...objects);

// Output
var __p_6344935930;
(__p_6344935930 = array).push.apply(__p_6344935930, [].concat(Array.prototype.slice.call(objects)));
```

## Template String

The ES5 option supports transpiling template strings.

```js
// Input
var myString = `Hello ${userName}`;

// Output
var myString = 'Hello ' + (userName + '');
```

## Object getters/setters

The ES5 option supports transpiling getter and setter methods.

```js
// Input
var _name;
var myObject = {
get name(){
return _name;
},
set name(newName){
_name = newName;
}
};

// Output
function __p_6886881506(base, computedProps, getters, setters) {
for (var i = 0; i < computedProps.length; i++) {
base[computedProps[i][0]] = computedProps[i][1];
}
var keys = Object.create(null);
Object.keys(getters).forEach(function (key) {
return keys[key] = 1;
});
Object.keys(setters).forEach(function (key) {
return keys[key] = 1;
});
Object.keys(keys).forEach(function (key) {
Object.defineProperty(base, key, {
set: setters[key],
get: getters[key],
configurable: true
});
});
return base;
}
var _name;
var myObject = __p_6886881506({}, [], {
'name': function () {
return _name;
}
}, {
'name': function (newName) {
_name = newName;
}
});
```

## Arrow Functions

The ES5 option converts arrow functions into regular functions.

```js
// Input
var print = message => console.log(message);

// Output
var print = function (message) {
return console.log(message);
};
```

## Const/Let

The ES5 option converts `const` and `let` to a regular `var` keyword.

```js
// Input
let myVar1 = true;
const myVar2 = "String";

// Output
var myVar1 = true;
var myVar2 = 'String';
```

## Classes

The ES5 option partially supports transpiling classes.

## Reserved Identifiers

The ES5 option will change any illegal uses of reserved identifiers.

```js
// Input
var myObject = {true: 1};
myObject.for = true;

// Output
var myObject = {"true": 1};
myObject["for"] = true;
```

## Features not supported

- Promises
- Async / Await
- Generator functions
- Nullish coalescing
- Optional chaining

Use [Babel](https://babel.dev/) to transpile these features. JS-Confuser will only support features the obfuscator may potentially add to your code.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "js-confuser",
"version": "1.7.0",
"version": "1.7.1",
"description": "JavaScript Obfuscation Tool.",
"main": "dist/index.js",
"types": "index.d.ts",
Expand All @@ -22,7 +22,7 @@
"author": "MichaelXF",
"license": "MIT",
"dependencies": {
"acorn": "^8.8.2",
"acorn": "^8.10.0",
"escodegen": "^2.0.0"
},
"devDependencies": {
Expand Down
10 changes: 10 additions & 0 deletions src/transforms/dispatcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,16 @@ export default class Dispatcher extends Transform {
return "EXIT";
}
}

// Avoid functions with function expressions as they have a different scope
if (
(oo.type === "FunctionExpression" ||
oo.type === "ArrowFunctionExpression") &&
pp.find((x) => x == o.params)
) {
illegalFnNames.add(name);
return "EXIT";
}
});

functionDeclarations[name] = [o, p];
Expand Down
6 changes: 5 additions & 1 deletion src/transforms/extraction/duplicateLiteralsRemoval.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { ComputeProbabilityMap } from "../../probability";
import { ok } from "assert";
import { chance, choice, getRandomInteger } from "../../util/random";
import { getBlock } from "../../traverse";
import { getIdentifierInfo } from "../../util/identifiers";

/**
* [Duplicate Literals Removal](https://docs.jscrambler.com/code-integrity/documentation/transformations/duplicate-literals-removal) replaces duplicate literals with a variable name.
Expand Down Expand Up @@ -221,7 +222,10 @@ export default class DuplicateLiteralsRemoval extends Transform {

transform(object: Node, parents: Node[]) {
return () => {
var value = object.value;
if (object.type === "Identifier") {
var info = getIdentifierInfo(object, parents);
if (info.isLabel || info.spec.isDefined) return;
}
if (object.regex) {
return;
}
Expand Down
4 changes: 4 additions & 0 deletions src/transforms/extraction/objectExtraction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,10 @@ export default class ObjectExtraction extends Transform {
...variableDeclarators
);

if (declaration.kind === "const") {
declaration.kind = "var";
}

// update all identifiers that pointed to the old object
objectDefChanges[name] &&
objectDefChanges[name].forEach((change) => {
Expand Down
9 changes: 9 additions & 0 deletions src/transforms/rgf.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
} from "../util/gen";
import { getIdentifierInfo } from "../util/identifiers";
import { prepend, getDefiningContext } from "../util/insert";
import Integrity from "./lock/integrity";
import Transform from "./transform";

/**
Expand Down Expand Up @@ -200,6 +201,14 @@ export default class RGF extends Transform {

if (obfuscator.options.lock) {
delete obfuscator.options.lock.countermeasures;

// Integrity will not recursively apply to RGF'd functions. This is intended.
var lockTransform = obfuscator.transforms["Lock"];
if (lockTransform) {
lockTransform.before = lockTransform.before.filter(
(beforeTransform) => !(beforeTransform instanceof Integrity)
);
}
}

var transforms = obfuscator.array.filter(
Expand Down
9 changes: 6 additions & 3 deletions src/util/identifiers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,14 @@ export function getIdentifierInfo(object: Node, parents: Node[]) {
parents.find((x) => x.type == "VariableDeclaration") &&
objectPatternCheck(object, parents);

var functionIndex = parents.findIndex((x) => isFunction(x));

// Assignment pattern check!
if (isVariableDeclaration) {
var slicedParents = parents.slice(0, varIndex - 1);
var slicedParents = parents.slice(
0,
functionIndex != -1 ? Math.min(varIndex, functionIndex) : varIndex
);
var i = 0;
for (var parent of slicedParents) {
var childNode = slicedParents[i - 1] || object;
Expand All @@ -113,8 +118,6 @@ export function getIdentifierInfo(object: Node, parents: Node[]) {
forIndex != -1 &&
parents[forIndex].init == (parents[forIndex - 1] || object);

var functionIndex = parents.findIndex((x) => isFunction(x));

var isFunctionDeclaration =
functionIndex != -1 &&
parents[functionIndex].type == "FunctionDeclaration" &&
Expand Down
27 changes: 27 additions & 0 deletions test/transforms/dispatcher.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -373,3 +373,30 @@ test("Variant #16: Don't change functions that use 'eval'", async () => {

expect(TEST_OUTPUT).toStrictEqual(2);
});

// https://github.com/MichaelXF/js-confuser/issues/103
test("Variant #17: Don't break default parameter, function expression", async () => {
var output = await JsConfuser(
`
var X = "Correct Value";

function printX(
getX = function () {
return X;
}
) {
var X = "Incorrect Value";

TEST_OUTPUT = getX();
}

printX();
`,
{ target: "node", dispatcher: true }
);

var TEST_OUTPUT;
eval(output);

expect(TEST_OUTPUT).toStrictEqual("Correct Value");
});
Loading
Loading