17 poin oleh GN⁺ 2026-03-12 | 3 komentar | Bagikan ke WhatsApp
  • DRM berbasis JavaScript yang berjalan di browser pada dasarnya selalu bisa dilewati karena data audio yang sudah didekripsi pada akhirnya harus melewati area yang bisa diakses JavaScript
  • HotAudio adalah platform hosting audio ASMR NSFW yang menerapkan proteksi salin dengan skema enkripsi dan pengiriman chunk miliknya sendiri menggunakan MediaSource Extensions API
  • Ini adalah catatan pertarungan tiga tahap, ketika pengembang berulang kali menambal sistemnya (menghapus variabel global, verifikasi hash, pemeriksaan integritas .toString(), isolasi iframe/Shadow DOM) dan penyerang selalu membalas dengan hooking prototype dan teknik penyamaran
  • DRM yang benar-benar efektif membutuhkan perlindungan perangkat keras berbasis Trusted Execution Environment (TEE) seperti Widevine atau FairPlay, tetapi platform kecil sulit mengaksesnya karena biaya lisensi dan masalah infrastruktur
  • DRM JavaScript memang berfungsi sebagai friksi bagi pengguna umum, tetapi tidak bisa menghentikan penyerang yang terampil, sehingga ada jurang besar antara ekspektasi dan kenyataan jika ini disebut "DRM"

Latar belakang: HotAudio dan batas bawaan DRM JavaScript

  • HotAudio adalah situs hosting audio ASMR NSFW yang mengklaim menyediakan fitur perlindungan DRM untuk kreator
  • Platform ini muncul sebagai alternatif setelah layanan hosting seperti Soundgasm dan Mega menjadi lebih terbatas karena pengetatan ToS
  • Analisis ini bermula dari komentar pengembang fermaw di Reddit yang menyebut implementasi DRM tersebut "menyenangkan"
  • Kode JavaScript pada hakikatnya berada di wilayah "userland", yakni kode yang didistribusikan kepada pengguna dan bisa diakses maupun dimodifikasi
  • Seberapa pun rumitnya key, nonce, atau format file terenkripsi yang digunakan, data yang sudah melewati logika dekripsi JavaScript pada akhirnya harus dikirim dalam bentuk plaintext ke engine audio browser

Peran Trusted Execution Environment (TEE)

  • Menurut definisi Microsoft, TEE adalah "area terisolasi pada CPU dan memori yang dilindungi dengan kriptografi", sehingga kode dari luar tidak dapat membaca atau memodifikasi data di dalamnya
  • TEE adalah area keamanan berbasis perangkat keras seperti ARM TrustZone atau Intel SGX, dan di atasnya berjalan Content Decryption Module (CDM) seperti Widevine, FairPlay, dan PlayReady
  • CDM ini memastikan key enkripsi dan buffer media yang sudah didekripsi tidak terekspos ke host OS
  • Untuk memperoleh lisensi Widevine diperlukan kontrak lisensi dengan Google, integrasi binary native, infrastruktur, prosedur hukum, dan biaya yang besar
  • Bagi platform audio NSFW skala kecil, mendapatkan lisensi Widevine pada praktiknya hampir mustahil

Cara kerja implementasi HotAudio dan "batas PCM"

  • HotAudio mengirim audio dalam bentuk terenkripsi dan memakai skema dekripsi kustom berbasis JavaScript yang mendekripsi serta memutar per chunk melalui MediaSource Extensions (MSE) API
  • Pendekatan ini efektif untuk mencegah simpan lewat klik kanan atau unduh langsung dari tab network bagi pengguna biasa
  • PCM (Pulse-Code Modulation) adalah format audio digital tak terkompresi terakhir yang dikirim ke speaker, titik akhir dari semua pipeline audio
  • Dalam serangan nyata, pelaku bahkan tidak perlu menelusuri sampai PCM; target terpenting adalah metode SourceBuffer.appendBuffer(), titik terakhir yang masih dapat diakses JavaScript
  • Saat appendBuffer dipanggil, data sebenarnya sudah didekripsi oleh JavaScript, dan decoder AAC/Opus browser tidak memahami enkripsi kustom HotAudio, sehingga yang bisa diterima hanyalah data hasil dekripsi dalam format codec standar
  • Momen di antara dekripsi selesai dan penyerahan ke engine media browser itulah "golden moment" yang bisa diintersep

Act 1: V1.0 — paparan variabel global dan hooking prototype

  • Player HotAudio mengekspos objek sumber audio sebagai variabel global window.as
  • Ekstensi V1 mencegat file nozzle.js yang selalu dikirim HotAudio pada tahap permintaan network lalu menyuntikkan kode yang sudah dimodifikasi
  • SourceBuffer.prototype.appendBuffer di-monkey patch untuk menyimpan chunk yang telah didekripsi ke dalam array sambil tetap memanggil fungsi aslinya secara normal
  • window.as.el dibisukan dan kecepatan putar diatur ke 16x (batas maksimum browser) agar seluruh audio cepat ter-buffer, lalu ketika event ended terjadi semua chunk digabung sebagai Blob dan diunduh sebagai file .m4a
  • Ini adalah serangan man-in-the-middle (MITM) sisi klien yang memanfaatkan API ekstensi browser, sehingga server HotAudio tidak bisa mengetahui adanya modifikasi
  • Respons pertama fermaw

    • Sekitar dua minggu setelah rilis publik, fermaw menerapkan patch
    • Paparan variabel global window.as dihapus, dan kode inisialisasi dibungkus dalam closure untuk mencegah akses dari luar
    • Diperkenalkan juga pemeriksaan verifikasi hash untuk nozzle.js (diduga SRI, hashing kustom, atau sistem nonce sisi server)
      • Jika file yang dimodifikasi tidak cocok dengan hash yang diharapkan, player tidak akan diinisialisasi

Act 2: V2.0 — teknik penyamaran dan hooking generik

  • Pertahanan in-memory dari fermaw

    • Dalam JavaScript, memanggil .toString() pada fungsi native mengembalikan "function appendBuffer() { [native code] }", sedangkan fungsi yang sudah di-monkey patch akan menampilkan kode sumber sebenarnya; fermaw memanfaatkan sifat ini
    • fermaw menambahkan pemeriksaan integritas yang menolak pemutaran jika SourceBuffer.prototype.appendBuffer.toString() tidak mengandung '[native code]'
    • Proses inisialisasi player juga diobfusikasi sehingga kelas AudioSource tidak lagi mudah ditemukan lewat polling loop
  • mockToString — fungsi penyamaran untuk menipu pemeriksaan integritas

    • .toString() dari fungsi yang sudah di-hook di-override agar mengembalikan "function nama() { [native code] }"
    • Hasilnya, pemeriksaan integritas fermaw menghasilkan false negative, sehingga keberadaan hook tidak bisa dideteksi
  • Hooking HTMLMediaElement.prototype.play

    • Alih-alih mencari window.as atau nama kelas tertentu, pendekatan generik dengan hooking HTMLMediaElement.prototype.play dipakai
    • Terlepas dari nama objek player atau seberapa dalam closure-nya, elemen audio akan tertangkap otomatis saat .play() dipanggil
    • Karena perangkat mobile umumnya hanya menjalankan satu player aktif, banyaknya pemanggilan .play() tidak terlalu efektif untuk mengganggu reverse engineering
  • Penguncian permanen lewat Object.defineProperty

    • window.Audio diganti dengan constructor hasil pembajakan, lalu diatur dengan writable: false dan configurable: false
    • Jika kode fermaw mencoba mengembalikan constructor Audio asli, browser akan melempar TypeError
    • Dengan begitu, hook tetap bertahan permanen selama umur halaman

Act 3: V3.0 — hooking total di level property descriptor

  • Upaya isolasi iframe dan Shadow DOM oleh fermaw

    • <iframe> memiliki window, document, dan rantai prototype yang independen, sehingga hook pada parent window tidak berlaku di dalam iframe
    • Shadow DOM adalah subtree DOM terisolasi yang elemennya tidak bisa dijelajahi dari dokumen utama dengan querySelector
    • Juga dicoba pendekatan yang menghindari intersepsi berbasis URL dengan menetapkan objek MediaStream atau MediaSource langsung melalui srcObject
  • Respons V3: hooking pada level property descriptor browser

    • Dengan Object.getOwnPropertyDescriptor, setter src dan srcObject pada HTMLMediaElement.prototype di-hook secara langsung
      • Di mana pun elemen audio berada—dokumen utama, iframe, atau web component—hook akan aktif saat source ditetapkan
      • Hook dipasang melalui injeksi document_start, sebelum iframe selesai diinisialisasi
  • Hooking addSourceBuffer: menyelesaikan race condition

    • Pada versi sebelumnya, jika SourceBuffer.prototype.appendBuffer di-hook di level prototype, kode fermaw masih bisa menghindarinya bila referensi appendBuffer di-cache sebelum hook dipasang
    • Di V3, MediaSource.prototype.addSourceBuffer di-hook untuk mencegat momen pembuatan instance SourceBuffer
      • Segera setelah instance dikembalikan, hook appendBuffer dipasang langsung ke instance tersebut sebagai own property
      • Karena hook selesai sebelum kode halaman melihat instance itu, penghindaran lewat cache menjadi mustahil sejak awal
  • Event listener fase capture — jaring pengaman terakhir

    • document.addEventListener dipakai dengan useCapture: true untuk memantau event play dan loadedmetadata pada fase capture
    • Event browser menyebar lebih dulu pada fase capture (root→target), sehingga listener ini selalu berjalan lebih dulu daripada listener event milik HotAudio
    • Kombinasi empat lapis: hooking prototype addSourceBuffer, hooking property descriptor src/srcObject, hooking play(), dan event listener fase capture, mencakup semua jalur pemutaran media browser

Otomatisasi: proses unduh berkecepatan tinggi

  • Elemen audio yang tertangkap dibisukan, playbackRate diatur ke 16x, lalu diputar dari awal
  • Browser kemudian berulang cepat menjalankan fetch → dekripsi → pengiriman ke SourceBuffer untuk mengisi buffer di depan posisi putar, dan semua chunk terkumpul lewat hook appendBuffer
  • Chrome membatasi kecepatan putar hingga 16x (HTML spec tidak menetapkan batas atas, tetapi implementasi Chromium memang membatasi)
  • fermaw menerapkan throttling untuk burst traffic (ratusan KB/detik → sekitar 50 KB/detik), tetapi ini tetap berkali-kali lebih cepat daripada mendengarkan secara real-time
    • Pembatasan yang lebih ketat sulit diterapkan karena akan memicu buffering pada pengguna normal
  • Kontrol kecepatan adaptif

    • Fitur tambahan di V3 memantau rentang waktu buffered dan menyesuaikan kecepatan putar secara dinamis sesuai kondisi buffer
      • Jika cadangan buffer lebih dari 15 detik, kecepatan dinaikkan; jika kurang dari 3 detik, kecepatan diturunkan
      • Ini mencegah browser macet (stall) dan masalah event ended yang tidak muncul pada koneksi lambat
  • Pembuatan file akhir

    • Saat pemutaran selesai (ended event atau currentTime sudah mendekati duration), semua chunk yang terkumpul digabung menjadi Blob lalu diunduh sebagai .m4a
    • Dapat muncul artefak padding senyap akibat chunk yang tidak utuh di batas buffer, dan ini bisa dirapikan dengan pascaproses ffmpeg

Fungsi spoof() di V3: penyamaran yang lebih canggih

  • mockToString pada V2 mengembalikan string kode native dengan hardcode, tetapi ini rapuh karena spasi dan format [native code] bisa sedikit berbeda antar-browser atau platform
  • spoof() di V3 mencapai pemalsuan yang sempurna dengan menangkap string kode native asli dari fungsi original sebelum hooking, lalu mengembalikannya apa adanya
  • Bentuk _call.call(_toString, original) memakai referensi Function.prototype.call dan Function.prototype.toString yang sudah di-cache sejak awal skrip
    • Karena itu, walaupun .toString kemudian dimodifikasi oleh kode lain, mekanisme ini tetap tidak terpengaruh

Batas mendasar DRM dan pertimbangan etis

  • Sepanjang sejarah DRM, masalah yang sama terus berulang: "memberi kotak terkunci sambil sekaligus menyerahkan kuncinya"
  • Sejak DVD dengan enkripsi CSS pertama kali dibobol pada 1999, industri film dan musik terus kalah dalam pertarungan ini
  • Bahkan Denuvo, DRM game paling canggih, juga dibobol untuk sebagian besar game besar hanya dalam hitungan minggu setelah rilis
    • Laju cracking sempat melambat setelah cracker terkenal Empress pensiun, tetapi kini kembali aktif berkat munculnya eksploit bergaya hypervisor
  • Selama konten dan key dekripsi sama-sama ada di mesin klien, intersepsi oleh pengguna yang punya motivasi dan alat yang memadai pada dasarnya tak terelakkan

Kesimpulan: DRM JavaScript hanyalah "friksi yang canggih", bukan DRM sejati

  • DRM HotAudio bukan gagal karena fermaw kurang mampu, melainkan karena inilah batas terbaik yang bisa dicapai DRM berbasis JavaScript
  • Ia sudah menerapkan dekripsi sisi klien, pengiriman per chunk, dan pemeriksaan anti-tamper aktif; bagi mayoritas pengguna yang tidak mengenal ekstensi browser, efeknya nyaris memblokir sepenuhnya
  • Namun, menyebutnya "DRM" menciptakan ekspektasi yang sama dengan DRM sejati berbasis hardware TEE, dan di situlah letak masalahnya
  • Penggemar berat kreator ASMR sering cukup berdedikasi hingga menginginkan salinan offline, dan jika tersedia kanal berbayar seperti Patreon, mereka kemungkinan bersedia membeli
  • Bisa dipahami bahwa kreator konten membutuhkan bentuk perlindungan tertentu, tetapi menerapkannya dengan JavaScript pada dasarnya adalah pendekatan yang tidak cocok

3 komentar

 
joyfui 2026-03-13

Sepertinya itu benar-benar adu akal yang sangat seru.
Saya juga pernah mengalami respons API yang tiba-tiba datang dalam keadaan terenkripsi, jadi saya berpikir, kalau menerima nilai terenkripsi berarti pasti ada proses dekripsi di sisi klien. Saya lalu menyalin seluruh kode JavaScript yang sudah dibundel apa adanya, menambahkan satu baris console.log tepat sebelum kode dekripsi, lalu menempelkannya begitu saja ke konsol developer. Tak disangka, itu langsung berfungsi. Bagaimanapun, setelah tahu kunci enkripsinya, langkah berikutnya jadi mudah. Ternyata kuncinya diambil dan dipakai dari respons API yang lain haha

 
crawler 2026-03-12

Kalau dipikir-pikir, menerapkan DRM pada audio itu... memang sangat sulit, bukan?
Rasanya bahkan tanpa peretasan yang rumit, cukup mengalirkan audio lewat kabel virtual saja sudah seperti bisa melakukan sesuatu.

 
crawler 2026-03-12

> Di JavaScript, saat .toString() dipanggil pada fungsi native, hasilnya adalah "function appendBuffer() { [native code] }", tetapi fungsi yang di-monkey patch akan mengembalikan source code aslinya — memanfaatkan karakteristik ini

Tapi seru juga lihat saling balasnya wkwkwk. Kelihatan ada akal-akalan yang bahkan AI pun pasti tidak kepikiran.