- Seorang pengembang memasukkan JavaScript yang sudah diminifikasi ke ChatGPT untuk memahami implementasi komponen ASCII art yang ia lihat di web, dan ChatGPT menguraikan alur yang terobfusikasi menjadi struktur yang bisa dibaca
- Aslinya, itu adalah komponen React yang menghitung kolom dan baris sesuai ukuran jendela, lalu memperbarui grid string 60fps dengan
setInterval - ChatGPT kemudian menjelaskan pemilihan set karakter, perhitungan karakter berbasis koordinat dan waktu, serta alur pembaruan
div.textContent, lalu menuliskannya ulang sebagai kode TypeScript/React yang setara - Awalnya sempat dianggap implementasinya berbeda karena karakter blok seperti
░▒▓█hilang, tetapi setelah skrip asli diperiksa ulang ternyata penyebabnya adalah masalah encoding saat salin-tempel - Setelah diperbarui dengan set karakter yang benar, hasil output menjadi sama dengan komponen asli, menunjukkan bahwa ChatGPT dapat digunakan secara praktis untuk memahami dan mengimplementasikan ulang kode yang sudah diminifikasi
Menemukan implementasi ASCII art dari JavaScript yang diminifikasi
- Kode sumber diperiksa untuk mengetahui bagaimana blok ASCII art pada halaman reactive.network hackathon diimplementasikan
- Kode terkait sudah diminifikasi sehingga sulit dibaca langsung oleh manusia, dan biasanya situasi seperti ini mengharuskan orang mendekripsinya sendiri atau mencari file
.mapuntuk memulihkan sumber aslinya - Kali ini seluruh kode yang diminifikasi ditempel ke ChatGPT dan diminta menjelaskan cara kerjanya
Struktur yang terungkap dari kode yang diminifikasi
- Kode tersebut ternyata memiliki struktur untuk menghasilkan konten teks dinamis menggunakan JavaScript dan React
- Elemen utamanya adalah sebagai berikut
- Fungsi matematika seperti
Math.floor,Math.abs, danMath.mindipakai lewat alias pendek - Ada set karakter yang terdiri dari
"reactive.network REACTIVE.NETWORK"serta karakter khusus dan karakter blok - Set karakter yang dipakai dipilih berdasarkan hasil
Date.now() % 3 - Indeks karakter yang ditampilkan pada tiap koordinat dihitung berdasarkan panjang set karakter yang terpilih
- Fungsi matematika seperti
- Fungsi inti
eTmenerima koordinat posisi dan nilai waktu lalu mengembalikan satu karakter untuk ditampilkan- Nilai waktu diubah dengan
t.time * 8e-5 - Koordinat dikoreksi menggunakan nilai yang lebih kecil antara jumlah kolom dan baris serta rasio layar
- Indeks karakter ditentukan dengan menggabungkan hasil
Math.cos(position.x * position.x - position.y * position.y)dan nilai waktu
- Nilai waktu diubah dengan
Cara komponen React melakukan rendering
- Komponen menggunakan
useRefuntuk merujuk kedivtempat teks akan dimasukkan, danuseStateuntuk menyimpan height dan width jendela useEffectpertama menetapkan ukuran awal denganwindow.innerHeightdanwindow.innerWidth, lalu memperbarui ukuran saat eventresizeterjadiuseEffectkedua menghitung ukuran grid ASCII berdasarkan ukuran layarcolsadalahMath.floor(width / 12) * 1.6rowsadalahMath.floor(height / 12)aspectadalahcols / rows
setIntervaldijalankan dengan interval1_000 / 60untuk membangun ulang string sesuai 60fps- Pada setiap frame, semua baris dan kolom diiterasi untuk menyambungkan karakter yang sudah dihitung, lalu string akhir dimasukkan ke
element.textContent
Menulis ulang kode agar mudah dibaca dalam TypeScript
- Pengembang kemudian meminta implementasi kode yang setara dalam TypeScript, tetapi dibuat agar mudah dibaca manusia
- Kode yang dibuat ChatGPT menguraikan peran kode yang diminifikasi ke dalam nama-nama berikut
selectedCharacterSetcharacterSetLengthcalculateCharacter- tipe
Size - komponen React
AsciiArtGenerator
- Nama variabel yang sulit dipahami diubah menjadi nama yang menunjukkan maksud implementasinya
calculateCharactermenghitung karakter yang akan ditampilkan berdasarkan koordinat, jumlah kolom dan baris, rasio layar, serta nilai waktutextRefmenunjuk kedivtempat teks sebenarnya dimasukkansizedansetSizemewakili state ukuran jendela
- Kode hasil penulisan ulang jauh lebih mudah dibaca dibanding kode asli yang diminifikasi, dan cukup memadai untuk mempelajari cara komponen itu diimplementasikan
Kesalahpahaman soal karakter yang hilang dan masalah encoding
- Pada perbandingan awal, LLM sempat tampak seperti melewatkan beberapa detail implementasi
- Secara khusus, disimpulkan bahwa karakter seperti
░▒▓█yang terlihat pada komponen asli tidak muncul di hasil ChatGPT - Setelah itu, seorang pengguna forum HN menunjukkan kemungkinan adanya masalah salin-tempel, dan pemeriksaan lanjutan menunjukkan bahwa kode asli memang berisi karakter yang berbeda dari yang ditempel ke ChatGPT
- Setelah skrip diunduh secara langsung, karakter yang benar bisa diperoleh, dan penyebab masalah dipastikan sebagai perbedaan encoding
- Setelah set karakter diperbaiki, output menjadi identik dengan komponen asli
1 komentar
Opini Hacker News
Saya pembuat HumanifyJS, dan saya membuat alat berbasis LLM terpisah untuk tujuan ini
Alat ini menggunakan LLM pada level AST, sehingga memastikan kode tetap berjalan setelah deobfuscation: https://github.com/jehna/humanify
Maksudnya fitur yang menghapus semua nama bermakna dari pengguna pada kode biasa, lalu memilih nama baru berdasarkan algoritma dan nama-nama yang tersisa, misalnya nama bawaan
Saat refactoring, kadang saya melakukannya secara manual dengan LLM, dan ini berguna untuk menemukan istilah yang lebih standar seperti
antiparallel_linealih-alihparallel_line_opposite_direction, atau menemukan nama yang lebih dapat digeneralisasi sepertifind_instance_in_listalih-alihfind_animal_instance_in_animalsSejujurnya, saya masih menunggu version control pada level AST
Apakah caranya memberi seluruh fungsi lalu berulang kali bertanya “apa yang harus diganti namanya?” sampai semuanya berubah, atau menyuruhnya mengerjakan semuanya sekaligus lalu mem-parse output dan memeriksa apakah AST masih cocok
Maksudnya sekitar 50 ribu baris
Edit: sekarang saya sedang mencoba menjalankan file JS yang hanya 1,2 ribu baris dalam mode openai, dan setelah 20 menit baru selesai 70%. Walaupun secara teori bisa bekerja pada file 50 ribu baris, sepertinya lebih baik tidak mencobanya
Minifikasi JS cukup mekanis dan sederhana, jadi membalikkannya juga semestinya relatif mudah
Tentu saja secara umum cukup membosankan untuk dilakukan manusia secara manual, tetapi transformasinya sendiri cukup terbatas sehingga bisa dibaca asalkan ada catatan untuk melacak identifier yang diobfuscate
Deminifikasi atau deobfuscation yang lebih umum tampaknya masih menjadi masalah terbuka. Dulu saya pernah menulis beberapa program yang sengaja diobfuscate, dan dalam pengalaman saya ChatGPT bahkan tidak memahaminya pada level permukaan
Misalnya ada komentar yang mencoba menjelaskan kode dengan GPT-4 pada gist interpreter Brainfuck 160 byte yang ditulis dalam C [1], tetapi “versi yang diperjelas” itu sama sekali tidak mirip dengan kode aslinya
[1] https://gist.github.com/lifthrasiir/596667#gistcomment-47512...
Contohnya perkalian/faktorisasi prima, diferensiasi/integrasi, mengingat masa lalu/memprediksi masa depan
Deobfuscation kode jelas termasuk salah satu inverse problem yang sulit seperti ini, dan bisa dengan mudah menjadi lebih sulit karena bug, routine yang tidak digunakan atau tidak relevan, serta implementasi keliru yang kebetulan menghasilkan keluaran benar
Dalam pengertian itu, jika ChatGPT memberikan hasil yang lumayan dalam deobfuscation, itu hal yang patut disyukuri; tidak ada ekspektasi apriori bahwa ia memang harus bisa. Bagus bahwa batas ChatGPT diuji dengan masalah yang lebih sulit, tetapi menurut saya yang ditemukan hanyalah batas atas. Saya tidak menganggap contoh di artikel asli itu remeh
let userSignedInTimestamp = new Date()menjadilet x = new Date()itu sepele, tetapi untuk membaliknya kemungkinan besar perlu membaca dan memahami kode di sekitarnya untuk melihatxdigunakan dalam konteks apaDitambah lagi sisa kodenya juga sudah diminifikasi, jadi makin sulit, dan sekalipun semuanya benar, pada akhirnya itu tetap transformasi lossy, sehingga nama variabelnya mungkin memuat sifat yang tidak tertulis eksplisit di kode
Itu karena data hilang dalam prosesnya
Minifikasi juga bekerja dengan cara yang sama. Banyak informasi yang diperlukan untuk memahami kode hilang, dan mendapatkan kembali informasi itu bisa sangat rumit
timeFactormenjadiiyang jauh lebih pendek bisa saja mekanis dan sederhana, tetapi proses itu destruktif dan tidak relatif mudah dibalikTidak mungkin dilakukan tanpa memahami dengan cukup rinci apa yang sebenarnya dilakukan kode. Itulah bagian yang dilakukan LLM di sini, dan walau tidak mengejutkan, ini tetap keren. Sikap yang terlalu cepat meremehkan itu kurang bagus
Saya tidak sedang di PC, jadi belum bisa mengujinya
Bukankah di judul seharusnya memakai ChatGPT atau nama model GPT-4, bukan OpenAI yang merupakan nama perusahaan?
LLM unggul dalam transformasi teks
Ini adalah kekuatan intinya, tetapi rasanya belum dimanfaatkan secara memadai
Kemampuan lain seperti bernalar atau mempertahankan pengetahuan hanyalah efek samping dari kemampuan supermanusiawi ini untuk mereproduksi teks tanpa “memahami” makna yang dimaksud
Misalnya, ia tidak bisa mengurutkan daftar, tetapi bisa menerjemahkan bahasa. Sebab daftar yang hampir benar urutannya tetap salah, sedangkan terjemahan yang hampir benar sering kali kita terima
Jika sebuah tim mempertimbangkan apakah layak mengubah bagian besar kode Python menjadi Elixir, mereka tidak perlu lagi sekadar menebak-nebak
Belum lama ini saya mencoba menerjemahkan skrip Python ke JavaScript, hasilnya tanpa cela, dan dengan sedikit guardrail rasanya bisa diskalakan
Kami terutama memakainya untuk mengekstrak data terstruktur dari format lain
Selain itu, juga harus ada kekurangan pengetahuan atau keterampilan untuk menanganinya lebih cepat dengan awk, Python, Perl, dan sebagainya
Sebagian developer yang memakai kompresi sebagai sarana obfuscation pasti akan marah
Saya teringat dulu ada alat “enkripsi” kode di versi ColdFusion lama. Algoritmanya sangat lemah, sehingga tidak butuh waktu lama sampai seseorang membuat alat dekripsinya
Meski begitu, sebagian orang tidak suka karena mereka percaya alat itu aman, dan memakainya untuk menjual kode tanpa membuka source. Ini kisah akhir 90-an/awal 2000-an, sebelum open source menjadi default yang dominan
Sebuah website menawarkan kompetisi yang sebagian bergantung pada kode sisi klien yang di-obfuscate, dan peserta yang cerdik kini bisa memasukkannya ke ChatGPT untuk meningkatkan peluang menang
Ini baru permulaan
Ini adalah contoh kinerja intelektual yang lebih unggul daripada manusia
Tidak bisa disangkal. Tugas ini bersifat intelektual, dan tidak terkait dengan hafalan sederhana. Di web juga tidak ada begitu banyak pasangan kode terkompresi/kode yang sudah didekompresi yang bisa dipelajari LLM
LLM memahami apa yang sedang didekompresinya, dan untuk topik khusus ini, secara umum lebih unggul daripada manusia
Apa kita bisa yakin bahwa di web tidak banyak pasangan kode terkompresi dan tidak terkompresi? Itu mudah dibuat dari JS yang ada untuk dipakai sebagai set pelatihan, dan JS yang tidak terkompresi yang sudah dipakai untuk pelatihan juga luar biasa banyak
Alasan manusia sulit memahami kode terkompresi adalah nama variabel yang buram, loop yang canggung, whitespace yang diminimalkan, dan sebagainya. Komputer tidak kesulitan dengan hal-hal ini, dan memang itulah alasan kita melakukan kompresi sejak awal. Struktur attention semestinya cocok untuk tugas seperti ini
Saya juga berpendapat ada sangat banyak kode terkompresi/tidak terkompresi. Itulah tujuan file source map. Melihat investasi OpenAI dalam web browsing dan pengembangan perangkat lunak, tidak mengherankan jika data terkompresi/tidak terkompresi ikut masuk ke pelatihan
Komputer yang dapat langsung mengalikan angka 1000 digit adalah contoh manusia yang terlebih dahulu membuat alat semacam itu dan berhasil melakukan perkalian. Selain itu, apa lagi yang berhasil secara intelektual di sana? Komputer juga tidak menciptakan dirinya sendiri
Jika batas kecerdasan manusia dipotong di tengkorak, dan alat yang dibuat serta digunakan oleh kecerdasan itu tidak dihitung sebagai tahap dalam proses pemecahan masalah, maka kita juga harus menerima bahwa manusia tidak cukup cerdas untuk terbang ke luar angkasa, melakukan operasi, atau memasak sebagian besar makanan
Mengenali bentuk abstrak dari kode yang kehilangan nama variabel, lalu memetakan nama variabel yang dapat dibaca manusia ke pola serupa yang pernah dilihatnya di internet raksasa, bukanlah hal yang terdengar mustahil
Menarik, dan sepertinya sudah jauh membaik
Sedikit lebih dari setahun lalu, saya menerima email yang meminta bantuan untuk plugin kustom di situs WordPress yang diretas, lalu mencoba memakai GPT untuk deobfuscation kode berbahaya. Saat itu, menelusuri kode sendiri langkah demi langkah jauh lebih cepat kemajuannya
Setelah membaca tulisan ini, saya mencobanya lagi [0]. Memang memberi penjelasan yang bisa dipahami, tetapi obfuscation-nya pada dasarnya melakukan eval terhadap string yang tidak dapat dibaca melalui objek Window, jadi itu saja belum cukup
Sebagian laporan yang saya kirim saat itu berbunyi seperti ini: saya bisa membongkar kode JavaScript yang sangat di-obfuscate, mendeteksi page load, memanggil semacam kedok kalkulasi yang secara teori konstan, lalu menguraikan logika yang me-redirect halaman ke situs berbahaya
[0] https://chatgpt.com/share/f51fbd50-8df0-49e9-86ef-fc972bca6b...
Apakah ada yang sedang mengerjakan LLM decompiler?
Rasanya ini bisa membuat semua kode menjadi seperti open source.
Dalam kasus ini, data pelatihan mudah dibuat. Cukup build kode GitHub gratis secara massal dengan berbagai compiler, lalu latih model untuk membalik proses kompilasi. Ini adalah kasus di mana data pelatihan sintetis cocok dan cukup mudah dibuat.
Decompiler cukup dilatih hanya untuk membalik kompilasi, sedangkan tugas seperti menambahkan komentar bisa memakai LLM kode yang lebih besar yang sudah ada.
Bukan hanya membuatnya open source; kita bisa membayangkan situasi ketika aplikasi proprietary dapat dengan mudah didecompile dan dimodifikasi untuk memperbaiki bug atau menambahkan fitur. Ini bisa menjadi ruang kebebasan besar terutama untuk program lama yang sudah lama ditinggalkan.
Karena alasan hukum, kemungkinan besar perilaku seperti ini akan menjadi fitur yang diblokir di model-model utama.
Hak seperti itu hanya bisa diberikan oleh penulis kode.
Jika AI benar-benar memahami kode dengan baik, ia akan langsung membuat atau memperbaiki binary.
Saya percaya ketika programmer AI sejati muncul, ia tidak akan peduli pada kode yang bisa dibaca manusia dan akan menulis semuanya dalam machine code. Jika diberi tugas memelihara sistem yang ada, ia akan memahami seluruh stack software dan hardware secara utuh.
Mirip dengan model difusi pembuat gambar yang tidak peduli untuk mempelajari teknik menggambar yang sebenarnya.
Ini lebih dekat ke mengganti nama variabel dan fungsi serta menambahkan line break.
Ini sangat mirip dengan cara saya sering memakai LLM [0].
Saya memakainya sebagai langkah pertama dalam decoding ketika harus membaca kode dengan tenaga sendiri.
Rasanya sangat membebaskan ketika bisa memasukkan kode kacau balau seperti spaghetti, memintanya menguraikan agar lebih mudah dibaca, lalu mulai dari sana.
Seperti yang juga ditemukan penulis, LLM kadang melewatkan detail, tetapi bagian seperti itu bisa saya tangkap sendiri.
Kegunaan lainnya adalah ketika saya memahami apa yang dilakukan kode, tetapi tidak bisa benar-benar memahami mengapa dibuat dengan cara seperti itu. Ini terutama terjadi ketika orang yang menulis kode tersebut sudah tidak lagi bekerja di perusahaan. Saat itu saya memasukkan method ke chat LLM, menjelaskan apa yang dilakukannya, lalu bertanya mengapa beberapa hal mungkin dibuat dengan cara tertentu.
Tidak selalu sempurna, tetapi cukup sering ia memberikan penjelasan yang benar-benar masuk akal, tetap bertahan saat ditinjau, dan memberi wawasan baru. Sekali dua kali, ini bahkan mencegah saya melakukan refactoring yang nantinya akan menyulitkan.
[0] Saya memakai chatGPT dan belakangan beberapa model lain, terutama varian Claude, melalui openwebUI sebagai frontend untuk melihat perbedaannya. Ada juga konfigurasi menarik yang memungkinkan model-model berbeda meninjau jawaban satu sama lain.
Jika kode yang sudah di-unminify tidak cocok dengan kode yang diminify, seperti bagian akhir yang mengatakan “respons LLM tampaknya melewatkan beberapa detail implementasi”, kegunaannya akan sangat berkurang.
Terutama karena dalam banyak kasus kita tidak bisa sekadar menjalankan kode dan memeriksa perbedaannya seperti dalam artikel.
Edit: melihat thread di bawah, sepertinya itu masalah encoding. Namun akurasi tetap masih sedikit mengkhawatirkan.
Dalam beberapa kasus, ChatGPT melakukan refactoring sendiri selain unminifying.
Kode asli tidak langsung memanggil
handleResize, melainkan memiliki isinya secara inline. Mungkin minifier memang melakukan inlining sungguhan. Satu-satunya perbedaan nyata di sini adalah hilangnya kondisiif (typeof window < "u").Secara spesifik, yang dimaksud adalah karakter blok, tetapi sepertinya HN tidak mengizinkan penempelan karakter Unicode. Karakter itu terlihat di versi asli, tetapi tidak terlihat di versi yang dibuat ChatGPT.
Namun, sangat mungkin juga karena saya tidak menyertakan semua konteks yang diperlukan.
Mengurangi nilai seluruh output hanya karena beberapa karakter hilang rasanya terlalu seperti mencari-cari kesalahan yang sangat rewel. Selain itu, menurut saya outputnya identik.
Kalau hanya diminta mengganti nama variabel dan method, kemungkinan hasilnya akan lebih dekat dengan aslinya.