1-1. 모바일 앱 모의해킹이란?
모바일 앱 모의해킹은 실제 공격자의 관점에서 모바일 애플리케이션(APP)의 보안 취약점을 식별하고 검증하는 작업이다.
1-2. 주요 목적
| 앱 내 민감정보 노출 여부 확인 |
| 인증/인가 우회 가능성 검증 |
| 비즈니스 로직 취약점 발견 |
| 클라이언트-서버 통신 보안 검증 |
| 리버스 엔지니어링 방어 수준평가 |
2-1. Android 플랫폼 특징
| 오픈소스 기반(Linux 커널 사용) | 여러 회사가 안드로이드를 자유롭게 커스터마이징해서 사용할 수 있음 |
| 다양한 제조사 (삼성,LG,구글등) | 아이폰은 애플에서만 제작하지만 안드로이드는 여러 제조사가 만들어 스마트폰 종류가 매우 다양 |
| 높은 커스터마이징 자유도 | 화면 테마, 런처, 위젯 등 사용자가 바꿀수 있는게 많음 개발자도 앱 기능을 자유롭게 확장하기가 유리함 |
| 구글 플레이스토어 + 써드파티마켓 | 다양한 접근으로 애플리케이션을 설치할 수 있음 |
2-2. Android 보안 구조
| 샌드박스(Sandbox) | 각 앱은 독립된 UID로 실행 한 앱이 "방 하나"를 배정받고 그 안에서만 활동한다고 생각할 수 있음 앱끼리는 각자의 방을 침법할 수 없어 서로 간섭하거나 해킹하기 어렵게 만드는 구조 |
| SELinux (강제 접근 제어) | 시스템 안에서는 "이 앱이 이 파일에 접근해도 되는지"를 파악하는 보안 규칙이라 볼 수 있음 |
| 권한 시스템 | 앱이 카메라 또는 위치 같은 민감한 기능을 쓰려고 하면 사용자에게 허락을 받아야하는 구조임 이 허락 목록을 개발자가 Manifest 파일에 미리 적어두는 방식으로 허락을 받는 구조 |
| 앱 서명 | 만든 앱이 누가 만든 것인지 확인 하기 위한 서명이 필요함 |
2-3. Android 파일 시스템 - "/data/data/[APP Package name]/"
앱만 접근할 수 있는 개인 금고 같은 공간이다 따라서 다른 앱이 몰래 접근할 수 없다.
이곳에는 다음 같은 것들이 저장된다.
| shared_prefs/ | 설정 같은 가벼운 정보 저장 (XML 파일) |
| databases/ | 앱 내부 데이터(SQLite DB) |
| files/ | 앱 전용 파일 |
| cache/ | 임시 데이터 |
/sdcard/ => 외부 저장소
- 누구나 드나들 수 있는 "공용 공간"
- 여러 앱이 접근 가능하기 때문에 민감한 정보를 저장하면 위험하다.
3-1. IOS 플랫폼 특징
| 폐쇄적 생태계 | 안드로이드 처럼 아무나 시스템을 수정할 수 없고 모든것이 애플이 정한 규칙 안에서만 움직인다. |
| 제한된 하드웨어 | 애플이 만든 기기에서만 IOS가 작동한다. |
| 엄격한 앱 심사 | 심사가 까다로워 악성 앱이 올라올 가능성이 매우 낮다. |
| 통일된 사용자 경험 | 모든 기기가 애플 기준으로 만들어져 동일한 조작 방식이다. |
3-2. IOS 보안 구조
| 샌드박스 | IOS에서는 앱마다 완전히 독립된 "방"을 준다. 안드로이드보다 제약이 휠씬 많다. |
| 코드 서명 | 모든 앱은 애플 인증서로 서명되지 않으면 실행이 불가능하다. |
| ASLR/DEP | 메모리 보호 기법이 강제로 적용되어 있다. |
| Secure Enclave | 지문, 페이스ID, 암호키 같은 민감한 데이터를 칩 안에 있는 따로 격리된 공간에서 처리한다. |
🔀 ASLR(Address Space Layout Randomization)
⇨ 프로그램과 라이브러리, 스택, 힙 등이 메모리 어디에 배치되는지 매번 랜덤 하게 바꿈
⇨ 익스플로잇의 핵심은 정확한 주소를 알아내는 것이다. 따라서 공격자는 취약한 함수 위치를 알 수 없게 된다.
🔒 DEP(데이터 실행 방지, Data Execution Prevention)
⇨ 메모리 코드가 아니라 데이터로만 사용되어야 하는 영역에서 실행이 일어나는 것을 차단한다.
⇨ 버퍼 오버플로우에서는 공격자가 데이터 영역(Stack/Heap)에 악성 코드를 넣어 실행시키는 방식이 있음
⇨ 즉 실행되면 안 되는 메모리 구역에서 코드 실행을 막는 것
🔐 Secure Enclave: 하드웨어 기반 암호화
⇨ 일반 CPU 옆에 붙어 있는 작은 프로세서 이자, 독립된 메모리 운영 환경을 갖춘 '소형 컴퓨터'라고 보면 된다.
- 자체 CPU
- 자체 메모리
- 자체 난수 생성기(TRNG)
- 자체 Secure Boot 체인
- 외부에서 접근 불가능한 Key 저장 공간
따라서 공격자 입장에서는 침입이 불가능한 영역이기도 하다.
⇨ OS가 루팅되거나 커널이 해킹돼도 키는 안전하다.
3-3. IOS 파일 시스템 - "/var/mobile/Containers/Data/Application/[UUID]/"
| Documents/ | 사용자가 만든 문서 혹은 데이터 |
| Library/ | 앱이 쓰는 여러 지원 파일 |
| Library/Preferences | 설정(plist) |
| Library/Caches | 캐시데이터 |
| tmp/ | 임시 파일 |
IOS는 Android보다 앱 간 파일 공유가 훨씬 제한된다.
4-1. 네이티브 앱 (Native App)
플랫폼별로 공식 언어와 런타임을 그대로 사용한다.
Android
- 언어 : Java, Kotlin
- UI : XML 레이아웃
- 빌드: .dex => ART/Dalvik VM 실행
- 네이티브 모듈: .so (NDK)
IOS
- 언어 : Swift, Objective-C
- UI : Storyboard, SwiftUI
- 빌드 : ARM64 머신 코드
4-2. 하이브리드 앱 (Hybrid App)
웹 기술(HTML/CSS,JS)을 네이티브 컨테이너(WebView 또는 브리지)를 통해 실행되는 앱
| 프레임워크 | 렌더링 방식 |
| React Native | JavaScript → 네이티브 UI |
| Flutter | Dart → 자체 렌더링 엔진 |
| Cordova/PhoneGap | WebView 기반 |
5-1. Android 앱 구조 + Kotiln
APK 내부 구조
| AndroidManifest.xml | 권한, 컴포넌트 핵심 1순위 분석 대상 : 권한 남용 , exported 컴포넌트 , 디버그 설정 |
| classes.dex | Java/Kotlin 코드 |
| lib/*.so | 네이티브 코드 |
| assets/ | 리소스 (하이브리드 흔적) |
| res/ | UI |
Manifest 예시
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.bankapp">
<!-- ❌ 위험한 권한들 -->
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_SMS"/>
<uses-permission android:name="android.permission.CAMERA"/>
<application
android:debuggable="true" ← ⚠️ 디버깅 허용 (취약!)
android:allowBackup="true" ← ⚠️ 백업 허용 (민감정보 유출)
android:usesCleartextTraffic="true" ← ⚠️ HTTP 허용 (중간자 공격)
android:name=".MyApplication">
<!-- exported="true" → 외부 앱이 호출 가능 -->
<activity
android:name=".PaymentActivity"
android:exported="true"> ← 🔥 취약! 인증 없이 결제 화면 접근
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<data android:scheme="bankapp"/>
</intent-filter>
</activity>
<!-- ❌ 노출된 브로드캐스트 리시버 -->
<receiver
android:name=".SMSReceiver"
android:exported="true"> ← 외부에서 SMS 가로채기 가능
</receiver>
</application>
</manifest>
식별 시 검토 해야하는 패턴
| if (isRooted()) { ... } | 루팅 탐지 코드 |
| SharedPreferences | 민감정보 저장 |
| HttpURLConnection / Retrofit | API 통신 |
| Cipher.getInstance("AES") | 암호화 |
Manifest 예시
public class SecurityUtils {
public static boolean isRooted() {
// 🔥 취약한 루팅 탐지
String[] paths = {
"/system/app/Superuser.apk",
"/system/xbin/su",
"/system/bin/su"
};
for (String path : paths) {
if (new File(path).exists()) {
return true;
}
}
return false;
}
}
// 우회 방법: Frida로 isRooted() 함수 후킹
SharedPreferences 예시
public class TokenManager {
public void saveToken(String token) {
SharedPreferences prefs = context.getSharedPreferences("user_data", MODE_PRIVATE);
// ❌ 평문으로 토큰 저장 (취약!)
prefs.edit()
.putString("access_token", token)
.putString("user_id", "12345")
.apply();
}
}
# 루팅된 디바이스에서
$ adb shell
$ su
$ cd /data/data/com.example.bankapp/shared_prefs/
$ cat user_data.xml
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
<string name="access_token">eyJhbGciOiJIUzI1NiIs...</string>
<string name="user_id">12345</string>
</map>
HttpURLConnection 예시
public class ApiClient {
// ❌ 하드코딩된 서버 URL
private static final String BASE_URL = "https://api.example.com";
private static final String API_KEY = "sk_live_abc123"; // 🔥 API 키 노출!
public void login(String username, String password) {
// ❌ 평문으로 비밀번호 전송
String url = BASE_URL + "/login?user=" + username + "&pass=" + password;
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
conn.setRequestMethod("GET"); // ❌ GET으로 인증 정보 전송
// ...
}
}
취약점:
API 키 하드코딩 → 탈취 가능
GET 메서드로 비밀번호 전송 → 로그에 노출
HTTPS여도 URL에 민감정보 → 프록시 캡처 가능
Cipher 예시
public class CryptoUtils {
// ❌ 하드코딩된 암호화 키
private static final String SECRET_KEY = "1234567890123456";
public static String encrypt(String data) {
// ❌ 취약한 DES 알고리즘
Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
SecretKeySpec keySpec = new SecretKeySpec(SECRET_KEY.getBytes(), "DES");
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
byte[] encrypted = cipher.doFinal(data.getBytes());
return Base64.encodeToString(encrypted, Base64.DEFAULT);
}
}
취약점:
DES는 취약한 알고리즘 (AES 권장)
ECB 모드는 패턴 노출 (CBC/GCM 권장)
키가 소스코드에 평문 노출
6-1. IOS IPA 구조
# IPA 압축 해제
$ unzip app.ipa -d ipa-extracted/
$ tree ipa-extracted/
Payload/
└── MyApp.app/
├── MyApp ← 🔥 실행 바이너리 (ARM64)
├── Info.plist ← 🔥 iOS의 Manifest
├── Base.lproj/
│ └── Main.storyboardc ← UI
├── Frameworks/ ← 프레임워크
├── PlugIns/ ← 확장 기능
├── _CodeSignature/ ← 코드 서명
│ └── CodeResources
└── embedded.mobileprovision ← 프로비저닝
Info.plist 분석
# plist를 XML로 변환
$ plutil -convert xml1 Info.plist -o Info-readable.plist
$ cat Info-readable.plist
<?xml version="1.0" encoding="UTF-8"?>
<plist version="1.0">
<dict>
<!-- ⚠️ HTTP 허용 (ATS 비활성화) -->
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/> ← 🔥 모든 HTTP 통신 허용
</dict>
<!-- URL Scheme (딥링크) -->
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>myapp</string> ← myapp:// 로 앱 실행 가능
</array>
</dict>
</array>
<!-- 카메라 권한 -->
<key>NSCameraUsageDescription</key>
<string>We need camera access</string>
<!-- 위치 권한 -->
<key>NSLocationWhenInUseUsageDescription</key>
<string>We track your location</string>
</dict>
</plist>
NSAllowsArbitraryLoads=true → HTTP 통신 허용
CFBundleURLSchemes → 딥링크 (URL Scheme 하이재킹)
과도한 권한 요청 → 카메라, 위치, 연락처
UIFileSharingEnabled=true → iTunes 파일 공유 허용
바이너리 분석 - Strings 명령어
$ strings MyApp | less
# 특정 키워드 검색
$ strings MyApp | grep -i "password"
hardcoded_password_123
user_password_salt
decrypt_password_key
$ strings MyApp | grep -i "http"
https://api.example.com/login
http://test-server.com/debug ← 🔥 테스트 서버 URL 노출
$ strings MyApp | grep -i "key"
api_key_production_abc123xyz ← 🔥 API 키 하드코딩
$ strings MyApp | grep -i "sql"
SELECT * FROM users WHERE username='%@' AND password='%@' ← SQL 인젝션 가능성
'Mobile_security' 카테고리의 다른 글
| Android reversing - Plan (0) | 2026.02.03 |
|---|---|
| 0. Android - NDK 학습 (0) | 2025.12.22 |
| 0. Android - 아키텍처 (0) | 2025.12.17 |
| 0. Android - AVD, ADB, Rooting, Pm (1) | 2025.07.22 |
| 0. Android Components (글 주의) (0) | 2025.02.01 |
