9

I am trying to edit a Greasemonkey/jQuery script. I can't post the link here.
The code is obfuscated and compressed with minify.
It starts like this:

var _0x21e9 = ["\x67\x65\x74\x4D\x6F\x6E\x74\x68", "\x67\x65\x74\x55\x54\x43\x44\x61\x74\x65", ...

After "decoding" it, I got this:

var _0x21e9=["getMonth","getUTCDate","getFullYear", ...   

It is a huge list (500+ ). Then, it has some variables like this:

 month = date[_0x21e9[0]](), day = date[_0x21e9[1]](), ...

_0x21e9[0] is getMonth, _0x21e9[1] is getUTCDate, etc.

Is it possible to replace the square brackets with the actual variable name? How?
I have little knowledge in javascript/jQuery and can not "read" the code the way it is right now.
I just want to use some functions from this huge script and remove the others I do not need.

Update: I tried using jsbeautifier.org as suggested here and in the duplicated question but nothing changed, except the "indent".

It did not replace the array variables with the decoded names.
For example:

  1. jsbeautifier still gives: month = date[_0x21e9[0]]().
  2. But I need: month = date["getMonth"]().

None of the online deobfuscators seem to do this, How can I?


Is there a way for me to share the code with someone, at least part of it? I read I can not post pastebin, or similar here. I can not post it the full code here.

Here is another part of the code:

$(_0x21e9[8] + vid)[_0x21e9[18]]();    

[8] is "." and [18] is "remove". Manually replacing it gives a strange result.

nex
  • 93
  • 1
  • 4
  • Why would you want to replace the square brackets with the actual variable name? What would be the point of accessing a variable named _0x21e9getMonth to retrieve the string "getMonth". ? – hofan41 Dec 23 '14 at 20:01
  • It is a huge list of 500+ strings. To know [0] is getMonth, I have to manually check the list and count. If it is [500], I willll have to count the strings separated by a comma. How can I do this? It is not my script, I just want to remove the things I will not use. – nex Dec 23 '14 at 20:07
  • This code is pretty 'obfuscated'... Are you trying to decode someones javascript and use it? Meaning, this code was probably obfuscated for a reason and if you know who did it then they can just as easily revert it. – BuddhistBeast Dec 23 '14 at 20:11
  • It is not my script. It adds some functions to a forum I use, like blocking users, adding some menus etc. I want to remove all of it and keep only the function to refresh the page. Some users were even saying it was "keylogger". I just want to remove some functions for personal use, I did not even post the script here. – nex Dec 23 '14 at 20:20
  • Okay, I see that this is a new wrinkle on the "standard" deobfuscation questions. To do what you want, you will need to write a "filter" to parse the JS text, substituting array values -- Basically, an automated search and replace. I'm going offline, but I'll post an answer in several hours if someone doesn't beat me to it. – Brock Adams Dec 23 '14 at 22:06
  • PS: It's perfectly fine to link to a PasteBin, and would help in this case. The only requirement is that the question must also stand on its own, as if the pastebin never existed. – Brock Adams Dec 23 '14 at 22:12
  • This is _not_ that obfuscated. I've seen far worse. But then you realise that its a PITA to use obfuscated code and its easier to write your own code from scratch. – Alex Dec 24 '14 at 00:03
  • See also [How to restore obfuscated property names?](http://stackoverflow.com/q/30879056/1048572) – Bergi Jul 17 '16 at 23:37

3 Answers3

14

I haven't seen any online deobfuscator that does this yet, but the principle is simple.
Construct a text filter that parses the "key" array and then replaces each instance that that array is referenced, with the appropriate array value.

For example, suppose you have a file, evil.js that looks like this (AFTER you have run it though jsbeautifier.org with the Detect packers and obfuscators? and the Unescape printable chars... options set):

var _0xf17f = ["(", ")", 'div', "createElement", "id", "log", "console"];
var _0x41dcx3 = eval(_0xf17f[0] + '{id: 3}' + _0xf17f[1]);
var _0x41dcx4 = document[_0xf17f[3]](_0xf17f[2]);
var _0x41dcx5 = _0x41dcx3[_0xf17f[4]];
window[_0xf17f[6]][_0xf17f[5]](_0x41dcx5);

In that case, the "key" variable would be _0xf17f and the "key" array would be ["(", ")", ...].

The filter process would look like this:

  1. Extract the key name using text processing on the js file. Result: _0xf17f
  2. Extract the string src of the key array. Result:

    keyArrayStr = '["(", ")", \'div\', "createElement", "id", "log", "console"]';
    
  3. In javascript, we can then use .replace() to parse the rest of the JS src. Like so:

var keyArrayStr = '["(", ")", \'div\', "createElement", "id", "log", "console"]';
var restOfSrc   = "var _0x41dcx3 = eval(_0xf17f[0] + '{id: 3}' + _0xf17f[1]);\n"
                + "var _0x41dcx4 = document[_0xf17f[3]](_0xf17f[2]);\n"
                + "var _0x41dcx5 = _0x41dcx3[_0xf17f[4]];\n"
                + "window[_0xf17f[6]][_0xf17f[5]](_0x41dcx5);\n"
                ;
var keyArray    = eval (keyArrayStr);
//-- Note that `_0xf17f` is the key name we already determined.
var keyRegExp   = /_0xf17f\s*\[\s*(\d+)\s*\]/g;

var deObsTxt    = restOfSrc.replace (keyRegExp, function (matchStr, p1Str) {
    return '"' + keyArray[ parseInt(p1Str, 10) ] + '"';
} );
console.log (deObsTxt);

if you run that code, you get:

var _0x41dcx3 = eval("(" + '{id: 3}' + ")");
var _0x41dcx4 = document["createElement"]("div");
var _0x41dcx5 = _0x41dcx3["id"];
window["console"]["log"](_0x41dcx5);

-- which is a bit easier to read/understand.


I've also created an online page that takes JS source and does all 3 remapping steps in a slightly more automated and robust manner. You can see it at:

jsbin.com/hazevo

(Note that that tool expects the source to start with the "key" variable declaration, like your code samples do)

Brock Adams
  • 90,639
  • 22
  • 233
  • 295
4

@Brock Adams solution is brilliant, but there is a small bug: it doesn't take into account simple quoted vars.

Example:

var _0xbd34 = ["hello ", '"my" world'];
(function($) {
  alert(_0xbd34[0] + _0xbd34[1])
});

If you try to decipher this example, it will result on this:

alert("hello " + ""my" world")

To resolve this, just edit the replacedSrc.replace into @Brock code:

replacedSrc     = replacedSrc.replace (nameRegex, function (matchStr, p1Str) {
    var quote = keyArry[parseInt (p1Str, 10)].indexOf('"')==-1? '"' : "'";
    return quote + keyArry[ parseInt (p1Str, 10) ] + quote;
} );

Here you have a patched version.

Ivan
  • 14,692
  • 17
  • 59
  • 96
0
for (var i = 0; i < _0x21e9.length; i++) {
  var funcName = _0x21e9[i];
  _0x21e9[funcName] = funcName;
}

this will add all the function names as keys to the array. allowing you to do

date[_0x21e9["getMonth"]]()
hofan41
  • 1,438
  • 1
  • 11
  • 25