How does the following JavaScript work?
I understand that it is minified code. I have tried de-obfuscating it a little, but I can't get a clear concept of how it achieves this effect. I can see that it is using Strings for iteration of some kind, use of the Date object, strange string manipulation, Math functions, then the code prints itself.
How could the same effect be rewritten with a minimal example?
eval(z='p="<"+"pre>"/* ,.oq#+ ,._, */;for(y in n="zw24l6k\ 4e3t4jnt4qj24xh2 x/* =<,m#F^ A W###q. */42kty24wrt413n243n\ 9h243pdxt41csb yz/* #K q##H######Am */43iyb6k43pk7243nm\ r24".split(4)){/* dP cpq#q##########b, */for(a in t=pars\ eInt(n[y],36)+/* p##@###YG=[#######y */(e=x=r=[]))for\ (r=!r,i=0;t[a/* d#qg `*PWo##q#######D */]>i;i+=.05)wi\ th(Math)x-= /* aem1k.com Q###KWR#### W[ */.05,0>cos(o=\ new Date/1e3/* .Q#########Md#.###OP A@ , */+x/PI)&&(e[~\ ~(32*sin(o)*/* , (W#####Xx######.P^ T % */sin(.5+y/7))\ +60] =-~ r);/* #y `^TqW####P###BP */for(x=0;122>\ x;)p+=" *#"/* b. OQ####x#K */[e[x++]+e[x++\ ]]||(S=("eval"/* l `X#####D , */+"(z=\'"+z.spl\ it(B = "\\\\")./* G####B" # */join(B+B).split\ (Q="\'").join(B+Q/* VQBP` */)+Q+")//m1k")[x/2\ +61*y-1]).fontcolor/* TP */(/\\w/.test(S)&&"#\ 03B");document.body.innerHTML=p+=B+"\\n"}setTimeout(z)')//
JSFiddle
How does the obfuscation work? Through a series of transformations, such as variable / function / arguments renaming, string removal, and others, your source code is transformed into something unreadable, while working exactly as before.
Obfuscation in computer code uses complex roundabout phrases and redundant logic to make the code difficult for the reader to understand. The goal is to distract the reader with the complicated syntax of what they are reading and make it difficult for them to determine the true content of the message.
Advantages of obfuscating JSPrevent people from copying or modifying your code without authorization. The obfuscated JavaScript will be way larger and difficult to understand.
Obfuscation is a means of "obscuring" the real meaning and intent of your javascript code. Some sites use it as an obstacle to people who want to copy/borrow their code. Other sites use it as a means to hide the actual intention of the code.
Foreword: I beautified and annotated the code extensively at http://jsfiddle.net/WZXYr/2/
Consider the outermost layer:
eval(z = '...');
A code string is stored in the variable z
. The assignment operator returns the value assigned, so the code string also is passed as an argument into eval
.
The code string z
runs inside of eval
. The code is extremely obtuse, even when cleaned up, but it seems to:
4
.e
, x
, and y
to hold map state. Map state is, in part, a function of the current second on the wall clock (new Date / 1e3
).p
p += " *#"[index]
to decide whether to use a space, asterisk, or hash mark, where index
is actually e[x++] + e[x++]
(as said above, e
and x
are responsible for map state)" *#"
, there is fallback code that populates the output p
with characters from z
. Inner characters are populated with animation characters, while outer characters are pulled from z
.At the end of the code, there is a call to setTimeout(z)
, which asynchronously evaluates the code string z
. This repeat invocation of z
allows the code to loop.
Simple example:
Here's a super-simple version (http://jsfiddle.net/5QXn8/):
eval(z='p="<"+"pre>";for(i=0;i<172;++i)if(i > 62 && i < 67)p+="!---"[~~(new Date/1e2 + i)%4];else p += ("eval(z=\'" + z + "\')")[i];document.body.innerHTML = p;setTimeout(z)')
The for
loop adds each character to the output string p
(the string is 172 characters long):
for(i=0;i<172;++i)
The inner conditional decides if we're on a character between position 62 to 67, which are the animated characters:
if(i > 62 && i < 67)
If we are, then print out !---
, shifted based on the tenth of the second wall-clock value. This provides the animation effect.
p+="!---"[~~(new Date/1e2 + i)%4]
(All the nastiness around new Date
is really just there to transform a date value into a number between 0 and 3.)
Otherwise, if we're not on an animated character, then print the index-i
character from the string defined by
"eval(z='" + z + "')"
That is, the code string z
surrounded by eval('
and ')
.
Finally, output the string and use setTimeout
to queue up another execution of z
:
document.body.innerHTML = p;setTimeout(z)
Note that my final output isn't quite right -- I haven't accounted for the backslashes toward the end -- but it should still give you a pretty good idea of how the technique works generally.
Here is the annotated source. Ps: I'm the author ;)
function z(){ // will be replaced with eval p = "<" + "pre>"; // use <pre> tag for formatted output for ( // loop though lines y in n = ( // y - the line number "zw24" + // n - the encoded data "l6k4" + // every line holds encoded data "e3t4" + "jnt4" + // string will be concated in build process "qj24" + "xh2 4" + // data after spaces will be ignored but "2kty24" + // … is used to not break block comments "wrt4" + // … which will save some chars "13n24" + "3n9h24" + "3pdxt4" + "1csb 4" + "3iyb6k4" + "3pk724" + "3nmr24" ).split(4) // data will be split by (unused) 4 ){ for ( // loop throug every char in line a in t = parseInt( // numbers are encoded as string n[y], // … with a base of 36 36 ) + ( // large number will be converted to string e = // e - holds the rendered globe x = // x - horizonal position r = [] // r - bitmap flag if pixel is set ) ){ r = !r; // toggle binary flag for ( // look though bitmap states i = 0; t[a] > i; // draw pixel t[a]-times i += .05 ) with (Math) // refer to Math later x -= .05, 0 > cos( // prevent backface visibility o = new Date / 1e3 + // get rotation based on current time x / PI ) && ( e[ // access matrix ~~( // convert float to integer sin(o) * // rotate around y axis sin(.5 + y/7) * 32 // scale up the globe ) + 60 // move to center ] = -~r // store bitmap state in render matrix ) } for ( // loop through columns x = 0; 122 > x; // break after char 122 ) p += " *#"[ // add space, asterisk or hash e[x++] + // … based pixel opacity e[x++] ] || (S = ( // otherwise use the original code "eval(z='" + // inception of missing "eval" statement z .split(B = "\\") // escape \ with \\ .join(B + B) .split(Q = "'") // escape ' with \' .join(B + Q) + Q + // add missing ') ")////////" // add extra chars to fill mapping )[ x / 2 + // get character at current position 61 * y-1 ] ).fontcolor( // colorize outpu /\w/.test(S) && // test for [0-9A-Z] "#03B" // render blue // otherwise pink (default) ); document.body.innerHTML = // render output p += // append new line B + // add backspace "\n"; // add new line } setTimeout(z) // render animation on next frame } z()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With