Added class scope sanitizing

This commit is contained in:
sanex3339
2020-01-27 20:11:40 +03:00
parent 5ccb690f65
commit c0117912c1
10 changed files with 266 additions and 25 deletions
+4
View File
@@ -1,5 +1,9 @@
Change Log
v0.24.1
---
* Fixed https://github.com/javascript-obfuscator/javascript-obfuscator/issues/531
v0.24.0
---
* **Internal refactoring:** completely new mechanism to rename variable names
+3 -3
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "javascript-obfuscator",
"version": "0.24.0",
"version": "0.24.1",
"description": "JavaScript obfuscator",
"keywords": [
"obfuscator",
@@ -132,6 +132,35 @@ export class ScopeAnalyzer implements IScopeAnalyzer {
throw new Error('Cannot acquire scope for node');
}
this.sanitizeScopes(scope);
return scope;
}
/**
* @param {Scope} scope
*/
private sanitizeScopes (scope: eslintScope.Scope): void {
scope.childScopes.forEach((childScope: eslintScope.Scope) => {
// fix of class scopes
// trying to move class scope references to the parent scope
if (childScope.type === 'class' && childScope.upper) {
const upperVariable: eslintScope.Variable | undefined = childScope.upper.variables
.find((variable: eslintScope.Variable) => {
// class name variable is always first
const classNameVariable: eslintScope.Variable = childScope.variables[0];
const isValidClassNameVariable: boolean = classNameVariable.defs
.some((definition: eslintScope.Definition) => definition.type === 'ClassName');
return isValidClassNameVariable && variable.name === classNameVariable.name;
});
upperVariable?.references.push(...childScope.variables[0].references);
}
});
for (const childScope of scope.childScopes) {
this.sanitizeScopes(childScope);
}
}
}
+23 -4
View File
@@ -7,13 +7,32 @@ import { NO_ADDITIONAL_NODES_PRESET } from '../../src/options/presets/NoCustomNo
let obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
`
var passthrough = value => value;
var foo = 1, bar = {baz: passthrough(foo)}
class A {
foo() {
return A;
}
bar() {
var A = 1;
return A;
}
}
console.log(A);
function foo () {
class B {
foo() {
return B;
}
}
console.log(B);
}
`,
{
...NO_ADDITIONAL_NODES_PRESET,
compact: false,
transformObjectKeys: true
compact: false
}
).getObfuscatedCode();
@@ -38,28 +38,107 @@ describe('ScopeIdentifiersTransformer ClassDeclaration identifiers', () => {
describe('Variant #2: `classDeclaration` parent block scope is a `ProgramNode`', () => {
describe('Variant #1: `renameGlobals` option is disabled', () => {
const classNameIdentifierRegExp: RegExp = /class *Foo *\{/;
const classCallIdentifierRegExp: RegExp = /new *Foo *\( *\);/;
describe('Variant #1: base', () => {
const classNameIdentifierRegExp: RegExp = /class *Foo *\{/;
const classCallIdentifierRegExp: RegExp = /new *Foo *\( *\);/;
let obfuscatedCode: string;
let obfuscatedCode: string;
before(() => {
const code: string = readFileAsString(__dirname + '/fixtures/parent-block-scope-is-program-node.js');
before(() => {
const code: string = readFileAsString(__dirname + '/fixtures/parent-block-scope-is-program-node.js');
obfuscatedCode = JavaScriptObfuscator.obfuscate(
code,
{
...NO_ADDITIONAL_NODES_PRESET
}
).getObfuscatedCode();
obfuscatedCode = JavaScriptObfuscator.obfuscate(
code,
{
...NO_ADDITIONAL_NODES_PRESET
}
).getObfuscatedCode();
});
it('match #1: shouldn\'t transform class name', () => {
assert.match(obfuscatedCode, classNameIdentifierRegExp);
});
it('match #2: shouldn\'t transform class name', () => {
assert.match(obfuscatedCode, classCallIdentifierRegExp);
});
});
it('match #1: shouldn\'t transform class name', () => {
assert.match(obfuscatedCode, classNameIdentifierRegExp);
describe('Variant #2: correct class name references in global scope', () => {
const classNameIdentifierRegExp: RegExp = /class A *\{/;
const outerClassNameReferenceRegExp: RegExp = /console\['log']\(A\);/;
const innerClassNameReferenceRegExp: RegExp = /return A;/;
let obfuscatedCode: string;
before(() => {
const code: string = readFileAsString(__dirname + '/fixtures/class-name-references-global-scope.js');
obfuscatedCode = JavaScriptObfuscator.obfuscate(
code,
{
...NO_ADDITIONAL_NODES_PRESET
}
).getObfuscatedCode();
});
it('match #1: shouldn\'t transform class name', () => {
assert.match(obfuscatedCode, classNameIdentifierRegExp);
});
it('match #2: shouldn\'t transform class name reference outside of class', () => {
assert.match(obfuscatedCode, outerClassNameReferenceRegExp);
});
it('match #3: shouldn\'t transform class name reference inside class', () => {
assert.match(obfuscatedCode, innerClassNameReferenceRegExp);
});
});
it('match #2: shouldn\'t transform class name', () => {
assert.match(obfuscatedCode, classCallIdentifierRegExp);
describe('Variant #3: correct class name references in function scope', () => {
const classNameIdentifierRegExp: RegExp = /class (_0x[a-f0-9]{4,6}) *\{/;
const outerClassNameReferenceRegExp: RegExp = /console\['log']\((_0x[a-f0-9]{4,6})\);/;
const innerClassNameReferenceRegExp: RegExp = /return (_0x[a-f0-9]{4,6});/;
let obfuscatedCode: string;
let classNameIdentifier: string;
let outerClassNameReferenceIdentifierName: string;
let innerClassNameReferenceIdentifierName: string;
before(() => {
const code: string = readFileAsString(__dirname + '/fixtures/class-name-references-function-scope.js');
obfuscatedCode = JavaScriptObfuscator.obfuscate(
code,
{
...NO_ADDITIONAL_NODES_PRESET
}
).getObfuscatedCode();
classNameIdentifier = getRegExpMatch(obfuscatedCode, classNameIdentifierRegExp);
outerClassNameReferenceIdentifierName = getRegExpMatch(obfuscatedCode, outerClassNameReferenceRegExp);
innerClassNameReferenceIdentifierName = getRegExpMatch(obfuscatedCode, innerClassNameReferenceRegExp);
});
it('match #1: should transform class name', () => {
assert.match(obfuscatedCode, classNameIdentifierRegExp);
});
it('match #2: should transform class name reference outside of class', () => {
assert.match(obfuscatedCode, outerClassNameReferenceRegExp);
});
it('match #3: should transform class name reference inside class', () => {
assert.match(obfuscatedCode, innerClassNameReferenceRegExp);
});
it('match #4: should generate same identifier names for class name and outer class name reference', () => {
assert.equal(classNameIdentifier, outerClassNameReferenceIdentifierName);
});
it('match #5: should generate same identifier names for class name and inner class name reference', () => {
assert.equal(classNameIdentifier, innerClassNameReferenceIdentifierName);
});
});
});
@@ -117,6 +196,100 @@ describe('ScopeIdentifiersTransformer ClassDeclaration identifiers', () => {
assert.match(obfuscatedCode, identifierRegExp2);
});
});
describe('Variant #3: correct class name references in global scope', () => {
const classNameIdentifierRegExp: RegExp = /class (_0x[a-f0-9]{4,6}) *\{/;
const outerClassNameReferenceRegExp: RegExp = /console\['log']\((_0x[a-f0-9]{4,6})\);/;
const innerClassNameReferenceRegExp: RegExp = /return (_0x[a-f0-9]{4,6});/;
let obfuscatedCode: string;
let classNameIdentifier: string;
let outerClassNameReferenceIdentifierName: string;
let innerClassNameReferenceIdentifierName: string;
before(() => {
const code: string = readFileAsString(__dirname + '/fixtures/class-name-references-global-scope.js');
obfuscatedCode = JavaScriptObfuscator.obfuscate(
code,
{
...NO_ADDITIONAL_NODES_PRESET,
renameGlobals: true
}
).getObfuscatedCode();
classNameIdentifier = getRegExpMatch(obfuscatedCode, classNameIdentifierRegExp);
outerClassNameReferenceIdentifierName = getRegExpMatch(obfuscatedCode, outerClassNameReferenceRegExp);
innerClassNameReferenceIdentifierName = getRegExpMatch(obfuscatedCode, innerClassNameReferenceRegExp);
});
it('match #1: should transform class name', () => {
assert.match(obfuscatedCode, classNameIdentifierRegExp);
});
it('match #2: should transform class name reference outside of class', () => {
assert.match(obfuscatedCode, outerClassNameReferenceRegExp);
});
it('match #3: should transform class name reference inside class', () => {
assert.match(obfuscatedCode, innerClassNameReferenceRegExp);
});
it('match #4: should generate same identifier names for class name and outer class name reference', () => {
assert.equal(classNameIdentifier, outerClassNameReferenceIdentifierName);
});
it('match #5: should generate same identifier names for class name and inner class name reference', () => {
assert.equal(classNameIdentifier, innerClassNameReferenceIdentifierName);
});
});
describe('Variant #4: correct class name references in function scope', () => {
const classNameIdentifierRegExp: RegExp = /class (_0x[a-f0-9]{4,6}) *\{/;
const outerClassNameReferenceRegExp: RegExp = /console\['log']\((_0x[a-f0-9]{4,6})\);/;
const innerClassNameReferenceRegExp: RegExp = /return (_0x[a-f0-9]{4,6});/;
let obfuscatedCode: string;
let classNameIdentifier: string;
let outerClassNameReferenceIdentifierName: string;
let innerClassNameReferenceIdentifierName: string;
before(() => {
const code: string = readFileAsString(__dirname + '/fixtures/class-name-references-function-scope.js');
obfuscatedCode = JavaScriptObfuscator.obfuscate(
code,
{
...NO_ADDITIONAL_NODES_PRESET,
renameGlobals: true
}
).getObfuscatedCode();
classNameIdentifier = getRegExpMatch(obfuscatedCode, classNameIdentifierRegExp);
outerClassNameReferenceIdentifierName = getRegExpMatch(obfuscatedCode, outerClassNameReferenceRegExp);
innerClassNameReferenceIdentifierName = getRegExpMatch(obfuscatedCode, innerClassNameReferenceRegExp);
});
it('match #1: should transform class name', () => {
assert.match(obfuscatedCode, classNameIdentifierRegExp);
});
it('match #2: should transform class name reference outside of class', () => {
assert.match(obfuscatedCode, outerClassNameReferenceRegExp);
});
it('match #3: should transform class name reference inside class', () => {
assert.match(obfuscatedCode, innerClassNameReferenceRegExp);
});
it('match #4: should generate same identifier names for class name and outer class name reference', () => {
assert.equal(classNameIdentifier, outerClassNameReferenceIdentifierName);
});
it('match #5: should generate same identifier names for class name and inner class name reference', () => {
assert.equal(classNameIdentifier, innerClassNameReferenceIdentifierName);
});
});
});
});
@@ -0,0 +1,9 @@
function foo () {
class B {
foo() {
return B;
}
}
console.log(B);
}