
Security News
ECMAScript 2025 Finalized with Iterator Helpers, Set Methods, RegExp.escape, and More
ECMAScript 2025 introduces Iterator Helpers, Set methods, JSON modules, and more in its latest spec update approved by Ecma in June 2025.
restringer
Advanced tools
Deobfuscate Javascript and reconstruct strings. Simplify cumbersome logic where possible while adhering to scope limitations.
Try it online @ restringer.tech.
For comments and suggestions feel free to open an issue or find me on Twitter - @ctrl__esc
npm install -g restringer
Requires Node 16 or newer.
git clone git@github.com:PerimeterX/restringer.git
cd restringer
npm install
The restringer.js uses generic deobfuscation methods that reconstruct and restore obfuscated strings and simplifies redundant logic meant only to encumber. REstringer employs the Obfuscation Detector to identify specific types of obfuscation for which there's a need to apply specific deobfuscation methods in order to circumvent anti-debugging mechanisms or other code traps preventing the script from being deobfuscated.
Usage: restringer input_filename [-h] [-c] [-q | -v] [-m M] [-o [output_filename]]
positional arguments:
input_filename The obfuscated JS file
optional arguments:
-h, --help Show this help message and exit.
-c, --clean Remove dead nodes from script after deobfuscation is complete (unsafe).
-q, --quiet Suppress output to stdout. Output result only to stdout if the -o option is not set.
Does not go with the -v option.
-m, --max-iterations M Run at most M iterations
-v, --verbose Show more debug messages while deobfuscating. Does not go with the -q option.
-o, --output [output_filename] Write deobfuscated script to output_filename.
<input_filename>-deob.js is used if no filename is provided.
Examples:
restringer [target-file.js]
restringer [target-file.js] -o output.js
restringer [target-file.js] -v
restringer [target-file.js] -q
import {REstringer} from 'restringer';
const restringer = new REstringer('"RE" + "stringer"');
if (restringer.deobfuscate()) {
console.log(restringer.script);
} else {
console.log('Nothing was deobfuscated :/');
}
// Output: 'REstringer';
REstringer is highly modularized. It exposes modules that allow creating custom deobfuscators that can solve specific problems.
The basic structure of such a deobfuscator would be an array of deobfuscation modules (either safe or unsafe), run via flAST's applyIteratively utility function.
Unsafe modules run code through eval
(using isolated-vm to be on the safe side) while safe modules do not.
import {applyIteratively} from 'flast';
import {safe, unsafe} from 'restringer';
const {normalizeComputed} = safe;
const {resolveDefiniteBinaryExpressions, resolveLocalCalls} = unsafe;
let script = 'obfuscated JS here';
const deobModules = [
resolveDefiniteBinaryExpressions,
resolveLocalCalls,
normalizeComputed,
];
script = applyIteratively(script, deobModules);
console.log(script); // Deobfuscated script
With the additional candidateFilter
function argument, it's possible to narrow down the targeted nodes:
import {unsafe} from 'restringer';
const {resolveLocalCalls} = unsafe;
import {applyIteratively} from 'flast';
let script = 'obfuscated JS here';
// It's better to define a function with a meaningful name that can show up in the log
function resolveLocalCallsInGlobalScope(arb) {
return resolveLocalCalls(arb, n => n.parentNode?.type === 'Program');
}
script = applyIteratively(script, [resolveLocalCallsInGlobalScope]);
console.log(script); // Deobfuscated script
You can also customize any deobfuscation method while still using REstringer without running the loop yourself:
import fs from 'node:fs';
import {REstringer} from 'restringer';
const inputFilename = process.argv[2];
const code = fs.readFileSync(inputFilename, 'utf-8');
const res = new REstringer(code);
// res.logger.setLogLevelDebug();
res.detectObfuscationType = false; // Skip obfuscation type detection, including any pre and post processors
const targetFunc = res.unsafeMethods.find(m => m.name === 'resolveLocalCalls');
let changes = 0; // Resolve only the first 5 calls
res.safeMethods[res.unsafeMethods.indexOf(targetFunc)] = function customResolveLocalCalls(n) {return targetFunc(n, () => changes++ < 5)}
res.deobfuscate();
if (res.script !== code) {
console.log('[+] Deob successful');
fs.writeFileSync(`${inputFilename}-deob.js`, res.script, 'utf-8');
} else console.log('[-] Nothing deobfuscated :/');
import {applyIteratively, logger} from 'flast';
// Optional loading from file
// import fs from 'node:fs';
// const inputFilename = process.argv[2] || 'target.js';
// const code = fs.readFileSync(inputFilename, 'utf-8');
const code = `(function() {
function createMessage() {return 'Hello' + ' ' + 'there!';}
function print(msg) {console.log(msg);}
print(createMessage());
})();`;
logger.setLogLevelDebug();
/**
* Replace specific strings with other strings
* @param {Arborist} arb
* @return {Arborist}
*/
function replaceSpecificLiterals(arb) {
const replacements = {
'Hello': 'General',
'there!': 'Kenobi!',
};
// Iterate over only the relevant nodes by targeting specific types using the typeMap property on the root node
const relevantNodes = [
...(arb.ast[0].typeMap.Literal || []),
// ...(arb.ast.typeMap.TemplateLiteral || []), // unnecessary for this example, but this is how to add more types
];
for (const n of relevantNodes) {
if (replacements[n.value]) {
// dynamically define a replacement node by creating an object with a type and value properties
// markNode(n) would delete the node, while markNode(n, {...}) would replace the node with the supplied node.
arb.markNode(n, {type: 'Literal', value: replacements[n.value]});
}
}
return arb;
}
let script = code;
script = applyIteratively(script, [
replaceSpecificLiterals,
]);
if (code !== script) {
console.log(script);
// fs.writeFileSync(inputFilename + '-deob.js', script, 'utf-8');
} else console.log(`No changes`);
FAQs
Deobfuscate Javascript with emphasis on reconstructing strings
The npm package restringer receives a total of 283 weekly downloads. As such, restringer popularity was classified as not popular.
We found that restringer demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
ECMAScript 2025 introduces Iterator Helpers, Set methods, JSON modules, and more in its latest spec update approved by Ecma in June 2025.
Security News
A new Node.js homepage button linking to paid support for EOL versions has sparked a heated discussion among contributors and the wider community.
Research
North Korean threat actors linked to the Contagious Interview campaign return with 35 new malicious npm packages using a stealthy multi-stage malware loader.