Bu gizlenmiş JavaScript nasıl çalışır?


93

Aşağıdaki JavaScript nasıl çalışır?

Bunun küçültülmüş kod olduğunu anlıyorum. Biraz şaşırtmayı denedim, ancak bu etkiyi nasıl sağladığına dair net bir fikir alamıyorum. Bir tür yineleme, Date nesnesinin kullanımı, garip dize işleme, Matematik işlevleri için Strings kullandığını görebiliyorum, sonra kod kendini yazdırıyor.

Aynı etki minimal bir örnekle nasıl yeniden yazılabilir?

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


8
Harika bir animasyon ... bunu bir yerlerde kullanmakla sonuçlanabilir!
tymeJV

7
Oh iyi. Kemancayı fark etmedim.
ThiefMaster

37
Buna Quine denir ve bu şimdiye kadar gördüğüm en fantastik Quine'lerden biridir. en.wikipedia.org/wiki/Quine_(computing)
David Souther

9
@Roko C. Buljan Sanırım bu onun sayfası: aem1k.com
Alexander

5
Görünüşe göre yazar şimdi GitHub'a açıklamalı bir sürüm koymuş .
Der Hochstapler

Yanıtlar:


67

Önsöz : Kodu, http://jsfiddle.net/WZXYr/2/ adresinde kapsamlı bir şekilde güzelleştirdim ve açıklama ekledim.

En dıştaki katmanı düşünün:

eval(z = '...');

Değişkende bir kod dizisi saklanır z. Atama operatörü atanan değeri döndürür, böylece kod dizesi de bir argüman olarak içine aktarılır eval.

Kod dizesi ziçinde çalışır eval. Kod, temizlendiğinde bile son derece geniş, ancak öyle görünüyor:

  1. Karakterle ayrılmış 36 tabanındaki bir sayı dizesini ayrıştırın 4.
  2. Küresel değişkenler kullanarak, değerlerin bir harita doldurma e, xve ytutma haritası durumuna. Harita durumu, kısmen, duvar saatindeki ( new Date / 1e3) geçerli saniyenin bir fonksiyonudur .
  3. Harita değerlerini kullanarak kod bir çıktı dizesi oluşturur, p
    • kod , gerçekte p += " *#"[index]nerede indexolduğu bir boşluk, yıldız işareti veya karma işareti kullanıp kullanmayacağınıza karar vermek için kullanılır e[x++] + e[x++](yukarıda belirtildiği gibi eve xharita durumundan sorumludur)
    • dizin uzunluğundan daha büyükse " *#", çıktıyı ' pdan karakterlerle dolduran bir geri dönüş kodu vardır z. İç karakterler animasyon karakterleri ile doldurulurken, dış karakterler çekilir z.

Kodun sonunda setTimeout(z), kod dizesini eşzamansız olarak değerlendiren bir çağrı vardır z. Bu tekrarlanan çağrı z, kodun döngüye girmesine izin verir.

Basit örnek:

İşte süper basit bir sürüm ( 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. forDöngü çıkış dizesine her karakter ekler p(dize uzunluğunda 172 karakterdir):

    for(i=0;i<172;++i)
    
  2. İç koşullu, animasyonlu karakterler olan 62 ile 67. konumlar arasında bir karakterde olup olmadığımıza karar verir:

    if(i > 62 && i < 67)
    
  3. Eğer !---öyleysek, ikinci duvar saati değerinin onda birine göre değiştirilirsek çıktı alırız . Bu, animasyon efekti sağlar.

    p+="!---"[~~(new Date/1e2 + i)%4]
    

    (Etraftaki tüm iğrençlik new Date, bir tarih değerini 0 ile 3 arasında bir sayıya dönüştürmek için gerçekten oradadır.)

  4. Aksi takdirde, animasyonlu bir karakter üzerinde değilsek, o zaman dizin ikarakterini ile tanımlanan dizeden yazdırın.

    "eval(z='" + z + "')"
    

    Olduğunu, kod dizisi zile çevrilidir eval('ve ').

  5. Son olarak, dizeyi setTimeoutçıkarın ve başka bir yürütmeyi sıraya almak için kullanın z:

    document.body.innerHTML = p;setTimeout(z)
    

Son çıktımın pek doğru olmadığını unutmayın - sonlara doğru ters eğik çizgileri hesaba katmadım - ancak yine de tekniğin genel olarak nasıl çalıştığı konusunda size oldukça iyi bir fikir vermesi gerekir.


8
Bu github.com/aemkei/world/blob/master/annotated.js - yazarın GitHub'da kendi açıklamalı sürümü olan bu olduğuna dikkat edin.
Benjamin Gruenbaum

36

İşte açıklamalı kaynak. Not: Ben yazarım;)

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()

5
Ayrıca bu videoda da açıklanmıştır youtube.com/watch?v=RTxtiLp1C8Y
Benjamin Gruenbaum

21

Burada, tüm başlatmaları ifadeden kendi ifadelerine taşıyan, manuel olarak gizlemesi kaldırılmış başka bir sürüm var:

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)

İşte olanlar:

  • zkodun tamamını içeren çok satırlı bir dizedir. O edilir evaled.
  • Kodun sonunda ' za geçilir setTimeout. Mümkün olan en yüksek oranda bir aralıkta değerlendirerek, benzer requestAnimationFrameve evalbirlikte çalışır .
  • Kodun kendisi p, HTML'nin ekleneceği dize arabelleğini ve n36 tabanlı kodlanmış sayılardan oluşan bir diziyi başlatır ( "4"yorumlar tarafından dikkate alınmayan alakasız çöplükler tarafından bir dizeye birleştirilir parseInt).
  • her sayı nbir satırı ( n.length == 16) kodlar . Şimdi numaralandırılmıştır .
  • Bir grup değişken başlatılır, bazıları edizinin değişmezi olarak gizlenir, ancak daha sonra kullanıldıklarında sayılara ( x) veya booleanlara ( r) veya dizelere ( t) dönüştürülürler.
  • Sayıdaki her basamak, her dönüşte tboole tersine çevrilerek numaralandırılır r. Farklı açılardan için xve bağlı akım zaman new Date / 1000 (bir animasyon verir böylece), dizi ebazı kullanarak doldurulur bit seviyesinde operatörleri - ile 1zaman ryanlıştır ve 2zaman s ro zaman doğrudur.
  • Daha sonra bir döngü, görüntünün 61 sütununu x=0çift ​​adımlarla 122 sütununa kadar yineler, tek karakterleri ekler p.
  • Bters eğik çizgi olduğundan, dize S, zkaynakta göründüğü şeyin doğru bir temsilini elde etmek için ters eğik çizgi ve kesme işaretlerinden kaçınarak kod dizesinden oluşturulur .
  • Her iki ardışık sayı eeklenir ve " *#"animasyonlu görüntüyü oluşturmak için bir karaktere erişmek için kullanılır . Endekslerden biri tanımlanmamışsa, NaNdizin tanımlanmamış bir karaktere çözümlenir ve bunun yerine Sdizeden ilgili karakter alınır (formüle bakın x/2+61*y-1). Bu karakterin bir kelime karakteri olması gerekiyorsa , fontcolorString yöntemi kullanılarak farklı şekilde renklendirilir .
  • Her satırdan sonra, sondaki geri alma ve bir satır sonu eklenir pve HTML dizesi belge gövdesine atanır.

Minimal bir örnek için aynı etki nasıl yeniden yazılabilir?

İşte başka bir örnek:

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

( jsfiddle.net'te demo )

Bu tür bir animasyon için ihtiyacınız olan tüm ilgili şeylere sahiptir:

  • setIntervalve Dateanimasyon için
  • Burada kendi kodunun yeniden inşası ( kine benzeri):

    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
    
  • Üzerinden çıkış document.body.innerHTMLve bir <pre>öğe

  • Kodun bazı bölümlerini animasyonlu dizeyle değiştirme

2
itiraf etmeliyim, harika cevap!
rafaelcastrocouto

5

Tüm kodu içeren bir dizge değerlendirilir ve bir zaman aşımı döngüyü oluşturur; Dize, adlandırılmış bir değişkende zve kodun ortasında, yorumlar arasında saklanır /*ve */bir "Earth ASCII Sanatı" vardır. Kod, yorumları ayrıştırır ve belge içeriğini değiştirir, js'yi korur ve resmi günceller. Körük sadece dilimlenmiş koddur:

  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
  }

6
Her halükarda, Ekvatorun etrafında grafiğin daha fazla dönüşü olması inanılmaz ... inanılmaz. +1 BTW
Roko C. Buljan
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.