Gambar yang juga merupakan kode Javascript



Gambar biasanya disimpan sebagai file biner dan file Javascript pada dasarnya adalah teks biasa. Kedua jenis file harus mengikuti aturannya masing-masing: gambar memiliki format file tertentu yang menyandikan data dengan cara tertentu. Agar file Javascript dapat dieksekusi, mereka harus mengikuti sintaks tertentu. Saya bertanya-tanya: apakah mungkin untuk membuat file gambar yang memiliki sintaks Javascript yang valid sehingga dapat dijalankan?



Sebelum Anda melanjutkan membaca, saya sangat menyarankan untuk menjelajahi kotak pasir kode ini dengan hasil eksperimen saya:



https://codesandbox.io/s/executable-gif-8yq0j?file=/index.html



Jika Anda ingin melihat gambar dan menjelajahinya sendiri, maka Anda dapat mendownloadnya dari sini:



https://executable-gif.glitch.me/image.gif



Memilih jenis gambar yang tepat



Sayangnya, gambar mengandung banyak data biner yang, jika diartikan sebagai Javascript, akan menimbulkan kesalahan. Jadi pikiran pertama saya adalah ini: bagaimana jika saya memasukkan semua data gambar ke dalam komentar besar, seperti ini:



/*ALL OF THE BINARY IMAGE DATA*/


Ini akan menjadi file Javascript yang valid. Namun, file gambar harus dimulai dengan urutan byte tertentu, header file khusus untuk format gambar. Misalnya, file PNG harus selalu dimulai dengan urutan byte 89 50 4E 47 0D 0A 1A 0A . Jika gambar dimulai dengan /*, maka file tersebut bukan lagi file gambar.



File header ini membawa saya ke ide berikut: bagaimana jika kita menggunakan urutan byte ini sebagai nama variabel dan memberikannya nilai string panjang:



PNG=`ALL OF THE BINARY IMAGE DATA`;


Kami menggunakan string template daripada string biasa, "atau 'karena data biner dapat berisi jeda baris, dan string template bekerja lebih baik dengannya.



Sayangnya, sebagian besar urutan byte di header file gambar berisi karakter yang tidak dapat dicetak yang tidak dapat digunakan dalam nama variabel. Tapi ada satu format yang bisa kita gunakan: GIF. Blok header GIF terlihat seperti 47 49 46 38 39 61 , yang dengan mudah diubah menjadi string ASCII GIF89a - nama variabel yang benar-benar valid!



Memilih ukuran gambar yang tepat



Sekarang kita telah menemukan format gambar yang dimulai dengan nama variabel yang valid, kita perlu menambahkan tanda sama dengan dan backtick. Oleh karena itu, empat byte berikutnya dari file tersebut adalah: 3D 09 60 04





Byte Pertama Gambar



Dalam format GIF, empat byte setelah header menentukan dimensi gambar. Kita perlu memasukkannya 3D (tanda sama dengan) dan 60 (backtick, membuka baris). GIF menggunakan urutan endian kecil, jadi karakter kedua dan keempat memiliki pengaruh besar pada ukuran gambar. Mereka harus sekecil mungkin agar gambar tidak memiliki lebar dan tinggi puluhan ribu piksel. Oleh karena itu, kita perlu menyimpan byte 3D besar dan 60 byte paling signifikan.



Lebar gambar byte kedua harus berupa spasi kosong yang valid, karena akan menjadi spasi antara tanda sama dengan dan awal barisGIF89a= `...... Perlu juga diingat bahwa kode karakter heksadesimal harus sekecil mungkin, jika tidak gambar akan menjadi besar.



Karakter spasi terkecil adalah 09 (karakter tab horizontal). Ini memberi kita lebar gambar 3D 09 , yaitu 2365 di little endian; sedikit lebih lebar dari yang saya inginkan, tetapi masih bisa diterima.



Untuk tinggi byte kedua, Anda dapat memilih nilai yang memberikan rasio aspek yang baik. Saya memilih 04 , yang memberi kita tinggi 60 04 , atau 1120 piksel.



Menempatkan script di file



Sejauh ini, GIF kami yang dapat dieksekusi hampir tidak melakukan apa pun. Ini hanya memberikan GIF89astring panjang ke variabel global . Kami ingin sesuatu yang menarik terjadi! Sebagian besar data di dalam GIF digunakan untuk menyandikan gambar, jadi jika kami mencoba memasukkan Javascript di sana, gambar kemungkinan besar akan terdistorsi. Tetapi untuk beberapa alasan, format GIF mengandung sesuatu yang disebut Ekstensi Komentar . Ini adalah tempat untuk menyimpan metadata yang tidak ditafsirkan oleh decoder GIF - tempat yang tepat untuk logika Javascript kita.



Ekstensi komentar ini ditemukan tepat setelah bagan warna GIF. Karena kami dapat meletakkan konten apa pun di sana, kami dapat dengan mudah menutup baris GIF89a, tambahkan semua Javascript dan kemudian mulai blok komentar multi-baris sehingga sisa gambar tidak mempengaruhi pengurai Javascript.



Pada akhirnya, file kita mungkin terlihat seperti ini:



GIF89a= ` BINARY COLOR TABLE DATA ... COMMENT BLOCK:

`;alert("Javascript!");/*

REST OF THE IMAGE */


Namun, ada batasan kecil: meskipun blok komentar itu sendiri dapat berukuran berapa pun, ia terdiri dari beberapa sub blok, dan ukuran maksimum masing-masing adalah 255. Ada satu byte di antara sub blokir, yang menentukan panjang sub blokir berikutnya. Oleh karena itu, agar sesuai dengan skrip besar di sana, itu perlu dibagi menjadi beberapa fragmen kecil, seperti ini:



alert('Javascript');/*0x4A*/console.log('another subblock');/*0x1F*/...


Kode heksadesimal di komentar adalah byte yang menentukan ukuran subblock berikutnya. Mereka tidak spesifik untuk Javascript, tapi dibutuhkan untuk format file GIF. Untuk menghindari gangguan dengan kode lainnya, mereka perlu ditempatkan di komentar. Saya menulis skrip kecil yang memproses fragmen skrip dan menambahkannya ke file gambar:



https://gist.github.com/SebastianStamm/c2433819cb9e2e5af84df0904aa43cb8



Membersihkan data biner



Sekarang kita memiliki struktur dasar, kita perlu memastikan bahwa data gambar biner tidak mengacaukan sintaks kode. Seperti yang disebutkan di bagian sebelumnya, file dibagi menjadi tiga bagian: yang pertama adalah penugasan ke variabel GIF89a , yang kedua adalah kode Javascript, dan yang ketiga adalah komentar multi-baris.



Mari kita lihat bagian pertama tentang menetapkan nilai ke variabel:



GIF89a= ` BINARY DATA `;


Jika data biner berisi karakter `atau kombinasi karakter ${, maka kami memiliki masalah, karena keduanya akan menghentikan string pola, atau membuat ekspresi yang tidak valid. Cara mengatasinya cukup sederhana: cukup ubah data biner! Misalnya, alih-alih karakter `(kode hex 60 ), Anda dapat menggunakan karakter a(kode hex 61 ). Karena bagian file ini berisi palet warna, ini akan menyebabkan perubahan kecil pada beberapa warna, misalnya, menggunakan warna #286148sebagai pengganti #286048. Tidak mungkin ada orang yang akan melihat perbedaannya.



Berurusan dengan distorsi



Di akhir kode Javascript, kami telah membuka komentar multi-baris sehingga data gambar biner tidak memengaruhi penguraian Javascript:



alert("Script done");/*BINARY IMAGE DATA ...


Jika data gambar berisi urutan karakter */, komentar akan berakhir sebelum waktunya, membuat file Javascript menjadi tidak valid. Di sini sekali lagi, kita dapat mengubah salah satu dari dua karakter secara manual sehingga tidak mengakhiri komentar. Namun, karena kita sekarang berada di bagian gambar yang disandikan, hasilnya adalah gambar yang rusak, misalnya ini:





Gambar rusak



Dalam kasus terburuk, gambar mungkin tidak ditampilkan sama sekali. Dengan hati-hati memilih bit untuk dibalik, saya dapat meminimalkan distorsi. Untungnya, hanya ada beberapa kasus kombinasi yang merusak */. Masih ada sedikit distorsi pada gambar jadi, misalnya, di bagian bawah baris "Valid Javascript File", tapi secara keseluruhan saya cukup puas dengan hasilnya.



Menyelesaikan file



Kita dibiarkan dengan operasi terakhir - penyelesaian file. File harus diakhiri dengan 00 3B byte , jadi kita harus mengakhiri komentar lebih awal. Karena ini adalah akhir dari file dan potensi kerusakan tidak akan terlihat, saya baru saja mengakhiri komentar blok dan menambahkan komentar satu baris sehingga akhir file tidak akan menyebabkan masalah penguraian:



/* BINARY DATA*/// 00 3B


Membujuk browser untuk mengeksekusi gambar



Sekarang, setelah semua ini, akhirnya kita memiliki file yang berupa gambar dan file Javascript yang valid. Namun, kita perlu mengatasi kendala terakhir: jika kita mengunggah gambar ke server dan mencoba menggunakannya dalam tag script, kemungkinan besar kita akan mendapatkan kesalahan serupa:



Menolak untuk mengeksekusi skrip dari ' http: // localhost: 8080 / image.gif ' karena jenis MIME-nya ('image / gif') tidak dapat dijalankan. [Mengabaikan eksekusi skrip dari ' http: // localhost: 8080 / image.gif ' karena jenis MIME-nya tidak dapat dijalankan.]


Artinya, browser dengan tepat mengatakan: "Ini adalah gambar, saya tidak akan menjalankannya!" Dan dalam banyak kasus, ini cukup tepat. Tapi kami tetap ingin memenuhinya. Solusinya adalah dengan tidak memberi tahu browser bahwa ini adalah gambar. Untuk ini, saya menulis server kecil yang menyajikan gambar tanpa informasi header.



Tanpa informasi jenis MIME dari header, browser tidak tahu itu adalah gambar dan melakukan apa yang terbaik dalam konteks: merendernya sebagai gambar dalam tag, <img>atau menjalankannya sebagai Javascript dalam tag <script>.



Tapi ... kenapa ini semua?



Saya belum menemukan jawabannya sendiri. Tugas semacam itu adalah pemanasan yang baik untuk pikiran, tetapi jika Anda dapat memikirkan situasi yang benar-benar berguna, beri tahu saya!






Periklanan



Server untuk pengembang adalah tentang server virtual dari perusahaan kami.

Untuk waktu yang lama kami telah menggunakan drive server cepat eksklusif dari Intel dan tidak menghemat perangkat keras - hanya peralatan bermerek dan solusi paling modern di pasar untuk menyediakan layanan.






All Articles