Unpacking /packer/

Ever since I started working on the mostly Ajax app “VKitty“, I’ve been looking into JavaScript compression, and trying to figure out how it works.  Most compressors have very simple ways to compress JavaScript, by simply removing whitespace, but Dean Edwards’s /packer/ defies the simplicity of most compressors by making an unreadable function that acts the same as the JavaScript you feed it, also known as obfusication.

I’ve decided to find out how it works, and I’m starting with something very simple.  “alert(‘STUFF GOES HERE’)“.

First, I packed it in /packer/.  I got back the code “eval(function(p,a,c,k,e,r){e=String;if(!”.replace(/^/,String)){while(c–)r[c]=k[c]||c;k=[function(e){return r[e]}];e=function(){return’\\w+’};c=1};while(c–)if(k[c])p=p.replace(new RegExp(‘\\b’+e(c)+’\\b’,’g’),k[c]);return p}(‘0(\’1 2 3\’)’,4,4,’alert|STUFF|GOES|HERE’.split(‘|’),0,{}))“, which is really unreadable.

Let’s unpack the /packer/.

I did a bit of formatting on the function returned by /packer/: (it’s an image because I couldn’t get syntax highlighting to work on my blog)

/packer/: Unpacked

/packer/: Unpacked (Click for a bigger view)

If you can’t already see what’s happening, I’ll walk you through it.  It basically creates a function, calls itself, and evaluates the result as JavaScript.  Here it is, line by line:

Line 1: eval(
Evaluates the code that is created by the function.

Line 2: function (p, a, c, k, e, r) {
Starts the declaration of a function, via shameless plug.

Line 3: e=String;
Makes the variable e into a function that returns whatever it is given as a string.

Line 4: if (!”.replace(/^/, String)) {
This seems pointless to me, because evaluating the code inside the if statement would always return true.  I even removed the code, and it kept working!  The code is probably for compliance with less-up-to-date JavaScript implementations.

Line 5: while(c–) r[c] = k[c] || c;
While the c variable is above zero, reducing c by 1 every time, the r variable (an empty object) gets a new variable inside it: one of the words contained in k, or ‘alert|STUFF|GOES|HERE’, split at the |‘s.  If the variable doesn’t exist (which shouldn’t happen), it puts the key into the array so it will replace with itself.

Line 6: k = [function (e) {
The variable k is turned into an array with a function inside it.

Line 7: return r[e]
Return the xth word in r. (x is the variable e)

Line 8: }];
Closing the function-in-an-array statement.

Line 9: e = function () {
The variable e is now another function, not the String function, let’s see what it does:

Line 10: return ‘\\w+’
In regex, this means “find as many alphanumeric characters as possible”.

Line 11: };
Closing a function.

Line 12: c=1
We are no  longer looking for words 4 (in this case) times, but 1.  This is only possible because of the stuff inside the if statement.

Line 13: };
Ending an if statement.  Note the unnecessary semicolon.

Line 14: while (c–)
While the variable c is nonzero, reducing it by 1 after we test for nonzero-ness.

Line 15: if (k[c])
Make sure k has c as one of its keys.

Line 16: p = p.replace(new RegExp(‘\\b’+e(c)+’\\b’,’g’), k[c]);
Replace the p variable with the k[c] variable instead of the c variable’s value.

Line 17: return p
Return the final value.

Line 18: } (‘0(\’1 2 3\’)’, 4, 4, ‘alert|STUFF|GOES|HERE’.split(‘|’), 0, {})
Set the p, a, c, k, e, r variables.

Line 19: )
Close the eval statement.

One thought on “Unpacking /packer/

Comments are closed.