| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214 | import { assert } from 'chai';import { IObfuscationResult } from '../../../../src/interfaces/IObfuscationResult';import { NO_CUSTOM_NODES_PRESET } from '../../../../src/options/presets/NoCustomNodes';import { readFileAsString } from '../../../helpers/readFileAsString';import { JavaScriptObfuscator } from '../../../../src/JavaScriptObfuscator';describe('DeadCodeInjectionTransformer', () => {    const variableMatch: string = '_0x([a-f0-9]){4,6}';    const hexMatch: string = '0x[a-f0-9]';    describe('transformNode (programNode: ESTree.Program, parentNode: ESTree.Node): ESTree.Node', () => {        describe('variant #1 - 5 simple block statements', () => {            const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(                readFileAsString(__dirname + '/fixtures/input-1.js'),                {                    ...NO_CUSTOM_NODES_PRESET,                    deadCodeInjection: true,                    deadCodeInjectionThreshold: 1,                    stringArray: true,                    stringArrayThreshold: 1                }            );            const obfuscatedCode: string = obfuscationResult.getObfuscatedCode();            const deadCodeMatch: string = `` +                `if *\\(${variableMatch}\\('${hexMatch}'\\) *[=|!]== *${variableMatch}\\('${hexMatch}'\\)\\) *\\{`+                    `console\\[${variableMatch}\\('${hexMatch}'\\)\\]\\(${variableMatch}\\('${hexMatch}'\\)\\);` +                `\\} *else *\\{`+                    `console\\[${variableMatch}\\('${hexMatch}'\\)\\]\\(${variableMatch}\\('${hexMatch}'\\)\\);` +                `\\}` +            ``;            const regexp: RegExp = new RegExp(deadCodeMatch, 'g');            const matches: RegExpMatchArray = <RegExpMatchArray>obfuscatedCode.match(regexp);            it('should replace block statements with condition with original block statements and dead code', () => {                assert.isNotNull(matches);                assert.equal(matches.length, 5);            });        });        describe('variant #2 - 4 simple block statements', () => {            const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(                readFileAsString(__dirname + '/fixtures/block-statements-min-count.js'),                {                    ...NO_CUSTOM_NODES_PRESET,                    deadCodeInjection: true,                    deadCodeInjectionThreshold: 1,                    stringArray: true,                    stringArrayThreshold: 1                }            );            const obfuscatedCode: string = obfuscationResult.getObfuscatedCode();            const codeMatch: string = `` +                `var *${variableMatch} *= *function *\\(\\) *\\{` +                    `console\\[${variableMatch}\\('${hexMatch}'\\)\\]\\(${variableMatch}\\('${hexMatch}'\\)\\);` +                `\\};` +            ``;            const regexp: RegExp = new RegExp(codeMatch, 'g');            const matches: RegExpMatchArray = <RegExpMatchArray>obfuscatedCode.match(regexp);            it('shouldn\'t add dead code if block statements count is less than 5', () => {                assert.isNotNull(matches);                assert.equal(matches.length, 4);            });        });        describe('variant #3 - deadCodeInjectionThreshold: 0', () => {            const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(                readFileAsString(__dirname + '/fixtures/input-1.js'),                {                    ...NO_CUSTOM_NODES_PRESET,                    deadCodeInjection: true,                    deadCodeInjectionThreshold: 0,                    stringArray: true,                    stringArrayThreshold: 1                }            );            const obfuscatedCode: string = obfuscationResult.getObfuscatedCode();            const codeMatch: string = `` +                `var *${variableMatch} *= *function *\\(\\) *\\{` +                    `console\\[${variableMatch}\\('${hexMatch}'\\)\\]\\(${variableMatch}\\('${hexMatch}'\\)\\);` +                `\\};` +            ``;            const regexp: RegExp = new RegExp(codeMatch, 'g');            const matches: RegExpMatchArray = <RegExpMatchArray>obfuscatedCode.match(regexp);            it('shouldn\'t add dead code if `deadCodeInjectionThreshold` option value is `0`', () => {                assert.isNotNull(matches);                assert.equal(matches.length, 5);            });        });        describe('variant #4 - break or continue statement in block statement', () => {            const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(                readFileAsString(__dirname + '/fixtures/break-continue-statement.js'),                {                    ...NO_CUSTOM_NODES_PRESET,                    deadCodeInjection: true,                    deadCodeInjectionThreshold: 1,                    stringArray: true,                    stringArrayThreshold: 1                }            );            const obfuscatedCode: string = obfuscationResult.getObfuscatedCode();            const functionMatch: string = `` +                `var *${variableMatch} *= *function *\\(\\) *\\{` +                    `console\\[${variableMatch}\\('${hexMatch}'\\)\\]\\(${variableMatch}\\('${hexMatch}'\\)\\);` +                `\\};` +            ``;            const loopMatch: string = `` +                `for *\\(var *${variableMatch} *= *${hexMatch}; *${variableMatch} *< *${hexMatch}; *${variableMatch}\\+\\+\\) *\\{` +                    `(?:continue|break);` +                `\\}` +            ``;            const functionRegExp: RegExp = new RegExp(functionMatch, 'g');            const loopRegExp: RegExp = new RegExp(loopMatch, 'g');            const functionMatches: RegExpMatchArray = <RegExpMatchArray>obfuscatedCode.match(functionRegExp);            const loopMatches: RegExpMatchArray = <RegExpMatchArray>obfuscatedCode.match(loopRegExp);            it('shouldn\'t add dead code if block statement contains `continue` or `break` statements', () => {                assert.isNotNull(functionMatches);                assert.isNotNull(loopMatches);                assert.equal(functionMatches.length, 4);                assert.equal(loopMatches.length, 2);            });        });        describe('variant #5 - chance of `IfStatement` variant', () => {            const samplesCount: number = 1000;            const delta: number = 0.1;            const expectedValue: number = 0.25;            const ifMatch: string = `if *\\(!!\\[\\]\\) *\\{`;            const functionMatch: string = `var *${variableMatch} *= *function *\\(\\) *\\{`;            const match1: string = `` +                `if *\\(${variableMatch}\\('${hexMatch}'\\) *=== *${variableMatch}\\('${hexMatch}'\\)\\) *\\{` +                    `console.*` +                `\\} *else *\\{` +                    `${variableMatch}.*` +                `\\}` +            ``;            const match2: string = `` +                `if *\\(${variableMatch}\\('${hexMatch}'\\) *!== *${variableMatch}\\('${hexMatch}'\\)\\) *\\{` +                    `console.*` +                `\\} *else *\\{` +                    `${variableMatch}.*` +                `\\}` +            ``;            const match3: string = `` +                `if *\\(${variableMatch}\\('${hexMatch}'\\) *=== *${variableMatch}\\('${hexMatch}'\\)\\) *\\{` +                    `${variableMatch}.*` +                `\\} *else *\\{` +                    `console.*` +                `\\}` +            ``;            const match4: string = `` +                `if *\\(${variableMatch}\\('${hexMatch}'\\) *!== *${variableMatch}\\('${hexMatch}'\\)\\) *\\{` +                    `${variableMatch}.*` +                `\\} *else *\\{` +                    `console.*` +                `\\}` +            ``;            const regExp1: RegExp = new RegExp(`${ifMatch}${functionMatch}${match1}`);            const regExp2: RegExp = new RegExp(`${ifMatch}${functionMatch}${match2}`);            const regExp3: RegExp = new RegExp(`${ifMatch}${functionMatch}${match3}`);            const regExp4: RegExp = new RegExp(`${ifMatch}${functionMatch}${match4}`);            let count1: number = 0;            let count2: number = 0;            let count3: number = 0;            let count4: number = 0;            for (let i = 0; i < samplesCount; i++) {                const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(                    readFileAsString(__dirname + '/fixtures/if-statement-variants-distribution.js'),                    {                        ...NO_CUSTOM_NODES_PRESET,                        deadCodeInjection: true,                        deadCodeInjectionThreshold: 1,                        stringArray: true,                        stringArrayThreshold: 1                    }                );                const obfuscatedCode: string = obfuscationResult.getObfuscatedCode();                if (regExp1.test(obfuscatedCode)) {                    count1++;                } else if (regExp2.test(obfuscatedCode)) {                    count2++;                } else if (regExp3.test(obfuscatedCode)) {                    count3++;                } else if (regExp4.test(obfuscatedCode)) {                    count4++;                }            }            it('each of four `IfStatement` variant should have distribution close to `0.25`', () => {                assert.closeTo(count1 / samplesCount, expectedValue, delta);                assert.closeTo(count2 / samplesCount, expectedValue, delta);                assert.closeTo(count3 / samplesCount, expectedValue, delta);                assert.closeTo(count4 / samplesCount, expectedValue, delta);            });        });    });});
 |