Android Applications Basics

Tip

AWS ν•΄ν‚Ή 배우기 및 μ—°μŠ΅ν•˜κΈ°:HackTricks Training AWS Red Team Expert (ARTE)
GCP ν•΄ν‚Ή 배우기 및 μ—°μŠ΅ν•˜κΈ°: HackTricks Training GCP Red Team Expert (GRTE) Azure ν•΄ν‚Ή 배우기 및 μ—°μŠ΅ν•˜κΈ°: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks μ§€μ›ν•˜κΈ°

Android Security Model

두 개의 λ ˆμ΄μ–΄κ°€ μžˆμŠ΅λ‹ˆλ‹€:

  • OS, μ„€μΉ˜λœ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ„ μ„œλ‘œ κ²©λ¦¬ν•©λ‹ˆλ‹€.
  • μ• ν”Œλ¦¬μΌ€μ΄μ…˜ 자체, κ°œλ°œμžκ°€ νŠΉμ • κΈ°λŠ₯을 λ…ΈμΆœν•˜κ³  μ• ν”Œλ¦¬μΌ€μ΄μ…˜ κΈ°λŠ₯을 ꡬ성할 수 있게 ν•©λ‹ˆλ‹€.

UID Separation

각 μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ€ νŠΉμ • μ‚¬μš©μž IDκ°€ ν• λ‹Ήλ©λ‹ˆλ‹€. μ΄λŠ” μ•± μ„€μΉ˜ 쀑에 이루어지며, 앱은 μžμ‹ μ˜ μ‚¬μš©μž IDκ°€ μ†Œμœ ν•œ νŒŒμΌμ΄λ‚˜ 곡유된 파일과만 μƒν˜Έμž‘μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€. λ”°λΌμ„œ μ•± 자체, OS의 νŠΉμ • ꡬ성 μš”μ†Œ 및 루트 μ‚¬μš©μžλ§Œ μ•± 데이터λ₯Ό μ ‘κ·Όν•  수 μžˆμŠ΅λ‹ˆλ‹€.

UID Sharing

두 개의 μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ΄ λ™μΌν•œ UIDλ₯Ό μ‚¬μš©ν•˜λ„λ‘ ꡬ성될 수 μžˆμŠ΅λ‹ˆλ‹€. μ΄λŠ” 정보λ₯Ό κ³΅μœ ν•˜λŠ” 데 μœ μš©ν•  수 μžˆμ§€λ§Œ, κ·Έ 쀑 ν•˜λ‚˜κ°€ μ†μƒλ˜λ©΄ 두 μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ˜ 데이터가 λͺ¨λ‘ 손상될 수 μžˆμŠ΅λ‹ˆλ‹€. κ·Έλž˜μ„œ μ΄λŸ¬ν•œ 행동은 ꢌμž₯λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.
λ™μΌν•œ UIDλ₯Ό κ³΅μœ ν•˜λ €λ©΄, μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ€ λ§€λ‹ˆνŽ˜μŠ€νŠΈμ—μ„œ λ™μΌν•œ android:sharedUserId 값을 μ •μ˜ν•΄μ•Ό ν•©λ‹ˆλ‹€.

Sandboxing

Android μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μƒŒλ“œλ°•μŠ€λŠ” 각 μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ„ λ³„λ„μ˜ μ‚¬μš©μž ID둜 λ³„λ„μ˜ ν”„λ‘œμ„ΈμŠ€λ‘œ μ‹€ν–‰ν•  수 있게 ν•©λ‹ˆλ‹€. 각 ν”„λ‘œμ„ΈμŠ€λŠ” 자체 가상 머신을 κ°€μ§€κ³  μžˆμ–΄, μ•±μ˜ μ½”λ“œλŠ” λ‹€λ₯Έ μ•±κ³Ό κ²©λ¦¬λ˜μ–΄ μ‹€ν–‰λ©λ‹ˆλ‹€.
Android 5.0(L)λΆ€ν„° SELinuxκ°€ μ μš©λ©λ‹ˆλ‹€. 기본적으둜 SELinuxλŠ” λͺ¨λ“  ν”„λ‘œμ„ΈμŠ€ μƒν˜Έμž‘μš©μ„ κ±°λΆ€ν•˜κ³ , κ·Έλ“€ κ°„μ˜ μ˜ˆμƒλ˜λŠ” μƒν˜Έμž‘μš©λ§Œ ν—ˆμš©ν•˜λŠ” 정책을 μƒμ„±ν•©λ‹ˆλ‹€.

Permissions

μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ„ μ„€μΉ˜ν•  λ•Œ κΆŒν•œμ„ μš”μ²­ν•˜λŠ” 경우, 앱은 AndroidManifest.xml 파일의 uses-permission μš”μ†Œμ— κ΅¬μ„±λœ κΆŒν•œμ„ μš”μ²­ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€. uses-permission μš”μ†ŒλŠ” name 속성 λ‚΄μ—μ„œ μš”μ²­λœ κΆŒν•œμ˜ 이름을 λ‚˜νƒ€λƒ…λ‹ˆλ‹€. λ˜ν•œ maxSdkVersion 속성이 μžˆμ–΄, μ§€μ •λœ 버전보닀 높은 λ²„μ „μ—μ„œλŠ” κΆŒν•œ μš”μ²­μ„ μ€‘λ‹¨ν•©λ‹ˆλ‹€.
μ•ˆλ“œλ‘œμ΄λ“œ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ€ μ²˜μŒμ— λͺ¨λ“  κΆŒν•œμ„ μš”μ²­ν•  ν•„μš”λŠ” μ—†μœΌλ©°, **λ™μ μœΌλ‘œ κΆŒν•œμ„ μš”μ²­ν•  수 μžˆμ§€λ§Œ λͺ¨λ“  κΆŒν•œμ€ λ§€λ‹ˆνŽ˜μŠ€νŠΈμ— λͺ…μ‹œλ˜μ–΄μ•Ό ν•©λ‹ˆλ‹€.

앱이 κΈ°λŠ₯을 λ…ΈμΆœν•  λ•Œ, μ§€μ •λœ κΆŒν•œμ„ κ°€μ§„ μ•±λ§Œ μ ‘κ·Όν•  수 μžˆλ„λ‘ μ œν•œν•  수 μžˆμŠ΅λ‹ˆλ‹€.
κΆŒν•œ μš”μ†ŒλŠ” μ„Έ κ°€μ§€ 속성을 κ°€μ§‘λ‹ˆλ‹€:

  • κΆŒν•œμ˜ 이름
  • κ΄€λ ¨ κΆŒν•œμ„ κ·Έλ£Ήν™”ν•  수 μžˆλŠ” permission-group 속성
  • κΆŒν•œμ΄ λΆ€μ—¬λ˜λŠ” 방식을 λ‚˜νƒ€λ‚΄λŠ” protection-level. λ„€ κ°€μ§€ μœ ν˜•μ΄ μžˆμŠ΅λ‹ˆλ‹€:
  • Normal: 앱에 μ•Œλ €μ§„ μœ„ν˜‘μ΄ 없을 λ•Œ μ‚¬μš©λ©λ‹ˆλ‹€. μ‚¬μš©μžκ°€ μŠΉμΈν•  ν•„μš”κ°€ μ—†μŠ΅λ‹ˆλ‹€.
  • Dangerous: μš”μ²­ν•˜λŠ” μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ— μƒμŠΉλœ 접근을 λΆ€μ—¬ν•˜λŠ” κΆŒν•œμ„ λ‚˜νƒ€λƒ…λ‹ˆλ‹€. μ‚¬μš©μžμ—κ²Œ μŠΉμΈμ„ μš”μ²­ν•©λ‹ˆλ‹€.
  • Signature: ꡬ성 μš”μ†Œλ₯Ό λ‚΄λ³΄λ‚΄λŠ” 것과 λ™μΌν•œ μΈμ¦μ„œλ‘œ μ„œλͺ…λœ μ•±λ§Œ κΆŒν•œμ„ 뢀여받을 수 μžˆμŠ΅λ‹ˆλ‹€. μ΄λŠ” κ°€μž₯ κ°•λ ₯ν•œ 보호 μœ ν˜•μž…λ‹ˆλ‹€.
  • SignatureOrSystem: **ꡬ성 μš”μ†Œλ₯Ό λ‚΄λ³΄λ‚΄λŠ” 것과 λ™μΌν•œ μΈμ¦μ„œλ‘œ μ„œλͺ…λœ μ•±μ΄λ‚˜ μ‹œμŠ€ν…œ μˆ˜μ€€ μ ‘κ·ΌμœΌλ‘œ μ‹€ν–‰λ˜λŠ” μ•±λ§Œ κΆŒν•œμ„ 뢀여받을 수 μžˆμŠ΅λ‹ˆλ‹€.

Pre-Installed Applications

이 앱듀은 일반적으둜 /system/app λ˜λŠ” /system/priv-app λ””λ ‰ν† λ¦¬μ—μ„œ 발견되며, μΌλΆ€λŠ” μ΅œμ ν™”λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€ (심지어 classes.dex νŒŒμΌμ„ μ°Ύμ§€ λͺ»ν•  μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€). μ΄λŸ¬ν•œ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ€ λ•Œλ•Œλ‘œ λ„ˆλ¬΄ λ§Žμ€ κΆŒν•œμœΌλ‘œ μ‹€ν–‰λ˜κ³  있기 λ•Œλ¬Έμ— 확인할 κ°€μΉ˜κ°€ μžˆμŠ΅λ‹ˆλ‹€ (루트둜).

  • AOSP (Android OpenSource Project) ROMκ³Ό ν•¨κ»˜ μ œκ³΅λ˜λŠ” 것듀
  • μž₯치 μ œμ‘°μ—…μ²΄μ— μ˜ν•΄ μΆ”κ°€λœ 것듀
  • μ „ν™” μ œκ³΅μ—…μ²΄μ— μ˜ν•΄ μΆ”κ°€λœ 것듀 (κ·Έλ“€λ‘œλΆ€ν„° κ΅¬λ§€ν•œ 경우)

Rooting

물리적 μ•ˆλ“œλ‘œμ΄λ“œ μž₯μΉ˜μ— 루트 접근을 μ–»μœΌλ €λ©΄ 일반적으둜 **1개 λ˜λŠ” 2개의 취약점을 μ•…μš©ν•΄μ•Ό ν•©λ‹ˆλ‹€. μ΄λŠ” μž₯치 및 버전에 νŠΉμ •μž…λ‹ˆλ‹€.
μ΅μŠ€ν”Œλ‘œμž‡μ΄ μ„±κ³΅ν•˜λ©΄, 일반적으둜 λ¦¬λˆ…μŠ€ su λ°”μ΄λ„ˆλ¦¬κ°€ μ‚¬μš©μžμ˜ PATH ν™˜κ²½ λ³€μˆ˜μ— μ§€μ •λœ μœ„μΉ˜μΈ /system/xbin에 λ³΅μ‚¬λ©λ‹ˆλ‹€.

su λ°”μ΄λ„ˆλ¦¬κ°€ κ΅¬μ„±λ˜λ©΄, λ‹€λ₯Έ μ•ˆλ“œλ‘œμ΄λ“œ 앱이 su λ°”μ΄λ„ˆλ¦¬μ™€ μΈν„°νŽ˜μ΄μŠ€ν•˜μ—¬ 루트 μ ‘κ·Ό μš”μ²­μ„ μ²˜λ¦¬ν•©λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄ Superuser 및 SuperSU (Google Play μŠ€ν† μ–΄μ—μ„œ μ‚¬μš© κ°€λŠ₯)와 같은 앱이 μžˆμŠ΅λ‹ˆλ‹€.

Caution

λ£¨νŒ… 과정은 맀우 μœ„ν—˜ν•˜λ©° μž₯치λ₯Ό μ‹¬κ°ν•˜κ²Œ μ†μƒμ‹œν‚¬ 수 μžˆμŠ΅λ‹ˆλ‹€.

ROMs

μ»€μŠ€ν…€ νŽŒμ›¨μ–΄λ₯Ό μ„€μΉ˜ν•˜μ—¬ OSλ₯Ό κ΅μ²΄ν•˜λŠ” 것이 κ°€λŠ₯ν•©λ‹ˆλ‹€. 이λ₯Ό 톡해 였래된 μž₯치의 μœ μš©μ„±μ„ ν™•μž₯ν•˜κ±°λ‚˜ μ†Œν”„νŠΈμ›¨μ–΄ μ œν•œμ„ μš°νšŒν•˜κ±°λ‚˜ μ΅œμ‹  μ•ˆλ“œλ‘œμ΄λ“œ μ½”λ“œμ— μ ‘κ·Όν•  수 μžˆμŠ΅λ‹ˆλ‹€.
OmniROM 및 LineageOSλŠ” μ‚¬μš©ν•˜κΈ°μ— κ°€μž₯ 인기 μžˆλŠ” 두 κ°€μ§€ νŽŒμ›¨μ–΄μž…λ‹ˆλ‹€.

μ»€μŠ€ν…€ νŽŒμ›¨μ–΄λ₯Ό μ„€μΉ˜ν•˜κΈ° μœ„ν•΄ μž₯치λ₯Ό λ£¨νŒ…ν•  ν•„μš”λŠ” 항상 μ—†μŠ΅λ‹ˆλ‹€. 일뢀 μ œμ‘°μ—…μ²΄λŠ” 잘 λ¬Έμ„œν™”λ˜κ³  μ•ˆμ „ν•œ λ°©μ‹μœΌλ‘œ λΆ€νŠΈλ‘œλ” μž κΈˆμ„ ν•΄μ œν•˜λŠ” 것을 ν—ˆμš©ν•©λ‹ˆλ‹€.

Implications

μž₯μΉ˜κ°€ λ£¨νŒ…λ˜λ©΄, μ–΄λ–€ 앱이든 루트둜 접근을 μš”μ²­ν•  수 μžˆμŠ΅λ‹ˆλ‹€. μ•…μ„± μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ΄ 이λ₯Ό μ–»μœΌλ©΄ 거의 λͺ¨λ“  것에 μ ‘κ·Όν•  수 있으며, μ „ν™”κΈ°λ₯Ό μ†μƒμ‹œν‚¬ 수 μžˆμŠ΅λ‹ˆλ‹€.

Android Application Fundamentals

  • μ•ˆλ“œλ‘œμ΄λ“œ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ˜ ν˜•μ‹μ€ _APK 파일 ν˜•μ‹_으둜 μ–ΈκΈ‰λ©λ‹ˆλ‹€. 본질적으둜 ZIP νŒŒμΌμž…λ‹ˆλ‹€ (파일 ν™•μž₯자λ₯Ό .zip으둜 λ³€κ²½ν•˜λ©΄ λ‚΄μš©μ„ μΆ”μΆœν•˜κ³  λ³Ό 수 μžˆμŠ΅λ‹ˆλ‹€).
  • APK λ‚΄μš© (포괄적이지 μ•ŠμŒ)
  • AndroidManifest.xml
  • resources.arsc/strings.xml
  • resources.arsc: 이진 XMLκ³Ό 같은 미리 컴파일된 λ¦¬μ†ŒμŠ€λ₯Ό ν¬ν•¨ν•©λ‹ˆλ‹€.
  • res/xml/files_paths.xml
  • META-INF/
  • μ—¬κΈ°μ—μ„œ μΈμ¦μ„œκ°€ μœ„μΉ˜ν•©λ‹ˆλ‹€!
  • classes.dex
  • 기본적으둜 μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ΄ μ‹€ν–‰ν•˜λŠ” 컴파일된 Java (λ˜λŠ” Kotlin) μ½”λ“œλ₯Ό λ‚˜νƒ€λ‚΄λŠ” Dalvik λ°”μ΄νŠΈμ½”λ“œλ₯Ό ν¬ν•¨ν•©λ‹ˆλ‹€.
  • lib/
  • CPU μ•„ν‚€ν…μ²˜μ— 따라 ν•˜μœ„ λ””λ ‰ν† λ¦¬λ‘œ λΆ„λ¦¬λœ λ„€μ΄ν‹°λΈŒ 라이브러리λ₯Ό ν¬ν•¨ν•©λ‹ˆλ‹€.
  • armeabi: ARM 기반 ν”„λ‘œμ„Έμ„œλ₯Ό μœ„ν•œ μ½”λ“œ
  • armeabi-v7a: ARMv7 및 κ·Έ μ΄μƒμ˜ ν”„λ‘œμ„Έμ„œλ₯Ό μœ„ν•œ μ½”λ“œ
  • x86: X86 ν”„λ‘œμ„Έμ„œλ₯Ό μœ„ν•œ μ½”λ“œ
  • mips: MIPS ν”„λ‘œμ„Έμ„œ μ „μš© μ½”λ“œ
  • assets/
  • μ•±μ—μ„œ ν•„μš”ν•œ λ‹€μ–‘ν•œ νŒŒμΌμ„ μ €μž₯ν•˜λ©°, μΆ”κ°€ λ„€μ΄ν‹°λΈŒ λΌμ΄λΈŒλŸ¬λ¦¬λ‚˜ DEX νŒŒμΌμ„ 포함할 수 있으며, λ•Œλ•Œλ‘œ μ•…μ„± μ½”λ“œ μž‘μ„±μžκ°€ μΆ”κ°€ μ½”λ“œλ₯Ό 숨기기 μœ„ν•΄ μ‚¬μš©ν•©λ‹ˆλ‹€.
  • res/
  • resources.arsc에 μ»΄νŒŒμΌλ˜μ§€ μ•Šμ€ λ¦¬μ†ŒμŠ€λ₯Ό ν¬ν•¨ν•©λ‹ˆλ‹€.

Dalvik & Smali

μ•ˆλ“œλ‘œμ΄λ“œ κ°œλ°œμ—μ„œλŠ” Java λ˜λŠ” Kotlin을 μ‚¬μš©ν•˜μ—¬ 앱을 μƒμ„±ν•©λ‹ˆλ‹€. λ°μŠ€ν¬νƒ‘ μ•±μ²˜λŸΌ JVM을 μ‚¬μš©ν•˜λŠ” λŒ€μ‹ , μ•ˆλ“œλ‘œμ΄λ“œλŠ” 이 μ½”λ“œλ₯Ό Dalvik Executable (DEX) λ°”μ΄νŠΈμ½”λ“œλ‘œ μ»΄νŒŒμΌν•©λ‹ˆλ‹€. μ΄μ „μ—λŠ” Dalvik 가상 머신이 이 λ°”μ΄νŠΈμ½”λ“œλ₯Ό μ²˜λ¦¬ν–ˆμ§€λ§Œ, μ΄μ œλŠ” μ΅œμ‹  μ•ˆλ“œλ‘œμ΄λ“œ λ²„μ „μ—μ„œ Android Runtime (ART)κ°€ 이λ₯Ό μ²˜λ¦¬ν•©λ‹ˆλ‹€.

λ¦¬λ²„μŠ€ μ—”μ§€λ‹ˆμ–΄λ§μ„ μœ„ν•΄ Smaliκ°€ μ€‘μš”ν•΄μ§‘λ‹ˆλ‹€. μ΄λŠ” DEX λ°”μ΄νŠΈμ½”λ“œμ˜ μ‚¬λžŒμ΄ 읽을 수 μžˆλŠ” λ²„μ „μœΌλ‘œ, μ†ŒμŠ€ μ½”λ“œλ₯Ό λ°”μ΄νŠΈμ½”λ“œ λͺ…λ ΉμœΌλ‘œ λ³€ν™˜ν•˜λŠ” μ–΄μ…ˆλΈ”λ¦¬ μ–Έμ–΄μ²˜λŸΌ μž‘μš©ν•©λ‹ˆλ‹€. Smali와 baksmaliλŠ” 이 λ§₯λ½μ—μ„œ μ–΄μ…ˆλΈ”λ¦¬ 및 μ—­μ–΄μ…ˆλΈ”λ¦¬ 도ꡬλ₯Ό λ‚˜νƒ€λƒ…λ‹ˆλ‹€.

Intents

μΈν…νŠΈλŠ” μ•ˆλ“œλ‘œμ΄λ“œ 앱이 ꡬ성 μš”μ†Œ κ°„ λ˜λŠ” λ‹€λ₯Έ μ•±κ³Ό ν†΅μ‹ ν•˜λŠ” μ£Όμš” μˆ˜λ‹¨μž…λ‹ˆλ‹€. μ΄λŸ¬ν•œ λ©”μ‹œμ§€ κ°μ²΄λŠ” μ•± κ°„ λ˜λŠ” ꡬ성 μš”μ†Œ 간에 데이터λ₯Ό 전달할 μˆ˜λ„ 있으며, HTTP ν†΅μ‹ μ—μ„œ GET/POST μš”μ²­μ΄ μ‚¬μš©λ˜λŠ” 방식과 μœ μ‚¬ν•©λ‹ˆλ‹€.

λ”°λΌμ„œ μΈν…νŠΈλŠ” 기본적으둜 ꡬ성 μš”μ†Œ 간에 μ „λ‹¬λ˜λŠ” λ©”μ‹œμ§€μž…λ‹ˆλ‹€. μΈν…νŠΈλŠ” νŠΉμ • ꡬ성 μš”μ†Œλ‚˜ μ•±μœΌλ‘œ μ§€ν–₯될 수 있으며, νŠΉμ • μˆ˜μ‹ μž 없이 전솑될 μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€.
κ°„λ‹¨νžˆ 말해 μΈν…νŠΈλŠ” λ‹€μŒκ³Ό 같이 μ‚¬μš©λ  수 μžˆμŠ΅λ‹ˆλ‹€:

  • ν™œλ™μ„ μ‹œμž‘ν•˜μ—¬ 일반적으둜 μ•±μ˜ μ‚¬μš©μž μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ—½λ‹ˆλ‹€.
  • μ‹œμŠ€ν…œκ³Ό 앱에 λ³€κ²½ 사항을 μ•Œλ¦¬κΈ° μœ„ν•œ λΈŒλ‘œλ“œμΊμŠ€νŠΈλ‘œ μ‚¬μš©λ©λ‹ˆλ‹€.
  • λ°±κ·ΈλΌμš΄λ“œ μ„œλΉ„μŠ€μ™€ μ‹œμž‘, 쀑지 및 ν†΅μ‹ ν•©λ‹ˆλ‹€.
  • ContentProvidersλ₯Ό 톡해 데이터에 μ ‘κ·Όν•©λ‹ˆλ‹€.
  • 이벀트λ₯Ό μ²˜λ¦¬ν•˜κΈ° μœ„ν•œ 콜백으둜 μ‚¬μš©λ©λ‹ˆλ‹€.

μ·¨μ•½ν•œ 경우, μΈν…νŠΈλ₯Ό μ‚¬μš©ν•˜μ—¬ λ‹€μ–‘ν•œ 곡격을 μˆ˜ν–‰ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

Intent-Filter

μΈν…νŠΈ ν•„ν„°λŠ” ν™œλ™, μ„œλΉ„μŠ€ λ˜λŠ” λΈŒλ‘œλ“œμΊμŠ€νŠΈ μˆ˜μ‹ μžκ°€ λ‹€μ–‘ν•œ μœ ν˜•μ˜ μΈν…νŠΈμ™€ μƒν˜Έμž‘μš©ν•  수 μžˆλŠ” 방법을 μ •μ˜ν•©λ‹ˆλ‹€. 본질적으둜, 이듀은 μ΄λŸ¬ν•œ ꡬ성 μš”μ†Œμ˜ κΈ°λŠ₯을 μ„€λͺ…ν•˜λ©°, μˆ˜ν–‰ν•  수 μžˆλŠ” μž‘μ—…μ΄λ‚˜ μ²˜λ¦¬ν•  수 μžˆλŠ” λΈŒλ‘œλ“œμΊμŠ€νŠΈμ˜ μ’…λ₯˜λ₯Ό λ‚˜νƒ€λƒ…λ‹ˆλ‹€. μ΄λŸ¬ν•œ ν•„ν„°λ₯Ό μ„ μ–Έν•˜λŠ” μ£Όμš” μž₯μ†ŒλŠ” AndroidManifest.xml 파일 내에 μžˆμ§€λ§Œ, λΈŒλ‘œλ“œμΊμŠ€νŠΈ μˆ˜μ‹ μžμ˜ 경우 μ½”λ”©ν•˜λŠ” 것도 μ˜΅μ…˜μž…λ‹ˆλ‹€.

μΈν…νŠΈ ν•„ν„°λŠ” μΉ΄ν…Œκ³ λ¦¬, μž‘μ—… 및 데이터 ν•„ν„°λ‘œ κ΅¬μ„±λ˜λ©°, μΆ”κ°€ 메타데이터λ₯Ό 포함할 수 μžˆλŠ” κ°€λŠ₯성이 μžˆμŠ΅λ‹ˆλ‹€. 이 섀정은 ꡬ성 μš”μ†Œκ°€ μ„ μ–Έλœ 기쀀에 λ§žλŠ” νŠΉμ • μΈν…νŠΈλ₯Ό μ²˜λ¦¬ν•  수 있게 ν•©λ‹ˆλ‹€.

μ•ˆλ“œλ‘œμ΄λ“œ ꡬ성 μš”μ†Œ(ν™œλ™/μ„œλΉ„μŠ€/μ½˜ν…μΈ  제곡자/λΈŒλ‘œλ“œμΊμŠ€νŠΈ μˆ˜μ‹ μž)의 μ€‘μš”ν•œ 츑면은 κ·Έλ“€μ˜ κ°€μ‹œμ„± λ˜λŠ” 곡개 μƒνƒœμž…λ‹ˆλ‹€. ꡬ성 μš”μ†Œκ°€ exported 속성이 **true**둜 μ„€μ •λ˜μ–΄ μžˆκ±°λ‚˜ λ§€λ‹ˆνŽ˜μŠ€νŠΈμ— μΈν…νŠΈ ν•„ν„°κ°€ μ„ μ–Έλ˜μ–΄ 있으면, ν•΄λ‹Ή ꡬ성 μš”μ†ŒλŠ” 곡개둜 κ°„μ£Όλ˜λ©° λ‹€λ₯Έ μ•±κ³Ό μƒν˜Έμž‘μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ κ°œλ°œμžλŠ” μ΄λŸ¬ν•œ ꡬ성 μš”μ†Œλ₯Ό λͺ…μ‹œμ μœΌλ‘œ λΉ„κ³΅κ°œλ‘œ μœ μ§€ν•˜μ—¬ λ‹€λ₯Έ μ•±κ³Ό μ˜λ„μΉ˜ μ•Šκ²Œ μƒν˜Έμž‘μš©ν•˜μ§€ μ•Šλ„λ‘ ν•  수 μžˆλŠ” 방법이 μžˆμŠ΅λ‹ˆλ‹€. μ΄λŠ” λ§€λ‹ˆνŽ˜μŠ€νŠΈ μ •μ˜μ—μ„œ exported 속성을 **false**둜 μ„€μ •ν•˜μ—¬ λ‹¬μ„±λ©λ‹ˆλ‹€.

λ˜ν•œ, κ°œλ°œμžλŠ” νŠΉμ • κΆŒν•œμ„ μš”κ΅¬ν•˜μ—¬ μ΄λŸ¬ν•œ ꡬ성 μš”μ†Œμ— λŒ€ν•œ 접근을 λ”μš± μ•ˆμ „ν•˜κ²Œ ν•  수 μžˆλŠ” μ˜΅μ…˜μ΄ μžˆμŠ΅λ‹ˆλ‹€. permission 속성을 μ„€μ •ν•˜μ—¬ μ§€μ •λœ κΆŒν•œμ„ κ°€μ§„ μ•±λ§Œ ꡬ성 μš”μ†Œμ— μ ‘κ·Όν•  수 μžˆλ„λ‘ ν•˜μ—¬, λˆ„κ°€ μƒν˜Έμž‘μš©ν•  수 μžˆλŠ”μ§€μ— λŒ€ν•œ μΆ”κ°€ λ³΄μ•ˆ 및 μ œμ–΄λ₯Ό μΆ”κ°€ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

<activity android:name=".MyActivity" android:exported="false">
<!-- Intent filters go here -->
</activity>

μ•”μ‹œμ  μΈν…νŠΈ

μΈν…νŠΈλŠ” μΈν…νŠΈ μƒμ„±μžλ₯Ό μ‚¬μš©ν•˜μ—¬ ν”„λ‘œκ·Έλž˜λ°μ μœΌλ‘œ μƒμ„±λ©λ‹ˆλ‹€:

Intent email = new Intent(Intent.ACTION_SEND, Uri.parse("mailto:"));

이전에 μ„ μ–Έλœ μΈν…νŠΈμ˜ μ•‘μ…˜μ€ ACTION_SEND이고, μ—‘μŠ€νŠΈλΌλŠ” mailto Uriμž…λ‹ˆλ‹€ (μ—‘μŠ€νŠΈλΌλŠ” μΈν…νŠΈκ°€ κΈ°λŒ€ν•˜λŠ” μΆ”κ°€ μ •λ³΄μž…λ‹ˆλ‹€).

이 μΈν…νŠΈλŠ” λ‹€μŒ μ˜ˆμ™€ 같이 λ§€λ‹ˆνŽ˜μŠ€νŠΈ 내에 μ„ μ–Έλ˜μ–΄μ•Ό ν•©λ‹ˆλ‹€:

<activity android:name="ShareActivity">
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>

μΈν…νŠΈ ν•„ν„°λŠ” λ©”μ‹œμ§€λ₯Ό μˆ˜μ‹ ν•˜κΈ° μœ„ν•΄ action, data 및 category와 μΌμΉ˜ν•΄μ•Ό ν•©λ‹ˆλ‹€.

β€œμΈν…νŠΈ 해상도” ν”„λ‘œμ„ΈμŠ€λŠ” 각 λ©”μ‹œμ§€λ₯Ό μˆ˜μ‹ ν•  앱을 κ²°μ •ν•©λ‹ˆλ‹€. 이 ν”„λ‘œμ„ΈμŠ€λŠ” μš°μ„  μˆœμœ„ 속성을 κ³ λ €ν•˜λ©°, μ΄λŠ” μΈν…νŠΈ ν•„ν„° μ„ μ–Έμ—μ„œ μ„€μ •ν•  수 있고, 더 높은 μš°μ„  μˆœμœ„λ₯Ό κ°€μ§„ 것이 μ„ νƒλ©λ‹ˆλ‹€. 이 μš°μ„  μˆœμœ„λŠ” -1000μ—μ„œ 1000 μ‚¬μ΄λ‘œ μ„€μ •ν•  수 있으며, μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ€ SYSTEM_HIGH_PRIORITY 값을 μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€. 좩돌이 λ°œμƒν•˜λ©΄ β€œμ„ νƒκΈ°β€ 창이 λ‚˜νƒ€λ‚˜ μ‚¬μš©μžκ°€ κ²°μ •ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

λͺ…μ‹œμ  μΈν…νŠΈ

λͺ…μ‹œμ  μΈν…νŠΈλŠ” νƒ€κ²ŸμœΌλ‘œ ν•˜λŠ” 클래슀 이름을 μ§€μ •ν•©λ‹ˆλ‹€:

Intent downloadIntent = new (this, DownloadService.class):

λ‹€λ₯Έ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ—μ„œλŠ” 이전에 μ„ μ–Έλœ μΈν…νŠΈμ— μ ‘κ·Όν•˜κΈ° μœ„ν•΄ λ‹€μŒμ„ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€:

Intent intent = new Intent();
intent.setClassName("com.other.app", "com.other.app.ServiceName");
context.startService(intent);

Pending Intents

이것은 λ‹€λ₯Έ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ΄ λ‹Ήμ‹ μ˜ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ„ λŒ€μ‹ ν•˜μ—¬ μž‘μ—…μ„ μˆ˜ν–‰ν•  수 μžˆλ„λ‘ ν•˜λ©°, λ‹Ήμ‹ μ˜ μ•±μ˜ 아이덴티티와 κΆŒν•œμ„ μ‚¬μš©ν•©λ‹ˆλ‹€. Pending Intentλ₯Ό ꡬ성할 λ•ŒλŠ” μ˜λ„μ™€ μˆ˜ν–‰ν•  μž‘μ—…μ„ μ§€μ •ν•΄μ•Ό ν•©λ‹ˆλ‹€. μ„ μ–Έλœ μ˜λ„κ°€ λͺ…μ‹œμ μ΄μ§€ μ•ŠμœΌλ©΄ (μ–΄λ–€ μ˜λ„κ°€ ν˜ΈμΆœν•  수 μžˆλŠ”μ§€ μ„ μ–Έν•˜μ§€ μ•ŠμŒ) μ•…μ˜μ μΈ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ΄ ν”Όν•΄μž 앱을 λŒ€μ‹ ν•˜μ—¬ μ„ μ–Έλœ μž‘μ—…μ„ μˆ˜ν–‰ν•  수 μžˆμŠ΅λ‹ˆλ‹€. κ²Œλ‹€κ°€, μž‘μ—…μ΄ μ§€μ •λ˜μ§€ μ•ŠμœΌλ©΄, μ•…μ˜μ μΈ 앱은 ν”Όν•΄μžλ₯Ό λŒ€μ‹ ν•˜μ—¬ μ–΄λ–€ μž‘μ—…μ΄λ“  μˆ˜ν–‰ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

Broadcast Intents

μ΄μ „μ˜ μΈν…νŠΈμ™€ 달리, 단일 μ•±μ—μ„œλ§Œ μˆ˜μ‹ λ˜λŠ” 것이 μ•„λ‹ˆλΌ, broadcast intentsλŠ” μ—¬λŸ¬ μ•±μ—μ„œ μˆ˜μ‹ λ  수 μžˆμŠ΅λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ API 버전 14λΆ€ν„°λŠ” λ©”μ‹œμ§€λ₯Ό μˆ˜μ‹ ν•΄μ•Ό ν•˜λŠ” 앱을 μ§€μ •ν•  수 μžˆμŠ΅λ‹ˆλ‹€ Intent.setPackageλ₯Ό μ‚¬μš©ν•˜μ—¬.

λ˜ν•œ λΈŒλ‘œλ“œμΊμŠ€νŠΈλ₯Ό 보낼 λ•Œ κΆŒν•œμ„ μ§€μ •ν•  μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€. μˆ˜μ‹  앱은 ν•΄λ‹Ή κΆŒν•œμ„ κ°€μ Έμ•Ό ν•©λ‹ˆλ‹€.

λΈŒλ‘œλ“œμΊμŠ€νŠΈμ—λŠ” 두 κ°€μ§€ μœ ν˜•μ΄ μžˆμŠ΅λ‹ˆλ‹€: 정상 (비동기) 및 μ£Όλ¬Έν˜• (동기). μˆœμ„œλŠ” μˆ˜μ‹ κΈ° μš”μ†Œ λ‚΄μ—μ„œ κ΅¬μ„±λœ μš°μ„  μˆœμœ„μ— κΈ°λ°˜ν•©λ‹ˆλ‹€. 각 앱은 λΈŒλ‘œλ“œμΊμŠ€νŠΈλ₯Ό 처리, 쀑계 λ˜λŠ” μ‚­μ œν•  수 μžˆμŠ΅λ‹ˆλ‹€.

Context 클래슀의 sendBroadcast(intent, receiverPermission) ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜μ—¬ λΈŒλ‘œλ“œμΊμŠ€νŠΈλ₯Ό 보낼 수 μžˆμŠ΅λ‹ˆλ‹€.
λ˜ν•œ **LocalBroadCastManager**의 sendBroadcast ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜λ©΄ λ©”μ‹œμ§€κ°€ 앱을 λ– λ‚˜μ§€ μ•Šλ„λ‘ 보μž₯ν•©λ‹ˆλ‹€. 이λ₯Ό μ‚¬μš©ν•˜λ©΄ μˆ˜μ‹ κΈ° ꡬ성 μš”μ†Œλ₯Ό 내보낼 ν•„μš”μ‘°μ°¨ μ—†μŠ΅λ‹ˆλ‹€.

Sticky Broadcasts

이런 μ’…λ₯˜μ˜ λΈŒλ‘œλ“œμΊμŠ€νŠΈλŠ” μ „μ†‘λœ ν›„ μ˜€λž«λ™μ•ˆ μ ‘κ·Όν•  수 μžˆμŠ΅λ‹ˆλ‹€.
이것은 API 레벨 21μ—μ„œ μ‚¬μš© μ€‘λ‹¨λ˜μ—ˆμœΌλ©° μ‚¬μš©ν•˜μ§€ μ•ŠλŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€.
이듀은 μ–΄λ–€ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ΄ 데이터λ₯Ό μ—Ώλ³Ό 수 μžˆλ„λ‘ ν—ˆμš©ν•˜μ§€λ§Œ, λ˜ν•œ μˆ˜μ •ν•  수 μžˆλ„λ‘ ν•©λ‹ˆλ‹€.

β€œstickyβ€œλΌλŠ” 단어가 ν¬ν•¨λœ ν•¨μˆ˜, 예λ₯Ό λ“€μ–΄ sendStickyBroadcast λ˜λŠ” **sendStickyBroadcastAsUser**λ₯Ό λ°œκ²¬ν•˜λ©΄, 영ν–₯을 ν™•μΈν•˜κ³  μ œκ±°ν•˜λ„λ‘ μ‹œλ„ν•˜μ„Έμš”.

μ•ˆλ“œλ‘œμ΄λ“œ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ—μ„œ λ”₯ λ§ν¬λŠ” URL을 톡해 직접 μž‘μ—…(Intent)을 μ‹œμž‘ν•˜λŠ” 데 μ‚¬μš©λ©λ‹ˆλ‹€. μ΄λŠ” ν™œλ™ λ‚΄μ—μ„œ νŠΉμ • URL μŠ€ν‚΄μ„ μ„ μ–Έν•¨μœΌλ‘œμ¨ μ΄λ£¨μ–΄μ§‘λ‹ˆλ‹€. μ•ˆλ“œλ‘œμ΄λ“œ μž₯μΉ˜κ°€ 이 μŠ€ν‚΄μ„ κ°€μ§„ URL에 μ ‘κ·Όν•˜λ €κ³  ν•  λ•Œ, μ• ν”Œλ¦¬μΌ€μ΄μ…˜ λ‚΄μ—μ„œ μ§€μ •λœ ν™œλ™μ΄ μ‹œμž‘λ©λ‹ˆλ‹€.

μŠ€ν‚΄μ€ AndroidManifest.xml νŒŒμΌμ— μ„ μ–Έλ˜μ–΄μ•Ό ν•©λ‹ˆλ‹€:

[...]
<activity android:name=".MyActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="examplescheme" />
</intent-filter>
[...]

이전 예제의 μŠ€ν‚΄μ€ examplescheme://μž…λ‹ˆλ‹€ (λ˜ν•œ **category BROWSABLE**도 μ£Όλͺ©ν•˜μ„Έμš”)

그런 λ‹€μŒ, 데이터 ν•„λ“œμ—μ„œ host와 pathλ₯Ό μ§€μ •ν•  수 μžˆμŠ΅λ‹ˆλ‹€:

<data android:scheme="examplescheme"
android:host="example"
/>

μ›Ήμ—μ„œ μ ‘κ·Όν•˜κΈ° μœ„ν•΄ λ‹€μŒκ³Ό 같은 링크λ₯Ό μ„€μ •ν•  수 μžˆμŠ΅λ‹ˆλ‹€:

<a href="examplescheme://example/something">click here</a>
<a href="examplescheme://example/javascript://%250dalert(1)">click here</a>

μ•±μ—μ„œ 싀행될 μ½”λ“œλ₯Ό μ°ΎκΈ° μœ„ν•΄, λ”₯링크둜 호좜된 μ•‘ν‹°λΉ„ν‹°λ‘œ κ°€μ„œ onNewIntent ν•¨μˆ˜λ₯Ό κ²€μƒ‰ν•˜μ„Έμš”.

HTML νŽ˜μ΄μ§€λ₯Ό μ‚¬μš©ν•˜μ§€ μ•Šκ³  λ”₯ 링크λ₯Ό ν˜ΈμΆœν•˜λŠ” 방법을 λ°°μš°μ„Έμš”.

AIDL - Android μΈν„°νŽ˜μ΄μŠ€ μ •μ˜ μ–Έμ–΄

**Android μΈν„°νŽ˜μ΄μŠ€ μ •μ˜ μ–Έμ–΄ (AIDL)**λŠ” Android μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ—μ„œ ν”„λ‘œμ„ΈμŠ€ κ°„ 톡신 (IPC)을 톡해 ν΄λΌμ΄μ–ΈνŠΈμ™€ μ„œλΉ„μŠ€ κ°„μ˜ 톡신을 μš©μ΄ν•˜κ²Œ ν•˜κΈ° μœ„ν•΄ μ„€κ³„λ˜μ—ˆμŠ΅λ‹ˆλ‹€. Androidμ—μ„œλŠ” λ‹€λ₯Έ ν”„λ‘œμ„ΈμŠ€μ˜ λ©”λͺ¨λ¦¬μ— 직접 μ ‘κ·Όν•˜λŠ” 것이 ν—ˆμš©λ˜μ§€ μ•ŠκΈ° λ•Œλ¬Έμ—, AIDL은 객체λ₯Ό 운영 μ²΄μ œκ°€ 이해할 수 μžˆλŠ” ν˜•μ‹μœΌλ‘œ λ³€ν™˜ν•˜μ—¬ μ„œλ‘œ λ‹€λ₯Έ ν”„λ‘œμ„ΈμŠ€ κ°„μ˜ 톡신을 μ‰½κ²Œ ν•©λ‹ˆλ‹€.

μ£Όμš” κ°œλ…

  • λ°”μš΄λ“œ μ„œλΉ„μŠ€: μ΄λŸ¬ν•œ μ„œλΉ„μŠ€λŠ” IPCλ₯Ό μœ„ν•΄ AIDL을 μ‚¬μš©ν•˜μ—¬ μ•‘ν‹°λΉ„ν‹°λ‚˜ ꡬ성 μš”μ†Œκ°€ μ„œλΉ„μŠ€μ— λ°”μΈλ”©ν•˜κ³  μš”μ²­μ„ ν•˜λ©° 응닡을 받을 수 있게 ν•©λ‹ˆλ‹€. μ„œλΉ„μŠ€ 클래슀의 onBind λ©”μ†Œλ“œλŠ” μƒν˜Έμž‘μš©μ„ μ‹œμž‘ν•˜λŠ” 데 μ€‘μš”ν•˜λ©°, 취약점을 μ°ΎκΈ° μœ„ν•œ λ³΄μ•ˆ κ²€ν† μ˜ μ€‘μš”ν•œ μ˜μ—­μœΌλ‘œ ν‘œμ‹œλ©λ‹ˆλ‹€.

  • λ©”μ‹ μ €: λ°”μš΄λ“œ μ„œλΉ„μŠ€λ‘œ μž‘λ™ν•˜λŠ” λ©”μ‹ μ €λŠ” onBind λ©”μ†Œλ“œλ₯Ό 톡해 데이터λ₯Ό μ²˜λ¦¬ν•˜λŠ” 데 쀑점을 두고 IPCλ₯Ό μš©μ΄ν•˜κ²Œ ν•©λ‹ˆλ‹€. 이 λ©”μ†Œλ“œλ₯Ό λ©΄λ°€νžˆ κ²€μ‚¬ν•˜μ—¬ μ•ˆμ „ν•˜μ§€ μ•Šμ€ 데이터 μ²˜λ¦¬λ‚˜ λ―Όκ°ν•œ κΈ°λŠ₯의 싀행이 μžˆλŠ”μ§€ ν™•μΈν•˜λŠ” 것이 μ€‘μš”ν•©λ‹ˆλ‹€.

  • 바인더: AIDL의 μΆ”μƒν™”λ‘œ 인해 바인더 클래슀λ₯Ό 직접 μ‚¬μš©ν•˜λŠ” 것은 덜 μΌλ°˜μ μ΄μ§€λ§Œ, 바인더가 μ„œλ‘œ λ‹€λ₯Έ ν”„λ‘œμ„ΈμŠ€μ˜ λ©”λͺ¨λ¦¬ 곡간 κ°„ 데이터 전솑을 μš©μ΄ν•˜κ²Œ ν•˜λŠ” 컀널 μˆ˜μ€€ λ“œλΌμ΄λ²„ 역할을 ν•œλ‹€λŠ” 것을 μ΄ν•΄ν•˜λŠ” 것이 μœ μ΅ν•©λ‹ˆλ‹€. 더 μžμ„Έν•œ 이해λ₯Ό μœ„ν•΄ https://www.youtube.com/watch?v=O-UHvFjxwZ8μ—μ„œ λ¦¬μ†ŒμŠ€λ₯Ό ν™•μΈν•˜μ„Έμš”.

ꡬ성 μš”μ†Œ

μ—¬κΈ°μ—λŠ” μ•‘ν‹°λΉ„ν‹°, μ„œλΉ„μŠ€, λΈŒλ‘œλ“œμΊμŠ€νŠΈ λ¦¬μ‹œλ²„ 및 ν”„λ‘œλ°”μ΄λ”κ°€ ν¬ν•¨λ©λ‹ˆλ‹€.

런처 μ•‘ν‹°λΉ„ν‹° 및 기타 μ•‘ν‹°λΉ„ν‹°

Android μ•±μ—μ„œ μ•‘ν‹°λΉ„ν‹°λŠ” ν™”λ©΄κ³Ό κ°™μœΌλ©°, μ•±μ˜ μ‚¬μš©μž μΈν„°νŽ˜μ΄μŠ€μ˜ λ‹€μ–‘ν•œ 뢀뢄을 λ³΄μ—¬μ€λ‹ˆλ‹€. 앱은 μ—¬λŸ¬ 개의 μ•‘ν‹°λΉ„ν‹°λ₯Ό κ°€μ§ˆ 수 있으며, 각 μ•‘ν‹°λΉ„ν‹°λŠ” μ‚¬μš©μžμ—κ²Œ κ³ μœ ν•œ 화면을 μ œκ³΅ν•©λ‹ˆλ‹€.

런처 μ•‘ν‹°λΉ„ν‹°λŠ” μ•±μ˜ μ£Όμš” κ²Œμ΄νŠΈμ›¨μ΄λ‘œ, μ•± μ•„μ΄μ½˜μ„ νƒ­ν•  λ•Œ μ‹€ν–‰λ©λ‹ˆλ‹€. μ΄λŠ” μ•±μ˜ λ§€λ‹ˆνŽ˜μŠ€νŠΈ νŒŒμΌμ— νŠΉμ • MAIN 및 LAUNCHER μΈν…νŠΈλ‘œ μ •μ˜λ©λ‹ˆλ‹€:

<activity android:name=".LauncherActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

λͺ¨λ“  앱이 런처 μ•‘ν‹°λΉ„ν‹°λ₯Ό ν•„μš”λ‘œ ν•˜λŠ” 것은 μ•„λ‹ˆλ©°, μ‚¬μš©μž μΈν„°νŽ˜μ΄μŠ€κ°€ μ—†λŠ” λ°±κ·ΈλΌμš΄λ“œ μ„œλΉ„μŠ€μ™€ 같은 앱은 특히 κ·Έλ ‡μŠ΅λ‹ˆλ‹€.

μ•‘ν‹°λΉ„ν‹°λŠ” λ§€λ‹ˆνŽ˜μŠ€νŠΈμ—μ„œ β€œexportedβ€œλ‘œ ν‘œμ‹œν•˜μ—¬ λ‹€λ₯Έ μ•±μ΄λ‚˜ ν”„λ‘œμ„ΈμŠ€μ—μ„œ μ‚¬μš©ν•  수 μžˆλ„λ‘ λ§Œλ“€ 수 μžˆμŠ΅λ‹ˆλ‹€. 이 섀정은 λ‹€λ₯Έ 앱이 이 μ•‘ν‹°λΉ„ν‹°λ₯Ό μ‹œμž‘ν•  수 μžˆλ„λ‘ ν—ˆμš©ν•©λ‹ˆλ‹€:

<service android:name=".ExampleExportedService" android:exported="true"/>

κ·ΈλŸ¬λ‚˜ λ‹€λ₯Έ μ•±μ˜ ν™œλ™μ— μ ‘κ·Όν•˜λŠ” 것이 항상 λ³΄μ•ˆ μœ„ν—˜μ€ μ•„λ‹™λ‹ˆλ‹€. λ―Όκ°ν•œ 데이터가 λΆ€μ μ ˆν•˜κ²Œ 곡유될 경우 μš°λ €κ°€ λ°œμƒν•˜λ©°, μ΄λŠ” 정보 유좜둜 μ΄μ–΄μ§ˆ 수 μžˆμŠ΅λ‹ˆλ‹€.

ν™œλ™μ˜ 생λͺ… μ£ΌκΈ° λŠ” onCreate λ©”μ„œλ“œλ‘œ μ‹œμž‘λ˜λ©°, UIλ₯Ό μ„€μ •ν•˜κ³  μ‚¬μš©μžμ™€μ˜ μƒν˜Έμž‘μš©μ„ μœ„ν•΄ ν™œλ™μ„ μ€€λΉ„ν•©λ‹ˆλ‹€.

μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μ„œλΈŒν΄λž˜μŠ€

μ•ˆλ“œλ‘œμ΄λ“œ κ°œλ°œμ—μ„œ 앱은 Application 클래슀의 μ„œλΈŒν΄λž˜μŠ€λ₯Ό 생성할 수 μžˆλŠ” μ˜΅μ…˜μ΄ μžˆμ§€λ§Œ, ν•„μˆ˜λŠ” μ•„λ‹™λ‹ˆλ‹€. μ΄λŸ¬ν•œ μ„œλΈŒν΄λž˜μŠ€κ°€ μ •μ˜λ˜λ©΄, μ•± λ‚΄μ—μ„œ κ°€μž₯ λ¨Όμ € μΈμŠ€ν„΄μŠ€ν™”λ˜λŠ” ν΄λž˜μŠ€κ°€ λ©λ‹ˆλ‹€. 이 μ„œλΈŒν΄λž˜μŠ€μ—μ„œ κ΅¬ν˜„λœ attachBaseContext λ©”μ„œλ“œλŠ” onCreate λ©”μ„œλ“œ 이전에 μ‹€ν–‰λ©λ‹ˆλ‹€. 이 섀정은 μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ˜ λ‚˜λ¨Έμ§€ 뢀뢄이 μ‹œμž‘λ˜κΈ° 전에 μ΄ˆκΈ°ν™”λ₯Ό 쑰기에 μˆ˜ν–‰ν•  수 있게 ν•©λ‹ˆλ‹€.

public class MyApp extends Application {
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
// Initialization code here
}

@Override
public void onCreate() {
super.onCreate();
// More initialization code
}
}

Services

ServicesλŠ” λ°±κ·ΈλΌμš΄λ“œ μž‘μ—…μžλ‘œ, μ‚¬μš©μž μΈν„°νŽ˜μ΄μŠ€ 없이 μž‘μ—…μ„ μ‹€ν–‰ν•  수 μžˆμŠ΅λ‹ˆλ‹€. μ΄λŸ¬ν•œ μž‘μ—…μ€ μ‚¬μš©μžκ°€ λ‹€λ₯Έ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μœΌλ‘œ μ „ν™˜ν•˜λ”λΌλ„ 계속 싀행될 수 μžˆμ–΄, μž₯κΈ° μ‹€ν–‰ μž‘μ—…μ— μžˆμ–΄ μ„œλΉ„μŠ€λŠ” 맀우 μ€‘μš”ν•©λ‹ˆλ‹€.

μ„œλΉ„μŠ€λŠ” λ‹€μž¬λ‹€λŠ₯ν•˜λ©°, λ‹€μ–‘ν•œ λ°©λ²•μœΌλ‘œ μ‹œμž‘λ  수 있으며, Intentsκ°€ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ˜ μ§„μž…μ μ„ μ‹œμž‘ν•˜λŠ” μ£Όμš” λ°©λ²•μž…λ‹ˆλ‹€. startService λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ μ„œλΉ„μŠ€κ°€ μ‹œμž‘λ˜λ©΄, onStart λ©”μ„œλ“œκ°€ μž‘λ™μ„ μ‹œμž‘ν•˜κ³  stopService λ©”μ„œλ“œκ°€ λͺ…μ‹œμ μœΌλ‘œ 호좜될 λ•ŒκΉŒμ§€ 계속 μ‹€ν–‰λ©λ‹ˆλ‹€. λ˜λŠ” μ„œλΉ„μŠ€μ˜ 역할이 ν™œμ„± ν΄λΌμ΄μ–ΈνŠΈ 연결에 μ˜μ‘΄ν•˜λŠ” 경우, bindService λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ ν΄λΌμ΄μ–ΈνŠΈλ₯Ό μ„œλΉ„μŠ€μ— λ°”μΈλ”©ν•˜κ³ , 데이터 전솑을 μœ„ν•΄ onBind λ©”μ„œλ“œλ₯Ό ν™œμ„±ν™”ν•©λ‹ˆλ‹€.

μ„œλΉ„μŠ€μ˜ ν₯미둜운 μ‘μš© ν”„λ‘œκ·Έλž¨μ—λŠ” λ°±κ·ΈλΌμš΄λ“œ μŒμ•… μž¬μƒμ΄λ‚˜ μ‚¬μš©μžμ™€ μ•± κ°„μ˜ μƒν˜Έμž‘μš©μ„ λ°©ν•΄ν•˜μ§€ μ•Šκ³  λ„€νŠΈμ›Œν¬ 데이터 κ°€μ Έμ˜€κΈ°κ°€ ν¬ν•¨λ©λ‹ˆλ‹€. λ˜ν•œ, μ„œλΉ„μŠ€λŠ” 내보내기λ₯Ό 톡해 λ™μΌν•œ μž₯치의 λ‹€λ₯Έ ν”„λ‘œμ„ΈμŠ€μ—μ„œ μ ‘κ·Όν•  수 μžˆλ„λ‘ μ„€μ •ν•  수 μžˆμŠ΅λ‹ˆλ‹€. μ΄λŠ” κΈ°λ³Έ λ™μž‘μ΄ μ•„λ‹ˆλ©° Android Manifest νŒŒμΌμ—μ„œ λͺ…μ‹œμ μΈ ꡬ성이 ν•„μš”ν•©λ‹ˆλ‹€:

<service android:name=".ExampleExportedService" android:exported="true"/>

Broadcast Receivers

Broadcast receiversλŠ” λ©”μ‹œμ§• μ‹œμŠ€ν…œμ—μ„œ λ¦¬μŠ€λ„ˆ 역할을 ν•˜μ—¬ μ—¬λŸ¬ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ΄ μ‹œμŠ€ν…œμ˜ λ™μΌν•œ λ©”μ‹œμ§€μ— 응닡할 수 μžˆλ„λ‘ ν•©λ‹ˆλ‹€. 앱은 Manifestλ₯Ό 톡해 λ˜λŠ” registerReceiver APIλ₯Ό μ‚¬μš©ν•˜μ—¬ μ•± μ½”λ“œ λ‚΄μ—μ„œ 두 κ°€μ§€ μ£Όμš” λ°©λ²•μœΌλ‘œ λ¦¬μ‹œλ²„λ₯Ό 등둝할 수 μžˆμŠ΅λ‹ˆλ‹€. Manifestμ—μ„œλŠ” λΈŒλ‘œλ“œμΊμŠ€νŠΈκ°€ κΆŒν•œμœΌλ‘œ ν•„ν„°λ§λ˜λ©°, λ™μ μœΌλ‘œ λ“±λ‘λœ λ¦¬μ‹œλ²„λŠ” 등둝 μ‹œ κΆŒν•œμ„ μ§€μ •ν•  μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€.

Intent ν•„ν„°λŠ” 두 등둝 방법 λͺ¨λ‘μ—μ„œ μ€‘μš”ν•˜λ©°, μ–΄λ–€ λΈŒλ‘œλ“œμΊμŠ€νŠΈκ°€ λ¦¬μ‹œλ²„λ₯Ό νŠΈλ¦¬κ±°ν•˜λŠ”μ§€λ₯Ό κ²°μ •ν•©λ‹ˆλ‹€. μΌμΉ˜ν•˜λŠ” λΈŒλ‘œλ“œμΊμŠ€νŠΈκ°€ μ „μ†‘λ˜λ©΄ λ¦¬μ‹œλ²„μ˜ onReceive λ©”μ„œλ“œκ°€ ν˜ΈμΆœλ˜μ–΄ 앱이 μ €μ „λ ₯ 경고에 따라 행동을 μ‘°μ •ν•˜λŠ” λ“±μ˜ λ°©μ‹μœΌλ‘œ λ°˜μ‘ν•  수 있게 ν•©λ‹ˆλ‹€.

λΈŒλ‘œλ“œμΊμŠ€νŠΈλŠ” 비동기일 수 있으며, λͺ¨λ“  λ¦¬μ‹œλ²„μ— μˆœμ„œ 없이 λ„λ‹¬ν•˜κ±°λ‚˜ 동기일 수 있으며, λ¦¬μ‹œλ²„κ°€ μ„€μ •λœ μš°μ„  μˆœμœ„μ— 따라 λΈŒλ‘œλ“œμΊμŠ€νŠΈλ₯Ό λ°›μŠ΅λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ λͺ¨λ“  앱이 λΈŒλ‘œλ“œμΊμŠ€νŠΈλ₯Ό κ°€λ‘œμ±„κΈ° μœ„ν•΄ μžμ‹ μ„ μš°μ„ μ‹œν•  수 μžˆμœΌλ―€λ‘œ 잠재적인 λ³΄μ•ˆ μœ„ν—˜μ„ μ£Όμ˜ν•΄μ•Ό ν•©λ‹ˆλ‹€.

λ¦¬μ‹œλ²„μ˜ κΈ°λŠ₯을 μ΄ν•΄ν•˜λ €λ©΄ ν•΄λ‹Ή 클래슀 λ‚΄μ—μ„œ onReceive λ©”μ„œλ“œλ₯Ό μ°Ύμ•„λ³΄μ„Έμš”. 이 λ©”μ„œλ“œμ˜ μ½”λ“œλŠ” μˆ˜μ‹ λœ Intentλ₯Ό μ‘°μž‘ν•  수 있으며, 특히 Intentλ₯Ό μˆ˜μ •ν•˜κ±°λ‚˜ μ‚­μ œν•  수 μžˆλŠ” Ordered Broadcastsμ—μ„œ λ¦¬μ‹œλ²„μ— μ˜ν•œ 데이터 κ²€μ¦μ˜ ν•„μš”μ„±μ„ κ°•μ‘°ν•©λ‹ˆλ‹€.

Content Provider

Content ProvidersλŠ” μ•± 간에 κ΅¬μ‘°ν™”λœ 데이터λ₯Ό κ³΅μœ ν•˜λŠ” 데 ν•„μˆ˜μ μ΄λ©°, 데이터 λ³΄μ•ˆμ„ 보μž₯ν•˜κΈ° μœ„ν•΄ κΆŒν•œ κ΅¬ν˜„μ˜ μ€‘μš”μ„±μ„ κ°•μ‘°ν•©λ‹ˆλ‹€. 이듀은 앱이 λ°μ΄ν„°λ² μ΄μŠ€, 파일 μ‹œμŠ€ν…œ λ˜λŠ” 웹을 ν¬ν•¨ν•œ λ‹€μ–‘ν•œ μ†ŒμŠ€μ˜ 데이터에 μ ‘κ·Όν•  수 μžˆλ„λ‘ ν•©λ‹ˆλ‹€. readPermission 및 **writePermission**κ³Ό 같은 νŠΉμ • κΆŒν•œμ€ μ ‘κ·Ό μ œμ–΄μ— μ€‘μš”ν•©λ‹ˆλ‹€. λ˜ν•œ, μ•±μ˜ λ§€λ‹ˆνŽ˜μŠ€νŠΈμ—μ„œ grantUriPermission 섀정을 톡해 μž„μ‹œ 접근을 λΆ€μ—¬ν•  수 있으며, path, pathPrefix, pathPatternκ³Ό 같은 속성을 ν™œμš©ν•˜μ—¬ 세뢀적인 μ ‘κ·Ό μ œμ–΄λ₯Ό μˆ˜ν–‰ν•©λ‹ˆλ‹€.

μž…λ ₯ 검증은 SQL μΈμ μ…˜κ³Ό 같은 취약점을 λ°©μ§€ν•˜κΈ° μœ„ν•΄ 맀우 μ€‘μš”ν•©λ‹ˆλ‹€. Content ProvidersλŠ” 데이터 μ‘°μž‘ 및 μ• ν”Œλ¦¬μΌ€μ΄μ…˜ κ°„ 곡유λ₯Ό μš©μ΄ν•˜κ²Œ ν•˜λŠ” κΈ°λ³Έ μž‘μ—…μΈ insert(), update(), delete(), query()λ₯Ό μ§€μ›ν•©λ‹ˆλ‹€.

FileProviderλŠ” νŒŒμΌμ„ μ•ˆμ „ν•˜κ²Œ κ³΅μœ ν•˜λŠ” 데 쀑점을 λ‘” μ „λ¬Έν™”λœ Content Providerμž…λ‹ˆλ‹€. μ΄λŠ” μ•±μ˜ λ§€λ‹ˆνŽ˜μŠ€νŠΈμ— μ •μ˜λ˜λ©°, 폴더에 λŒ€ν•œ 접근을 μ œμ–΄ν•˜κΈ° μœ„ν•œ νŠΉμ • 속성을 ν¬ν•¨ν•˜κ³  있으며, android:exported 및 android:resourceκ°€ 폴더 κ΅¬μ„±μœΌλ‘œ μ§€μ •λ©λ‹ˆλ‹€. λ―Όκ°ν•œ 데이터가 μš°μ—°νžˆ λ…ΈμΆœλ˜μ§€ μ•Šλ„λ‘ 디렉토리λ₯Ό κ³΅μœ ν•  λ•Œ μ£Όμ˜ν•΄μ•Ό ν•©λ‹ˆλ‹€.

FileProvider에 λŒ€ν•œ μ˜ˆμ‹œ λ§€λ‹ˆνŽ˜μŠ€νŠΈ μ„ μ–Έ:

<provider android:name="androidx.core.content.FileProvider"
android:authorities="com.example.myapp.fileprovider"
android:grantUriPermissions="true"
android:exported="false">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>

filepaths.xmlμ—μ„œ 곡유 폴더λ₯Ό μ§€μ •ν•˜λŠ” 예:

<paths>
<files-path path="images/" name="myimages" />
</paths>

더 λ§Žμ€ μ •λ³΄λŠ” λ‹€μŒμ„ ν™•μΈν•˜μ„Έμš”:

WebViews

WebViewsλŠ” Android μ•± λ‚΄μ˜ λ―Έλ‹ˆ μ›Ή λΈŒλΌμš°μ €μ™€ κ°™μœΌλ©°, μ›Ή λ˜λŠ” 둜컬 νŒŒμΌμ—μ„œ μ½˜ν…μΈ λ₯Ό κ°€μ Έμ˜΅λ‹ˆλ‹€. 이듀은 일반 λΈŒλΌμš°μ €μ™€ μœ μ‚¬ν•œ μœ„ν—˜μ— μ§λ©΄ν•˜μ§€λ§Œ, νŠΉμ • 섀정을 톡해 μ΄λŸ¬ν•œ μœ„ν—˜μ„ 쀄일 수 μžˆλŠ” 방법이 μžˆμŠ΅λ‹ˆλ‹€.

AndroidλŠ” 두 κ°€μ§€ μ£Όμš” WebView μœ ν˜•μ„ μ œκ³΅ν•©λ‹ˆλ‹€:

  • WebViewClientλŠ” κΈ°λ³Έ HTML에 μ ν•©ν•˜μ§€λ§Œ JavaScript μ•Œλ¦Ό κΈ°λŠ₯을 μ§€μ›ν•˜μ§€ μ•Šμ•„ XSS 곡격 ν…ŒμŠ€νŠΈ 방식에 영ν–₯을 λ―ΈμΉ©λ‹ˆλ‹€.
  • WebChromeClientλŠ” 전체 Chrome λΈŒλΌμš°μ € κ²½ν—˜κ³Ό 더 μœ μ‚¬ν•˜κ²Œ μž‘λ™ν•©λ‹ˆλ‹€.

μ€‘μš”ν•œ 점은 WebView λΈŒλΌμš°μ €κ°€ μž₯치의 μ£Όμš” λΈŒλΌμš°μ €μ™€ μΏ ν‚€λ₯Ό κ³΅μœ ν•˜μ§€ μ•ŠλŠ”λ‹€λŠ” κ²ƒμž…λ‹ˆλ‹€.

μ½˜ν…μΈ λ₯Ό λ‘œλ“œν•˜κΈ° μœ„ν•΄ loadUrl, loadData, loadDataWithBaseURL와 같은 방법이 μ œκ³΅λ©λ‹ˆλ‹€. μ΄λŸ¬ν•œ URL λ˜λŠ” 파일이 μ•ˆμ „ν•˜κ²Œ μ‚¬μš©λ  수 μžˆλŠ”μ§€ ν™•μΈν•˜λŠ” 것이 μ€‘μš”ν•©λ‹ˆλ‹€. λ³΄μ•ˆ 섀정은 WebSettings 클래슀λ₯Ό 톡해 관리할 수 μžˆμŠ΅λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄, setJavaScriptEnabled(false)둜 JavaScriptλ₯Ό λΉ„ν™œμ„±ν™”ν•˜λ©΄ XSS 곡격을 λ°©μ§€ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

JavaScript β€œBridgeβ€œλŠ” Java 객체가 JavaScript와 μƒν˜Έμž‘μš©ν•  수 있게 ν•˜λ©°, Android 4.2 이상뢀터 λ³΄μ•ˆμ„ μœ„ν•΄ λ©”μ„œλ“œμ— @JavascriptInterface둜 ν‘œμ‹œν•΄μ•Ό ν•©λ‹ˆλ‹€.

μ½˜ν…μΈ  접근을 ν—ˆμš©ν•˜λŠ” 것(setAllowContentAccess(true))은 WebViewsκ°€ Content Providers에 μ ‘κ·Όν•  수 있게 ν•˜λ©°, μ½˜ν…μΈ  URL이 μ•ˆμ „ν•˜λ‹€κ³  ν™•μΈλ˜μ§€ μ•ŠμœΌλ©΄ μœ„ν—˜μ΄ 될 수 μžˆμŠ΅λ‹ˆλ‹€.

파일 접근을 μ œμ–΄ν•˜κΈ° μœ„ν•΄:

  • 파일 접근을 λΉ„ν™œμ„±ν™”ν•˜λŠ” 것(setAllowFileAccess(false))은 파일 μ‹œμŠ€ν…œμ— λŒ€ν•œ 접근을 μ œν•œν•˜λ©°, νŠΉμ • μžμ‚°μ— λŒ€ν•œ μ˜ˆμ™Έλ₯Ό 두어 비민감 μ½˜ν…μΈ μ—λ§Œ μ‚¬μš©λ˜λ„λ‘ 보μž₯ν•©λ‹ˆλ‹€.

기타 μ•± ꡬ성 μš”μ†Œ 및 λͺ¨λ°”일 μž₯치 관리

μ‘μš© ν”„λ‘œκ·Έλž¨μ˜ λ””μ§€ν„Έ μ„œλͺ…

  • λ””μ§€ν„Έ μ„œλͺ…은 Android 앱에 ν•„μˆ˜μ μ΄λ©°, μ„€μΉ˜ 전에 μ •ν’ˆ μž‘μ„±λ˜μ—ˆμŒμ„ 보μž₯ν•©λ‹ˆλ‹€. 이 과정은 μ•± 식별을 μœ„ν•œ μΈμ¦μ„œλ₯Ό μ‚¬μš©ν•˜λ©°, μ„€μΉ˜ μ‹œ μž₯치의 νŒ¨ν‚€μ§€ κ΄€λ¦¬μžκ°€ 확인해야 ν•©λ‹ˆλ‹€. 앱은 자체 μ„œλͺ…λ˜κ±°λ‚˜ μ™ΈλΆ€ CA에 μ˜ν•΄ 인증될 수 있으며, 무단 μ ‘κ·ΌμœΌλ‘œλΆ€ν„° λ³΄ν˜Έν•˜κ³  μž₯μΉ˜μ— μ „λ‹¬λ˜λŠ” λ™μ•ˆ 앱이 λ³€μ‘°λ˜μ§€ μ•Šλ„λ‘ 보μž₯ν•©λ‹ˆλ‹€.

κ°•ν™”λœ λ³΄μ•ˆμ„ μœ„ν•œ μ•± 검증

  • Android 4.2λΆ€ν„° Verify AppsλΌλŠ” κΈ°λŠ₯이 λ„μž…λ˜μ–΄ μ‚¬μš©μžκ°€ μ„€μΉ˜ 전에 μ•±μ˜ μ•ˆμ „μ„±μ„ 확인할 수 μžˆμŠ΅λ‹ˆλ‹€. 이 검증 과정은 μ‚¬μš©μžκ°€ 잠재적으둜 ν•΄λ‘œμš΄ 앱에 λŒ€ν•΄ κ²½κ³ ν•˜κ±°λ‚˜ 특히 악성인 μ•±μ˜ μ„€μΉ˜λ₯Ό λ°©μ§€ν•˜μ—¬ μ‚¬μš©μž λ³΄μ•ˆμ„ κ°•ν™”ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

λͺ¨λ°”일 μž₯치 관리 (MDM)

  • MDM μ†”λ£¨μ…˜μ€ μž₯치 관리 APIλ₯Ό 톡해 λͺ¨λ°”일 μž₯μΉ˜μ— λŒ€ν•œ 감독 및 λ³΄μ•ˆμ„ μ œκ³΅ν•©λ‹ˆλ‹€. 이듀은 λͺ¨λ°”일 μž₯치λ₯Ό 효과적으둜 κ΄€λ¦¬ν•˜κ³  λ³΄ν˜Έν•˜κΈ° μœ„ν•΄ Android μ•±μ˜ μ„€μΉ˜λ₯Ό ν•„μš”λ‘œ ν•©λ‹ˆλ‹€. μ£Όμš” κΈ°λŠ₯μ—λŠ” λΉ„λ°€λ²ˆν˜Έ μ •μ±… μ‹œν–‰, μ €μž₯μ†Œ μ•”ν˜Έν™” μ˜λ¬΄ν™”, 원격 데이터 μ‚­μ œ ν—ˆμš©μ΄ ν¬ν•¨λ˜μ–΄ μžˆμ–΄ λͺ¨λ°”일 μž₯μΉ˜μ— λŒ€ν•œ 포괄적인 μ œμ–΄ 및 λ³΄μ•ˆμ„ 보μž₯ν•©λ‹ˆλ‹€.
// Example of enforcing a password policy with MDM
DevicePolicyManager dpm = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
ComponentName adminComponent = new ComponentName(context, AdminReceiver.class);

if (dpm.isAdminActive(adminComponent)) {
// Set minimum password length
dpm.setPasswordMinimumLength(adminComponent, 8);
}

AIDL / Binder μ„œλΉ„μŠ€ μ—΄κ±° 및 μ•…μš©

Android Binder IPCλŠ” λ§Žμ€ μ‹œμŠ€ν…œ 및 곡급업체 제곡 μ„œλΉ„μŠ€λ₯Ό λ…ΈμΆœν•©λ‹ˆλ‹€. μ΄λŸ¬ν•œ μ„œλΉ„μŠ€λŠ” μ μ ˆν•œ κΆŒν•œ 검사가 없이 λ‚΄λ³΄λ‚΄μ§ˆ λ•Œ 곡격 ν‘œλ©΄μ΄ λ©λ‹ˆλ‹€ (AIDL λ ˆμ΄μ–΄ μžμ²΄λŠ” μ ‘κ·Ό μ œμ–΄λ₯Ό μˆ˜ν–‰ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€).

1. μ‹€ν–‰ 쀑인 μ„œλΉ„μŠ€ 발견

# from an adb shell (USB or wireless)
service list               # simple one-liner
am list services           # identical output, ActivityManager wrapper
  1. Android μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ˜ κΈ°λ³Έ 사항
  2. Android μ• ν”Œλ¦¬μΌ€μ΄μ…˜ ꡬ쑰
  3. Android μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ˜ ꡬ성 μš”μ†Œ
  4. AndroidManifest.xml 파일
  5. λ¦¬μ†ŒμŠ€ 파일
  6. μ½”λ“œ 파일
  7. Android μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ˜ λ³΄μ•ˆ
  8. 취약점 뢄석
  9. λ¦¬λ²„μŠ€ μ—”μ§€λ‹ˆμ–΄λ§
  10. λ³΄μ•ˆ ν…ŒμŠ€νŠΈ 도ꡬ
145  mtkconnmetrics: [com.mediatek.net.connectivity.IMtkIpConnectivityMetrics]
146  wifi             : [android.net.wifi.IWifiManager]
  • 인덱슀 (첫 번째 μ—΄)은 λŸ°νƒ€μž„μ— ν• λ‹Ήλ©λ‹ˆλ‹€ – μž¬λΆ€νŒ… 간에 이λ₯Ό μ‹ λ’°ν•˜μ§€ λ§ˆμ‹­μ‹œμ˜€.
  • 바인더 이름 (예: mtkconnmetrics)은 service call에 전달될 κ²ƒμž…λ‹ˆλ‹€.
  • κ΄„ν˜Έ μ•ˆμ˜ 값은 μŠ€ν…μ΄ μƒμ„±λœ μ™„μ „ν•œ AIDL μΈν„°νŽ˜μ΄μŠ€μž…λ‹ˆλ‹€.

2. μΈν„°νŽ˜μ΄μŠ€ μ„€λͺ…μž μ–»κΈ° (PING)

λͺ¨λ“  바인더 μŠ€ν…μ€ μžλ™μœΌλ‘œ νŠΈλžœμž­μ…˜ μ½”λ“œ 0x5f4e5446 (1598968902 μ‹­μ§„μˆ˜, ASCII β€œ_NTF”)λ₯Ό κ΅¬ν˜„ν•©λ‹ˆλ‹€.

# "ping" the service
service call mtkconnmetrics 1    # 1 == decimal 1598968902 mod 2^32

μœ νš¨ν•œ 응닡은 Parcel 내뢀에 UTF-16 λ¬Έμžμ—΄λ‘œ μΈμ½”λ”©λœ μΈν„°νŽ˜μ΄μŠ€ 이름을 λ°˜ν™˜ν•©λ‹ˆλ‹€.

3. νŠΈλžœμž­μ…˜ 호좜

ꡬ문: service call <name> <code> [type value ...]

일반 인수 μ§€μ •μž:

  • i32 <int> – λΆ€ν˜Έ μžˆλŠ” 32λΉ„νŠΈ κ°’
  • i64 <long> – λΆ€ν˜Έ μžˆλŠ” 64λΉ„νŠΈ κ°’
  • s16 <string> – UTF-16 λ¬Έμžμ—΄ (Android 13+λŠ” utf16 μ‚¬μš©)

예 – MediaTek ν•Έλ“œμ…‹μ—μ„œ uid 1둜 λ„€νŠΈμ›Œν¬ λͺ¨λ‹ˆν„°λ§ μ‹œμž‘:

service call mtkconnmetrics 8 i32 1

4. μ•Œ 수 μ—†λŠ” λ©”μ„œλ“œ κ°•μ œ 곡격

헀더 파일이 없을 λ•ŒλŠ” μ½”λ“œλ₯Ό 반볡 μ‹€ν–‰ν•˜μ—¬ 였λ₯˜κ°€ λ‹€μŒκ³Ό 같이 변경될 λ•ŒκΉŒμ§€ μ§„ν–‰ν•  수 μžˆμŠ΅λ‹ˆλ‹€:

Result: Parcel(00000000 00000000)  # "Not a data message"

정상 Parcel 응닡 λ˜λŠ” SecurityException.

for i in $(seq 1 50); do
printf "[+] %2d -> " $i
service call mtkconnmetrics $i 2>/dev/null | head -1
done

μ„œλΉ„μŠ€κ°€ proguard둜 컴파일된 경우 맀핑을 μΆ”μΈ‘ν•΄μ•Ό ν•©λ‹ˆλ‹€ – λ‹€μŒ 단계λ₯Ό μ°Έμ‘°ν•˜μ„Έμš”.

5. Mapping codes ↔ methods via onTransact()

μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•˜λŠ” jar/odexλ₯Ό λ””μ»΄νŒŒμΌν•©λ‹ˆλ‹€ (AOSP μŠ€ν…μ€ /system/frameworkλ₯Ό ν™•μΈν•˜μ„Έμš”; OEM은 μ’…μ’… /system_ext λ˜λŠ” /vendorλ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€). Stub.onTransact()λ₯Ό κ²€μƒ‰ν•˜μ„Έμš” – μ—¬κΈ°μ—λŠ” κ±°λŒ€ν•œ switch(transactionCode)κ°€ ν¬ν•¨λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€:

case TRANSACTION_updateCtaAppStatus:      // 5
data.enforceInterface(DESCRIPTOR);
int appId  = data.readInt();
boolean ok = data.readInt() != 0;
updateCtaAppStatus(appId, ok);
reply.writeNoException();
return true;

이제 ν”„λ‘œν† νƒ€μž…κ³Ό λ§€κ°œλ³€μˆ˜ μœ ν˜•μ΄ λͺ…ν™•ν•©λ‹ˆλ‹€.

6. λˆ„λ½λœ κΆŒν•œ 검사 μ°ΎκΈ°

κ΅¬ν˜„(μ’…μ’… λ‚΄λΆ€ Impl 클래슀)은 κΆŒν•œ λΆ€μ—¬λ₯Ό λ‹΄λ‹Ήν•©λ‹ˆλ‹€:

private void updateCtaAppStatus(int uid, boolean status) {
if (!isPermissionAllowed()) {
throw new SecurityException("uid " + uid + " rejected");
}
/* privileged code */
}

μ΄λŸ¬ν•œ 논리 λ˜λŠ” 특ꢌ UID의 ν™”μ΄νŠΈλ¦¬μŠ€νŠΈ(예: uid == 1000 /*system*/ )의 λΆ€μž¬λŠ” 취약점 μ§€ν‘œμž…λ‹ˆλ‹€.

사둀 연ꡬ – MediaTek startMonitorProcessWithUid() (νŠΈλžœμž­μ…˜ 8)은 κΆŒν•œ 게이트 없이 Netlink λ©”μ‹œμ§€λ₯Ό μ™„μ „νžˆ μ‹€ν–‰ν•˜μ—¬ λΉ„νŠΉκΆŒ 앱이 μ»€λ„μ˜ Netfilter λͺ¨λ“ˆκ³Ό μƒν˜Έμž‘μš©ν•˜κ³  μ‹œμŠ€ν…œ 둜그λ₯Ό μŠ€νŒΈν•  수 있게 ν•©λ‹ˆλ‹€.

7. 평가 μžλ™ν™”

Binder 정찰을 κ°€μ†ν™”ν•˜λŠ” 도ꡬ / 슀크립트:

  • binderfs – μ„œλΉ„μŠ€λ³„ λ…Έλ“œκ°€ μžˆλŠ” /dev/binderfsλ₯Ό λ…ΈμΆœ
  • binder-scanner.py – 바인더 ν…Œμ΄λΈ”μ„ νƒμƒ‰ν•˜κ³  ACL을 좜λ ₯
  • Frida 단좕킀: Java.perform(()=>console.log(android.os.ServiceManager.listServices().toArray()))

References

Tip

AWS ν•΄ν‚Ή 배우기 및 μ—°μŠ΅ν•˜κΈ°:HackTricks Training AWS Red Team Expert (ARTE)
GCP ν•΄ν‚Ή 배우기 및 μ—°μŠ΅ν•˜κΈ°: HackTricks Training GCP Red Team Expert (GRTE) Azure ν•΄ν‚Ή 배우기 및 μ—°μŠ΅ν•˜κΈ°: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks μ§€μ›ν•˜κΈ°