Obfuscator — mənbə kodu funksionallığını dəyişmədən oxunması çətin formaya çevirən alət. Obfuscator intellektual mülkiyyəti qorumaq, kod analizini çətinləşdirmək və reverse engineeringin qarşısını almaq üçün istifadə olunur. Android Developers Documentation-a görə, R8 və ProGuard vasitəsilə obfuskasiya Android tətbiqlərinin istehsal qurulmasının standart mərhələsidir.
Əsas məqamlar
Obfuscator — obfuskasiya həyata keçirən proqram: oxunaqlı kodu funksional baxımından ekvivalent, lakin insan üçün oxunmayan formaya çevirir. Obfuskatorun əsas vəzifələri — identifikatorların adının dəyişdirilməsi (identifier mangling), debug məlumatlarının silinməsi, idarəetmə axınının qarışdırılması (control flow obfuscation) və string literal şifrələməsidir (string encryption).
Obfuskasiya şifrələmə deyil. Şifrələnmiş kod deşifrələmədən icra oluna bilməz. Obfuskasiya olunmuş kod birbaşa JVM, ART və ya JavaScript mühərriki tərəfindən icra olunur, lakin insanın onu başa düşməsi olduqca çətindir. Obfuskasiya mütləq qoruma təmin etmir — motivasiyalı mütəxəssis həmişə deobfuskator və ya runtime debug vasitəsilə məntiqi bərpa edə bilər.
İlk kommersiya obfuskator ProGuard 2002-ci ildə Java appletləri üçün alət kimi ortaya çıxdı. Android-in inkişafı ilə (2008) ProGuard mobil inkişaf üçün standart oldu. 2018-ci ildə Google Android Gradle Plugin 3.4 üçün ProGuard-ı əvəz edən R8-i buraxdı. R8 ProGuard-dan 2–3 dəfə sürətlidir və SSA (Static Single Assignment) — məlumat axınını analiz etməyə imkan verən aralıq təmsil formatı səviyyəsində dərin optimallaşdırma hesabına daha yığcam bayt kodu yaradır.
Veb inkişafda obfuskasiya sadə əvəzetmələrdən (YUI Compressor, 2007) mürəkkəb AST transformatorlarına (Obfuscator.io, 2016) qədər təkamül etdi. Müasir JavaScript obfuskatorları control flow flattening, opaque predicates (həmişə true və ya false olan, lakin analizator üçün aşkar olmayan şərtlər) və runtime-də öz-özünə deşifrələnən string şifrələməsindən istifadə edir. Jscrambler (2012) obfuskasiyanı debuggerdən qoruma və DRM mexanizmləri ilə birləşdirir.
Tətbiq sahəsi genişdir. Mobil inkişafda obfuskatorlar kodu APK dekompilyatorlarından (jadx, APKTool, dex2jar) qoruyur. Veb inkişafda JavaScript obfuskasiyası alqoritmləri, API açarlarını və müştəri tərəfində biznes məntiqini qoruyur. Kitabxana və SDK-larda obfuskasiya kodun rəqiblər tərəfindən istifadəsinin qarşısını alır.
| Texnika | Obfuskasiyadan əvvəl | Obfuskasiyadan sonra |
|---|---|---|
| Sinif adlarının dəyişdirilməsi | NetworkManager | a |
| Metod adlarının dəyişdirilməsi | sendRequest() | b() |
| String şifrələməsi | "API_KEY" | decrypt("x9fK2p") |
| Şərtlərin qarışdırılması | if (a > b) | if (a > b ? true : false) |
Identifier mangling (identifikator adlarının dəyişdirilməsi) — ən geniş yayılmış metod. Sinif, metod, sahə və dəyişən adları qısa, məlumatsız stringlərlə əvəz olunur: a, b, c, aa, ab. Bu, kodun hər bir elementinin məqsədini anlamağı çətinləşdirir. ProGuard və R8 müxtəlif tiplər (sinif A, sahə A, metod A) üçün eyni adlardan istifadə edərək analizi daha da qarışdırır.
Control flow obfuscation (idarəetmə axınının qarışdırılması) kodun strukturunu elə dəyişir ki, xətti ardıcıllıq aşkar olmasın. Ölü budaqlar (dead branches) əlavə olunur, şərtlər tərsinə çevrilir (if (a) əvəzinə if (!a)), goto tipli operatorlar (break/continue etiketlərlə) yerləşdirilir. Bu, dekompilyator və debugger vasitəsilə analizi son dərəcə çətinləşdirir.
// Mənbə kodu
function authenticate(token) {
const url = "https://api.example.com/auth";
const headers = { Authorization: "Bearer " + token };
return fetch(url, { method: "POST", headers });
}// Obfuscator.io yüksək rejimdən sonra
const _0x4f2e = ["https://api.example.com/auth",
"Authorization", "Bearer ", "POST"];
(function(_0x5a3b, _0x4f2e) {
const _0x1c2d = function(_0x3e4f) {
while (--_0x3e4f) {
_0x5a3b["push"](_0x5a3b["shift"]());
}
};
_0x1c2d(++_0x4f2e);
}(_0x4f2e, _0x1c2d));
function _0x1c2d(_0x5a3b, _0x4f2e) {
return _0x4f2e[_0x5a3b];
}
function _0x3e4f(_0x1c2d) {
const _0x5a3b = _0x1c2d(0, "https://api.example.com/auth");
const _0x4f2e = { Authorization: "Bearer " + _0x1c2d };
return fetch(_0x5a3b, { method: "POST", headers: _0x4f2e });
}Obfuscator.io string massivləri, massivi qarışdırmaq üçün özünüçağıran funksiya əlavə etdi, bütün identifikatorların adını dəyişdi və stringləri massiv indeksləri ilə əvəz etdi. 5 sətirdən ibarət mənbə kodu 20+ oxunmayan sətirə çevrildi, lakin authenticate(token) funksionallığı tam qorundu. Deobfuskasiya AST analizi vasitəsilə mümkündür, lakin vaxt tələb edir.
ProGuard — 2002-ci ildən istifadə olunan Java və Android üçün klassik obfuskator. ProGuard üç tapşırığı yerinə yetirir: sıxma (shrinking — istifadə olunmayan sinif və metodların silinməsi), optimallaşdırma (bayt kodunun optimallaşdırılması) və obfuskasiya (identifikator adlarının dəyişdirilməsi). ProGuard Android Gradle Plugin-ə proguard-rules.pro faylı vasitəsilə kitabxanalar üçün istisna qaydaları ilə daxil edilir.
R8 — AGP 3.4-dən etibarən Android Gradle Plugin-ə daxil edilmiş daha müasir obfuskator. R8 ProGuard ilə eyni funksiyaları yerinə yetirir, lakin daha sürətlidir (sıfırdan Kotlin ilə yazılıb) və daha effektivdir (ART Runtime üçün bayt kodunu daha yaxşı optimallaşdırır). R8 konfiqurasiyası ProGuard üçün olduğu kimi eyni proguard-rules.pro faylları vasitəsilə aparılır. R8-i aktivləşdirmək üçün build.gradle-da minifyEnabled true təyin etmək kifayətdir.
Mapping faylı — R8/ProGuard-ın işinin nəticəsi, sinif, metod və sahələrin orijinal və obfuska olunmuş adları arasında uyğunluğu ehtiva edir. Mapping faylı crash report-ların analizi üçün kritik əhəmiyyətlidir: onsuz stack trace-də com.example.app.MainActivity.onCreate əvəzinə a.a.b olacaq. Firebase Crashlytics və Sentry avtomatik olaraq mapping fayllarını yükləyir və hesabatlarda orijinal adları bərpa edir.
Mapping faylları tətbiqin hər yeni versiyası dərc edilərkən Firebase və ya Sentry-ə yüklənməlidir. Mapping faylı itirilərsə və ya yüklənməzsə, obfuskasiyadan sonra bütün crash report-lar oxunmaz hala gəlir. Android Gradle Plugin mapping faylını avtomatik olaraq build/outputs/mapping/release/mapping.txt ünvanında saxlayır. Firebase üçün Crashlytics Gradle Plugin istifadə olunur, o release versiyasının qurulması zamanı mapping-i yükləyir.
// app/build.gradle — R8 vasitəsilə obfuskasiya
android {
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile(
"proguard-android-optimize.txt"),
"proguard-rules.pro"
}
}
}# proguard-rules.pro — saxlama qaydaları
# Gson üçün məlumat modelini saxla
-keep class com.example.model.** { *; }
# Retrofit interfeysləri üçün sinifləri saxla
-keep,allowobfuscation interface com.example.api.*
# İctimai activity-ləri obfuska etmə
-keep class * extends android.app.Activity {
public protected *;
}
# İstehsalda log-ları sil
-assumenosideeffects class android.util.Log {
public static boolean isLoggable(...);
public static int v(...);
public static int d(...);
}-keep qaydaları proguard-rules.pro-da kritik əhəmiyyətlidir — onlar olmadan R8 refeksiya (Gson, Retrofit, Room) vasitəsilə istifadə olunan sinif və metodları siləcək və ya adlarını dəyişəcək. assumenosideeffects istehsal kodundan Log.v və Log.d çağırışlarını silir. Gson, Retrofit və OkHttp kimi kitabxanalar AAR daxilində proguard.txt-də hazır qaydalar təqdim edir.
Obfuscator.io — identifikator adlarının dəyişdirilməsi, string şifrələməsi, idarəetmə axınının qarışdırılması (control flow flattening) və debugdan qoruma (debug protection) dəstəyi ilə ən populyar açıq JavaScript obfuscatorudur. Obfuskasiya konfiqurasiyası JSON-konfiq və ya CLI vasitəsilə aparılır. Pulsuz versiya əsas metodları dəstəkləyir; Enterprise versiyası polimorfik kod və özünümüdafiə əlavə edir.
Jscrambler — genişləndirilmiş qoruma ilə kommersiya JavaScript obfuscatoru: polimorfik transformasiyalar (hər işə salma yeni obfuska olunmuş kod yaradır), debuggerlərdən qoruma (DevTools aşkarlanması), ekran görüntülərindən qoruma (self-defending) və sona çatma mexanizmləri (kod müəyyən tarixdən sonra işləməyi dayandırır). Jscrambler bank tətbiqlərində və DRM sistemlərində istifadə olunur.
// obfuscate.js — Obfuscator.io konfiqurasiyası
const JavaScriptObfuscator = require("javascript-obfuscator");
const fs = require("fs");
const code = fs.readFileSync("app.js", "utf8");
const result = JavaScriptObfuscator.obfuscate(code, {
compact: true,
controlFlowFlattening: true,
controlFlowFlatteningThreshold: 0.75,
numbersToExpressions: true,
simplify: false,
stringArray: true,
stringArrayThreshold: 0.8,
debugProtection: true,
disableConsoleOutput: true,
});
fs.writeFileSync("app.obfuscated.js", result.code);Parametrlər Obfuscator.io: controlFlowFlattening: 0.75 blokların 75%-də idarəetmə axınını qarışdırır; stringArray: true string-ləri massivə çıxarır; debugProtection DevTools-un açılmasının qarşısını alır; disableConsoleOutput console.log-u silir. Həddlər nə qədər yüksəkdirsə, obfuskasiya vaxtı və kod ölçüsü bir o qədər böyük, lakin analiz bir o qədər çətindir.
Obfuskasiya qorumur runtime analizindən. Hücumçu tətbiqi debuggerdə (Frida, Objection, Xposed) işə sala və metodları real vaxtda ələ keçirə bilər. Obfuskasiya statik analizdən (APK dekompilyasiyası, bayt kodunun oxunması) qoruyur, lakin dinamik analizdən yox. Runtime analizindən qorunmaq üçün əlavə tədbirlər tələb olunur: SSL Pinning, Root Detection, Integrity Verification.
Tətbiq ölçüsü obfuskasiyadan sonra 20–50% arta bilər. Control flow obfuscation ölü budaqlar əlavə edir və şərtləri təkrarlayır — bu, bayt kodunun miqdarını artırır. String encryption qısa string literallarını decrypt() çağırışları ilə əvəz edir, bu da ölçüsü artırır. Mobil tətbiqlər üçün bu kritikdir, çünki APK ölçüsü birbaşa Google Play-də konversiyaya təsir göstərir.
Performans da əziyyət çəkir. Control flow obfuscation əlavə yoxlamalar və budaqlanmalar əlavə edir, metodların icra müddətini 5–15% artırır. String encryption hər stringə müraciət zamanı decrypt çağırışı əlavə edir. Performans üçün kritik funksiyalarda (Android-də onDraw, React-də render) obfuskasiya -keep qaydaları vasitəsilə söndürülməlidir.
Tez-tez verilən suallar
Şifrələmə kodu deşifrələmə olmadan icra olunmaz edir — icra üçün deşifrator tələb olunur. Obfuskasiya kodu oxunmaz, lakin birbaşa icra oluna bilən edir. Şifrələmə daha güclü qoruma təmin edir, lakin özü analiz oluna bilən yükləyici-deşifrator tələb edir.
Deobfuskasiya mümkündür, lakin zəhmətlidir. jadx, JEB Decompiler və UnConfuser kimi alətlər qismən deobfuskasiya ilə bayt kodunu bərpa edir. Orijinal adlarla mənbə kodunun tam bərpası mümkün deyil — adlar geri qaytarılmaz şəkildə itir. Müasir obfuskatorlar (R8, ProGuard) avtomatik deobfuskasiyaya davamlıdır.
Google Play obfuskasiya tələb etmir, lakin minifyEnabled vasitəsilə build.gradle-da onu tövsiyə edir. Obfuskasiyasız tətbiqlər APKTool və jadx vasitəsilə asanlıqla dekompilyasiya olunur, bu da onları API açar oğurluğu, modifikasiya və piratlıq üçün həssas edir. Əksər böyük tətbiqlər R8 və ya ProGuard istifadə edir.
Crash report-lar obfuskasiyadan sonra obfuska olunmuş adlar ehtiva edir (com.example.app.MainActivity əvəzinə a.b.c). Bərpa üçün R8/ProGuard tərəfindən yaradılan mapping faylları istifadə olunur. Mapping faylı stack trace-lərin avtomatik deobfuskasiyası üçün Firebase Crashlytics və ya Sentry-ə yüklənməlidir.
String Encryption — string literallarının (API açarları, URL, mesajlar) runtime-də decrypt funksiyasının çağırışı ilə şifrələnmiş məlumatlarla əvəz edilməsi. Bu, məxfi string-ləri dekompilyasiya olunmuş koddakı sadə axtarış vasitəsilə oxunmaqdan qoruyur. R8/ProGuard -encryptstrings qaydası vasitəsilə string encryption dəstəkləyir.
Nəticə
Açar təslim mobil tətbiq hazırlayacağıq
IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.
Həm də oxuyun