Skip to content
Merged
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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
Change Log

v5.4.2
---
* Fixed obfuscated code hanging in Bun when `selfDefending` is enabled. Fixes https://github.com/javascript-obfuscator/javascript-obfuscator/issues/1404

v5.4.1
---
* Fixed `Utils.nodeRequire` causing `ReferenceError: require is not defined` in browser build by making it lazy-evaluated
Expand Down
7 changes: 2 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "javascript-obfuscator",
"version": "5.4.1",
"version": "5.4.2",
"description": "JavaScript obfuscator",
"keywords": [
"obfuscator",
Expand Down Expand Up @@ -132,10 +132,7 @@
"author": {
"name": "Timofei Kachalov"
},
"contributors": [
"Timofei Kachalov (https://github.com/sanex3339)",
"Dmitry Zamotkin (https://github.com/zamotkin)"
],
"contributors": ["Timofei Kachalov (https://github.com/sanex3339)", "Dmitry Zamotkin (https://github.com/zamotkin)"],
"license": "BSD-2-Clause",
"packageManager": "yarn@1.22.21+sha512.ca75da26c00327d26267ce33536e5790f18ebd53266796fbb664d2a4a5116308042dd8ee7003b276a20eace7d3c5561c3577bdd71bcb67071187af124779620a"
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,29 @@ export function AtobTemplate(selfDefending: boolean): string {

let output = '';
let tempEncodedString = '';
${selfDefending ? 'let func = output + {atobFunctionName};' : ''}

${
selfDefending
? `
let func = output + {atobFunctionName};
let __ = ('' + function(){return 0;}).indexOf('\\n') !== -1;
`
: ''
}

for (
let bc = 0, bs, buffer, idx = 0;
buffer = input.charAt(idx++);
~buffer && (bs = bc % 4 ? bs * 64 + buffer : buffer, bc++ % 4)
? output += ${((): string => {
const basePart: string = 'String.fromCharCode(255 & bs >> (-2 * bc & 6))';

return selfDefending ? `((func.charCodeAt(idx + 10) - 10 !== 0) ? ${basePart} : bc)` : basePart;
return selfDefending
? `
((__ || func.charCodeAt(idx + 10) - 10 !== 0)
? ${basePart}
: bc)
`
: basePart;
})()}
: 0
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ export function SelfDefendingTemplate(
return ${rc4BytesIdentifier}(this.${statesIdentifier}[0]);
};

new StatesClass({stringArrayCallsWrapperName}).${checkStateIdentifier}();
if (('' + function(){return 0;}).indexOf('\\n') === -1) {
new StatesClass({stringArrayCallsWrapperName}).${checkStateIdentifier}();
}
`;
}
Original file line number Diff line number Diff line change
Expand Up @@ -332,9 +332,9 @@ describe('StringArrayCallsWrapperTemplate', () => {

decodedValue = Function(`
${stringArrayTemplate}

${stringArrayCallsWrapperTemplate}

return ${stringArrayCallsWrapperName}(${index});
`)();
});
Expand Down Expand Up @@ -379,9 +379,9 @@ describe('StringArrayCallsWrapperTemplate', () => {

decodedValue = Function(`
${stringArrayTemplate}

${stringArrayCallsWrapperTemplate}

return ${stringArrayCallsWrapperName}(${index});
`)();
});
Expand All @@ -391,6 +391,118 @@ describe('StringArrayCallsWrapperTemplate', () => {
});
});
});

describe('Variant #3: correct code evaluation when engine reformats Function.prototype.toString', () => {
const origToString = Function.prototype.toString;

afterEach(() => {
Function.prototype.toString = origToString;
});

describe('Variant #1: long decoded string', () => {
const index: string = '0x0';

const indexShiftAmount: number = 0;

const expectedDecodedValue: string = 'test1test1';

let decodedValue: string;

before(() => {
const stringArrayTemplate = format(StringArrayTemplate(), {
stringArrayName,
stringArrayFunctionName,
stringArrayStorageItems: `'${cryptUtilsSwappedAlphabet.btoa('test1test1')}'`
});
const atobPolyfill = format(AtobTemplate(selfDefendingEnabled), {
atobFunctionName
});
const atobDecodeTemplate: string = format(StringArrayBase64DecodeTemplate(randomGenerator), {
atobPolyfill,
atobFunctionName,
selfDefendingCode: '',
stringArrayCacheName,
stringArrayCallsWrapperName
});
const stringArrayCallsWrapperTemplate: string = format(StringArrayCallsWrapperTemplate(), {
decodeCodeHelperTemplate: atobDecodeTemplate,
indexShiftAmount,
stringArrayCacheName,
stringArrayCallsWrapperName,
stringArrayFunctionName
});

// Simulate Bun/JSC: Function.prototype.toString adds newlines
Function.prototype.toString = function () {
return origToString.call(this).replace('){', '){\n');
};

decodedValue = Function(`
${stringArrayTemplate}

${stringArrayCallsWrapperTemplate}

return ${stringArrayCallsWrapperName}(${index});
`)();
});

it('should correctly return decoded value when engine reformats toString', () => {
assert.deepEqual(decodedValue, expectedDecodedValue);
});
});

describe('Variant #2: 3-characters decoded string', () => {
const index: string = '0x0';

const indexShiftAmount: number = 0;

const expectedDecodedValue: string = 'foo';

let decodedValue: string;

before(() => {
const stringArrayTemplate = format(StringArrayTemplate(), {
stringArrayName,
stringArrayFunctionName,
stringArrayStorageItems: `'${cryptUtilsSwappedAlphabet.btoa('foo')}'`
});
const atobPolyfill = format(AtobTemplate(selfDefendingEnabled), {
atobFunctionName
});
const atobDecodeTemplate: string = format(StringArrayBase64DecodeTemplate(randomGenerator), {
atobPolyfill,
atobFunctionName,
selfDefendingCode: '',
stringArrayCacheName,
stringArrayCallsWrapperName
});
const stringArrayCallsWrapperTemplate: string = format(StringArrayCallsWrapperTemplate(), {
decodeCodeHelperTemplate: atobDecodeTemplate,
indexShiftAmount,
stringArrayCacheName,
stringArrayCallsWrapperName,
stringArrayFunctionName
});

// Simulate Bun/JSC: Function.prototype.toString adds newlines
Function.prototype.toString = function () {
return origToString.call(this).replace('){', '){\n');
};

decodedValue = Function(`
${stringArrayTemplate}

${stringArrayCallsWrapperTemplate}

return ${stringArrayCallsWrapperName}(${index});
`)();
});

it('should correctly return decoded value when engine reformats toString', () => {
assert.deepEqual(decodedValue, expectedDecodedValue);
});
});
});
});
});

Expand Down
Loading