Replace array-mapped variables with the actual variable name/string?
Asked Answered
E

3

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.

Emigration answered 23/12, 2014 at 19:57 Comment(8)
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". ?Takishatakken
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.Emigration
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.Starlastarlene
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.Emigration
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.Thetes
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.Thetes
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.Nitrogenize
See also How to restore obfuscated property names?Foulard
T
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)

Thetes answered 26/12, 2014 at 8:16 Comment(0)
N
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.

Nea answered 22/2, 2016 at 12:46 Comment(0)
T
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"]]()
Takishatakken answered 23/12, 2014 at 20:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.