restringer
Advanced tools
Comparing version 1.4.6 to 1.5.0
{ | ||
"name": "restringer", | ||
"version": "1.4.6", | ||
"version": "1.5.0", | ||
"description": "Deobfuscate Javascript with emphasis on reconstructing strings", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -25,3 +25,6 @@ module.exports = { | ||
resolveRedundantLogicalExpressions: require(__dirname + '/resolveRedundantLogicalExpressions'), | ||
simplifyCalls: require(__dirname + '/simplifyCalls'), | ||
unwrapFunctionShells: require(__dirname + '/unwrapFunctionShells'), | ||
unwrapIIFEs: require(__dirname + '/unwrapIIFEs'), | ||
unwrapSimpleOperations: require(__dirname + '/unwrapSimpleOperations'), | ||
}; |
@@ -11,2 +11,3 @@ module.exports = { | ||
resolveEvalCallsOnNonLiterals: require(__dirname + '/resolveEvalCallsOnNonLiterals'), | ||
resolveFunctionToArray: require(__dirname + '/resolveFunctionToArray'), | ||
resolveInjectedPrototypeMethodCalls: require(__dirname + '/resolveInjectedPrototypeMethodCalls'), | ||
@@ -13,0 +14,0 @@ resolveLocalCalls: require(__dirname + '/resolveLocalCalls'), |
@@ -22,3 +22,12 @@ const evalInVm = require(__dirname + '/evalInVm'); | ||
const newNode = evalInVm(c.src); | ||
if (newNode !== badValue) arb.markNode(c, newNode); | ||
if (newNode !== badValue) { | ||
// Fix issue where a number below zero would be replaced with a string | ||
if (newNode.type === 'UnaryExpression' && typeof c?.left?.value === 'number' && typeof c?.right?.value === 'number') { | ||
// noinspection JSCheckFunctionSignatures | ||
const v = parseInt(newNode.argument.value); | ||
newNode.argument.value = v; | ||
newNode.argument.raw = `${v}`; | ||
} | ||
arb.markNode(c, newNode); | ||
} | ||
} | ||
@@ -25,0 +34,0 @@ return arb; |
@@ -64,2 +64,3 @@ const getCache = require(__dirname + '/getCache'); | ||
examineStack.push(relevantNode.right); | ||
if (relevantNode.init) examineStack.push(relevantNode.init); | ||
break; | ||
@@ -69,6 +70,7 @@ case 'CallExpression': | ||
references.push(...relevantNode.arguments.filter(a => a.type === 'Identifier')); | ||
examineStack.push(relevantNode.callee); | ||
break; | ||
case 'MemberExpression': | ||
relevantScope = relevantNode.object.scope; | ||
examineStack.push(relevantNode.property); | ||
examineStack.push(relevantNode.object, relevantNode.property); | ||
break; | ||
@@ -75,0 +77,0 @@ case 'Identifier': |
@@ -19,3 +19,4 @@ /** | ||
unsafe: { | ||
evalInVm | ||
evalInVm, | ||
resolveFunctionToArray, | ||
}, | ||
@@ -47,6 +48,8 @@ config: { | ||
const relevantArrayIdentifier = candidate.arguments.find(n => n.type === 'Identifier'); | ||
const declKind = /function/i.test(relevantArrayIdentifier.declNode.parentNode.type) ? '' : 'var '; | ||
const ref = !declKind ? `${relevantArrayIdentifier.name}()` : relevantArrayIdentifier.name; | ||
// The context for this eval is the relevant array and the IIFE augmenting it (the candidate). | ||
const context = `var ${relevantArrayIdentifier.declNode.parentNode.src}\n!${createOrderedSrc(getDeclarationWithContext(candidate))}`; | ||
const context = `${declKind}${relevantArrayIdentifier.declNode.parentNode.src}\n!${createOrderedSrc(getDeclarationWithContext(candidate))}`; | ||
// By adding the name of the array after the context, the un-shuffled array is procured. | ||
const src = `${context};\n${relevantArrayIdentifier.name};`; | ||
const src = `${context};\n${ref};`; | ||
const newNode = evalInVm(src); // The new node will hold the un-shuffled array's assignment | ||
@@ -59,3 +62,11 @@ if (newNode !== badValue) { | ||
arb.markNode(candidateExpression ? candidateExpression : candidate); | ||
arb.markNode(relevantArrayIdentifier.declNode.parentNode.init, newNode); | ||
if (relevantArrayIdentifier.declNode.parentNode.type === 'FunctionDeclaration') { | ||
arb.markNode(relevantArrayIdentifier.declNode.parentNode.body, { | ||
type: 'BlockStatement', | ||
body: [{ | ||
type: 'ReturnStatement', | ||
argument: newNode, | ||
}], | ||
}); | ||
} else arb.markNode(relevantArrayIdentifier.declNode.parentNode.init, newNode); | ||
} | ||
@@ -67,4 +78,4 @@ } | ||
module.exports = { | ||
preprocessors: [replaceArrayWithStaticAugmentedVersion], | ||
preprocessors: [replaceArrayWithStaticAugmentedVersion, resolveFunctionToArray], | ||
postprocessors: [], | ||
}; |
@@ -7,44 +7,10 @@ /** | ||
unsafe: { | ||
evalInVm, | ||
resolveFunctionToArray, | ||
}, | ||
utils: { | ||
createOrderedSrc, | ||
getDeclarationWithContext, | ||
}, | ||
config: { | ||
badValue, | ||
} | ||
} = require(__dirname + '/../modules'); | ||
/** | ||
* Run the generating function and replace it with the actual array. | ||
* Candidates are variables which are assigned a call expression, and every reference to them is a member expression. | ||
* E.g. | ||
* function getArr() {return ['One', 'Two', 'Three']}; | ||
* const a = getArr(); | ||
* console.log(`${a[0]} + ${a[1]} = ${a[2]}`); | ||
* @param {Arborist} arb | ||
* @return {Arborist} | ||
*/ | ||
function replaceFunctionWithArray(arb) { | ||
const candidates = arb.ast.filter(n => | ||
n.type === 'VariableDeclarator' && | ||
n.init?.type === 'CallExpression' && | ||
n.id?.references && | ||
!n.id.references.find(r => r.parentNode.type !== 'MemberExpression')); | ||
for (const c of candidates) { | ||
const targetNode = c.init.callee?.declNode?.parentNode || c.init; | ||
const src = createOrderedSrc(getDeclarationWithContext(targetNode).concat(c.init)); | ||
const newNode = evalInVm(src); | ||
if (newNode !== badValue) { | ||
arb.markNode(c.init, newNode); | ||
} | ||
} | ||
return arb; | ||
} | ||
module.exports = { | ||
preprocessors: [replaceFunctionWithArray], | ||
preprocessors: [resolveFunctionToArray], | ||
postprocessors: [], | ||
}; |
@@ -34,3 +34,6 @@ #!/usr/bin/env node | ||
rearrangeSequences, | ||
simplifyCalls, | ||
rearrangeSwitches, | ||
unwrapIIFEs, | ||
unwrapSimpleOperations, | ||
}, | ||
@@ -48,2 +51,3 @@ unsafe: { | ||
resolveEvalCallsOnNonLiterals, | ||
resolveFunctionToArray, | ||
}, | ||
@@ -101,2 +105,3 @@ config: { | ||
resolveRedundantLogicalExpressions, | ||
unwrapSimpleOperations, | ||
resolveProxyCalls, | ||
@@ -118,3 +123,5 @@ resolveProxyVariables, | ||
replaceFunctionShellsWithWrappedValueIIFE, | ||
simplifyCalls, | ||
unwrapFunctionShells, | ||
unwrapIIFEs, | ||
]; | ||
@@ -128,2 +135,3 @@ } | ||
return [ | ||
resolveFunctionToArray, | ||
resolveMinimalAlphabet, | ||
@@ -130,0 +138,0 @@ resolveDefiniteBinaryExpressions, |
@@ -0,0 +0,0 @@ /* |
@@ -90,2 +90,8 @@ module.exports = [ | ||
enabled: true, | ||
name: 'Replace Augmented Function with Corrected Array', | ||
source: `(function(a, b){const myArr=a();for(let i=0;i<b;i++)myArr.push(myArr.shift());})(arr,1);function arr(){var a1=[2, 1];arr=function(){return a1;};return arr();}const a = arr();console.log(a[0], a[1]);`, | ||
expected: `function arr() {\n return [\n 1,\n 2\n ];\n}\nconst a = [\n 1,\n 2\n];\nconsole.log(1, 2);`, | ||
}, | ||
{ | ||
enabled: true, | ||
name: 'Replace Deterministic If Statement', | ||
@@ -92,0 +98,0 @@ source: 'if(true){a;}if(false){b}if(false||c){c}if(true&&d){d}', |
@@ -372,2 +372,94 @@ const {generateFlatAST} = require('flast'); | ||
}, | ||
{ | ||
enabled: true, | ||
name: 'unwrapIIFEs - TP-1 (arrow functions)', | ||
func: __dirname + '/../src/modules/safe/unwrapIIFEs', | ||
source: `var a = (() => { | ||
return b => { | ||
return c(b - 40); | ||
}; | ||
})();`, | ||
expected: `var a = b => {\n return c(b - 40);\n};`, | ||
}, | ||
{ | ||
enabled: true, | ||
name: 'unwrapIIFEs - TP-2 (function expression)', | ||
func: __dirname + '/../src/modules/safe/unwrapIIFEs', | ||
source: `var a = (function () { | ||
return b => c(b - 40); | ||
})();`, | ||
expected: `var a = b => c(b - 40);`, | ||
}, | ||
{ | ||
enabled: true, | ||
name: 'unwrapSimpleOperations - TP-1', | ||
func: __dirname + '/../src/modules/safe/unwrapSimpleOperations', | ||
source: `function add(b,c){return b + c;} | ||
function minus(b,c){return b - c;} | ||
function mul(b,c){return b * c;} | ||
function div(b,c){return b / c;} | ||
function power(b,c){return b ** c;} | ||
function and(b,c){return b && c;} | ||
function band(b,c){return b & c;} | ||
function or(b,c){return b || c;} | ||
function bor(b,c){return b | c;} | ||
function xor(b,c){return b ^ c;} | ||
add(1, 2); | ||
minus(1, 2); | ||
mul(1, 2); | ||
div(1, 2); | ||
power(1, 2); | ||
and(1, 2); | ||
band(1, 2); | ||
or(1, 2); | ||
bor(1, 2); | ||
xor(1, 2);`, | ||
expected: `function add(b, c) { | ||
return b + c; | ||
} | ||
function minus(b, c) { | ||
return b - c; | ||
} | ||
function mul(b, c) { | ||
return b * c; | ||
} | ||
function div(b, c) { | ||
return b / c; | ||
} | ||
function power(b, c) { | ||
return b ** c; | ||
} | ||
function and(b, c) { | ||
return b && c; | ||
} | ||
function band(b, c) { | ||
return b & c; | ||
} | ||
function or(b, c) { | ||
return b || c; | ||
} | ||
function bor(b, c) { | ||
return b | c; | ||
} | ||
function xor(b, c) { | ||
return b ^ c; | ||
} | ||
1 + 2; | ||
1 - 2; | ||
1 * 2; | ||
1 / 2; | ||
1 ** 2; | ||
1 && 2; | ||
1 & 2; | ||
1 || 2; | ||
1 | 2; | ||
1 ^ 2;`, | ||
}, | ||
{ | ||
enabled: true, | ||
name: 'simplifyCalls - TP-1', | ||
func: __dirname + '/../src/modules/safe/simplifyCalls', | ||
source: `func1.apply(this, [arg1, arg2]); func2.call(this, arg1, arg2);`, | ||
expected: `func1(arg1, arg2);\nfunc2(arg1, arg2);`, | ||
}, | ||
@@ -503,2 +595,9 @@ // Unsafe | ||
enabled: true, | ||
name: 'resolveFunctionToArray - TP-1', | ||
func: __dirname + '/../src/modules/unsafe/resolveFunctionToArray', | ||
source: `function a() {return [1];}\nconst b = a();`, | ||
expected: `function a() {\n return [1];\n}\nconst b = [1];`, | ||
}, | ||
{ | ||
enabled: true, | ||
name: 'resolveInjectedPrototypeMethodCalls - TP-1', | ||
@@ -505,0 +604,0 @@ func: __dirname + '/../src/modules/unsafe/resolveInjectedPrototypeMethodCalls', |
@@ -569,3 +569,3 @@ var _0x3378 = [ | ||
_0x70dec9 = null; | ||
return _0x4a23a5.call(this, _0x4cd1e1); | ||
return _0x4a23a5(_0x4cd1e1); | ||
}; | ||
@@ -572,0 +572,0 @@ } |
@@ -167,3 +167,3 @@ var polyfill, sendBeacon, isSupported, b2h, last, progress_, th, lo; | ||
for (var a = 0; C(a, arguments.length); a += 2) { | ||
b[arguments[a]] = arguments[A(a, 1)]; | ||
b[arguments[a]] = arguments[a + 1]; | ||
} | ||
@@ -181,6 +181,6 @@ return b; | ||
for (var f = 0; C(f, r.length); f++) { | ||
g._ = A(m._ * A(f, 200), y(m._, 43467)); | ||
s._ = A(m._ * A(f, 194), y(m._, 49057)); | ||
l._ = y(g._, r.length); | ||
k._ = y(s._, r.length); | ||
g._ = m._ * (f + 200) + m._ % 43467; | ||
s._ = m._ * (f + 194) + m._ % 49057; | ||
l._ = g._ % r.length; | ||
k._ = s._ % r.length; | ||
w._ = j._[l._]; | ||
@@ -201,6 +201,3 @@ bp(l, j, k); | ||
function b() { | ||
if (e.call(this)) { | ||
return; | ||
} | ||
if (bo(H('navigator', this))) { | ||
if (!H('navigator', this)) { | ||
this.navigator = {}; | ||
@@ -251,3 +248,3 @@ } | ||
if (G(j.indexOf(b._), -1)) { | ||
c._ = A(A(e._[f._].value + '&', b._) + '=', localStorage.getItem(b._)); | ||
c._ = e._[f._].value + '&' + b._ + '=' + localStorage.getItem(b._); | ||
} | ||
@@ -258,3 +255,3 @@ } | ||
} | ||
if (bo(jQuery('select[name="region"] option:selected').val()) && bo(jQuery('input[name="region"]').val()) && jQuery('select[name="region_id"] option:selected').val() && jQuery('select[name="region_id"] option:selected').text()) { | ||
if (!jQuery('select[name="region"] option:selected').val() && !jQuery('input[name="region"]').val() && jQuery('select[name="region_id"] option:selected').val() && jQuery('select[name="region_id"] option:selected').text()) { | ||
rg = jQuery('select[name="region_id"] option:selected').text(); | ||
@@ -322,3 +319,3 @@ localStorage.setItem('region', rg); | ||
for (var g = 0; C(g, ln.length); g++) { | ||
lc.push(A(la[f._], ln[g])); | ||
lc.push(la[f._] + ln[g]); | ||
} | ||
@@ -329,3 +326,3 @@ } | ||
while (G(ctr, 0)) { | ||
f._ = Math.floor(z(Math.random(), ctr)); | ||
f._ = Math.floor(Math.random() * ctr); | ||
bB(); | ||
@@ -338,3 +335,3 @@ bC(); | ||
if (F(localStorage.getItem('gaudid'), null)) { | ||
gaudid = [...Array(16)].map(b => (~bn(z(Math.random(), 36))).toString(36)).join('').toUpperCase(); | ||
gaudid = [...Array(16)].map(b => (~~(Math.random() * 36)).toString(36)).join('').toUpperCase(); | ||
localStorage.setItem('gaudid', gaudid); | ||
@@ -349,6 +346,6 @@ } else { | ||
if (w(i, 'infoResult') && D(k.length, 1000)) { | ||
d += A(A(lr[f._], '=') + f(A(i + '=', k)), '&'); | ||
d += lr[f._] + '=' + f(i + '=' + k) + '&'; | ||
} | ||
} | ||
if (bo(navigator.sendBeacon(u, d))) { | ||
if (!navigator.sendBeacon(u, d)) { | ||
l._ = H('XMLHttpRequest', this) ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP'); | ||
@@ -381,3 +378,3 @@ l._.open('POST', u); | ||
return function (b, c) { | ||
return B(b.length, c.length); | ||
return b.length - c.length; | ||
}; | ||
@@ -497,3 +494,3 @@ } | ||
const b = G(window.outerHeight - window.innerHeight, 160); | ||
if (bo(b && c) && (window.Firebug && window.Firebug.chrome && window.Firebug.chrome.isInitialized || c || b)) { | ||
if (!(b && c) && (window.Firebug && window.Firebug.chrome && window.Firebug.chrome.isInitialized || c || b)) { | ||
bH(); | ||
@@ -513,3 +510,3 @@ clearInterval(lo); | ||
function br(b, a, c) { | ||
b._ = y(A(a._, c._), 1632567); | ||
b._ = (a._ + c._) % 1632567; | ||
} | ||
@@ -531,3 +528,3 @@ function bt(b) { | ||
} | ||
t += A(A(b._, '=') + c._[e._].value, '&'); | ||
t += b._ + '=' + c._[e._].value + '&'; | ||
} | ||
@@ -534,0 +531,0 @@ function bx(b, e, c) { |
@@ -150,3 +150,3 @@ var _ya = [ | ||
}; | ||
return a(); | ||
return true; | ||
}); | ||
@@ -153,0 +153,0 @@ _yh(); |
@@ -20,6 +20,3 @@ const assert = require('node:assert'); | ||
restringer.deobfuscate(); | ||
assert((restringer.script === expected || | ||
restringer.script.replace(/'/g, '"') === expected.replace(/'/g, '"') || | ||
restringer.script.replace(/"/g, `'`) === expected.replace(/"/g, `'`)), | ||
`\n\tFAIL: deobfuscation result !== expected:\n-------------\n${restringer.script}\n\t!==\n${expected}\n-------------`); | ||
assert.equal(restringer.script, expected); | ||
console.timeEnd('PASS'); | ||
@@ -26,0 +23,0 @@ } |
@@ -10,17 +10,8 @@ const availableTests = { | ||
console.time('\nAll tests completed in'); | ||
let exception = ''; | ||
// let exception = ''; | ||
for (const [testName, testFile] of Object.entries(availableTests)) { | ||
const padLength = Math.floor((120 - testName.length - 4) / 2); | ||
console.log(`\n${'>'.padStart(padLength, '-')} ${testName} ${'<'.padEnd(padLength, '-')}`); | ||
try { | ||
require(testFile); | ||
} catch (e) { | ||
exception = e.message; | ||
break; | ||
} | ||
require(testFile); | ||
} | ||
console.timeEnd('\nAll tests completed in'); | ||
if (exception) { | ||
console.error(exception); | ||
process.exit(1); | ||
} |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
621152
115
10991
178
1