This is not really useful in any way in it's current form (String obfuscation).
See original GitHub issueIn it’s current form, the string obfuscation is pretty useless. I was lead to this after reversing a js program and seeing this inside the package.json.
How to use: Simply open the script in a node.js environment with a seperate console window. Paste this code inside it and replace ‘scriptinquestion.js’ with the js file you are running:
fs.readFile('scriptinquestion.js', 'utf8', (err, data) => {
let str = data.substring(data.indexOf("_0x"));
while (str) {
for (let start = 0; start < 15; start++) {
if (str[start] === '=') {
for (let eol = 0; eol < 15; eol++) {
if (str[start + eol] === ',' || str[start + eol] === ';') {
let first = str.substring(0, start - 1);
let second = str.substring(start + 2, start + eol);
let callStr = str.substring(0, start + eol + 1);
console.log("first:" + first + ", second:" + second + " from: " + callStr);
if (second.startsWith("_0x")) {
remaps.push({from: first, to: second});
}
break;
}
}
}
}
let strIndex = str.substring(10).indexOf("_0x");
if (strIndex !== -1) {
str = str.substring(strIndex + 10);
} else {
break;
}
}
str = data.substring(data.indexOf("_0x"));
for (let index in remaps) {
let remap = remaps[index];
console.log("remap " + remap.from + "," + remap.to);
}
let newString = data;
while (str) {
for (let openBracket = 0; openBracket < 10; openBracket++) {
if (str[openBracket] === '(') {
for (let closeBracket = 0; closeBracket < 8; closeBracket++) {
if (str[openBracket + closeBracket] === ')') {
let callStr = str.substring(0, openBracket + closeBracket + 1);
let originalCallStr = callStr;
// chained obfuscation.
for (let i = 0; i < 3; i++) {
for (let index in remaps) {
let remap = remaps[index];
callStr = callStr.replace(remap.from, remap.to);
}
}
if (callStr.includes("!")) break;
let result = eval(callStr);
console.log("found call:" + callStr + " eval: " + result);
newString = newString.replace(originalCallStr, "'" + result + "'");
break;
}
}
}
}
let strIndex = str.substring(10).indexOf("_0x");
if (strIndex !== -1) {
str = str.substring(strIndex + 10);
} else {
console.log(newString);
fs.writeFile("out.js", newString, function (err) {
process.exit(-1);
});
return;
}
}
process.exit(-1);
})
How does this work? It simply evaluates inside the scripts context (after you run it), finds strings in sourcecode and simply evaluates them in-place. There (should) be virtually no way to block eval effectively.
How would I defend against this attack? I am not am not knowledgeable in javascript, however, I would include a rolling number to encrypt and decrypt array offsets at function start and end with a call stack analysis, I would first execute the script and analyze which functions call what by adding start and end loggers to each function which would generate something like this. a() calls b() calls c() that means that it would have to call a() deobfuscation and then b() deobfuscation for the string offsets in order to be able to eval the strings inside function c(). This would make it extremely time-consuming as you would have to use a debugger, which this obfuscator already provides protection against. While it would still be possible to add in logstart and logend to just run the program to generate your own call stack, it could still be improved in a way which would trigger other protections unlike the one I specified above.
Closing notes: I do understand that javascript has it’s limits, however, currently this offers near zero protection. This is just an example, you can apply the same concept to remove opaque predicates(dead code), string splitting and what-not.
Issue Analytics
- State:
- Created 2 years ago
- Reactions:3
- Comments:21 (12 by maintainers)
Top GitHub Comments
Yeah, I see.
eval
within the obfuscated code context can show original values, but for this cases, I added more variants withoptions.
Right now your example is very code-specific, it won’t work with many cases of obfuscated code (chained calls,
mangled
generator).Please try to adapt your code for this:
I want to see, how this code will look like, to collect more information.
But in general, I have to think about how to prevent code evaluation within the obfuscated code context. For example, we can break
eval
(with a new option, for example). We can break both: external evaluation and evaluation within the same obfuscated context. The main problem is to do this in a sneaky way.Closed. Btw,
stringArrayCallsTransform
option was added.