Obfuscator เป็นเครื่องมือที่แปลงซอร์สโค้ดให้อยู่ในรูปแบบที่อ่านยากโดยไม่เปลี่ยนแปลงฟังก์ชันการทำงาน Obfuscator ใช้เพื่อปกป้องทรัพย์สินทางปัญญา ทำให้การวิเคราะห์โค้ดซับซ้อน และป้องกันการวิเคราะห์ย้อนกลับ ตาม เอกสารของ Android Developers การทำให้สับสนผ่าน R8 และ ProGuard เป็นขั้นตอนมาตรฐานในการ build โปรดักชันของแอปพลิเคชัน Android
ประเด็นสำคัญ
Obfuscator เป็นโปรแกรมที่ทำการทำให้สับสน: การแปลงโค้ดที่อ่านได้ให้เป็นโค้ดที่เทียบเท่าทางฟังก์ชันแต่อ่านไม่ได้สำหรับมนุษย์ งานหลักของเครื่องมือทำให้สับสนคือการสลับตัวระบุ การลบข้อมูลดีบัก การทำให้โฟลว์ควบคุมสับสน และการเข้ารหัสสตริง
การทำให้สับสนไม่ใช่การเข้ารหัส โค้ดที่เข้ารหัสแล้วไม่สามารถทำงานได้หากไม่ถอดรหัส โค้ดที่ทำให้สับสนแล้วทำงานโดยตรงบน JVM, ART หรือเอ็นจิน JavaScript แต่เป็นเรื่องยากมากที่มนุษย์จะเข้าใจ การทำให้สับสนไม่ได้ให้การป้องกันที่สมบูรณ์ — ผู้เชี่ยวชาญที่มุ่งมั่นสามารถกู้คืนตรรกะได้เสมอผ่านเครื่องมือดีอบฟัสเคชันหรือการดีบักรันไทม์
เครื่องมือทำให้สับสนเชิงพาณิชย์ตัวแรก ProGuard ปรากฏในปี 2002 ในฐานะเครื่องมือสำหรับ Java applet ด้วยการเติบโตของ Android (2008) ProGuard จึงกลายเป็นมาตรฐานสำหรับการพัฒนาโมบายล์ ในปี 2018 Google เปิดตัว R8 เพื่อแทนที่ ProGuard สำหรับ Android Gradle Plugin 3.4 R8 เร็วกว่า ProGuard 2–3 เท่าและสร้างไบต์โค้ดที่กะทัดรัดยิ่งขึ้นเนื่องจากการปรับให้เหมาะสมเชิงลึกในระดับ SSA (Static Single Assignment) ซึ่งเป็นรูปแบบการแสดงผลขั้นกลางที่ช่วยให้วิเคราะห์โฟลว์ข้อมูลได้
ในการพัฒนาเว็บ การทำให้สับสนได้วิวัฒนาการจากเครื่องมือย่อขนาดง่าย ๆ (YUI Compressor, 2007) ไปเป็นตัวแปลง AST ที่ซับซ้อน (Obfuscator.io, 2016) เครื่องมือทำให้สับสน JavaScript สมัยใหม่ใช้การทำให้โฟลว์ควบคุมแบนราบ ภาคแสดงทึบแสง (เงื่อนไขที่เป็นจริงหรือเท็จเสมอแต่ไม่ชัดเจนสำหรับผู้วิเคราะห์) และการเข้ารหัสสตริงด้วยการถอดรหัสตัวเองในรันไทม์ Jscrambler (2012) รวมการทำให้สับสนเข้ากับการป้องกันดีบักเกอร์และกลไก DRM
ขอบเขตการใช้งาน กว้างขวาง ในการพัฒนาโมบายล์ เครื่องมือทำให้สับสนป้องกันโค้ดจากการถูกขโมยผ่านดีคอมไพเลอร์ APK (jadx, APKTool, dex2jar) ในการพัฒนาเว็บ การทำให้ JavaScript สับสนช่วยปกป้องอัลกอริทึม คีย์ API และตรรกะทางธุรกิจฝั่งไคลเอ็นต์ ในไลบรารีและ SDK การทำให้สับสนป้องกันคู่แข่งจากการใช้โค้ด
| เทคนิค | ก่อนทำให้สับสน | หลังทำให้สับสน |
|---|---|---|
| การเปลี่ยนชื่อคลาส | NetworkManager | a |
| การเปลี่ยนชื่อเมธอด | sendRequest() | b() |
| การเข้ารหัสสตริง | "API_KEY" | decrypt("x9fK2p") |
| การทำให้เงื่อนไขสับสน | if (a > b) | if (a > b ? true : false) |
Identifier Mangling เป็นวิธีการที่พบได้บ่อยที่สุด ชื่อของคลาส เมธอด ฟิลด์ และตัวแปรถูกแทนที่ด้วยสตริงสั้น ๆ ที่ไม่มีข้อมูล: a, b, c, aa, ab ซึ่งทำให้เข้าใจวัตถุประสงค์ของแต่ละองค์ประกอบโค้ดได้ยาก ProGuard และ R8 ใช้ชื่อที่เหมือนกันสำหรับประเภทต่าง ๆ (คลาส A, ฟิลด์ A, เมธอด A) ทำให้การวิเคราะห์ซับซ้อนยิ่งขึ้น
การทำให้โฟลว์ควบคุมสับสน เปลี่ยนโครงสร้างโค้ดเพื่อให้ลำดับเชิงเส้นไม่ชัดเจน มีการเพิ่มสาขาที่ตายแล้ว เงื่อนไขถูกกลับด้าน (if (!a) แทน if (a)) ตัวดำเนินการแบบ goto (break/continue พร้อมป้ายกำกับ) ถูกแทรกเข้าไป ซึ่งทำให้การวิเคราะห์ผ่านดีคอมไพเลอร์และดีบักเกอร์ใช้เวลาอย่างมาก
// ซอร์สโค้ด
function authenticate(token) {
const url = "https://api.example.com/auth";
const headers = { Authorization: "Bearer " + token };
return fetch(url, { method: "POST", headers });
}// หลัง Obfuscator.io ในโหมดสูง
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 เพิ่มอาร์เรย์สตริง ฟังก์ชันเรียกตัวเองเพื่อสลับอาร์เรย์ เปลี่ยนชื่อตัวระบุทั้งหมด และแทนที่สตริงด้วยดัชนีอาร์เรย์ โค้ดต้นฉบับ 5 บรรทัดกลายเป็น 20+ บรรทัดที่อ่านไม่ได้ แต่ฟังก์ชัน authenticate(token) ยังคงทำงานได้อย่างสมบูรณ์ การดีอบฟัสเคชันสามารถทำได้ผ่านการวิเคราะห์ AST แต่ต้องใช้เวลา
ProGuard เป็นเครื่องมือทำให้สับสนคลาสสิกสำหรับ Java และ Android ที่ใช้งานตั้งแต่ปี 2002 ProGuard ทำสามอย่าง: การบีบอัด (ลบคลาสและเมธอดที่ไม่ใช้), การปรับให้เหมาะสม (ปรับไบต์โค้ดให้เหมาะสม) และการทำให้สับสน (เปลี่ยนชื่อตัวระบุ) ProGuard ถูกรวมเข้ากับ Android Gradle Plugin ผ่านไฟล์ proguard-rules.pro พร้อมกฎยกเว้นสำหรับไลบรารี
R8 เป็นเครื่องมือทำให้สับสนที่ทันสมัยกว่าซึ่งรวมอยู่ใน Android Gradle Plugin ตั้งแต่ AGP 3.4 R8 ทำหน้าที่เดียวกันกับ ProGuard แต่เร็วกว่า (เขียนด้วย Kotlin ตั้งแต่เริ่มต้น) และมีประสิทธิภาพมากกว่า (ปรับไบต์โค้ดให้เหมาะสมสำหรับ ART Runtime ได้ดีกว่า) R8 ถูกกำหนดค่าโดยใช้ไฟล์ proguard-rules.pro เดียวกับ ProGuard ในการเปิดใช้งาน R8 เพียงตั้งค่า minifyEnabled true ใน build.gradle
ไฟล์ Mapping เป็นผลลัพธ์ของ R8/ProGuard ที่ประกอบด้วยการจับคู่ระหว่างชื่อดั้งเดิมและชื่อที่ทำให้สับสนของคลาส เมธอด และฟิลด์ ไฟล์ Mapping มีความสำคัญอย่างยิ่งสำหรับการวิเคราะห์รายงานข้อขัดข้อง: หากไม่มี สแต็กเทรซจะมี a.a.b แทน com.example.app.MainActivity.onCreate Firebase Crashlytics และ Sentry อัปโหลดไฟล์ Mapping โดยอัตโนมัติและกู้คืนชื่อดั้งเดิมในรายงาน
ไฟล์ Mapping ต้องอัปโหลดไปยัง Firebase หรือ Sentry ทุกครั้งที่เผยแพร่แอปพลิเคชันเวอร์ชันใหม่ หากไฟล์ Mapping หายไปหรือไม่ได้อัปโหลด รายงานข้อขัดข้องทั้งหมดหลังจากการทำให้สับสนจะอ่านไม่ได้ Android Gradle Plugin จะบันทึกไฟล์ Mapping โดยอัตโนมัติที่ build/outputs/mapping/release/mapping.txt Firebase ใช้ Crashlytics Gradle Plugin ซึ่งอัปโหลด Mapping ระหว่าง build รุ่น release
// app/build.gradle — การทำให้สับสนผ่าน R8
android {
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile(
"proguard-android-optimize.txt"),
"proguard-rules.pro"
}
}
}# proguard-rules.pro — กฎการเก็บรักษา
# เก็บโมเดลข้อมูลสำหรับ Gson
-keep class com.example.model.** { *; }
# เก็บคลาสสำหรับอินเทอร์เฟซ Retrofit
-keep,allowobfuscation interface com.example.api.*
# ไม่ทำให้กิจกรรมสาธารณะสับสน
-keep class * extends android.app.Activity {
public protected *;
}
# ลบบันทึกในโปรดักชัน
-assumenosideeffects class android.util.Log {
public static boolean isLoggable(...);
public static int v(...);
public static int d(...);
}กฎ -keep ใน proguard-rules.pro มีความสำคัญอย่างยิ่ง — หากไม่มี R8 จะลบหรือเปลี่ยนชื่อคลาสและเมธอดที่ใช้งานผ่านรีเฟลกชัน (Gson, Retrofit, Room) assumentSideEffects ลบการเรียก Log.v และ Log.d ออกจากโค้ดโปรดักชัน ไลบรารีเช่น Gson, Retrofit และ OkHttp มีกฎพร้อมใช้งานใน proguard.txt ภายใน AAR
Obfuscator.io เป็นเครื่องมือทำให้ JavaScript สับสนแบบโอเพนซอร์ซที่ได้รับความนิยมมากที่สุด รองรับการเปลี่ยนชื่อตัวระบุ การเข้ารหัสสตริง การทำให้โฟลว์ควบคุมแบนราบ และการป้องกันดีบักเกอร์ การกำหนดค่าทำผ่าน JSON config หรือ CLI เวอร์ชันฟรีรองรับวิธีการพื้นฐาน เวอร์ชัน Enterprise เพิ่มโค้ดพหุสัณฐานและการป้องกันตัวเอง
Jscrambler เป็นเครื่องมือทำให้ JavaScript สับสนเชิงพาณิชย์ที่มีการป้องกันขั้นสูง: การแปลงพหุสัณฐาน (แต่ละรันสร้างโค้ดที่ทำให้สับสนใหม่), การป้องกันดีบักเกอร์ (การตรวจจับ DevTools), การป้องกันภาพหน้าจอ (self-defending) และกลไกหมดอายุ (โค้ดหยุดทำงานหลังจากวันที่กำหนด) Jscrambler ใช้ในแอปพลิเคชันธนาคารและระบบ DRM
// obfuscate.js — การกำหนดค่า Obfuscator.io
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);พารามิเตอร์ ของ Obfuscator.io: controlFlowFlattening: 0.75 ทำให้โฟลว์ควบคุมสับสนใน 75% ของบล็อก; stringArray: true ย้ายสตริงไปยังอาร์เรย์; debugProtection ป้องกันการเปิด DevTools; disableConsoleOutput ลบ console.log ยิ่งค่าเกณฑ์สูง เวลาในการทำให้สับสนและขนาดโค้ดก็ยิ่งมากขึ้น แต่การวิเคราะห์ก็ยิ่งยากขึ้น
การทำให้สับสนไม่ป้องกัน การวิเคราะห์รันไทม์ ผู้โจมตีสามารถรันแอปพลิเคชันในดีบักเกอร์ (Frida, Objection, Xposed) และสกัดกั้นเมธอดแบบเรียลไทม์ การทำให้สับสนป้องกันการวิเคราะห์แบบสถิต (การดีคอมไพล์ APK, การอ่านไบต์โค้ด) แต่ไม่ป้องกันการวิเคราะห์แบบไดนามิก สำหรับการป้องกันรันไทม์จำเป็นต้องมีมาตรการเพิ่มเติม: SSL Pinning, Root Detection, Integrity Verification
ขนาดแอปพลิเคชัน อาจเพิ่มขึ้น 20–50% หลังจากการทำให้สับสน การทำให้โฟลว์ควบคุมสับสนเพิ่มสาขาที่ตายแล้วและทำซ้ำเงื่อนไข — ซึ่งเพิ่มขนาดไบต์โค้ด การเข้ารหัสสตริงแทนที่สตริงลิเทอรัลสั้น ๆ ด้วยการเรียก decrypt() ซึ่งเพิ่มขนาดเช่นกัน สำหรับแอปพลิเคชันโมบายล์นี่เป็นสิ่งสำคัญ เพราะขนาด APK ส่งผลโดยตรงต่ออัตราการแปลงใน Google Play
ประสิทธิภาพ ก็ได้รับผลกระทบเช่นกัน การทำให้โฟลว์ควบคุมสับสนเพิ่มการตรวจสอบและการแตกกิ่งเพิ่มเติม ทำให้เวลาในการทำงานของเมธอดเพิ่มขึ้น 5–15% การเข้ารหัสสตริงเพิ่มการเรียก decrypt ทุกครั้งที่เข้าถึงสตริง สำหรับฟังก์ชันที่สำคัญต่อประสิทธิภาพ (onDraw ใน Android, render ใน React) ควรปิดการทำให้สับสนผ่านกฎ -keep
คำถามที่พบบ่อย
การเข้ารหัส ทำให้โค้ดไม่สามารถทำงานได้หากไม่ถอดรหัส — จำเป็นต้องมีตัวถอดรหัสเพื่อทำงาน การทำให้สับสน ทำให้โค้ดอ่านไม่ได้แต่ยังคงทำงานได้โดยตรง การเข้ารหัสให้การป้องกันที่แข็งแกร่งกว่าแต่ต้องมีตัวโหลดถอดรหัส ซึ่งตัวเองอาจถูกวิเคราะห์ได้
การดีอบฟัสเคชัน เป็นไปได้แต่ใช้แรงงานมาก เครื่องมือเช่น jadx, JEB Decompiler และ UnConfuser กู้คืนไบต์โค้ดด้วยการดีอบฟัสเคชันบางส่วน การกู้คืนซอร์สโค้ดดั้งเดิมอย่างสมบูรณ์ด้วยชื่อดั้งเดิมนั้นเป็นไปไม่ได้ — ชื่อจะสูญหายอย่างถาวร เครื่องมือทำให้สับสนสมัยใหม่ (R8, ProGuard) ทนทานต่อการดีอบฟัสเคชันอัตโนมัติ
Google Play ไม่จำเป็นต้องทำให้สับสนแต่แนะนำอย่างยิ่งผ่าน minifyEnabled ใน build.gradle แอปพลิเคชันที่ไม่มีการทำให้สับสนสามารถถูกดีคอมไพล์ได้ง่ายผ่าน APKTool และ jadx ทำให้เสี่ยงต่อการขโมยคีย์ API การแก้ไขและการละเมิดลิขสิทธิ์ แอปพลิเคชันขนาดใหญ่ส่วนใหญ่ใช้ R8 หรือ ProGuard
รายงานข้อขัดข้อง หลังจากการทำให้สับสนจะมีชื่อที่ทำให้สับสน (a.b.c แทน com.example.app.MainActivity) ไฟล์ Mapping ที่สร้างโดย R8/ProGuard ใช้สำหรับการกู้คืน ต้องอัปโหลดไฟล์ Mapping ไปยัง Firebase Crashlytics หรือ Sentry สำหรับการดีอบฟัสเคชันสแต็กเทรซอัตโนมัติ
String Encryption แทนที่สตริงลิเทอรัล (คีย์ API, URL, ข้อความ) ด้วยข้อมูลที่เข้ารหัสและการเรียกฟังก์ชัน decrypt ในรันไทม์ ซึ่งป้องกันสตริงที่ละเอียดอ่อนจากการถูกอ่านผ่านการค้นหาอย่างง่ายในโค้ดที่ถูกดีคอมไพล์ R8/ProGuard รองรับการเข้ารหัสสตริงผ่านกฎ -encryptstrings
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ
อ่านเพิ่มเติม