Dokümantasyon
/
Tarifler
/

Fonksiyon Adlarını LLM Analizinden Gizleme

Fonksiyon Adlarını LLM Analizinden Gizleme

Pro

Sorun

vmObfuscation: true seçeneğini etkinleştirdiniz, validateLicense gibi bir fonksiyon içeren bir dosya üzerinde çalıştırdınız ve obfuscate edilmiş çıktının hâlâ validateLicense metnini aynen içerdiğini fark ettiniz: gövde yok olmuş, yerini bayt kodu almış, ancak adın kendisi açıkça ortada duruyor.

JavaScript

Bunu gerçek bir kod tabanının tamamına yayın; validateLicense, decryptPayload, processPayment, checkSubscription gibi fonksiyon adlarından oluşan bir liste elde edersiniz. Bir LLM'in programın ne yaptığını anlamak için bayt kodunu kırmasına gerek yoktur: modülün davranışına dair kendinden emin ve doğru bir özet çıkarmak için yalnızca adlar yeterlidir. Bayt kodu anlaşılmazdır; içindekiler tablosu ise öyle değildir.

VM obfuscation bu adları neden korur

vmTargetFunctionsMode: 'root' (varsayılan) ile obfuscator kök düzeydeki her fonksiyonun gövdesini VM bayt koduna dönüştürür, ancak adına kasıtlı olarak dokunmaz. Kök düzeydeki bir fonksiyon bildirimi, anlamsal olarak çevreleyen kapsam üzerindeki bir bağlamadır: bir betik için bu global nesne, bir modül için ise modül kapsamı demektir (dışa aktarılmayan en üst düzey bir fonksiyon global değil modül kapsamındadır, ancak dosyada yine de kök düzeydedir). Obfuscator onu güvenli biçimde yeniden adlandıramaz, çünkü ona başka kimin başvurduğunu bilmesinin hiçbir yolu yoktur: başka bir paket, satır içi bir <script>, bir HTML onclick="validateLicense(...)" özniteliği, dinamik bir window['validateLicense'] araması vb.

Dolayısıyla varsayılan ayarın yaptığı ödünleşim şudur: uygulamayı koru, herkese açık yüzeyi olduğu gibi bırak. Bu, entegrasyonu bozulmadan tutar, ancak aynı zamanda bir LLM'in her giriş noktasının bedava bir dizinini elde etmesi anlamına gelir. Bu durumda obfuscation sonucu, okunabilir kalan adları listeleyen bir VMGlobalFunctionNamesNotRenamed uyarısı bildirir.

LLM destekli tersine mühendislik için bunun önemi

Birkaç yüz satırlık bayt kodu dağıtımıyla karşılaşan bir insan saldırgan genellikle vazgeçer. Aynı dosyayı alan bir LLM ise bayt koduna saldırmaya hiç uğraşmaz: adları okur, görebildiği birkaç string değişmeziyle çapraz karşılaştırma yapar ve şuna benzer bir şey üretir:

"Bu modül ücretli bir özelliğe erişimi denetler. validateLicense imzalı bir token'ı doğrular, checkExpiry süresi dolmuş lisansları reddeder ve activateFeature denetim geçtiğinde arayüzün kilidini açar. Şifre çözme yardımcısı decryptPayload içindedir."

Bu özet, bir saldırganın VM'e hiç dokunmadan hedefe yönelik bir atlatma planlaması için yeterlidir. Sızıntı adların kendisidir.

Çözüm: kodunuzu bir IIFE'ye sarmalayın

Bu sızıntıyı ortadan kaldırmanın en basit ve en sağlam yolu, hassas fonksiyonlarınızı kapsam ağacında bir düzey aşağı itmektir. Başka bir fonksiyonun içinde bildirilen fonksiyonlar kök düzeyde değildir; bu nedenle obfuscator onları yeniden adlandırmakta ve bildirimlerini diğer herhangi bir ifade gibi bayt koduna dahil etmekte serbesttir.

Bir IIFE (Immediately-Invoked Function Expression, hemen çağrılan fonksiyon ifadesi) bunu yapmanın en hafif yoludur: bir kez çalışan ve adıyla hiçbir şeyi dışarı açmayan tek bir sarmalayıcı fonksiyon ekler.

Önce: adlar açıkta

JavaScript

VM obfuscation sonrasında hem validateLicense hem de checkExpiry çıktıda adlarıyla varlığını sürdürür.

Sonra: adlar bir IIFE'nin arkasında gizli

JavaScript

Artık her iki fonksiyon bildirimi de IIFE'nin gövdesinde yer alır. Kök düzeydeki tek yapı IIFE'nin kendisidir ve anonim bir IIFE'nin sızdıracak bir adı yoktur. VM obfuscation sonrasında fonksiyon adları yeniden adlandırılır ve gövdeler bayt koduna dönüştürülür.

Ne değişti. Fonksiyonlara artık global değişkenler olarak erişilemez (adlarını sızdıran da buydu). Hâlâ çağrılabilirler, yalnızca aynı IIFE'nin içinden. Bir şeyin validateLicense fonksiyonunu gerçekten dışarıdan çağırması gerekiyorduysa artık ona ulaşamaz; aşağıdaki aktarıcı (trampoline) kalıbına bakın. Hiçbir şey çağırmıyorduysa hiçbir şey kaybetmediniz.

Dışa aktarılan adlar, ayrılmış tanımlayıcılar, string'ler ve gözlemlenebilir davranış görünür kalabilir. Sarmalamadan sonra entegrasyonları test edin; özellikle global değişkenleri, modül dışa aktarımlarını ve fonksiyon adlarını inceleyen kodu.

Bilinmesi gereken bir ödünleşim: IIFE gövdesi doğrudan bir eval ya da dinamik gövdeli bir new Function(...) / Function(...) çağrısı içeriyorsa, VM obfuscation o fonksiyonun tamamını ve içindeki her şeyi atlar (bir VMDynamicCodeSkipped uyarısı), çünkü çalışma zamanında oluşturulan kaynak, obfuscator aracının yeniden adlandırdığı tanımlayıcılara başvurabilir. IIFE'nin içine taşıdığınız kod bu durumda sıradan obfuscation'a geri düşer ve bayt kodu korumasını kaybeder. Dolaylı eval - (0, eval)(...) - kullanın veya seçenekler için VM obfuscation altında doğrudan eval sayfasına bakın.

Bir fonksiyonun gerçekten global olması gerekiyorsa ne olur?

Bazen bir fonksiyon gerçekten herkese açık bir giriş noktasıdır: satır içi bir olay işleyici, bir JSONP geri çağırması, üçüncü taraf bir SDK hook'u. İki seçeneğiniz vardır:

  • İnce bir aktarıcı (trampoline) dışa açın, mantığı IIFE'nin içinde tutun. Tek görevi IIFE kapsamındaki uygulamayı çağırmak olan küçük bir global sarmalayıcı bildirin. Aktarıcının adı yine sızar, ancak hiçbir anlamsal bilgi taşımaz (ona __entry1 veya benzeri bir ad verin) ve anlamlı mantığın tamamı gizli kalır.

    JavaScript

  • Çağrı noktasını yeniden yazın. Global değişken yalnızca satır içi bir onclick="validateLicense(...)" ona ihtiyaç duyduğu için varsa, satır içi işleyiciyi IIFE'nin içinden addEventListener ile değiştirin. HTML fonksiyonun adını anmaz, fonksiyonun global olmasına gerek kalmaz ve sızıntı tamamen ortadan kalkar.

En üst düzey değişken başlatıcıları: vmWrapTopLevelInitializers

Bir dosyanın kökünde yer alan tek şey fonksiyon bildirimleri değildir. En üst düzey değişken başlatıcıları (string sabitleri, yapılandırma nesneleri, arama tabloları) düz JavaScript olarak kaldıklarında çıktıda aynı ölçüde okunabilirdir. const API_BASE = '/api/v2/license' gibi bir satır, bir LLM'e function validateLicense kadar bilgi verir.

vmWrapTopLevelInitializers seçeneği (boolean, varsayılan false; güncel VM ön ayarları bunu etkinleştirir) uygun en üst düzey başlatıcıları bir IIFE'ye sarmalar; böylece değerin kendisi kaynakta bir değişmez olarak durmak yerine çalışma zamanında VM bayt kodu tarafından hesaplanır. Root modunda, düz JavaScript olarak kalan başlatıcılar bir VMTopLevelInitializerNotVirtualized uyarısıyla bildirilir.

Seçenek olmadan

JavaScript

vmWrapTopLevelInitializers: true ile

JavaScript

Bağlama adı (MY_STRING), fonksiyon adlarıyla aynı nedenle hâlâ kök düzeydedir (dosyanın dışındaki bir şey ona başvurabilir), ancak tuttuğu değer artık VM tarafından üretilir ve okunabilir metin olarak görünmez.

Yalnızca vmTargetFunctionsMode değeri 'root' (varsayılan) olduğunda ve vmAsyncExecutor kapalıyken etkilidir. Comment modunda seçeneğin hiçbir etkisi olmaz ve hiçbir uyarı bildirilmez. Root modunda vmAsyncExecutor altında (yalnızca async fonksiyonları sanallaştırır) da hiçbir etkisi olmaz ve derleme, düz JavaScript olarak bırakılan başlatıcılar için VMTopLevelInitializerNotVirtualized bildirir.

Bir dosyada VM'in sanallaştırabileceği hiçbir fonksiyon yoksa sonuç VMNoFunctionsToVirtualize bildirir; korumak istediğiniz kodu bir fonksiyona sarmalayın veya hassas fonksiyonları açıkça seçmek için comment modunu kullanın.

Bu yeterli olmadığında

  • Diğer modüllerden içe aktarılan adlar. Birden fazla dosyayı paketliyorsanız ve bir modül validateLicense fonksiyonunu başka bir modülün içe aktarması için dışa aktarıyorsa, paketleyici bu adı kök düzeydeki fonksiyonların görünür olduğu şekilde paketlenmiş çıktıda görünür tutar. Paketin kendisini bir IIFE'ye sarmalayın (çoğu paketleyici bunu yapabilir) veya dışa aktarımı bir IIFE'nin içine taşıyıp anlamsız bir aktarıcı aracılığıyla yeniden dışa açın.
  • Çalışma zamanı hâlâ gözlemlenebilir. Obfuscation, kodu anlamak ve değiştirmek için gereken çabayı artırır; tersine mühendisliğin imkânsız olduğunu garanti edemez. Gizli bilgileri ve belirleyici güvenlik kararlarını sunucuda tutun.

İlk olarak renameGlobals seçeneğine başvurmayın. Bu seçenek vardır ve kök düzeydeki tanımlayıcıları yeniden adlandırır, ancak bu tanımlayıcılardan hangilerine dosyanın dışından (diğer paketler, satır içi HTML, dinamik aramalar) başvurulduğunu bilmesinin hiçbir yolu yoktur. Onu açmak entegrasyonu çoğu zaman fark edilmesi zor şekillerde bozar. IIFE sarmalaması daha güvenlidir: global hiçbir şeyi yeniden adlandırmaz, yalnızca ihtiyacınız olmayan global değişkenleri oluşturmayı bırakır.