How does this obfuscated JavaScript work?

前端 未结 4 1790
清歌不尽
清歌不尽 2021-01-29 17:31

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 achiev

相关标签:
4条回答
  • 2021-01-29 18:09

    A string with the all the code is evaluated, and a timeout makes the loop; The string is stored in a variable named z and in the middle of the code, between comments /* and */there is an "Earth ASCII Art". The code parses the comments and changes the document content, keeping the js and updating the art. Bellow is just the code sliced:

      p="<pre>";
      for(y in n="zw24l6k4e3t4jnt4qj24xh2 x42kty24wrt413n243n9h243pdxt41csb yz43iyb6k43pk7243nmr24".split(4)){ 
        for(a in t = parseInt(n[y],36)+(e=x=r=[]))
          for(r=!r,i=0;t[a]>i;i+=.05)
            with(Math) x-= .05,0>cos(o=new Date/1e3+x/PI)&&(e[~~(32*sin(o)*sin(.5+y/7))+60] =-~ r);
              for(x=0;122>x;) p += "   *#"[e[x++]+e[x++\]] ||
                  (S=("eval"+"(z=\'"+z.split(B = "\\\\").join(B+B).split(Q="\'").join(B+Q)+Q+")//m1k")[x/2+61*y-1]).fontcolor(/\\w/.test(S)&&"#\03B");
        p += B+"\\n"
        document.body.innerHTML= p
      }
    
    0 讨论(0)
  • 2021-01-29 18:10

    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:

    1. Parse a string of base-36 numbers, delineated by the character 4.
    2. Populate a map of values, using the global variables 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).
    3. Using the map values, the code generates an output string, p
      • the code uses 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)
      • if the index is larger than the length of " *#", 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)')
    
    1. The for loop adds each character to the output string p (the string is 172 characters long):

      for(i=0;i<172;++i)
      
    2. 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)
      
    3. 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.)

    4. 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 ').

    5. 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.

    0 讨论(0)
  • 2021-01-29 18:10

    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()
    
    0 讨论(0)
  • 2021-01-29 18:15

    Here is another manually deobfuscated version, moving all initialisation out of expression into own statements:

    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)';
    
    p = "<" + "pre>";
    n = ["zw2", "l6k", "e3t", "jnt", "qj2", "xh2 x/* =<,m#F^    A W###q. */", "2kty2", "wrt", "13n2", "3n9h2", "3pdxt", "1csb yz/* #K       q##H######Am */", "3iyb6k", "3pk72", "3nmr2", ""]
    for (y in n) {
        e = [];
        x = 0;
        r = true;
        t = parseInt(n[y], 36) + "";
        for (a in t) {
            r = !r
            for (i = 0; i < t[a]; i += 0.05) {
                 x -= 0.05;
                 o = new Date / 1e3 + x / Math.PI
                 if (Math.cos(o) < 0)
                     e[~~(32 * Math.sin(o) * Math.sin(0.5 + y / 7)) + 60] = -~r;
            }
        for (x = 0; x < 122;) {
            S = "eval" + "(z='" + z.split(B = "\\").join(B + B).split(Q = "'").join(B + Q) + Q + ")//m1k"
            p += "   *#"[e[x++] + e[x++]] || S[x/2+61*y-1]).fontcolor(/\w/.test(S[x/2+61*y-1]) && "#03B");
        }
        p += B + "\n";
        document.body.innerHTML = p;
    }
    setTimeout(z)
    

    Here is what happens:

    • z is a multiline string containing all of the code. It is evaled.
    • At the end of the code, z is passed to setTimeout. It works like requestAnimationFrame and eval together, evaluating it in an interval at the highest possible rate.
    • The code itself initialises p, the string buffer onto which the HTML will be appended, and n, an array of base-36-encoded numbers (joined into a string by "4", the comments being irrelevant garbage that is not considered by parseInt).
    • each number in n does encode one line (n.length == 16). It is now enumerated.
    • A bunch of variables is initialised, some disguised as the e array literal but they are then cast to numbers (x) or booleans (r) or strings (t) when used.
    • Each digit in the number t is enumerated, inverting the boolean r each turn. For different angles x, and depending on the current time new Date / 1000 (so that it gives an animation), the array e is filled using some bitwise operators - with 1 when r is false and 2s when r is true at that time.
    • Then a loop does iterate the 61 columns of the image, from x=0 to 122 in double steps, appending single characters to p.
    • B being the backslash, the string S is built from the code string z by escaping backslashes and apostrophes, to get an accurate representation of what it looked in the source.
    • Every two consecutive numbers from e are added and used to access a character from " *#", to build up the animated image. If one of the indices is not defined, the NaN index resolves to an undefined character and instead the respective character from the S string is taken (check out the formula x/2+61*y-1). If that character should be a word character, it is colored differently using the fontcolor String method.
    • After each line, the trailing backspace and a linebreak are added to p, and the HTML string gets assigned to the document body.

    How the same effect could be rewritten for a minimal example?

    Here is an other example:

    setInterval(z='s=("setInterval(z=\'"+\
    z.replace(/[\\\\\']/g,"\\\\$&")+"\')"\
    ).match(/.{1,37}/g).join("\\\\\\n");d\
    ocument.body.innerHTML=\"<\\pre>"+s.s\
    lice(0, 175)+String( + new Date()).fo\
    ntcolor("red")+s.slice(188)')
    

    (demo at jsfiddle.net)

    It has all the releveant things you need for this kind of animation:

    • setInterval and Date for the animation
    • A reconstruction of its own code (quine-like), in here:

      s = ( "setInterval(z='" // the outer invokation
            + z.replace(/[\\\']/g,"\\$&") // the escaped version
          + "\')" ) // the end of the assignment
          .match(/.{1,37}/g).join("\\\n"); // chunked into lines
      
    • The output via document.body.innerHTML and a <pre> element

    • Replacing some parts of the code with the animated string
    0 讨论(0)
提交回复
热议问题