คลัง
mobile

Android APK Analysis

Android APK Analysis คือการแกะและวิเคราะห์แอป Android ครบวงจร: โครงสร้าง APK, static analysis (jadx/apktool หา secret/endpoint/logic), การอ่าน smali, exported component abuse, dynamic analysis ด้วย Frida/objection (bypass SSL pinning, root detection, hook ฟังก์ชัน), การ patch+repackage APK และ native lib reverse บทนี้มี setup ครบ + lab walkthrough + troubleshooting (เนื้อหาเพื่อฝึกใน lab/CTF/ระบบที่ได้รับอนุญาตเท่านั้น)

BeginnerIntermediateAdvanced#android#apk#mobile#jadx#frida#objection#smali#reverse

1. โครงสร้าง APK

APK เป็นไฟล์ ZIP ที่มี: AndroidManifest.xml (binary XML — permission, component, exported flag), classes.dex (โค้ด Dalvik bytecode), resources.arsc + res/ (resource compiled), assets/ (ไฟล์ดิบ), lib/ (native .so แยกตาม ABI), META-INF/ (signature)

ดูข้างใน APK เร็วๆ
unzip -l app.apk            # ดูไฟล์ทั้งหมด
unzip app.apk -d app_raw    # แตกออกมา
file app_raw/lib/*/*.so     # ดู ABI ของ native lib
เนื้อหานี้เพื่อฝึกในสภาพแวดล้อมที่ได้รับอนุญาต (CTF, lab, mobile pentest) เท่านั้น

2. ตั้งค่าเครื่องมือ

ติดตั้ง toolchain
# jadx (decompile เป็น Java)
wget https://github.com/skylot/jadx/releases/latest/download/jadx.zip && unzip jadx.zip

# apktool (แกะ smali + resource + manifest)
wget https://github.com/iBotPeaches/Apktool/releases/latest/download/apktool.jar

# Frida (dynamic) — ฝั่ง PC
pip install frida-tools objection

# ฝั่งอุปกรณ์ (rooted/emulator): ดาวน์โหลด frida-server ให้ตรง arch
# adb push frida-server /data/local/tmp/ && adb shell "/data/local/tmp/frida-server &"

# adb (คุยกับอุปกรณ์)
adb devices

3. Static Analysis

decompile + ค้นหา
# decompile เป็น Java (อ่านง่ายสุด)
jadx -d out app.apk
jadx-gui app.apk        # GUI: ค้น string, ตาม xref

# แกะ smali + manifest (อ่าน manifest ได้, แก้+repack ได้)
apktool d app.apk -o app_apktool

# ค้น secret/flag/endpoint
grep -rnE 'flag|secret|api[_-]?key|password|token|Bearer|https?://[a-z]' out/
grep -rnE 'AKIA|firebaseio|amazonaws|\.herokuapp' out/   # cloud/3rd-party
ที่ซ่อนทำไมต้องดู
res/values/strings.xmlflag/API key/URL มัก hardcode
BuildConfig.java (ใน out/)constant ฝังตอน build (secret, base URL, DEBUG flag)
AndroidManifest.xmlexported component, permission, deep link, debuggable
assets/ไฟล์ config/db/JS ดิบ (บางทีมี key)
smali (ใน apktool)logic ที่ jadx decompile ไม่สมบูรณ์
lib/*/*.sologic สำคัญย้ายไป native (JNI)
เร็วสุด: รัน MobSF (docker) อัปโหลด APK → ได้รายงาน static เต็ม (permission, secret, cert, ช่องโหว่) ในคลิกเดียว

4. Manifest & Exported Component Abuse

component (Activity/Service/Receiver/Provider) ที่ android:exported="true" เรียกได้จากแอปอื่นหรือ adb — เป็นช่องโจมตี เช่น bypass login โดยเรียก Activity ภายในตรงๆ, หรือ ContentProvider ที่ leak data

หา + เรียก exported component
# ดู manifest (decode แล้ว)
cat app_apktool/AndroidManifest.xml | grep -A3 'exported="true"'

# เรียก exported Activity ตรงๆ (อาจ bypass หน้า login)
adb shell am start -n com.app/.SecretActivity

# ส่ง intent + extra
adb shell am start -n com.app/.Activity --es key value

# query ContentProvider ที่ exported (leak data)
adb shell content query --uri content://com.app.provider/users

# เช็ค debuggable (ถ้า true = debug ได้ = run-as อ่านไฟล์ได้)
grep 'debuggable' app_apktool/AndroidManifest.xml

5. Dynamic Analysis — Frida & objection

เมื่อ logic ซับซ้อน หรือมี SSL pinning/root detection → hook runtime งานหลัก: bypass pinning เพื่อดู traffic (แล้วทดสอบ API เหมือน web) + hook ฟังก์ชันเช็ค

objection (เร็วสุด — ไม่ต้องเขียน script)
# inject เข้า app ที่รันอยู่
objection -g com.app explore

# ใน objection prompt:
android sslpinning disable        # ปิด SSL pinning
android root disable              # ปิด root detection
android hooking list activities   # ดู activity ทั้งหมด
android hooking watch class_method com.app.Crypto.decrypt --dump-args --dump-return
android heap search instances com.app.User   # หา object ใน memory
Frida script (custom hook)
// hook.js — hook ฟังก์ชันเช็ค license/flag
Java.perform(function() {
  var C = Java.use('com.app.LicenseChecker');
  C.isValid.implementation = function() {
    console.log('[+] isValid() bypassed -> true');
    return true;
  };
  // dump ค่าที่ decrypt
  var Crypto = Java.use('com.app.Crypto');
  Crypto.decrypt.implementation = function(s) {
    var r = this.decrypt(s);
    console.log('[+] decrypt(' + s + ') = ' + r);
    return r;
  };
});
// รัน: frida -U -f com.app -l hook.js
  • bypass pinning → ตั้ง proxy (Burp) → ทดสอบ API (IDOR/JWT/auth) เหมือน web
  • hook ฟังก์ชัน root/jailbreak/license → return ค่าที่ต้องการ
  • dump runtime value: key ที่ decrypt, token, response ก่อน encrypt

6. Patch & Repackage

ถ้าต้องการแก้ logic ถาวร (เช่นลบ check, เปิด debug) → แก้ smali แล้ว repack + sign

patch smali → rebuild → sign
# 1. แกะ
apktool d app.apk -o app_mod

# 2. แก้ smali (เช่น เปลี่ยน check ให้ return true เสมอ)
#    หา method ใน app_mod/smali/.../X.smali แล้วแก้:
#    const/4 v0, 0x1   (return 1 = true)
#    return v0

# 3. rebuild
apktool b app_mod -o app_patched.apk

# 4. sign (ต้อง sign ถึงติดตั้งได้)
keytool -genkey -v -keystore my.keystore -alias a -keyalg RSA -keysize 2048 -validity 10000
apksigner sign --ks my.keystore --ks-key-alias a app_patched.apk

# 5. ติดตั้ง
adb install -r app_patched.apk

7. Native Library Reverse

แอปที่ป้องกันดีมักย้าย logic สำคัญ (crypto, flag check) ไป native .so ผ่าน JNI ต้อง reverse ด้วย Ghidra (ARM/ARM64)

วิเคราะห์ .so
# extract
unzip app.apk 'lib/*' -d native
file native/lib/arm64-v8a/libnative.so

# ใน Ghidra: หา JNI function (ชื่อขึ้นต้น Java_com_app_Class_method)
#   หรือ JNI_OnLoad ที่ RegisterNatives (dynamic registration)
strings native/lib/arm64-v8a/libnative.so | grep -iE 'flag|key'

# Frida hook native function
# Interceptor.attach(Module.findExportByName('libnative.so','Java_com_app_X_check'), {...})

8. Lab Walkthrough (crackme APK)

  1. 1jadx-gui app.apk → ดู MainActivity เจอ checkFlag(input) เรียก native หรือ Java
  2. 2ถ้าเป็น Java: อ่าน logic — เช่น XOR input กับ key คงที่แล้วเทียบ → คำนวณ flag ย้อนกลับ
  3. 3ถ้าเป็น native: grep flag ใน .so หรือ Frida hook checkFlag dump argument
  4. 4ถ้ามี SSL pinning + flag อยู่ server: objection -g com.app exploreandroid sslpinning disable → proxy → เห็น API → ทดสอบ
  5. 5ถ้า flag หลัง login: hook ฟังก์ชัน auth ให้ return true หรือเรียก exported Activity ตรงๆ
  6. 6เก็บ flag — มักได้จาก: strings, decrypt runtime (Frida dump), API response, หรือ logic ที่ reverse

9. Troubleshooting

อาการสาเหตุ / แก้
jadx decompile ไม่ครบ (// failed)ใช้ apktool ดู smali แทน ส่วนนั้น
Frida: unable to connectfrida-server ไม่รัน/ผิด arch — เช็ค adb shell ps | grep frida
objection: pinning ปิดแล้วยังไม่เห็น trafficproxy ผิด หรือ pinning custom — เขียน Frida hook เฉพาะ
ติดตั้ง patched APK ไม่ได้ (signature)ยังไม่ sign / sign ผิด — ใช้ apksigner sign
app crash หลัง patchsmali ผิด syntax/register — ตรวจ .locals + register count
root detection ไม่ผ่านแม้ hookมีหลายชั้น — hook ทุก method ที่เกี่ยว, หรือ patch smali
string ถูก obfuscatedecrypt ตอน runtime — Frida hook ฟังก์ชัน decrypt ดู output

10. Indicators & Quick Reference

สัญญาณ: AndroidManifest.xml + classes.dex = APK, hardcoded key/JWT ใน strings.xml/BuildConfig, exported="true" = ช่องเรียกตรง, lib/*.so = logic ซ่อน, SSL pinning = ต้อง Frida/objection
  • flow: jadx static → หา secret/logic → ถ้าตัน ใช้ Frida dynamic
  • MobSF = scan อัตโนมัติ (เริ่มเร็ว), jadx = อ่าน code ลึก
  • endpoint ที่เจอ → ทดสอบเหมือน web API (ดู Mentor หมวด web)
  • flag มักอยู่: strings.xml, assets/, decompiled logic, decrypt runtime, API response, native .so
  • iOS (IPA) คล้ายกัน: ใช้ class-dump/Hopper + Frida/objection (objection รองรับทั้งคู่)

🧭 จับมือทำทีละขั้น (มีแค่ Kali) + ถ้าติดไปไหนต่อ

สมมติเพิ่งเจอโจทย์ CTF/mobile pentest แล้วได้ไฟล์ .apk มาก้อนเดียว มีแค่เครื่อง Kali เปล่าๆ ไม่รู้จะเริ่มตรงไหน — ทำตามขั้นตอนนี้ทีละสเต็ป ถ้าไปต่อไม่ได้ให้ดู decision tree ด้านล่างว่าควรหักเลี้ยวไปทางไหน

  1. 1ติดตั้งเครื่องมือก่อน: sudo apt install apktool แล้วโหลด jadx จาก GitHub release (wget <jadx-release-url> && unzip jadx.zip -d jadx) ถ้ายังไม่มี
  2. 2แตก static ชั้นแรก: พิมพ์ apktool d app.apk -o app_apktool ควรเห็น folder ใหม่ที่มี smali/, res/, AndroidManifest.xml ฉบับอ่านออก
  3. 3decompile เป็น Java อ่านง่าย: พิมพ์ jadx app.apk -d app_jadx หรือเปิด jadx-gui app.apk แล้วดู source ใน MainActivity
  4. 4หา secret แบบเร็ว: พิมพ์ grep -rnE 'flag|secret|api[_-]?key|password|token|Bearer' app_jadx/ app_apktool/res/ ถ้าเจอ string ที่หน้าตาเป็น flag/key ให้เก็บไว้ก่อน
  5. 5ตรวจ AndroidManifest.xml หา exported component: พิมพ์ grep -B2 -A3 'exported="true"' app_apktool/AndroidManifest.xml ถ้าเจอ Activity/Provider ที่ exported แปลว่ามีช่องเรียกตรงได้
  6. 6เช็คว่าโจทย์มี logic client-side check ไหม (root detection, license check, ปุ่ม premium): เปิด jadx-gui ค้นคำว่า isRoot, checkLicense, isPremium
  7. 7ถ้าเจอ logic ที่ต้อง bypass runtime: เตรียม emulator/rooted device แล้ว push frida-server: adb push frida-server /data/local/tmp/ && adb shell chmod 755 /data/local/tmp/frida-server && adb shell '/data/local/tmp/frida-server &'
  8. 8เช็คว่า frida คุยกับ device ได้: พิมพ์ frida-ps -U ควรเห็น process list บนเครื่อง/emulator
  9. 9hook แบบเร็วด้วย objection ก่อน (ไม่ต้องเขียน script): พิมพ์ objection -g com.app explore แล้วลอง android root disable หรือ android sslpinning disable
  10. 10ถ้า objection ไม่พอ เขียน frida script เฉพาะจุด แล้วรัน frida -U -f com.app -l hook.js --no-pause ดู log ว่า hook ติดไหม
  11. 11ถ้าทุกทางตัน ลองอัปโหลดเข้า MobSF (self-hosted) ให้สแกนอัตโนมัติ อาจเจอจุดที่พลาดดู
Decision Tree: จาก APK ไปจนถึง flag/exploit
ได้ .apk มา — เริ่ม static analysis
apktool d app.apk -o out; jadx app.apk -d out_jadx
decompile ผ่าน อ่าน source/smali ได้search
decompile fail (error/ไฟล์เสีย)corrupt
decompile ไม่ผ่าน
เช็คไฟล์ (unzip -l app.apk), ลอง apktool/jadx เวอร์ชันใหม่กว่า หรือข้าม static ไปสแกนด้วย MobSF โดยตรง
ลองหลายเวอร์ชันแล้วยังไม่ได้อัปโหลด MobSF ให้สแกนแทน (ทางตันฝั่ง manual)
grep หา secret/flag ใน source, manifest, strings.xml
grep -rnE 'flag|secret|key|token' out/ out_jadx/
เจอ flag แบบ plaintext ตรงๆflagfound
เจอ hardcoded cloud key (AKIA.../firebaseio/amazonaws)cloudkey
เจอ logic น่าสงสัย (root/license/premium check) แต่ไม่เจอ flaglogiccheck
ไม่เจอ secret หรือ logic ชัดเจนmanifest
เจอ flag/secret แบบ plaintext แล้ว — จบ
เจอ client-side check (root detection/license/premium flag)
logic ป้องกันอยู่ฝั่ง client เท่านั้น ไม่ได้ enforce ฝั่ง server
ต้อง bypass runtimedynamic
ไม่เจอ secret ใน static — เช็ค exported component ใน manifest
grep exported="true" ใน AndroidManifest.xml
เจอ Activity/Provider/Receiver ที่ exportedexportedabuse
ไม่เจอ exported component ที่ใช้ได้dynamic
เรียก exported component ตรงด้วย adb
adb shell am start -n com.app/.SecretActivity หรือ adb shell content query --uri content://com.app.provider/...
ใช้ Frida/objection hook runtime
objection -g com.app explore -> android sslpinning disable / android root disable
hook ติด bypass ผ่าน เจอค่า/flag ที่ต้องการdynamicok
ปิด pinning แล้วเห็น traffic ไป backend APIapipivot
hook ไม่ติด เพราะ logic อยู่ใน native .so หรือ obfuscate หนักnativefail
bypass สำเร็จ ได้ flag/ผ่านเงื่อนไข — จบ
ขั้นตอน/งานเครื่องมือใน Kaliติดตั้งเพิ่ม (ถ้าไม่มี)เครื่องมือออนไลน์
แตก APK / อ่าน smali+manifestunzip, apktoolapktool เวอร์ชันล่าสุดจาก GitHub ถ้า apt เก่า-
decompile เป็น Java อ่านง่ายjadx-gui / jadxโหลด jadx.zip จาก GitHub release แล้ว unzipjadx online decompiler (จำกัดขนาดไฟล์)
dynamic instrumentation / hookfrida-tools, objectionfrida-server ฝั่งอุปกรณ์ (โหลดให้ตรง arch แล้ว adb push)-
scan อัตโนมัติ-MobSF (docker run มาตรฐาน)MobSF cloud demo (ถ้าเปิดให้ใช้)
คุยกับอุปกรณ์/emulatoradb (android-tools-adb)Android Studio emulator ถ้าไม่มีเครื่องจริง-
sign APK ที่ patch แล้วapksigner, keytoolมาพร้อม Android SDK build-tools-
ตรวจ native .sofile, strings, Ghidraติดตั้ง Ghidra (โหลดจาก GitHub release)-
เช็ค hash/reputation เบื้องต้น--VirusTotal
🚑 ถ้าตันสนิท ลองท่าถัดไป: เจอ hardcoded AWS/cloud key → ไป aws-iam-privesc หรือ aws-s3-attacks ทดสอบสิทธิ์จริงของ key นั้น | bypass pinning แล้วเจอ backend API → ทดสอบแบบ web ปกติที่ idor หรือ jwt-attacks (ตรวจ token/session) | logic ซ่อนใน native lib หรือ Frida hook ปกติไม่ติด → อ่านเทคนิคเจาะลึก dynamic instrumentation เพิ่มที่ frida | โจทย์มีทั้ง Android และ iOS build คู่กัน → เทียบ logic กับ ios-ipa-analysis อาจมี hint ฝั่งที่ป้องกันอ่อนกว่า

โน้ตของฉัน

ยังไม่มีโน้ตสำหรับหัวข้อนี้