Rumah >hujung hadapan web >tutorial js >Begini cara untuk membuat kekeliruan dalam JavaScript tanpa membakar makmal: AST, Babel, pemalam.

Begini cara untuk membuat kekeliruan dalam JavaScript tanpa membakar makmal: AST, Babel, pemalam.

DDD
DDDasal
2025-01-10 12:34:44149semak imbas

pengenalan

Hei, pernahkah anda terfikir tentang betapa hebat dan uniknya algoritma anda? ? Banyak pengaturcara dan syarikat melakukannya, itulah sebabnya mereka mungkin teragak-agak untuk berkongsi kerja mereka dengan semua orang. Masalah ini menjadi lebih baik sedikit jika sebahagian daripada kod dialihkan ke pelayan (untuk aplikasi pelayan pelanggan), tetapi pendekatan ini tidak selalu boleh dilakukan. Kadangkala, kita perlu meninggalkan bahagian kod sensitif di tempat terbuka.

Dalam artikel ini, kita akan melihat kekeliruan dalam JavaScript, mencipta cara untuk menyembunyikan algoritma dan menjadikannya lebih sukar untuk mempelajari kod. Kami juga akan meneroka apa itu AST dan menyediakan alatan yang boleh digunakan untuk berinteraksi dengannya bagi melaksanakan pengeliruan.

Apa urusannya?

Berikut ialah contoh bodoh. Cuba bayangkan situasi ini:

  1. Bob pergi ke tapak yang memberikan monitor komputer (ini dia -> ?). Monitor Bob lebih baik, tetapi barangan percuma sentiasa bagus!
  2. Apabila Bob melawat tapak, JavaScript berjalan dalam penyemak imbas, mengumpul data tentang peranti pengguna dan menghantarnya ke pelayan. Katakan ini:
let w = screen.width, h = screen.height;
// Let's say there's a logic with some check. 
console.info(w, h);
  1. Malangnya, Bob tidak dapat mengakses halaman pemberian, dan dia agak kecewa mengenainya. Dia tidak faham kenapa. Kemudian dia belajar dalam peraturan pemberian bahawa pengguna dengan monitor besar dan baik tidak dibenarkan.

  2. Nasib baik, Bob pernah mengikuti beberapa kelas sains komputer di sekolah menengah. Dia membuka konsol pembangun dengan tegas dengan menekan F12, mengkaji skrip, dan menyedari bahawa penganjur menyemak resolusi skrin. Dia kemudian memutuskan untuk mengambil bahagian dari telefonnya dan berjaya lulus ujian.

Cerita fiksyen dengan pengakhiran yang menggembirakan - tetapi ia tidak mungkin sehebat ini jika watak utama melihat ini dan bukannya kod sebelumnya:

l=~[];l={___:++l,$$$$:(![]+"")[l],__$:++l,$_$_:(![]+"")[l],_$_:++l,$_$$:({}+"")[l],$$_$:(l[l]+"")[l],_$$:++l,$$$_:(!""+"")[l],$__:++l,$_$:++l,$$__:({}+"")[l],$$_:++l,$$$:++l,$___:++l,$__$:++l};l.$_=(l.$_=l+"")[l.$_$]+(l._$=l.$_[l.__$])+(l.$$=(l.$+"")[l.__$])+((!l)+"")[l._$$]+(l.__=l.$_[l.$$_])+(l.$=(!""+"")[l.__$])+(l._=(!""+"")[l._$_])+l.$_[l.$_$]+l.__+l._$+l.$;l.$$=l.$+(!""+"")[l._$$]+l.__+l._+l.$+l.$$;l.$=(l.___)[l.$_][l.$_];l.$(l.$(l.$$+"\""+(![]+"")[l._$_]+l.$$$_+l.__+"\"+l.$__+l.___+"\"+l.__$+l.$$_+l.$$$+"\"+l.$__+l.___+"=\"+l.$__+l.___+"\"+l.__$+l.$$_+l._$$+l.$$__+"\"+l.__$+l.$$_+l._$_+l.$$$_+l.$$$_+"\"+l.__$+l.$_$+l.$$_+".\"+l.__$+l.$$_+l.$$$+"\"+l.__$+l.$_$+l.__$+l.$$_$+l.__+"\"+l.__$+l.$_$+l.___+",\"+l.$__+l.___+"\"+l.__$+l.$_$+l.___+"\"+l.$__+l.___+"=\"+l.$__+l.___+"\"+l.__$+l.$$_+l._$$+l.$$__+"\"+l.__$+l.$$_+l._$_+l.$$$_+l.$$$_+"\"+l.__$+l.$_$+l.$$_+".\"+l.__$+l.$_$+l.___+l.$$$_+"\"+l.__$+l.$_$+l.__$+"\"+l.__$+l.$__+l.$$$+"\"+l.__$+l.$_$+l.___+l.__+";\"+l.__$+l._$_+l.$$__+l._$+"\"+l.__$+l.$_$+l.$$_+"\"+l.__$+l.$$_+l._$$+l._$+(![]+"")[l._$_]+l.$$$_+".\"+l.__$+l.$_$+l.__$+"\"+l.__$+l.$_$+l.$$_+l.$$$$+l._$+"(\"+l.__$+l.$$_+l.$$$+",\"+l.$__+l.___+"\"+l.__$+l.$_$+l.___+");"+"\"")())();

Here
Saya memberi jaminan kepada anda, ia bukan omong kosong, ia JavaScript! Dan ia melakukan tindakan yang sama. Anda boleh cuba menjalankan kod dalam konsol di sini.

Saya rasa dalam kes ini, wira kita akan menerima nasibnya dengan tidak mengambil bahagian dalam pemberian hadiah, dan penganjur akan mengekalkan rancangan mereka.

Jadi apa gunanya di sini? Tahniah - anda telah mempelajari tentang alat jjencode dan apakah kebingungan dan peranan yang boleh dimainkannya.

Ringkasnya, kekeliruan ialah proses menukar kod atur cara atau data kepada bentuk yang sukar difahami manusia tetapi masih berfungsi untuk mesin atau atur cara.

Menyembunyikan rahsia. Cara cepat

Teori yang cukup, mari kita beralih kepada contoh yang lebih praktikal ?‍?. Sekarang mari cuba menukar kod dengan bantuan kekeliruan yang lebih mungkin anda temui di Internet. Mari ambil kod yang lebih menarik yang mengandungi operasi "tahu-cara" kami. Dan adalah sangat tidak diingini bahawa semua orang yang tidak terlalu malas untuk mencapai F12 boleh mengetahui tentang mereka:

let w = screen.width, h = screen.height;
// Let's say there's a logic with some check. 
console.info(w, h);

Kod ini mengumpul data peranti dan penyemak imbas dan mengeluarkan hasilnya kepada konsol, contohnya (kami akan menggunakan output sebagai metrik prestasi kod):

l=~[];l={___:++l,$$$$:(![]+"")[l],__$:++l,$_$_:(![]+"")[l],_$_:++l,$_$$:({}+"")[l],$$_$:(l[l]+"")[l],_$$:++l,$$$_:(!""+"")[l],$__:++l,$_$:++l,$$__:({}+"")[l],$$_:++l,$$$:++l,$___:++l,$__$:++l};l.$_=(l.$_=l+"")[l.$_$]+(l._$=l.$_[l.__$])+(l.$$=(l.$+"")[l.__$])+((!l)+"")[l._$$]+(l.__=l.$_[l.$$_])+(l.$=(!""+"")[l.__$])+(l._=(!""+"")[l._$_])+l.$_[l.$_$]+l.__+l._$+l.$;l.$$=l.$+(!""+"")[l._$$]+l.__+l._+l.$+l.$$;l.$=(l.___)[l.$_][l.$_];l.$(l.$(l.$$+"\""+(![]+"")[l._$_]+l.$$$_+l.__+"\"+l.$__+l.___+"\"+l.__$+l.$$_+l.$$$+"\"+l.$__+l.___+"=\"+l.$__+l.___+"\"+l.__$+l.$$_+l._$$+l.$$__+"\"+l.__$+l.$$_+l._$_+l.$$$_+l.$$$_+"\"+l.__$+l.$_$+l.$$_+".\"+l.__$+l.$$_+l.$$$+"\"+l.__$+l.$_$+l.__$+l.$$_$+l.__+"\"+l.__$+l.$_$+l.___+",\"+l.$__+l.___+"\"+l.__$+l.$_$+l.___+"\"+l.$__+l.___+"=\"+l.$__+l.___+"\"+l.__$+l.$$_+l._$$+l.$$__+"\"+l.__$+l.$$_+l._$_+l.$$$_+l.$$$_+"\"+l.__$+l.$_$+l.$$_+".\"+l.__$+l.$_$+l.___+l.$$$_+"\"+l.__$+l.$_$+l.__$+"\"+l.__$+l.$__+l.$$$+"\"+l.__$+l.$_$+l.___+l.__+";\"+l.__$+l._$_+l.$$__+l._$+"\"+l.__$+l.$_$+l.$$_+"\"+l.__$+l.$$_+l._$$+l._$+(![]+"")[l._$_]+l.$$$_+".\"+l.__$+l.$_$+l.__$+"\"+l.__$+l.$_$+l.$$_+l.$$$$+l._$+"(\"+l.__$+l.$$_+l.$$$+",\"+l.$__+l.___+"\"+l.__$+l.$_$+l.___+");"+"\"")())();

Sekarang mari kita ambil kod di atas dan ubah suai dengan obfuscator popular untuk JS - obfuscator.io. Hasilnya, kami akan mendapat kod seperti ini:

function getGpuData(){
  let cnv = document.createElement("canvas");
  let ctx = cnv.getContext("webgl");
  const rendererInfo = ctx.getParameter(ctx.RENDERER);
  const vendorInfo = ctx.getParameter(ctx.VENDOR);

  return [rendererInfo, vendorInfo]
}

function getLanguages(){
  return window.navigator.languages;
}

let data = {};
data.gpu = getGpuData();
data.langs = getLanguages();
console.log(JSON.stringify(data))

Vila! Kini, hanya mesin yang akan senang menghuraikan kod ini (anda dan saya mungkin bukan antara mereka ?). Namun begitu, ia masih berfungsi dan menghasilkan hasil yang sama. Perhatikan perubahan:

  1. Pemutus talian dan ruang tambahan hilang.
  2. Nama pembolehubah telah digantikan dengan nama yang tidak bermaklumat seperti _0x587f42.
  3. String dan sifat objek telah ditukar kepada panggilan fungsi yang mengembalikan nilainya daripada tatasusunan mengikut indeks. Contohnya, document.createElement(“kanvas”) bertukar menjadi document[_0x12260c(0x197)](_0x12260c(0x191)). Ini dimungkinkan dengan menggunakan sifat yang dikira.

Teknik terakhir mungkin yang paling jahat dalam kes ini, dari segi membebankan analisis kod statik.

Baiklah, nampaknya semua rahsia disembunyikan. Adakah kita akan menggunakan kod ke pengeluaran?

Tunggu... Jika ada perkhidmatan untuk mengelirukan kod, mungkin ada yang boleh menarik balik perkara ini? Sudah tentu ?, dan lebih daripada satu! Mari cuba gunakan salah satu daripadanya - webcrack. Dan lihat jika kita boleh mendapatkan kod asal yang boleh dibaca. Di bawah ialah hasil penggunaan deobfuscator ini:

{"gpu":["ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0), or similar","Mozilla"],"langs":["en-US","en"]}

Aduh ?. Sudah tentu, ia tidak mengembalikan nama pembolehubah, tetapi terima kasih untuk itu.

Jadi, ternyata satu-satunya halangan untuk mempelajari kod kami dengan tenang dalam kes ini ialah kemahuan penyelidik untuk menggunakan deobfuscator. Tidak dinafikan, anda juga boleh menggunakan penyelesaian dan penyesuaian lain, tetapi untuk sebarang kekeliruan yang popular, kemungkinan besar kita akan menjangkakan penyahkeliruan yang popular.

Perlukah kita berputus asa dan melepaskan rahsia kita tanpa perlawanan? Sudah tentu tidak! Jom tengok apa lagi yang boleh kita buat....

Here

Bagaimana anda menjadi orang yang mengelirukan

Obfuscator - bunyi seperti ahli sihir dari alam fantasi, bukan? ??‍♂️
Sudah tentu, seseorang boleh mengelirukan kod semasa menulisnya dan merupakan ahli silap mata yang dilahirkan. Anda mungkin secara tidak sengaja telah dapat melafazkan mantra sedemikian untuk seketika. Tetapi apakah yang perlu anda lakukan sekarang jika kemahiran telah hilang kerana kritikan "pengaturcara senior" dan anda mempunyai idea yang berpotensi membolehkan anda membuat program sukar untuk disiasat? Dalam kes ini, masuk akal untuk beralih kepada alat yang berinteraksi dengan struktur kod itu sendiri dan membolehkan anda mengubah suainya. Mari lihat mereka.

ASTools

Anda juga boleh mencuba mengubah suai kod dengan berinteraksi dengannya sama seperti dengan teks, menggantikan binaan tertentu dengan ungkapan biasa dan sebagainya. Tetapi saya akan katakan bahawa mengikut cara ini, anda mempunyai lebih banyak peluang untuk merosakkan kod dan masa anda daripada mengelirukannya.

Untuk pengubahsuaian yang lebih dipercayai dan terkawal, masuk akal untuk membawanya ke struktur abstrak, pokok (AST - pokok sintaks abstrak), yang melaluinya kita boleh menukar elemen dan binaan yang kita minati .

Terdapat penyelesaian berbeza untuk bekerja dengan kod JS, dengan perbezaan dalam AST akhir. Dalam artikel ini, kami akan menggunakan babel untuk tujuan ini. Anda tidak perlu memasang apa-apa, anda boleh mencuba segala-galanya pada sumber seperti astexplorer.

(Jika anda tidak mahu bermain-main dengan babel, lihat shift-refactor. Ia membolehkan anda berinteraksi dengan AST menggunakan **pemilih CSS. Pendekatan yang agak minimalis dan mudah untuk pembelajaran dan mengubah suai kod. Tetapi ia menggunakan versi AST yang khusus, berbeza daripada babel Anda boleh menguji pertanyaan CSS anda untuk alat ini di interaktif shift-query demo).

0. Bekerja dengan AST

Sekarang mari kita lihat bagaimana alat ini boleh digunakan dengan mudah tanpa meninggalkan penyemak imbas, berdasarkan contoh mudah. Katakan kita perlu menukar nama pembolehubah ujian dalam fungsi yang dinamakan sama kepada ditukar:

let w = screen.width, h = screen.height;
// Let's say there's a logic with some check. 
console.info(w, h);

Tampal kod ini ke dalam astexplorer (pilih JavaScript dan @babel/parser dari atas), ia sepatutnya muncul sebagai AST di sana. Anda boleh mengklik pada pembolehubah ujian untuk melihat sintaks bagi bahagian kod ini dalam tetingkap kanan:
Here

Untuk menyelesaikan masalah kami, kami boleh menulis pemalam babel berikut, yang akan menghuraikan kod kami dan mencari semua pengecam nama di dalamnya dan menamakan semula kod tersebut jika syarat tertentu dipenuhi. Mari tampalkannya ke dalam tetingkap kiri bawah dalam astexplorer (hidupkan peluncur transform dan pilih babelv7 untuk memaparkannya):

let w = screen.width, h = screen.height;
// Let's say there's a logic with some check. 
console.info(w, h);

Output konsol disertakan dalam pemalam ini atas sebab tertentu. Ini membolehkan kami menyahpepijat pemalam kami dengan memeriksa output dalam konsol penyemak imbas. Dalam kes ini, kami mengeluarkan maklumat tentang semua nod jenis Pengecam. Maklumat ini mengandungi data tentang nod itu sendiri (nod), nod induk (induk) dan persekitaran (skop- mengandungi pembolehubah yang dibuat dalam konteks semasa dan rujukan kepada mereka):
Here

Oleh itu, di bahagian bawah tetingkap kanan, kami dapat melihat bahawa pembolehubah dalam kod sumber kami telah berjaya ditukar tanpa menjejaskan pengecam lain:

l=~[];l={___:++l,$$$$:(![]+"")[l],__$:++l,$_$_:(![]+"")[l],_$_:++l,$_$$:({}+"")[l],$$_$:(l[l]+"")[l],_$$:++l,$$$_:(!""+"")[l],$__:++l,$_$:++l,$$__:({}+"")[l],$$_:++l,$$$:++l,$___:++l,$__$:++l};l.$_=(l.$_=l+"")[l.$_$]+(l._$=l.$_[l.__$])+(l.$$=(l.$+"")[l.__$])+((!l)+"")[l._$$]+(l.__=l.$_[l.$$_])+(l.$=(!""+"")[l.__$])+(l._=(!""+"")[l._$_])+l.$_[l.$_$]+l.__+l._$+l.$;l.$$=l.$+(!""+"")[l._$$]+l.__+l._+l.$+l.$$;l.$=(l.___)[l.$_][l.$_];l.$(l.$(l.$$+"\""+(![]+"")[l._$_]+l.$$$_+l.__+"\"+l.$__+l.___+"\"+l.__$+l.$$_+l.$$$+"\"+l.$__+l.___+"=\"+l.$__+l.___+"\"+l.__$+l.$$_+l._$$+l.$$__+"\"+l.__$+l.$$_+l._$_+l.$$$_+l.$$$_+"\"+l.__$+l.$_$+l.$$_+".\"+l.__$+l.$$_+l.$$$+"\"+l.__$+l.$_$+l.__$+l.$$_$+l.__+"\"+l.__$+l.$_$+l.___+",\"+l.$__+l.___+"\"+l.__$+l.$_$+l.___+"\"+l.$__+l.___+"=\"+l.$__+l.___+"\"+l.__$+l.$$_+l._$$+l.$$__+"\"+l.__$+l.$$_+l._$_+l.$$$_+l.$$$_+"\"+l.__$+l.$_$+l.$$_+".\"+l.__$+l.$_$+l.___+l.$$$_+"\"+l.__$+l.$_$+l.__$+"\"+l.__$+l.$__+l.$$$+"\"+l.__$+l.$_$+l.___+l.__+";\"+l.__$+l._$_+l.$$__+l._$+"\"+l.__$+l.$_$+l.$$_+"\"+l.__$+l.$$_+l._$$+l._$+(![]+"")[l._$_]+l.$$$_+".\"+l.__$+l.$_$+l.__$+"\"+l.__$+l.$_$+l.$$_+l.$$$$+l._$+"(\"+l.__$+l.$$_+l.$$$+",\"+l.$__+l.___+"\"+l.__$+l.$_$+l.___+");"+"\"")())();

Saya harap, berdasarkan contoh ini, ia menjadi lebih jelas sedikit cara kita boleh menghuraikan dan mengubah suai kod. Bagaimanapun, izinkan saya meringkaskan kerja yang dilakukan:

  1. Kami menukar kod kepada AST menggunakan babel melalui astexplorer.
  2. Dengan memeriksa AST, kami melihat bahawa pembolehubah ujian dilabelkan dengan jenis Pengecam, yang namanya boleh ditakrifkan menggunakan sifat nama.
  3. Seterusnya, menggunakan pemalam babel kami, kami memintas semua pengecam dan menukar nama mereka dalam fungsi dengan ujian nama ditukar.

1. Menyembunyikan fungsi dan nama pembolehubah

Kini jelas bagaimana pengubahsuaian kod boleh dilakukan. Mari cuba sesuatu yang lebih berguna, yang boleh kita panggil kebingungan :) Kami akan mengambil kod yang lebih kompleks yang kami cuba untuk mengelirukan dalam bahagian sebelumnya. Sekarang kita akan menukar semua nama pembolehubah dan fungsi di dalamnya kepada yang rawak. Jadi, seorang jurutera terbalik yang berpotensi akan mempunyai kurang maklumat tentang tujuan beberapa elemen kod.

Selain itu, jangan ragu untuk menggunakan sebarang kod JS untuk menyahpepijat masalah. Seperti yang mereka katakan, tiada guru yang lebih baik daripada kesakitan ?.

Pemalam berikut akan membantu kami menyelesaikan kerja:

function getGpuData(){
  let cnv = document.createElement("canvas");
  let ctx = cnv.getContext("webgl");
  const rendererInfo = ctx.getParameter(ctx.RENDERER);
  const vendorInfo = ctx.getParameter(ctx.VENDOR);

  return [rendererInfo, vendorInfo]
}

function getLanguages(){
  return window.navigator.languages;
}

let data = {};
data.gpu = getGpuData();
data.langs = getLanguages();
console.log(JSON.stringify(data))

Apakah fungsi kod ini? Hampir sama seperti contoh sebelumnya:

  1. Kami melalui semua nod AST jenis Pengecam;
  2. Kali ini, kami menggunakan fungsi generateRndName untuk menjana nama secara rawak untuk pengecam tanpa sebarang syarat;
  3. Menjana nama unik menjamin bahawa kami tidak akan secara rawak mendapat nama pendua yang boleh memecahkan logik program.

Sebagai hasil daripada pelaksanaan pemalam kami, kami mendapat kod berikut dengan nama dan fungsi pembolehubah rawak:

{"gpu":["ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0), or similar","Mozilla"],"langs":["en-US","en"]}

Anda boleh menyemaknya dengan melaksanakan kod dalam konsol - selepas manipulasi kami, ia masih berfungsi! Dan ini adalah kualiti utama obfuscator yang baik ✨.

Tetapi bagaimana pula dengan kualiti kekeliruan kami? Bagi saya - kejahatan masih belum terlalu kuat: walaupun dengan menggantikan nama, ia akan menjadi mudah bagi pengaturcara yang berpengalaman untuk memahami tujuan kod ini. Dan apa gunanya jika mana-mana pemendek JS boleh mengendalikan tugas ini. Adakah mungkin sekarang untuk melakukan sesuatu yang lebih praktikal dan menyusahkan untuk pembalikan? Ada lagi satu jampi...

Here

2. Sembunyi ? segala-galanya!

Saya mungkin agak yakin apabila saya menulis "semuanya", tetapi apa yang akan kami lakukan sekarang akan menyembunyikan tindakan kod kami pada tahap maksimum yang mungkin. Dalam bahagian ini, kami akan menyembunyikan rentetan dan pelbagai sifat objek untuk merumitkan analisis statik dan berpotensi menghalang "klien" daripada mengorek kod kami!

Mari kita ambil kod dengan nama tersembunyi yang diperoleh pada peringkat sebelumnya dan gunakan pemalam berikut padanya:

let w = screen.width, h = screen.height;
// Let's say there's a logic with some check. 
console.info(w, h);

Saya telah menerangkan serba sedikit kerja pemalam ini dalam ulasan kod, tetapi mari kita terangkan secara ringkas langkah demi langkah apa yang dilakukannya:

  1. Kami mencipta data tatasusunan yang akan menyimpan semua sifat dan rentetan untuk digantikan dalam kod. Tatasusunan ini akan digunakan dalam fungsi getData yang mengembalikan data kami;
  2. Seterusnya, kami melintasi AST dan mencari Program nod akar, yang menggunakan fungsi getData (mengembalikan sifat dan rentetan pada indeks tertentu) akan dimasukkan pada permulaan kod kami;
  3. Kemudian kami memintas nod jenis MemberExpression. Kami menggantikan sifat dengan panggilan ke fungsi getData. Dalam kes ini, binaan seperti document.createElement akan ditukar menjadi document[getData(0)], terima kasih kepada sifat yang dikira. Sepanjang perjalanan, kami meletakkan nama sifat ke dalam tatasusunan data;
  4. Akhir sekali, kami memintas nod jenis StringLiteral, di mana kami juga menggantikan rentetan dengan panggilan untuk mendapatkanData dengan indeks yang dikehendaki.

Perlu dinyatakan bahawa operasi penghuraian tidak dilakukan secara berurutan, tetapi kerana nod yang diperlukan ditemui semasa pemprosesan AST.

Sebagai hasil daripada melaksanakan pemalam ini, kami akan mendapat kod berikut:

l=~[];l={___:++l,$$$$:(![]+"")[l],__$:++l,$_$_:(![]+"")[l],_$_:++l,$_$$:({}+"")[l],$$_$:(l[l]+"")[l],_$$:++l,$$$_:(!""+"")[l],$__:++l,$_$:++l,$$__:({}+"")[l],$$_:++l,$$$:++l,$___:++l,$__$:++l};l.$_=(l.$_=l+"")[l.$_$]+(l._$=l.$_[l.__$])+(l.$$=(l.$+"")[l.__$])+((!l)+"")[l._$$]+(l.__=l.$_[l.$$_])+(l.$=(!""+"")[l.__$])+(l._=(!""+"")[l._$_])+l.$_[l.$_$]+l.__+l._$+l.$;l.$$=l.$+(!""+"")[l._$$]+l.__+l._+l.$+l.$$;l.$=(l.___)[l.$_][l.$_];l.$(l.$(l.$$+"\""+(![]+"")[l._$_]+l.$$$_+l.__+"\"+l.$__+l.___+"\"+l.__$+l.$$_+l.$$$+"\"+l.$__+l.___+"=\"+l.$__+l.___+"\"+l.__$+l.$$_+l._$$+l.$$__+"\"+l.__$+l.$$_+l._$_+l.$$$_+l.$$$_+"\"+l.__$+l.$_$+l.$$_+".\"+l.__$+l.$$_+l.$$$+"\"+l.__$+l.$_$+l.__$+l.$$_$+l.__+"\"+l.__$+l.$_$+l.___+",\"+l.$__+l.___+"\"+l.__$+l.$_$+l.___+"\"+l.$__+l.___+"=\"+l.$__+l.___+"\"+l.__$+l.$$_+l._$$+l.$$__+"\"+l.__$+l.$$_+l._$_+l.$$$_+l.$$$_+"\"+l.__$+l.$_$+l.$$_+".\"+l.__$+l.$_$+l.___+l.$$$_+"\"+l.__$+l.$_$+l.__$+"\"+l.__$+l.$__+l.$$$+"\"+l.__$+l.$_$+l.___+l.__+";\"+l.__$+l._$_+l.$$__+l._$+"\"+l.__$+l.$_$+l.$$_+"\"+l.__$+l.$$_+l._$$+l._$+(![]+"")[l._$_]+l.$$$_+".\"+l.__$+l.$_$+l.__$+"\"+l.__$+l.$_$+l.$$_+l.$$$$+l._$+"(\"+l.__$+l.$$_+l.$$$+",\"+l.$__+l.___+"\"+l.__$+l.$_$+l.___+");"+"\"")())();

Seperti yang anda lihat daripada kod yang terhasil, semua sifat telah digantikan dengan panggilan fungsi getData dengan indeks yang diberikan. Kami melakukan perkara yang sama dengan rentetan dan mula mendapatkannya melalui panggilan fungsi. Nama hartanah dan rentetan itu sendiri telah dikodkan dengan base64 untuk menjadikannya lebih sukar untuk diperhatikan...

Here

Saya rasa anda sudah perasan - pemalam ini, dan kod secara umum, mempunyai kelemahan pada peringkat ini. Contohnya, perkara berikut boleh dibetulkan:

  • Fungsi yang mengembalikan sifat dan rentetan kami menjerit tentang tujuannya - getData. Tetapi perkara yang baik ialah perkara ini boleh diperbetulkan dengan menggunakan pemalam pertama kami, yang menamakan semula pengecam.
  • Rentetan itu sendiri di dalam fungsi getData tidak dilindungi dengan pasti, agak mudah untuk mencari nilai awalnya, kerana ia hanya base64. Adalah lebih mencabar untuk menyelesaikan masalah ini, contohnya, anda boleh membuat semula fungsi getData dan menggunakan penyulitan dan bukannya pengekodan yang terkenal.
  • Fungsi getData adalah satu-satunya, dan tidak sukar untuk menulis skrip yang akan menggantikan semua panggilannya dengan nilai asal dengan menarik dan melaksanakan fungsi itu sendiri.

Walaupun semua kesederhanaan dan keburukan ini, saya rasa ia sudah boleh dipanggil kekeliruan. Tetapi sekali lagi, bagaimana kita berbeza daripada obfuscators sumber terbuka, kerana mereka melakukan perkara yang serupa?

Kita perlu ingat masalah asal — kekeliruan itu adalah satu kek untuk penyahkeliruan awam. Sekarang, mari kita ambil kod yang kita dapat dan nyahkelirukannya dalam webcrack! (semoga ia masih tidak dapat mengatasi mantera kami?). Saya rasa anda boleh mengatakan kepentingan praktikal telah dicapai - kod "dilindungi" kami tidak lagi boleh ditarik balik dalam satu klik melalui penyahkeliruan awam

Bonus. Penyahkeliruan

Sekarang mari belajar mantera baharu. Walaupun penyahkeliruan awam tidak dapat mengendalikan pemalam kami, namun, setelah mengkaji konsep sebenar pengeliruan kami, kami dapat melihat beberapa corak yang boleh digunakan untuk memulihkan kod sumber.

Mari kita mendalaminya, dan manfaatkan secara khusus:

  • Mempunyai satu fungsi dipanggil yang menyimpan sifat dan rentetan kami;
  • Panggilan ke fungsi ini tidak bertopeng;

Memandangkan kelemahan ini, kami boleh melaksanakan pemalam berikut:

let w = screen.width, h = screen.height;
// Let's say there's a logic with some check. 
console.info(w, h);

Mari kita terangkan fungsi pemalam nyahkeliruan ini:

  1. Kami menyalin fungsi getData daripada kod yang dikelirukan, dengan melaksanakannya dengan argumen (indeks) yang diperlukan, kami boleh mendapatkan rentetan yang diperlukan;
  2. Kami telah melalui semua panggilan fungsi getData dan menggantikannya dengan hasil pelaksanaannya;
  3. Akhir sekali, kami menemui fungsi getData dalam AST dan mengalih keluarnya daripada kod, kerana ia tidak lagi diperlukan di sana.

Hasilnya, kami mendapat kod berikut:

l=~[];l={___:++l,$$$$:(![]+"")[l],__$:++l,$_$_:(![]+"")[l],_$_:++l,$_$$:({}+"")[l],$$_$:(l[l]+"")[l],_$$:++l,$$$_:(!""+"")[l],$__:++l,$_$:++l,$$__:({}+"")[l],$$_:++l,$$$:++l,$___:++l,$__$:++l};l.$_=(l.$_=l+"")[l.$_$]+(l._$=l.$_[l.__$])+(l.$$=(l.$+"")[l.__$])+((!l)+"")[l._$$]+(l.__=l.$_[l.$$_])+(l.$=(!""+"")[l.__$])+(l._=(!""+"")[l._$_])+l.$_[l.$_$]+l.__+l._$+l.$;l.$$=l.$+(!""+"")[l._$$]+l.__+l._+l.$+l.$$;l.$=(l.___)[l.$_][l.$_];l.$(l.$(l.$$+"\""+(![]+"")[l._$_]+l.$$$_+l.__+"\"+l.$__+l.___+"\"+l.__$+l.$$_+l.$$$+"\"+l.$__+l.___+"=\"+l.$__+l.___+"\"+l.__$+l.$$_+l._$$+l.$$__+"\"+l.__$+l.$$_+l._$_+l.$$$_+l.$$$_+"\"+l.__$+l.$_$+l.$$_+".\"+l.__$+l.$$_+l.$$$+"\"+l.__$+l.$_$+l.__$+l.$$_$+l.__+"\"+l.__$+l.$_$+l.___+",\"+l.$__+l.___+"\"+l.__$+l.$_$+l.___+"\"+l.$__+l.___+"=\"+l.$__+l.___+"\"+l.__$+l.$$_+l._$$+l.$$__+"\"+l.__$+l.$$_+l._$_+l.$$$_+l.$$$_+"\"+l.__$+l.$_$+l.$$_+".\"+l.__$+l.$_$+l.___+l.$$$_+"\"+l.__$+l.$_$+l.__$+"\"+l.__$+l.$__+l.$$$+"\"+l.__$+l.$_$+l.___+l.__+";\"+l.__$+l._$_+l.$$__+l._$+"\"+l.__$+l.$_$+l.$$_+"\"+l.__$+l.$$_+l._$$+l._$+(![]+"")[l._$_]+l.$$$_+".\"+l.__$+l.$_$+l.__$+"\"+l.__$+l.$_$+l.$$_+l.$$$$+l._$+"(\"+l.__$+l.$$_+l.$$$+",\"+l.$__+l.___+"\"+l.__$+l.$_$+l.___+");"+"\"")())();

Here

Oleh itu, kami dapat menghilangkan kekeliruan yang menyembunyikan sifat dan rentetan dengan menulis pemalam mudah untuk babel menggunakan kelemahan yang ditunjukkan.

Saya harap contoh kecil ini menerangkan bagaimana anda boleh melawan gangguan sedemikian dengan bantuan babel. Menggunakan pendekatan ini, anda juga boleh menyelesaikan kekeliruan yang lebih kompleks - perkara utama ialah mencari corak dalam kod dan mengendalikan dengan mahir dengan AST.

Kesimpulan

Kami telah mempelajari tentang pengeliruan, teknik yang merumitkan kejuruteraan terbalik kod dan alatan untuk melaksanakannya. Walaupun terdapat penyelesaian awam yang mengelirukan kod JavaScript, terdapat sama banyak penyelesaian awam yang boleh mengalih keluar perlindungan ini dalam sekelip mata.

Oleh itu, anda perlu menulis penyelesaian anda sendiri untuk melindungi kod yang tidak boleh dialih keluar oleh deobfuscator awam. Satu cara yang boleh dipercayai untuk melaksanakan pengeliruan dalam JS ialah menulis pemalam babel tersuai yang berinteraksi dengan AST bagi kod yang dikehendaki, mengubahnya menjadi bentuk yang kurang boleh dibaca.

Sudah tentu, bidang ini mempunyai teknik dan pendekatan yang diketahui untuk mengelirukan, tetapi tetap terbuka kepada kreativiti dan "helah" baharu yang berpotensi menyukarkan pembelajaran kod. Walaupun sejumlah besar teknik sedemikian, mereka tidak menjamin kerahsiaan algoritma sama sekali, kerana kod sentiasa "di tangan" pelanggan. Selain itu, terdapat kemungkinan penyahpepijatan, yang boleh memudahkan untuk mengkaji kod tersebut. Kekeliruan membolehkan anda menolak penyelidik yang kurang bermotivasi, sekali gus meningkatkan kos kejuruteraan terbalik.

Terdapat beberapa pendekatan lanjutan, sebagai contoh, salah satu daripadanya antara kekeliruan ialah virtualisasi kod, atau secara ringkasnya, mencipta mesin maya dalam JS yang akan melaksanakan kod bait tersuai. Pendekatan ini hampir sepenuhnya menghapuskan peluang analisis statik dan menjadikan penyahpepijatan sesukar mungkin. Walau bagaimanapun, ini adalah subjek yang berasingan untuk perbincangan ?....

Saya harap ia berguna untuk anda mendapatkan maklumat tentang topik ini dan anda tidak akan menyalahkan diri sendiri atau pengaturcara anda untuk kod yang pada mulanya dikelirukan lagi. Hargai ahli sihir ini ??‍♀️! Saya akan berbesar hati untuk berbincang dengan anda tentang trend terkini dalam sihir di sini?

Atas ialah kandungan terperinci Begini cara untuk membuat kekeliruan dalam JavaScript tanpa membakar makmal: AST, Babel, pemalam.. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn