diff --git a/CHANGELOG.md b/CHANGELOG.md index ef3cad90..94cea206 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ Change Log +v4.0.0 +--- +* **Breaking change:** `debugProtectionInteraval` option now accepts value in milliseconds instead of `boolean` value. Fixed https://github.com/javascript-obfuscator/javascript-obfuscator/issues/1031 + v3.2.7 --- * Fixed cases when dead code is added to the inner code of `eval` expressions. Fixed https://github.com/javascript-obfuscator/javascript-obfuscator/issues/1053 diff --git a/README.md b/README.md index e8d19298..19b21fea 100644 --- a/README.md +++ b/README.md @@ -349,7 +349,7 @@ Following options are available for the JS Obfuscator: deadCodeInjection: false, deadCodeInjectionThreshold: 0.4, debugProtection: false, - debugProtectionInterval: false, + debugProtectionInterval: 0, disableConsoleOutput: false, domainLock: [], domainLockRedirectUrl: 'about:blank', @@ -413,7 +413,7 @@ Following options are available for the JS Obfuscator: --dead-code-injection --dead-code-injection-threshold --debug-protection - --debug-protection-interval + --debug-protection-interval --disable-console-output --domain-lock '' (comma separated) --domain-lock-redirect-url @@ -678,11 +678,11 @@ Type: `boolean` Default: `false` This option makes it almost impossible to use the `debugger` function of the Developer Tools (both on WebKit-based and Mozilla Firefox). ### `debugProtectionInterval` -Type: `boolean` Default: `false` +Type: `number` Default: `0` ##### :warning: Can freeze your browser! Use at own risk. -If checked, an interval is used to force the debug mode on the Console tab, making it harder to use other features of the Developer Tools. Works if [`debugProtection`](#debugprotection) is enabled. +If set, an interval in milliseconds is used to force the debug mode on the Console tab, making it harder to use other features of the Developer Tools. Works if [`debugProtection`](#debugprotection) is enabled. Recommended value is between `2000` and `4000` milliseconds. ### `disableConsoleOutput` Type: `boolean` Default: `false` @@ -1507,7 +1507,7 @@ The performance will be much slower than without obfuscation deadCodeInjection: true, deadCodeInjectionThreshold: 1, debugProtection: true, - debugProtectionInterval: true, + debugProtectionInterval: 4000, disableConsoleOutput: true, identifierNamesGenerator: 'hexadecimal', log: false, @@ -1545,7 +1545,7 @@ The performance will be slower than without obfuscation deadCodeInjection: true, deadCodeInjectionThreshold: 0.4, debugProtection: false, - debugProtectionInterval: false, + debugProtectionInterval: 0, disableConsoleOutput: true, identifierNamesGenerator: 'hexadecimal', log: false, @@ -1582,7 +1582,7 @@ The performance will be at a relatively normal level controlFlowFlattening: false, deadCodeInjection: false, debugProtection: false, - debugProtectionInterval: false, + debugProtectionInterval: 0, disableConsoleOutput: true, identifierNamesGenerator: 'hexadecimal', log: false, @@ -1614,7 +1614,7 @@ The performance will be at a relatively normal level controlFlowFlattening: false, deadCodeInjection: false, debugProtection: false, - debugProtectionInterval: false, + debugProtectionInterval: 0, disableConsoleOutput: false, identifierNamesGenerator: 'hexadecimal', log: false, diff --git a/package.json b/package.json index 0b635739..40cda55b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "javascript-obfuscator", - "version": "3.2.7", + "version": "4.0.0", "description": "JavaScript obfuscator", "keywords": [ "obfuscator", diff --git a/src/cli/JavaScriptObfuscatorCLI.ts b/src/cli/JavaScriptObfuscatorCLI.ts index cc9428eb..2a10bd11 100644 --- a/src/cli/JavaScriptObfuscatorCLI.ts +++ b/src/cli/JavaScriptObfuscatorCLI.ts @@ -223,9 +223,9 @@ export class JavaScriptObfuscatorCLI implements IInitializable { BooleanSanitizer ) .option( - '--debug-protection-interval ', - 'Disable browser Debug panel even after page was loaded (can cause DevTools enabled browser freeze)', - BooleanSanitizer + '--debug-protection-interval ', + 'Sets interval in milliseconds for debug protection so it is working even after page was loaded (can cause DevTools enabled browser freeze)', + parseInt ) .option( '--disable-console-output ', diff --git a/src/custom-code-helpers/debug-protection/DebugProtectionFunctionIntervalCodeHelper.ts b/src/custom-code-helpers/debug-protection/DebugProtectionFunctionIntervalCodeHelper.ts index 2fa806d5..686d32e5 100644 --- a/src/custom-code-helpers/debug-protection/DebugProtectionFunctionIntervalCodeHelper.ts +++ b/src/custom-code-helpers/debug-protection/DebugProtectionFunctionIntervalCodeHelper.ts @@ -9,9 +9,12 @@ import { ICustomCodeHelperObfuscator } from '../../interfaces/custom-code-helper import { IOptions } from '../../interfaces/options/IOptions'; import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator'; +import { ObfuscationTarget } from '../../enums/ObfuscationTarget'; + import { initializable } from '../../decorators/Initializable'; import { DebugProtectionFunctionIntervalTemplate } from './templates/debug-protection-function-interval/DebugProtectionFunctionIntervalTemplate'; +import { GlobalVariableNoEvalTemplate } from '../common/templates/GlobalVariableNoEvalTemplate'; import { AbstractCustomCodeHelper } from '../AbstractCustomCodeHelper'; import { NodeUtils } from '../../node/NodeUtils'; @@ -24,6 +27,12 @@ export class DebugProtectionFunctionIntervalCodeHelper extends AbstractCustomCod @initializable() private debugProtectionFunctionName!: string; + /** + * @type {number} + */ + @initializable() + private debugProtectionInterval!: number; + /** * @param {TIdentifierNamesGeneratorFactory} identifierNamesGeneratorFactory * @param {ICustomCodeHelperFormatter} customCodeHelperFormatter @@ -50,9 +59,11 @@ export class DebugProtectionFunctionIntervalCodeHelper extends AbstractCustomCod /** * @param {string} debugProtectionFunctionName + * @param {number} debugProtectionInterval */ - public initialize (debugProtectionFunctionName: string): void { + public initialize (debugProtectionFunctionName: string, debugProtectionInterval: number): void { this.debugProtectionFunctionName = debugProtectionFunctionName; + this.debugProtectionInterval = debugProtectionInterval; } /** @@ -67,8 +78,14 @@ export class DebugProtectionFunctionIntervalCodeHelper extends AbstractCustomCod * @returns {string} */ protected override getCodeHelperTemplate (): string { + const globalVariableTemplate: string = this.options.target !== ObfuscationTarget.BrowserNoEval + ? this.getGlobalVariableTemplate() + : GlobalVariableNoEvalTemplate(); + return this.customCodeHelperFormatter.formatTemplate(DebugProtectionFunctionIntervalTemplate(), { - debugProtectionFunctionName: this.debugProtectionFunctionName + debugProtectionFunctionName: this.debugProtectionFunctionName, + debugProtectionInterval: this.debugProtectionInterval, + globalVariableTemplate }); } } diff --git a/src/custom-code-helpers/debug-protection/group/DebugProtectionCodeHelperGroup.ts b/src/custom-code-helpers/debug-protection/group/DebugProtectionCodeHelperGroup.ts index d8827a35..cfe5e984 100644 --- a/src/custom-code-helpers/debug-protection/group/DebugProtectionCodeHelperGroup.ts +++ b/src/custom-code-helpers/debug-protection/group/DebugProtectionCodeHelperGroup.ts @@ -124,7 +124,7 @@ export class DebugProtectionCodeHelperGroup extends AbstractCustomCodeHelperGrou : nodeWithStatements.body.length; const randomIndex: number = this.randomGenerator.getRandomInteger(0, programBodyLength); - customCodeHelper.initialize(debugProtectionFunctionName); + customCodeHelper.initialize(debugProtectionFunctionName, this.options.debugProtectionInterval); NodeAppender.insertAtIndex(nodeWithStatements, customCodeHelper.getNode(), randomIndex); } diff --git a/src/custom-code-helpers/debug-protection/templates/debug-protection-function-interval/DebugProtectionFunctionIntervalTemplate.ts b/src/custom-code-helpers/debug-protection/templates/debug-protection-function-interval/DebugProtectionFunctionIntervalTemplate.ts index d1bdb7d3..fca700e5 100644 --- a/src/custom-code-helpers/debug-protection/templates/debug-protection-function-interval/DebugProtectionFunctionIntervalTemplate.ts +++ b/src/custom-code-helpers/debug-protection/templates/debug-protection-function-interval/DebugProtectionFunctionIntervalTemplate.ts @@ -3,8 +3,10 @@ */ export function DebugProtectionFunctionIntervalTemplate (): string { return ` - setInterval(function () { - {debugProtectionFunctionName}(); - }, 4000); + (function () { + {globalVariableTemplate} + + that.setInterval({debugProtectionFunctionName}, {debugProtectionInterval}); + })(); `; } diff --git a/src/custom-code-helpers/debug-protection/templates/debug-protection-function/DebugProtectionFunctionTemplate.ts b/src/custom-code-helpers/debug-protection/templates/debug-protection-function/DebugProtectionFunctionTemplate.ts index 8f2ee49d..ef61656f 100644 --- a/src/custom-code-helpers/debug-protection/templates/debug-protection-function/DebugProtectionFunctionTemplate.ts +++ b/src/custom-code-helpers/debug-protection/templates/debug-protection-function/DebugProtectionFunctionTemplate.ts @@ -5,7 +5,6 @@ export function DebugProtectionFunctionTemplate (): string { return ` function {debugProtectionFunctionName} (ret) { function debuggerProtection (counter) { - {debuggerTemplate} debuggerProtection(++counter); diff --git a/src/interfaces/options/IOptions.ts b/src/interfaces/options/IOptions.ts index 4675d5c7..01890971 100644 --- a/src/interfaces/options/IOptions.ts +++ b/src/interfaces/options/IOptions.ts @@ -18,7 +18,7 @@ export interface IOptions { readonly deadCodeInjection: boolean; readonly deadCodeInjectionThreshold: number; readonly debugProtection: boolean; - readonly debugProtectionInterval: boolean; + readonly debugProtectionInterval: number; readonly disableConsoleOutput: boolean; readonly domainLock: string[]; readonly domainLockRedirectUrl: string; diff --git a/src/options/Options.ts b/src/options/Options.ts index d114fc83..234673a5 100644 --- a/src/options/Options.ts +++ b/src/options/Options.ts @@ -112,10 +112,11 @@ export class Options implements IOptions { public readonly debugProtection!: boolean; /** - * @type {boolean} + * @type {number} */ - @IsBoolean() - public readonly debugProtectionInterval!: boolean; + @IsNumber() + @Min(0) + public readonly debugProtectionInterval!: number; /** * @type {boolean} diff --git a/src/options/presets/Default.ts b/src/options/presets/Default.ts index 78b91d32..b8e059f3 100644 --- a/src/options/presets/Default.ts +++ b/src/options/presets/Default.ts @@ -18,7 +18,7 @@ export const DEFAULT_PRESET: TInputOptions = Object.freeze({ deadCodeInjection: false, deadCodeInjectionThreshold: 0.4, debugProtection: false, - debugProtectionInterval: false, + debugProtectionInterval: 0, disableConsoleOutput: false, domainLock: [], domainLockRedirectUrl: 'about:blank', diff --git a/src/options/presets/HighObfuscation.ts b/src/options/presets/HighObfuscation.ts index e704b890..7dedef17 100644 --- a/src/options/presets/HighObfuscation.ts +++ b/src/options/presets/HighObfuscation.ts @@ -10,7 +10,7 @@ export const HIGH_OBFUSCATION_PRESET: TInputOptions = Object.freeze({ controlFlowFlatteningThreshold: 1, deadCodeInjectionThreshold: 1, debugProtection: true, - debugProtectionInterval: true, + debugProtectionInterval: 4000, optionsPreset: OptionsPreset.HighObfuscation, splitStringsChunkLength: 5, stringArrayCallsTransformThreshold: 1, diff --git a/src/options/presets/NoCustomNodes.ts b/src/options/presets/NoCustomNodes.ts index 2c95f930..eb80d021 100644 --- a/src/options/presets/NoCustomNodes.ts +++ b/src/options/presets/NoCustomNodes.ts @@ -16,7 +16,7 @@ export const NO_ADDITIONAL_NODES_PRESET: TInputOptions = Object.freeze({ deadCodeInjection: false, deadCodeInjectionThreshold: 0, debugProtection: false, - debugProtectionInterval: false, + debugProtectionInterval: 0, disableConsoleOutput: false, domainLock: [], domainLockRedirectUrl: 'about:blank', diff --git a/test/functional-tests/custom-code-helpers/debug-protection/templates/DebugProtectionFunctionCallTemplate.spec.ts b/test/functional-tests/custom-code-helpers/debug-protection/templates/debug-protection-function-call-template/DebugProtectionFunctionCallTemplate.spec.ts similarity index 92% rename from test/functional-tests/custom-code-helpers/debug-protection/templates/DebugProtectionFunctionCallTemplate.spec.ts rename to test/functional-tests/custom-code-helpers/debug-protection/templates/debug-protection-function-call-template/DebugProtectionFunctionCallTemplate.spec.ts index 8b8ece05..a8ebe185 100644 --- a/test/functional-tests/custom-code-helpers/debug-protection/templates/DebugProtectionFunctionCallTemplate.spec.ts +++ b/test/functional-tests/custom-code-helpers/debug-protection/templates/debug-protection-function-call-template/DebugProtectionFunctionCallTemplate.spec.ts @@ -1,15 +1,15 @@ import { assert } from 'chai'; -import { readFileAsString } from '../../../../helpers/readFileAsString'; +import { readFileAsString } from '../../../../../helpers/readFileAsString'; -import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../src/options/presets/NoCustomNodes'; +import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../../src/options/presets/NoCustomNodes'; -import { IdentifierNamesGenerator } from '../../../../../src/enums/generators/identifier-names-generators/IdentifierNamesGenerator'; -import { ObfuscationTarget } from '../../../../../src/enums/ObfuscationTarget'; +import { IdentifierNamesGenerator } from '../../../../../../src/enums/generators/identifier-names-generators/IdentifierNamesGenerator'; +import { ObfuscationTarget } from '../../../../../../src/enums/ObfuscationTarget'; -import { evaluateInWorker } from '../../../../helpers/evaluateInWorker'; +import { evaluateInWorker } from '../../../../../helpers/evaluateInWorker'; -import { JavaScriptObfuscator } from '../../../../../src/JavaScriptObfuscatorFacade'; +import { JavaScriptObfuscator } from '../../../../../../src/JavaScriptObfuscatorFacade'; describe('DebugProtectionFunctionCallTemplate', function () { const evaluationTimeout: number = 1500; diff --git a/test/functional-tests/custom-code-helpers/debug-protection/templates/fixtures/input.js b/test/functional-tests/custom-code-helpers/debug-protection/templates/debug-protection-function-call-template/fixtures/input.js similarity index 100% rename from test/functional-tests/custom-code-helpers/debug-protection/templates/fixtures/input.js rename to test/functional-tests/custom-code-helpers/debug-protection/templates/debug-protection-function-call-template/fixtures/input.js diff --git a/test/functional-tests/custom-code-helpers/debug-protection/templates/fixtures/single-call.js b/test/functional-tests/custom-code-helpers/debug-protection/templates/debug-protection-function-call-template/fixtures/single-call.js similarity index 100% rename from test/functional-tests/custom-code-helpers/debug-protection/templates/fixtures/single-call.js rename to test/functional-tests/custom-code-helpers/debug-protection/templates/debug-protection-function-call-template/fixtures/single-call.js diff --git a/test/functional-tests/custom-code-helpers/debug-protection/templates/debug-protection-function-interval-template/DebugProtectionFunctionIntervalTemplate.spec.ts b/test/functional-tests/custom-code-helpers/debug-protection/templates/debug-protection-function-interval-template/DebugProtectionFunctionIntervalTemplate.spec.ts new file mode 100644 index 00000000..8f6a061f --- /dev/null +++ b/test/functional-tests/custom-code-helpers/debug-protection/templates/debug-protection-function-interval-template/DebugProtectionFunctionIntervalTemplate.spec.ts @@ -0,0 +1,90 @@ +import { assert } from 'chai'; + +import { readFileAsString } from '../../../../../helpers/readFileAsString'; + +import { HIGH_OBFUSCATION_PRESET } from '../../../../../../src/options/presets/HighObfuscation'; +import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../../src/options/presets/NoCustomNodes'; + +import { JavaScriptObfuscator } from '../../../../../../src/JavaScriptObfuscatorFacade'; + +describe('DebugProtectionFunctionIntervalTemplate', function () { + const variableMatch: string = '_0x([a-f0-9]){4,6}'; + + describe('Variant #1 - `high-obfuscation` preset interval', () => { + const debugProtectionIntervalRegExp: RegExp = new RegExp( + `${variableMatch}\\['setInterval'\\]\\( *` + + `${variableMatch}, *` + + '0xfa0 *' + + `\\);` + ); + + let obfuscatedCode: string; + + beforeEach(() => { + const code: string = readFileAsString(__dirname + '/fixtures/input.js'); + obfuscatedCode = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_ADDITIONAL_NODES_PRESET, + debugProtection: true, + debugProtectionInterval: HIGH_OBFUSCATION_PRESET.debugProtectionInterval + } + ).getObfuscatedCode(); + + console.log(obfuscatedCode); + }); + + it('Should add debug protection interval code with default interval value', () => { + assert.match(obfuscatedCode, debugProtectionIntervalRegExp); + }); + }); + + describe('Variant #2 - custom interval', () => { + const debugProtectionIntervalRegExp: RegExp = new RegExp( + `${variableMatch}\\['setInterval'\\]\\( *` + + `${variableMatch}, *` + + '0x64 *' + + `\\);` + ); + + let obfuscatedCode: string; + + beforeEach(() => { + const code: string = readFileAsString(__dirname + '/fixtures/input.js'); + obfuscatedCode = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_ADDITIONAL_NODES_PRESET, + debugProtection: true, + debugProtectionInterval: 100 + } + ).getObfuscatedCode(); + }); + + it('Should add debug protection interval code with default interval value', () => { + assert.match(obfuscatedCode, debugProtectionIntervalRegExp); + }); + }); + + describe('Variant #3 - no interval', () => { + const debugProtectionIntervalRegExp: RegExp = /setInterval/ + + let obfuscatedCode: string; + + beforeEach(() => { + const code: string = readFileAsString(__dirname + '/fixtures/input.js'); + obfuscatedCode = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_ADDITIONAL_NODES_PRESET, + debugProtection: true, + debugProtectionInterval: 0 + } + ).getObfuscatedCode(); + }); + + it('Should not add debug protection interval code', () => { + assert.notMatch(obfuscatedCode, debugProtectionIntervalRegExp); + }); + }); +}); diff --git a/test/functional-tests/custom-code-helpers/debug-protection/templates/debug-protection-function-interval-template/fixtures/input.js b/test/functional-tests/custom-code-helpers/debug-protection/templates/debug-protection-function-interval-template/fixtures/input.js new file mode 100644 index 00000000..2a480331 --- /dev/null +++ b/test/functional-tests/custom-code-helpers/debug-protection/templates/debug-protection-function-interval-template/fixtures/input.js @@ -0,0 +1,3 @@ +(function () { + return 1; +})(); \ No newline at end of file diff --git a/test/functional-tests/javascript-obfuscator/JavaScriptObfuscator.spec.ts b/test/functional-tests/javascript-obfuscator/JavaScriptObfuscator.spec.ts index 36088f76..e264a30f 100644 --- a/test/functional-tests/javascript-obfuscator/JavaScriptObfuscator.spec.ts +++ b/test/functional-tests/javascript-obfuscator/JavaScriptObfuscator.spec.ts @@ -1442,7 +1442,7 @@ describe('JavaScriptObfuscator', () => { deadCodeInjection: true, deadCodeInjectionThreshold: 1, debugProtection: true, - debugProtectionInterval: true, + debugProtectionInterval: 4000, disableConsoleOutput: false, stringArrayRotate: true, selfDefending: true, diff --git a/test/index.spec.ts b/test/index.spec.ts index 5cf313d1..d8ed26eb 100644 --- a/test/index.spec.ts +++ b/test/index.spec.ts @@ -64,7 +64,8 @@ import './functional-tests/code-transformers/preparing-transformers/hashbang-ope import './functional-tests/custom-code-helpers/common/templates/GlobalVariableNoEvalTemplate.spec'; import './functional-tests/custom-code-helpers/console-output/ConsoleOutputDisableExpressionCodeHelper.spec'; import './functional-tests/custom-code-helpers/console-output/templates/ConsoleOutputDisableTemplate.spec'; -import './functional-tests/custom-code-helpers/debug-protection/templates/DebugProtectionFunctionCallTemplate.spec'; +import './functional-tests/custom-code-helpers/debug-protection/templates/debug-protection-function-call-template/DebugProtectionFunctionCallTemplate.spec'; +import './functional-tests/custom-code-helpers/debug-protection/templates/debug-protection-function-interval-template/DebugProtectionFunctionIntervalTemplate.spec'; import './functional-tests/custom-code-helpers/domain-lock/DomainLockCodeHelper.spec'; import './functional-tests/custom-code-helpers/domain-lock/templates/DomainLockNodeTemplate.spec'; import './functional-tests/custom-code-helpers/self-defending/SelfDefendingCodeHelper.spec'; diff --git a/test/performance-tests/JavaScriptObfuscatorMemory.spec.ts b/test/performance-tests/JavaScriptObfuscatorMemory.spec.ts index 87cb2634..2f58cecb 100644 --- a/test/performance-tests/JavaScriptObfuscatorMemory.spec.ts +++ b/test/performance-tests/JavaScriptObfuscatorMemory.spec.ts @@ -32,7 +32,7 @@ describe('JavaScriptObfuscator memory', function () { deadCodeInjection: true, deadCodeInjectionThreshold: 0.4, debugProtection: false, - debugProtectionInterval: false, + debugProtectionInterval: 0, disableConsoleOutput: true, identifierNamesGenerator: 'mangled', log: false,