Bagaimana cara mengunci kelas Java yang dikompilasi untuk mencegah dekompilasi?

96

Bagaimana cara mengunci kelas Java yang dikompilasi untuk mencegah dekompilasi?

Saya tahu ini pasti topik yang didiskusikan dengan sangat baik di Internet, tetapi saya tidak dapat mengambil kesimpulan apa pun setelah merujuk mereka.

Banyak orang menyarankan obfuscator, tetapi mereka hanya mengganti nama kelas, metode, dan bidang dengan urutan karakter yang sulit diingat, tetapi bagaimana dengan nilai konstanta sensitif?

Misalnya, Anda telah mengembangkan komponen enkripsi dan dekripsi berdasarkan teknik enkripsi berbasis kata sandi. Sekarang dalam kasus ini, setiap orang Java rata-rata dapat menggunakan JAD untuk mendekompilasi file kelas dan dengan mudah mengambil nilai kata sandi (didefinisikan sebagai konstan) serta garam dan pada gilirannya dapat mendekripsi data dengan menulis program independen kecil!

Atau haruskah komponen sensitif semacam itu dibangun dalam kode native (misalnya, VC ++) dan memanggilnya melalui JNI ?

jatanp
sumber
Bahkan kode asli yang dibongkar cukup dapat dibaca oleh sebagian orang, Anda mungkin harus menggunakan beberapa obfuscator atau rakitan buatan tangan untuk membuatnya tidak jelas (C ++ umum yang dikompilasi dengan pengoptimalan cukup dapat dibaca). Kode apa pun yang dijalankan pada perangkat pengguna, dapat dicegat. Meskipun biaya / keterampilan persyaratan untuk intersepsi tersebut mungkin cukup tinggi, misalnya membobol kode chip "tahan kerusakan" kartu pintar bukanlah hal yang sepele, hanya dapat dilakukan dengan peralatan dan keterampilan terbaik. Dengan kelas Java ... Saya tidak akan terlalu repot, Anda mungkin dapat mengenkripsinya cukup untuk membuat anak skrip menjauh, tidak lebih.
Ped7g

Jawaban:

96

Beberapa pembuat obfuscode bytecode Java yang lebih canggih melakukan lebih dari sekadar mangling nama kelas. Zelix KlassMaster , misalnya, juga dapat mengacak aliran kode Anda dengan cara yang membuatnya sangat sulit untuk diikuti dan berfungsi sebagai pengoptimal kode yang sangat baik ...

Juga banyak obfuscator yang juga dapat mengacak konstanta string Anda dan menghapus kode yang tidak digunakan.

Solusi lain yang mungkin (tidak harus mengecualikan obfuscation) adalah dengan menggunakan file JAR terenkripsi dan classloader kustom yang melakukan dekripsi (sebaiknya menggunakan library runtime native).

Ketiga (dan mungkin menawarkan perlindungan terkuat) adalah menggunakan kompiler asli sebelumnya seperti GCC atau Excelsior JET , misalnya, yang mengompilasi kode Java Anda langsung ke biner asli khusus platform.

Bagaimanapun Anda harus ingat bahwa seperti kata pepatah dalam bahasa Estonia "Kunci untuk binatang". Artinya bahwa setiap bit kode tersedia (dimuat ke dalam memori) selama runtime dan diberi keterampilan, tekad, dan motivasi yang cukup, orang dapat dan akan mendekompilasi, menguraikan, dan meretas kode Anda ... Tugas Anda hanyalah membuat prosesnya tidak nyaman seperti Anda dapat dan tetap menjalankannya ...

Roland Tepp
sumber
13
1 untuk "Kunci untuk hewan". Saya kira istilah yang tepat di sini adalah script kiddies.
Antimony
Maksudmu GCJ, dan itu sudah mati.
Marquis dari Lorne
1
Enkripsi file komponen jar komponen juga mati. Gunakan JarProtector sebagai gantinya.
J.Profi
16

Selama mereka memiliki akses ke data terenkripsi dan perangkat lunak yang mendekripsinya, pada dasarnya tidak ada cara Anda dapat membuat ini sepenuhnya aman. Cara memecahkan masalah ini sebelumnya adalah dengan menggunakan beberapa bentuk kotak hitam eksternal untuk menangani enkripsi / dekripsi, seperti dongle, server otentikasi jarak jauh, dll. Namun meskipun demikian, mengingat bahwa pengguna memiliki akses penuh ke sistem mereka sendiri, ini hanya membuat sesuatu sulit, bukan tidak mungkin -kecuali Anda dapat mengikat produk Anda secara langsung ke fungsionalitas yang disimpan dalam "kotak hitam", seperti, katakanlah, server game online.

Erlend Halvorsen
sumber
13

Penafian: Saya bukan ahli keamanan.

Ini terdengar seperti ide yang buruk: Anda membiarkan seseorang mengenkripsi barang dengan kunci 'tersembunyi' yang Anda berikan padanya. Saya tidak berpikir ini bisa dibuat aman.

Mungkin kunci asimetris bisa berfungsi:

  • menyebarkan lisensi terenkripsi dengan kunci publik untuk mendekripsi
  • biarkan pelanggan membuat lisensi baru dan mengirimkannya kepada Anda untuk dienkripsi
  • mengirim lisensi baru kembali ke klien.

Saya tidak yakin, tapi saya yakin klien benar-benar dapat mengenkripsi kunci lisensi dengan kunci publik yang Anda berikan padanya. Anda kemudian dapat mendekripsikannya dengan kunci pribadi Anda dan juga mengenkripsi ulang.

Anda dapat menyimpan pasangan kunci publik / pribadi yang terpisah per pelanggan untuk memastikan Anda benar-benar mendapatkan barang dari pelanggan yang tepat - sekarang Anda bertanggung jawab atas kuncinya ...

Daren Thomas
sumber
2
Saya telah menggunakan teknik ini sebelumnya dan itu berfungsi dengan baik. Namun, dari perspektif serangan, pendekatan pertama adalah dengan hanya memodifikasi kode yang melakukan pemeriksaan lisensi dan menghapusnya. Ada beberapa hal yang dapat Anda lakukan untuk membuat vektor serangan ini lebih sulit, tetapi jika Anda memberikan kendali atas perangkat keras kepada penyerang, Anda pasti akan gagal dengan penyerang yang memiliki motivasi dan keterampilan yang sesuai. Dalam praktiknya, tujuannya hanyalah untuk menjaga agar sebagian besar orang jujur, jujur.
Jim Rush
12

Tidak peduli apa yang Anda lakukan, itu bisa 'diuraikan'. Heck, Anda bisa membongkar saja. Atau lihat dump memori untuk menemukan konstanta Anda. Soalnya, komputer perlu mengetahuinya, jadi kode Anda juga perlu.

Apa yang harus dilakukan tentang ini?

Cobalah untuk tidak mengirimkan kunci sebagai konstanta hardcode dalam kode Anda: Simpan sebagai pengaturan per pengguna. Buat pengguna bertanggung jawab untuk menjaga kunci itu.

Daren Thomas
sumber
6

@jatanp: atau lebih baik lagi, mereka dapat mendekompilasi, menghapus kode lisensi, dan mengkompilasi ulang. Dengan Java, saya rasa tidak ada solusi yang tepat dan anti retas untuk masalah ini. Bahkan dongle kecil yang jahat tidak bisa mencegah ini dengan Java.

Manajer bisnis saya sendiri mengkhawatirkan hal ini, dan saya terlalu banyak berpikir. Tapi sekali lagi, kami menjual aplikasi kami ke perusahaan besar yang cenderung mematuhi ketentuan perizinan - umumnya lingkungan yang aman berkat penghitung kacang dan pengacara. Tindakan mendekompilasi itu sendiri bisa ilegal jika lisensi Anda ditulis dengan benar.

Jadi, saya harus bertanya, apakah Anda benar - benar membutuhkan perlindungan yang diperkuat seperti Anda mencari aplikasi Anda? Seperti apa basis pelanggan Anda? (Korporasi? Atau massa gamer remaja, di mana ini akan lebih menjadi masalah?)

Stu Thompson
sumber
Faktanya, ada solusi yang tepat dan tahan retas yang btw tampak seperti dongle: excelsior-usa.com/blog/excelsior-jet/…
Dmitry Leskov
@DmitryLeskov 'tahan retas', mungkin. Tapi itu hanyalah guncangan cepat bagi siapa saja yang menginginkan kode. Pada akhirnya, kode byte harus dijalankan pada platform host yang tidak dienkripsi. Titik.
Stu Thompson
Anda belum membaca postingan yang saya tautkan. Bytecode diubah menjadi kode CPU dongle dan dienkripsi. Saat pengguna akhir menjalankan aplikasi yang dilindungi, kode terenkripsi tersebut ditransfer ke "dongle". Dongle mendekripsi dan menjalankannya di CPU-nya.
Dmitry Leskov
2
Gamer remaja korporat.
odiszapc
3

Jika Anda mencari solusi lisensi, Anda dapat melihat API TrueLicense . Ini didasarkan pada penggunaan kunci asimetris. Namun, bukan berarti aplikasi Anda tidak bisa di-crack. Setiap aplikasi dapat diretas dengan usaha yang cukup. Yang paling penting adalah, seperti jawab Stu , mencari tahu seberapa kuat perlindungan yang Anda butuhkan.

hakan
sumber
2

Saya rasa tidak ada metode antipiracy offline yang efektif. Industri videogame telah mencoba untuk menemukannya berkali-kali dan program mereka selalu retak. Satu-satunya solusi adalah program harus dijalankan secara online yang terhubung dengan server Anda, sehingga Anda dapat memverifikasi kunci lincense, dan hanya ada satu koneksi aktif oleh pemegang lisensi pada satu waktu. Beginilah cara kerja World of Warcraft atau Diablo . Bahkan sulit ada server pribadi yang dikembangkan untuk melewati keamanan.

Karena itu, saya tidak percaya bahwa perusahaan menengah / besar menggunakan perangkat lunak yang disalin secara ilegal, karena biaya lisensi untuk mereka minimal (mungkin, saya tidak tahu berapa banyak biaya yang harus Anda kenakan untuk program Anda) dibandingkan dengan biaya versi percobaan.

Telcontar
sumber
2

Anda dapat menggunakan enkripsi kode byte tanpa rasa takut.

Faktanya adalah bahwa makalah yang dikutip di atas "Mengacak enkripsi kode byte Java" berisi kesalahan logika. Klaim utama kertas sebelum menjalankan semua kelas harus didekripsi dan diteruskan ke ClassLoader.defineClass(...)metode . Tapi ini tidak benar.

Asumsi yang terlewat di sini asalkan mereka berjalan dalam lingkungan run-time java yang otentik, atau standar . Tidak ada yang dapat mewajibkan aplikasi java yang dilindungi tidak hanya untuk meluncurkan kelas-kelas ini tetapi bahkan mendekripsi dan meneruskannya ClassLoader. Dengan kata lain, jika Anda menggunakan JRE standar, Anda tidak dapat mencegat defineClass(...)metode karena java standar tidak memiliki API untuk tujuan ini, dan jika Anda menggunakan JRE yang dimodifikasi dengan patched ClassLoaderatau "trik peretas" lainnya, Anda tidak dapat melakukannya karena dilindungi Aplikasi java tidak akan berfungsi sama sekali, dan oleh karena itu Anda tidak perlu melakukan apa pun. Dan sama sekali tidak masalah "pencari patch" mana yang digunakan atau trik mana yang digunakan oleh peretas. Detail teknis ini adalah cerita yang sangat berbeda.

Yury Bendersky
sumber
Bagaimana tepatnya Anda bermaksud mendeteksi JVM yang ditambal? Bagaimanapun, semua ini membuat segalanya sedikit lebih sulit.
Antimony
Tidak bisakah Anda menemukan panggilan ke defineClass () di peluncur aplikasi Anda? Ketika Anda melakukan panggilan itu, Anda tetap harus menyerahkan array byte yang didekripsi. Bukankah itu poin lain di mana sumber aslinya bisa bocor?
Ascendant
4
Saya tidak begitu setuju dengan jawaban ini. Bagi saya ini terdengar seperti, "Pertanyaan: Apa cara termudah untuk menemukan Pi? Jawaban: Ambil 2 * Pi dan bagi dua." Saya tidak setuju dengan gagasan itu, tetapi dapatkah Anda memasukkan lebih banyak detail? Misalnya, apakah Anda mengharapkan program utama ditulis dalam java murni? Apakah itu termasuk kode yang mencari modifikasi?
Patrick M
-1

T: Jika saya mengenkripsi file .class saya dan menggunakan classloader khusus untuk memuat dan mendekripsinya dengan cepat, apakah ini akan mencegah dekompilasi?

J: Masalah dalam mencegah dekompilasi kode byte Java hampir sama tuanya dengan bahasanya itu sendiri. Meskipun berbagai alat kebingungan tersedia di pasaran, programmer Java pemula terus memikirkan cara baru dan cerdas untuk melindungi kekayaan intelektual mereka. Dalam angsuran Tanya Jawab Java ini, saya menghilangkan beberapa mitos seputar ide yang sering diulang di forum diskusi.

Sangat mudahnya file .class Java dapat direkonstruksi menjadi sumber Java yang sangat mirip dengan aslinya sangat berkaitan dengan tujuan dan trade-off desain kode byte Java. Antara lain, kode byte Java dirancang untuk kekompakan, kemandirian platform, mobilitas jaringan, dan kemudahan analisis oleh juru bahasa kode-byte dan kompiler dinamis JIT (just-in-time) / HotSpot. Bisa dibilang, file .class yang dikompilasi mengekspresikan maksud pemrogram dengan sangat jelas sehingga lebih mudah dianalisis daripada kode sumber aslinya.

Beberapa hal bisa dilakukan, jika tidak untuk mencegah pembusukan sepenuhnya, setidaknya membuatnya lebih sulit. Misalnya, sebagai langkah pasca-kompilasi, Anda dapat memijat data .class untuk membuat kode byte lebih sulit dibaca saat didekompilasi atau lebih sulit untuk didekompilasi menjadi kode Java yang valid (atau keduanya). Teknik seperti melakukan overloading nama metode ekstrim bekerja dengan baik untuk yang pertama, dan memanipulasi aliran kontrol untuk membuat struktur kontrol yang tidak mungkin untuk direpresentasikan melalui sintaks Java bekerja dengan baik untuk yang terakhir. Obfuscator komersial yang lebih sukses menggunakan campuran teknik ini dan lainnya.

Sayangnya, kedua pendekatan tersebut harus benar-benar mengubah kode yang akan dijalankan JVM, dan banyak pengguna takut (memang seharusnya demikian) bahwa transformasi ini dapat menambahkan bug baru ke aplikasi mereka. Selanjutnya, metode dan penggantian nama bidang dapat menyebabkan panggilan refleksi berhenti bekerja. Mengubah nama kelas dan paket sebenarnya dapat merusak beberapa Java API lainnya (JNDI (Penamaan Java dan Antarmuka Direktori), penyedia URL, dll.). Selain nama yang diubah, jika asosiasi antara offset kode byte kelas dan nomor baris sumber diubah, memulihkan jejak tumpukan pengecualian asli bisa menjadi sulit.

Lalu ada opsi untuk mengaburkan kode sumber Java asli. Tetapi pada dasarnya hal ini menyebabkan serangkaian masalah serupa. Enkripsi, bukan obfuscate?

Mungkin hal di atas telah membuat Anda berpikir, "Bagaimana jika alih-alih memanipulasi kode byte saya mengenkripsi semua kelas saya setelah kompilasi dan mendekripsinya dengan cepat di dalam JVM (yang dapat dilakukan dengan classloader khusus)? Kemudian JVM menjalankan kode byte asli dan tidak ada yang perlu didekompilasi atau direkayasa balik, bukan? "

Sayangnya, Anda salah, baik dalam berpikir bahwa Anda adalah orang pertama yang mengemukakan ide ini dan berpikir bahwa ide itu benar-benar berhasil. Dan alasannya tidak ada hubungannya dengan kekuatan skema enkripsi Anda.

S Harish Morampudi
sumber