3 poin oleh GN⁺ 2024-08-30 | 1 komentar | Bagikan ke WhatsApp
  • 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 .map untuk 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, dan Math.min dipakai 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 inti eT menerima 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

Cara komponen React melakukan rendering

  • Komponen menggunakan useRef untuk merujuk ke div tempat teks akan dimasukkan, dan useState untuk menyimpan height dan width jendela
  • useEffect pertama menetapkan ukuran awal dengan window.innerHeight dan window.innerWidth, lalu memperbarui ukuran saat event resize terjadi
  • useEffect kedua menghitung ukuran grid ASCII berdasarkan ukuran layar
    • cols adalah Math.floor(width / 12) * 1.6
    • rows adalah Math.floor(height / 12)
    • aspect adalah cols / rows
  • setInterval dijalankan dengan interval 1_000 / 60 untuk 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
    • selectedCharacterSet
    • characterSetLength
    • calculateCharacter
    • tipe Size
    • komponen React AsciiArtGenerator
  • Nama variabel yang sulit dipahami diubah menjadi nama yang menunjukkan maksud implementasinya
    • calculateCharacter menghitung karakter yang akan ditampilkan berdasarkan koordinat, jumlah kolom dan baris, rasio layar, serta nilai waktu
    • textRef menunjuk ke div tempat teks sebenarnya dimasukkan
    • size dan setSize mewakili 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

 
GN⁺ 2024-08-30
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

    • Saya penasaran apakah sulit menambahkan fitur menamai ulang dari awal
      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_line alih-alih parallel_line_opposite_direction, atau menemukan nama yang lebih dapat digeneralisasi seperti find_instance_in_list alih-alih find_animal_instance_in_animals
    • Semestinya lebih banyak alat dibuat berbasis AST; kerja yang luar biasa
      Sejujurnya, saya masih menunggu version control pada level AST
    • Saya penasaran pertanyaan apa yang diajukan ke LLM
      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
    • Saya penasaran apakah ini bekerja juga pada file raksasa
      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...

    • Hanya karena suatu pekerjaan sederhana, bukan berarti pekerjaan kebalikannya juga harus sederhana
      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
    • Mengubah let userSignedInTimestamp = new Date() menjadi let x = new Date() itu sepele, tetapi untuk membaliknya kemungkinan besar perlu membaca dan memahami kode di sekitarnya untuk melihat x digunakan dalam konteks apa
      Ditambah 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
    • Mengubah foto berwarna menjadi hitam-putih cukup sederhana, tetapi mengembalikannya ke warna asli tidak mudah
      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
    • Mengubah nama variabel deskriptif timeFactor menjadi i yang jauh lebih pendek bisa saja mekanis dan sederhana, tetapi proses itu destruktif dan tidak relatif mudah dibalik
      Tidak 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 mencoba percobaan acak pertama dengan Claude 3.5 Sonnet: https://claude.site/artifacts/246c1b1a-3088-447a-a526-b1e716...
      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?

    • Mengingat OpenAI telah mengubah GPT, yang tadinya istilah teknis umum, menjadi merek, ada keadilan ironis tertentu dalam memakai OpenAI seolah-olah itu nama produk
  • LLM unggul dalam transformasi teks
    Ini adalah kekuatan intinya, tetapi rasanya belum dimanfaatkan secara memadai

    • Bukan hanya kekuatan inti, tetapi memang itulah hal yang dirancang untuk dilakukan oleh transformer, dan secara kontroversial bisa dibilang hanya itu yang bisa dilakukannya
      Kemampuan lain seperti bernalar atau mempertahankan pengetahuan hanyalah efek samping dari kemampuan supermanusiawi ini untuk mereproduksi teks tanpa “memahami” makna yang dimaksud
    • Terutama kuat pada transformasi yang hampir linear, ketika urutannya tidak banyak berubah dan tidak perlu mempertimbangkan hubungan antar-item secara mendalam
      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
    • Dengan alat yang tepat, seharusnya bisa memindahkan codebase ke bahasa dan framework lain hampir dengan sekali tekan tombol
      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
    • Bukankah ini sudah menjadi penggunaan utama di bisnis?
      Kami terutama memakainya untuk mengekstrak data terstruktur dari format lain
    • Masalahnya, kasusnya harus berupa situasi ketika risiko halusinasi tidak perlu terlalu dipikirkan, atau output bisa diverifikasi meski tidak ada data dalam format yang sudah berguna
      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

    • Sepertinya sebentar lagi akan muncul penggunaan seperti ini dan perlombaan senjata
      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

    • Ini hanya transformasi teks
      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
    • Saya optimistis terhadap AI, tetapi saya belum yakin ini contoh dari fenomena yang disebutkan
      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
    • Saya bukan ahli AI atau pemahaman kecerdasan, tetapi bukankah kita juga bisa mengatakan bahwa kalkulator portabel benar-benar memahami aritmetika dan memiliki kinerja intelektual yang lebih unggul daripada manusia?
    • Mengapa fakta bahwa manusia membuat alat untuk membantu dekompresi tidak boleh dimasukkan ke skor manusia?
      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
    • GPT-4 telah mengonsumsi lebih banyak kode daripada yang akan dilihat semua leluhur Anda sepanjang hidup mereka, dan memahami pola intrinsik antara kode dan versi terkompresinya
      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.

    • Potensi dampaknya sangat besar.
      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.
    • Memiliki source code hanyalah langkah pertama; kita juga membutuhkan hak untuk membaca, memodifikasi, menjalankan, dan mendistribusikan ulang versi modifikasi kode tersebut.
      Hak seperti itu hanya bisa diberikan oleh penulis kode.
    • Setuju. Menurut saya, “AI menghasilkan/memahami source code” adalah umpan pengalih perhatian yang besar.
      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.
    • Ada LLM yang mendecompile dari x86 ke C: https://github.com/albertan017/LLM4Decompile
    • Unminifying bukan decompile.
      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.

    • Untuk penggantian nama yang sebenarnya, harus memakai tool lain seperti HumanifyJS: https://github.com/jehna/humanify
    • Kode yang sudah di-unminify tampak cukup dekat dengan aslinya.
      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 kondisi if (typeof window < "u").
    • Bagian itu berarti versi yang dihasilkan ChatGPT kehilangan beberapa karakter yang dipakai dalam contoh asli.
      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.
    • Selain itu, ia juga diminta untuk mengimplementasikan ulang dari JavaScript ke TypeScript.
      Kalau hanya diminta mengganti nama variabel dan method, kemungkinan hasilnya akan lebih dekat dengan aslinya.