Jelajahi Sumber

`reservedStrings` option

sanex3339 6 tahun lalu
induk
melakukan
4aff0ec046

+ 4 - 0
CHANGELOG.md

@@ -1,5 +1,9 @@
 Change Log
 Change Log
 ===
 ===
+v0.18.0
+---
+* **New option:** `reservedStrings` disables transformation of string literals, which being matched by passed RegExp patterns
+
 v0.17.1
 v0.17.1
 ---
 ---
 * Fixed https://github.com/javascript-obfuscator/javascript-obfuscator/issues/293
 * Fixed https://github.com/javascript-obfuscator/javascript-obfuscator/issues/293

+ 18 - 0
README.md

@@ -297,6 +297,7 @@ Following options are available for the JS Obfuscator:
     log: false,
     log: false,
     renameGlobals: false,
     renameGlobals: false,
     reservedNames: [],
     reservedNames: [],
+    reservedStrings: [],
     rotateStringArray: true,
     rotateStringArray: true,
     seed: 0,
     seed: 0,
     selfDefending: false,
     selfDefending: false,
@@ -336,6 +337,7 @@ Following options are available for the JS Obfuscator:
     --log <boolean>
     --log <boolean>
     --rename-globals <boolean>
     --rename-globals <boolean>
     --reserved-names '<list>' (comma separated)
     --reserved-names '<list>' (comma separated)
+    --reserved-strings '<list>' (comma separated)
     --rotate-string-array <boolean>
     --rotate-string-array <boolean>
     --seed <number>
     --seed <number>
     --self-defending <boolean>
     --self-defending <boolean>
@@ -633,6 +635,22 @@ Example:
 	}
 	}
 ```
 ```
 
 
+### `reservedStrings`
+Type: `string[]` Default: `[]`
+
+Disables transformation of string literals, which being matched by passed RegExp patterns.
+
+Example:
+```ts
+	{
+		reservedStrings: [
+			'react-native',
+			'\.\/src\/test',
+			'some-string_\d'
+		]
+	}
+```
+
 ### `rotateStringArray`
 ### `rotateStringArray`
 Type: `boolean` Default: `true`
 Type: `boolean` Default: `true`
 
 

File diff ditekan karena terlalu besar
+ 0 - 0
dist/index.browser.js


File diff ditekan karena terlalu besar
+ 0 - 0
dist/index.cli.js


File diff ditekan karena terlalu besar
+ 0 - 0
dist/index.js


+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "javascript-obfuscator",
   "name": "javascript-obfuscator",
-  "version": "0.17.1",
+  "version": "0.18.0",
   "description": "JavaScript obfuscator",
   "description": "JavaScript obfuscator",
   "keywords": [
   "keywords": [
     "obfuscator",
     "obfuscator",

+ 5 - 0
src/cli/JavaScriptObfuscatorCLI.ts

@@ -268,6 +268,11 @@ export class JavaScriptObfuscatorCLI implements IInitializable {
                 'Disables obfuscation and generation of identifiers, which being matched by passed RegExp patterns (comma separated)',
                 'Disables obfuscation and generation of identifiers, which being matched by passed RegExp patterns (comma separated)',
                 ArraySanitizer
                 ArraySanitizer
             )
             )
+            .option(
+                '--reserved-strings <list> (comma separated, without whitespaces)',
+                'Disables transformation of string literals, which being matched by passed RegExp patterns (comma separated)',
+                ArraySanitizer
+            )
             .option(
             .option(
                 '--rename-globals <boolean>', 'Allows to enable obfuscation of global variable and function names with declaration.',
                 '--rename-globals <boolean>', 'Allows to enable obfuscation of global variable and function names with declaration.',
                 BooleanSanitizer
                 BooleanSanitizer

+ 1 - 1
src/cli/sanitizers/ArraySanitizer.ts

@@ -6,7 +6,7 @@ import { TCLISanitizer } from '../../types/cli/TCLISanitizer';
  */
  */
 export const ArraySanitizer: TCLISanitizer <string[]> = (value: string): string[] => {
 export const ArraySanitizer: TCLISanitizer <string[]> = (value: string): string[] => {
     if (/,$/.test(value)) {
     if (/,$/.test(value)) {
-        throw new SyntaxError(`Multiple <list> values should be wrapped inside quotes: --option-name 'value1, value2'`);
+        throw new SyntaxError(`Multiple <list> values should be wrapped inside quotes: --option-name 'value1','value2'`);
     }
     }
 
 
     return value.split(',').map((string: string) => string.trim());
     return value.split(',').map((string: string) => string.trim());

+ 1 - 0
src/interfaces/options/IOptions.d.ts

@@ -20,6 +20,7 @@ export interface IOptions {
     readonly log: boolean;
     readonly log: boolean;
     readonly renameGlobals: boolean;
     readonly renameGlobals: boolean;
     readonly reservedNames: string[];
     readonly reservedNames: string[];
+    readonly reservedStrings: string[];
     readonly rotateStringArray: boolean;
     readonly rotateStringArray: boolean;
     readonly seed: number;
     readonly seed: number;
     readonly selfDefending: boolean;
     readonly selfDefending: boolean;

+ 23 - 7
src/node-transformers/obfuscating-transformers/LiteralTransformer.ts

@@ -15,6 +15,7 @@ import { TransformationStage } from '../../enums/node-transformers/Transformatio
 import { AbstractNodeTransformer } from '../AbstractNodeTransformer';
 import { AbstractNodeTransformer } from '../AbstractNodeTransformer';
 import { NodeGuards } from '../../node/NodeGuards';
 import { NodeGuards } from '../../node/NodeGuards';
 import { NodeMetadata } from '../../node/NodeMetadata';
 import { NodeMetadata } from '../../node/NodeMetadata';
+import { NodeUtils } from '../../node/NodeUtils';
 
 
 @injectable()
 @injectable()
 export class LiteralTransformer extends AbstractNodeTransformer {
 export class LiteralTransformer extends AbstractNodeTransformer {
@@ -69,22 +70,37 @@ export class LiteralTransformer extends AbstractNodeTransformer {
             return literalNode;
             return literalNode;
         }
         }
 
 
+        let newLiteralNode: ESTree.Node;
+
         switch (typeof literalNode.value) {
         switch (typeof literalNode.value) {
             case 'boolean':
             case 'boolean':
-                return this.literalObfuscatingReplacerFactory(LiteralObfuscatingReplacer.BooleanLiteralObfuscatingReplacer)
-                    .replace(<boolean>literalNode.value);
+                newLiteralNode = this.literalObfuscatingReplacerFactory(
+                    LiteralObfuscatingReplacer.BooleanLiteralObfuscatingReplacer
+                ).replace(<boolean>literalNode.value);
+
+                break;
 
 
             case 'number':
             case 'number':
-                return this.literalObfuscatingReplacerFactory(LiteralObfuscatingReplacer.NumberLiteralObfuscatingReplacer)
-                    .replace(<number>literalNode.value);
+                newLiteralNode = this.literalObfuscatingReplacerFactory(
+                    LiteralObfuscatingReplacer.NumberLiteralObfuscatingReplacer
+                ).replace(<number>literalNode.value);
+
+                break;
 
 
             case 'string':
             case 'string':
-                return this.literalObfuscatingReplacerFactory(LiteralObfuscatingReplacer.StringLiteralObfuscatingReplacer)
-                    .replace(<string>literalNode.value);
+                newLiteralNode = this.literalObfuscatingReplacerFactory(
+                    LiteralObfuscatingReplacer.StringLiteralObfuscatingReplacer
+                ).replace(<string>literalNode.value);
+
+                break;
 
 
             default:
             default:
-                return literalNode;
+                newLiteralNode = literalNode;
         }
         }
+
+        NodeUtils.parentizeNode(newLiteralNode, parentNode);
+
+        return newLiteralNode;
     }
     }
 
 
     /**
     /**

+ 4 - 0
src/node-transformers/obfuscating-transformers/obfuscating-replacers/identifier-obfuscating-replacers/BaseIdentifierObfuscatingReplacer.ts

@@ -107,6 +107,10 @@ export class BaseIdentifierObfuscatingReplacer extends AbstractObfuscatingReplac
      * @returns {boolean}
      * @returns {boolean}
      */
      */
     private isReservedName (name: string): boolean {
     private isReservedName (name: string): boolean {
+        if (!this.options.reservedStrings.length) {
+            return false;
+        }
+
         return this.options.reservedNames
         return this.options.reservedNames
             .some((reservedName: string) => {
             .some((reservedName: string) => {
                 return new RegExp(reservedName, 'g').exec(name) !== null;
                 return new RegExp(reservedName, 'g').exec(name) !== null;

+ 19 - 0
src/node-transformers/obfuscating-transformers/obfuscating-replacers/literal-obfuscating-replacers/StringLiteralObfuscatingReplacer.ts

@@ -133,6 +133,10 @@ export class StringLiteralObfuscatingReplacer extends AbstractObfuscatingReplace
      * @returns {Node}
      * @returns {Node}
      */
      */
     public replace (nodeValue: string): ESTree.Node {
     public replace (nodeValue: string): ESTree.Node {
+        if (this.isReservedString(nodeValue)) {
+            return NodeFactory.literalNode(nodeValue);
+        }
+
         const useStringArray: boolean = this.canUseStringArray(nodeValue);
         const useStringArray: boolean = this.canUseStringArray(nodeValue);
         const cacheKey: string = `${nodeValue}-${String(useStringArray)}`;
         const cacheKey: string = `${nodeValue}-${String(useStringArray)}`;
         const useCacheValue: boolean = this.nodesCache.has(cacheKey) && this.options.stringArrayEncoding !== StringArrayEncoding.Rc4;
         const useCacheValue: boolean = this.nodesCache.has(cacheKey) && this.options.stringArrayEncoding !== StringArrayEncoding.Rc4;
@@ -263,4 +267,19 @@ export class StringLiteralObfuscatingReplacer extends AbstractObfuscatingReplace
             callExpressionArgs
             callExpressionArgs
         );
         );
     }
     }
+
+    /**
+     * @param {string} value
+     * @returns {boolean}
+     */
+    private isReservedString (value: string): boolean {
+        if (!this.options.reservedStrings.length) {
+            return false;
+        }
+
+        return this.options.reservedStrings
+            .some((reservedString: string) => {
+                return new RegExp(reservedString, 'g').exec(value) !== null;
+            });
+    }
 }
 }

+ 10 - 0
src/options/Options.ts

@@ -146,6 +146,16 @@ export class Options implements IOptions {
     })
     })
     public readonly reservedNames!: string[];
     public readonly reservedNames!: string[];
 
 
+    /**
+     * @type {string[]}
+     */
+    @IsArray()
+    @ArrayUnique()
+    @IsString({
+        each: true
+    })
+    public readonly reservedStrings!: string[];
+
     /**
     /**
      * @type {boolean}
      * @type {boolean}
      */
      */

+ 1 - 0
src/options/presets/Default.ts

@@ -22,6 +22,7 @@ export const DEFAULT_PRESET: TInputOptions = Object.freeze({
     log: false,
     log: false,
     renameGlobals: false,
     renameGlobals: false,
     reservedNames: [],
     reservedNames: [],
+    reservedStrings: [],
     rotateStringArray: true,
     rotateStringArray: true,
     seed: 0,
     seed: 0,
     selfDefending: false,
     selfDefending: false,

+ 1 - 0
src/options/presets/NoCustomNodes.ts

@@ -21,6 +21,7 @@ export const NO_ADDITIONAL_NODES_PRESET: TInputOptions = Object.freeze({
     log: false,
     log: false,
     renameGlobals: false,
     renameGlobals: false,
     reservedNames: [],
     reservedNames: [],
+    reservedStrings: [],
     rotateStringArray: false,
     rotateStringArray: false,
     seed: 0,
     seed: 0,
     selfDefending: false,
     selfDefending: false,

+ 155 - 0
test/functional-tests/node-transformers/obfuscating-transformers/literal-transformer/LiteralTransformer.spec.ts

@@ -315,6 +315,161 @@ describe('LiteralTransformer', () => {
                 assert.match(obfuscatedCode, regExp);
                 assert.match(obfuscatedCode, regExp);
             });
             });
         });
         });
+
+        describe('Variant #12: `reservedNames` option is enabled', () => {
+            describe('Variant #1: base `reservedStrings` values', () => {
+                describe('Variant #1: single reserved string value', () => {
+                    const stringLiteralRegExp1: RegExp = /const foo *= *'foo';/;
+                    const stringLiteralRegExp2: RegExp = /const bar *= *_0x([a-f0-9]){4}\('0x0'\);/;
+
+                    let obfuscatedCode: string;
+
+                    before(() => {
+                        const code: string = readFileAsString(__dirname + '/fixtures/reserved-strings-option.js');
+                        const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
+                            code,
+                            {
+                                ...NO_ADDITIONAL_NODES_PRESET,
+                                stringArray: true,
+                                stringArrayThreshold: 1,
+                                reservedStrings: ['foo']
+                            }
+                        );
+
+                        obfuscatedCode = obfuscationResult.getObfuscatedCode();
+                    });
+
+                    it('match #1: should ignore reserved strings', () => {
+                        assert.match(obfuscatedCode, stringLiteralRegExp1);
+                    });
+
+                    it('match #2: should transform non-reserved strings', () => {
+                        assert.match(obfuscatedCode, stringLiteralRegExp2);
+                    });
+                });
+
+                describe('Variant #2: two reserved string values', () => {
+                    const stringLiteralRegExp1: RegExp = /const foo *= *'foo';/;
+                    const stringLiteralRegExp2: RegExp = /const bar *= *'bar';/;
+
+                    let obfuscatedCode: string;
+
+                    before(() => {
+                        const code: string = readFileAsString(__dirname + '/fixtures/reserved-strings-option.js');
+                        const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
+                            code,
+                            {
+                                ...NO_ADDITIONAL_NODES_PRESET,
+                                stringArray: true,
+                                stringArrayThreshold: 1,
+                                reservedStrings: ['foo', 'bar']
+                            }
+                        );
+
+                        obfuscatedCode = obfuscationResult.getObfuscatedCode();
+                    });
+
+                    it('match #1: should ignore reserved strings', () => {
+                        assert.match(obfuscatedCode, stringLiteralRegExp1);
+                    });
+
+                    it('match #2: should ignore reserved strings', () => {
+                        assert.match(obfuscatedCode, stringLiteralRegExp2);
+                    });
+                });
+            });
+
+            describe('Variant #2: RegExp `reservedStrings` values', () => {
+                describe('Variant #1: single reserved string value', () => {
+                    const stringLiteralRegExp1: RegExp = /const foo *= *_0x([a-f0-9]){4}\('0x0'\);/;
+                    const stringLiteralRegExp2: RegExp = /const bar *= *'bar';/;
+
+                    let obfuscatedCode: string;
+
+                    before(() => {
+                        const code: string = readFileAsString(__dirname + '/fixtures/reserved-strings-option.js');
+                        const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
+                            code,
+                            {
+                                ...NO_ADDITIONAL_NODES_PRESET,
+                                stringArray: true,
+                                stringArrayThreshold: 1,
+                                reservedStrings: ['ar$']
+                            }
+                        );
+
+                        obfuscatedCode = obfuscationResult.getObfuscatedCode();
+                    });
+
+                    it('match #1: should transform non-reserved strings', () => {
+                        assert.match(obfuscatedCode, stringLiteralRegExp1);
+                    });
+
+                    it('match #2: should ignore reserved strings', () => {
+                        assert.match(obfuscatedCode, stringLiteralRegExp2);
+                    });
+                });
+
+                describe('Variant #2: two reserved string values', () => {
+                    const stringLiteralRegExp1: RegExp = /const foo *= *'foo';/;
+                    const stringLiteralRegExp2: RegExp = /const bar *= *'bar';/;
+
+                    let obfuscatedCode: string;
+
+                    before(() => {
+                        const code: string = readFileAsString(__dirname + '/fixtures/reserved-strings-option.js');
+                        const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
+                            code,
+                            {
+                                ...NO_ADDITIONAL_NODES_PRESET,
+                                stringArray: true,
+                                stringArrayThreshold: 1,
+                                reservedStrings: ['^fo', '.ar']
+                            }
+                        );
+
+                        obfuscatedCode = obfuscationResult.getObfuscatedCode();
+                    });
+
+                    it('match #1: should ignore reserved strings', () => {
+                        assert.match(obfuscatedCode, stringLiteralRegExp1);
+                    });
+
+                    it('match #2: should ignore reserved strings', () => {
+                        assert.match(obfuscatedCode, stringLiteralRegExp2);
+                    });
+                });
+            });
+
+            describe('Variant #3: `unicodeEscapeSequence` option is enabled', () => {
+                const stringLiteralRegExp1: RegExp = /const foo *= *'foo';/;
+                const stringLiteralRegExp2: RegExp = /const bar *= *'\\x62\\x61\\x72';/;
+
+                let obfuscatedCode: string;
+
+                before(() => {
+                    const code: string = readFileAsString(__dirname + '/fixtures/reserved-strings-option.js');
+                    const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
+                        code,
+                        {
+                            ...NO_ADDITIONAL_NODES_PRESET,
+                            reservedStrings: ['foo'],
+                            unicodeEscapeSequence: true
+                        }
+                    );
+
+                    obfuscatedCode = obfuscationResult.getObfuscatedCode();
+                });
+
+                it('match #1: should ignore reserved strings', () => {
+                    assert.match(obfuscatedCode, stringLiteralRegExp1);
+                });
+
+                it('match #2: should transform non-reserved strings', () => {
+                    assert.match(obfuscatedCode, stringLiteralRegExp2);
+                });
+            });
+        });
     });
     });
 
 
     describe('transformation of literal node with boolean value', () => {
     describe('transformation of literal node with boolean value', () => {

+ 2 - 0
test/functional-tests/node-transformers/obfuscating-transformers/literal-transformer/fixtures/reserved-strings-option.js

@@ -0,0 +1,2 @@
+const foo = 'foo';
+const bar = 'bar';

Beberapa file tidak ditampilkan karena terlalu banyak file yang berubah dalam diff ini