Bagaimana cara kerja JavaScript yang dikaburkan ini?

93

Bagaimana cara kerja JavaScript berikut?

Saya mengerti bahwa itu adalah kode yang diperkecil. Saya telah mencoba sedikit menghilangkan obfuscasinya, tetapi saya tidak bisa mendapatkan konsep yang jelas tentang bagaimana efek ini mencapai efek ini. Saya dapat melihat bahwa itu menggunakan String untuk iterasi dari beberapa jenis, penggunaan objek Tanggal, manipulasi string aneh, fungsi Matematika, lalu kode mencetak dirinya sendiri.

Bagaimana efek yang sama dapat ditulis ulang dengan contoh yang minimal?

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

Alexander
sumber
8
Animasi keren ... mungkin akhirnya menggunakan itu di suatu tempat sebenarnya!
tymeJV
7
Oh bagus. Tidak memperhatikan biolanya.
ThiefMaster
37
Ini disebut Quine, dan ini salah satu Quine yang paling fantastis yang pernah saya lihat. en.wikipedia.org/wiki/Quine_(computing)
David Souther
9
@Roko C. Buljan saya pikir ini adalah halamannya: aem1k.com
Alexander
5
Sepertinya penulis sekarang telah memasang versi beranotasi di GitHub.
Der Hochstapler

Jawaban:

67

Kata Pengantar : Saya mempercantik dan memberi anotasi kode secara ekstensif di http://jsfiddle.net/WZXYr/2/

Pertimbangkan lapisan terluar:

eval(z = '...');

Sebuah string kode disimpan dalam variabel z. Operator penugasan mengembalikan nilai yang ditetapkan, sehingga string kode juga dilewatkan sebagai argumen ke eval.

String kode zdijalankan di dalam eval. Kode tersebut sangat tumpul, bahkan ketika dibersihkan, tetapi tampaknya:

  1. Parse string bilangan basis 36, yang digambarkan oleh karakter 4.
  2. Mengisi peta nilai, menggunakan variabel global e, xdan yuntuk terus negara peta. Status peta, sebagian, merupakan fungsi detik saat ini di jam dinding ( new Date / 1e3).
  3. Menggunakan nilai peta, kode tersebut menghasilkan string keluaran, p
    • kode yang digunakan p += " *#"[index]untuk memutuskan apakah akan menggunakan spasi, asterisk, atau tanda pagar, di mana indexsebenarnya e[x++] + e[x++](seperti yang dikatakan di atas, edan xbertanggung jawab atas keadaan peta)
    • jika indeks lebih besar dari panjangnya " *#", ada kode fallback yang mengisi keluaran pdengan karakter dari z. Karakter dalam diisi dengan karakter animasi, sedangkan karakter luar ditarik dari z.

Di akhir kode, ada panggilan ke setTimeout(z), yang mengevaluasi string kode secara asinkron z. Permintaan berulang ini zmemungkinkan kode untuk mengulang.

Contoh sederhana:

Ini adalah versi yang sangat sederhana ( 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 forLoop menambahkan setiap karakter untuk output string p(string adalah 172 karakter):

    for(i=0;i<172;++i)
  2. Kondisi bagian dalam memutuskan apakah kita menggunakan karakter antara posisi 62 hingga 67, yang merupakan karakter animasi:

    if(i > 62 && i < 67)
  3. Jika ya, maka cetaklah !---, geser berdasarkan sepersepuluh dari nilai jam dinding kedua. Ini memberikan efek animasi.

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

    (Semua hal buruk di sekitar new Datehanya ada di sana untuk mengubah nilai tanggal menjadi angka antara 0 dan 3.)

  4. Jika tidak, jika kita tidak menggunakan karakter animasi, cetak ikarakter indeks dari string yang ditentukan oleh

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

    Artinya, string kode yang zdikelilingi oleh eval('dan ').

  5. Terakhir, keluarkan string dan gunakan setTimeoutuntuk mengantrekan eksekusi lain dari z:

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

Perhatikan bahwa hasil akhir saya tidak cukup tepat - saya belum menyumbang backslashes menuju akhir - tetapi masih harus memberikan Anda ide yang baik cukup tentang bagaimana teknik bekerja umumnya.

apsillers
sumber
8
Catat github.com/aemkei/world/blob/master/annotated.js ini - versi beranotasi milik penulis di GitHub.
Benjamin Gruenbaum
36

Berikut adalah sumber beranotasi. Ps: Saya penulisnya;)

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()
aemkei
sumber
5
Catatan, itu juga dijelaskan dalam video ini youtube.com/watch?v=RTxtiLp1C8Y
Benjamin Gruenbaum
21

Berikut adalah versi lain yang disederhanakan secara manual, memindahkan semua inisialisasi dari ekspresi ke dalam pernyataan sendiri:

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)

Inilah yang terjadi:

  • zadalah string multiline yang berisi semua kode. Itu evaled.
  • Di akhir kode, zditeruskan ke setTimeout. Ia bekerja seperti requestAnimationFramedan evalbersama - sama, mengevaluasinya dalam interval pada tingkat setinggi mungkin.
  • Kode itu sendiri diinisialisasi p, buffer string yang akan ditambahkan HTML, dan n, array bilangan yang dikodekan dengan basis 36 (digabungkan menjadi string oleh "4", komentar menjadi sampah yang tidak relevan yang tidak dipertimbangkan oleh parseInt).
  • setiap angka dalam nmenyandikan satu baris ( n.length == 16). Sekarang disebutkan .
  • Sekelompok variabel diinisialisasi, beberapa disamarkan sebagai eliteral array tetapi kemudian dimasukkan ke angka ( x) atau boolean ( r) atau string ( t) saat digunakan.
  • Setiap digit dalam nomor ttersebut dihitung, membalikkan boolean rsetiap putaran. Untuk sudut yang berbeda x, dan bergantung pada waktu saat ini new Date / 1000 (sehingga memberikan animasi), array ediisi menggunakan beberapa operator bitwise - dengan 1when ris false dan 2s when ris true pada saat itu.
  • Kemudian sebuah loop mengulang 61 kolom gambar, dari x=0122 menjadi 122 dalam langkah ganda, menambahkan karakter tunggal ke p.
  • Bsebagai garis miring terbalik, string Sdibangun dari string kode zdengan mengosongkan garis miring terbalik dan apostrof, untuk mendapatkan representasi akurat dari apa yang terlihat di sumber.
  • Setiap dua angka berurutan dari editambahkan dan digunakan untuk mengakses karakter dari " *#", untuk membangun gambar animasi. Jika salah satu indeks tidak ditentukan, NaNindeks memutuskan ke karakter yang tidak ditentukan dan sebagai gantinya karakter terkait dari Sstring diambil (lihat rumusnya x/2+61*y-1). Jika karakter itu harus berupa karakter kata , warnanya berbeda menggunakan fontcolormetode String .
  • Setelah setiap baris, spasi mundur dan pemutusan baris ditambahkan ke p, dan string HTML ditugaskan ke badan dokumen.

Bagaimana efek yang sama dapat ditulis ulang untuk contoh minimal?

Berikut contoh lainnya:

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 di jsfiddle.net )

Ia memiliki semua hal relevan yang Anda butuhkan untuk jenis animasi ini:

  • setIntervaldan Dateuntuk animasinya
  • Rekonstruksi kodenya sendiri ( seperti quine ), di sini:

    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
    
  • Output melalui document.body.innerHTMLdan <pre>elemen

  • Mengganti beberapa bagian kode dengan string animasi
Bergi
sumber
2
harus mengakui, jawaban yang bagus!
rafaelcastrocouto
5

Sebuah string dengan semua kodenya dievaluasi, dan batas waktu membuat loop; String disimpan dalam variabel bernama zdan di tengah kode, di antara komentar /*dan */ada "Seni ASCII Bumi". Kode mem-parsing komentar dan mengubah konten dokumen, mempertahankan js dan memperbarui seni. Di bawah ini hanyalah potongan kode:

  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
  }
rafaelcastrocouto
sumber
6
Bagaimanapun, luar biasa bagaimana di sekitar Khatulistiwa grafik memiliki lebih banyak putaran ... luar biasa. +1 BTW
Roko C. Buljan