Mobile/Android

Android Hacker's Handbook_2장 [정리 및 번역]

pyozzi 2019. 9. 21. 20:34

Android Hacker's Handbook Athor.Joshua J

해당 번역글은 개인 공부를 위해 번역한 글로써, 다소 틀린 표현들이 있을 수 있으니 참고할 때 유의해주시길 바랍니다.

원문은 https://www.pdfdrive.com/android-hackers-handbookpdf-e39599871.html 여기에서 받으실 수 있습니다.

Android Hacker's Handbook_2장.pdf
0.32MB


[2장. 안드로이드 보안 설계 및 아키텍처]

안드로이드는 보안 검사 및 처리를 몇 가지 메커니즘으로 구성하고 있다.
다른 운영 체제와 마찬가지로 이러한 메커니즘(App/User)객체(App/File,Device) 및 행할 작업(읽기,쓰기,삭제 등)에 

대한 정보를 교환할 수 있다. 

 

대부분의 경우에서는 이러한 과정에서 문제가 발생하지 않지만, 어떠한 균열을 통해 이러한 정보들이 빠져나가 

공격자에게 좋은 기회를 제공하기도 한다.

 

2장에서는 안드로이드 플랫폼의 전반적인 Attack Surface를 분석하기 위한 보안설계와 아키텍처에 대해 설명한다.


1. 안드로이드 시스템 아키텍처 이해

일반적인 안드로이드 아키텍처는 "Java on Linux"로 불려 왔다.
하지만, 이런 표현은 잘못된 표현이며 플랫폼의 복잡성과 아키텍처를 완벽히 정의하지 못한다.
전반적인 아키텍처는 '어플리케이션프레임워크달빅(Dalvik)가상머신사용자 공간의 Native Code리눅스 커널'로 

총 5가지 주요 레이어로 분류되는 컴포넌트들로 구성된다.

 

[그림2-1] 안드로이드 아키텍처

[그림 2-1]은 주요 레이어들이 Android 소프트웨어 스택을 구성하는 방법을 의미한다.

Android 어플리케이션을 사용하면 개발자가 Low-level까지 건들이지 않고 장치의 기능을 확장하고 향상시킬 수 있다.
또한, Android 프레임워크는 개발자에게 다양한 기능을 모두 사용할 수 있는 풍부한 API를 제공한다.

Android기기는 개발자가 UI(User Interface)요소 관리, 공유 데이터 저장소 액세스 및 응용 프로그램 구성 요소간에 

메시지 전달과 같은 일반적인 작업을 수행할 수 있도록 App과 Dalvik가상머신 간의 연결을 제공해야 한다.

어플리케이션과 프레임워크는 Java로 개발되어 달빅 가상시스템 내에서 실행된다.

달빅 가상시스템의 특징을 살펴보자면, 우선 Dalvik Executable(DEX)바이트 코드 형식을 해석하는 

'레지스터 기반 시스템'이다.  또한, Native Code 라이브러리를 지원하기 때문에 C/C++를 사용할 수 있다. 
이렇듯 DalvikVM은 기본 운영 체제에 효율적인 추상화 계층을 제공하도록 특별히 설계된 가상 시스템이다.

'안드로이드 사용자 공간의 고유 코드 구성 요소'에는 DBus와 같은 시스템 서비스가 포함된다. 

시스템 서비스에는 dhcpd, wpa_supplicant와 같은 네트워킹 서비스, bionic_libcWebKit, OpenSSL과 같은 

라이브러리가 있다. 이러한 서비스 및 라이브러리는 커널 서비스, 드라이버와 통신하지만 일부는

'Managed code'에 대한 Low-level 수준의 작동을 용이하게 하기도 한다.

안드로이드는 Linux커널 기반의 시스템이다.
안드로이드는 'Kernel-source-tree'에 대한 수많은 추가와 변경을 진행했으며, 그 중 일부는 자체 보안기능을 가지고 있다. 이 부분은 3,10,12장에서 좀 더 자세히 다루도록 하겠다.

 

커널 드라이버는 '카메라 액세스', 'Wi-Fi 및 기타 네트워크 장치 액세스'와 같은 추가적인 기능을 제공한다.
그 중 하나의 예로는 프로세스 간 통신(IPC)을 구현하는 '바인더 드라이버'가 있다.

바인더 드라이버에 대해서는 뒤에서 다시 다루도록 하겠다.


2. 보안 경계 및 처리 이해

'Trust Boundary'라고도 말하는 보안경계는 신뢰수준이 서로 다른 시스템의 특정위치를 의미한다.
가장 좋은 예로는 '커널 공간'과 '사용자 공간'의 경계이다.

 

커널 공간의 코드는 하드웨어에 대한 하위 수준의 작업을 수행하고 모든 가상 및 실제 메모리에 접근할 수 있도록 신뢰 된다.
그러나 사용자 공간 코드는 CPU에 의해 적용되는 경계로 인해 모든 메모리에 접근할 수 없다.


안드로이드는 Linux 사용자 기반 보호를 활용하여 'Users'와'Groups' 두 개로 권한을 분리한다.
두 개의 권한 그룹은 Linux 기반이며, 파일 시스템 항목 및 기타 Android관련 리소스에 대한 접근이 권한에 맞게 분리된다.
이것을 'Android SandBox'라고 한다.

'Groups'에 대한 권한은 Android런타임 때 달빅VM과 프레임워크를 통해 적용된다.
어플리케이션을 설치할 때 사용자가 App의 권한을 정의하는 것이 그것이다.  

이 과정에서 정의되는 권한은 실제OS의 특정 사용자,그룹 및 기능에 매핑된다.

2-1. Android SandBox

안드로이드는 Unix계열의 프로세스 격리 절차와 최소한의 권한 원칙을 따른다.
구체적으로 말하자면 '별도의 사용자로 실행되는 프로세스는 신호를 보내거나, 서로의 메모리 공간에 접근하는 것과 같은 

서로 간섭하는 행위가 불가능 하다.'는 개념을 말한다.

Android의 Sandbox는 '프로세스 격리', '프로세스에 대한 고유 사용자(UID)', '파일 시스템 권한'과 같은 핵심 개념을 전제로 하지만, Linux의 UID/GID(GroupID) 패러다임을 공유할 뿐 사용자 및 그룹 자격 증명 원본에 대한 암호 및 그룹 파일을 가지고 있지는 않는다.

대신 'Android ID'(AID)라고 하는 고유 식별자를 정의한다.
AID정의에는 시스템 사용자/그룹 과 같이 권한이 있거나, 시스템에 중요한 사용자를 위한 예약된 정적 항목이 들어 있다.  또한, 앱UID의 Provisioning을 위해 AID범위를 예약한다.

 

[?]계정Provisioning:  신입사원이 입사하거나 조직내에서 인사 이동을 하거나 직무변경이 발생해 사용자가 접근하는 자원(Resource)의 범주가 변경되었을 때 HR담당자와 IT관리자는 승인절차 밟은 후 e-mail ,그룹웨어 ,ERP등 다양한 어플리케이션에 필요한계정을 생성하거나 접근권한을 변경해주는데, 이러한 일련의 과정을 계정 프로바이저닝이라고 한다.

출처:https://web-front-end.tistory.com/104


Android v4.1 이후에는 여러 사용자 프로필 및 분리된 프로세스 사용자(예: Chrome 추가 샌드박싱)를 위해 추가 AID범위를 추가했다.
AOSP(Android Open Source Project)트리의 'symstem/core/include/private/android_filesystem_config.h'에서 

AID에 대한 정의를 찾을 수 있다. [그림2-2]는 해당 내용을 간략하게 편집한 것이다.

 

[그림2-2] AOSP_Define AID


AID 외에도 보조 그룹을 사용하여 프로세스가 공유나 보호된 자원에 접근을 허용하기도 한다. 
예를 들어, sdcard_rw그룹의 멤버쉽은 마운트 옵션이 읽기/쓰기가 가능한 그룹을 제한하기 때문에 프로세스가 /sdcard 디렉터리를 읽고 쓸 수 있다.  이것은 보조그룹이 많은 Linux배포판에서 사용되는 것과 유사하다.

[?]보조그룹: /etc/group 파일에 추가적인 Group들을 할당할 수 있다.

 

모든 AID항목은 UID와 GID로 매핑되지만 UID는 반드시 시스템의 사용자를 나타내는데 사용되지 않을 수 있다.
AID_SDCARD_RW는 sdcard_rw에 매핑되지만 시스템의 UID가 아닌 보조그룹으로만 사용되는 것처럼 말이다.


파일 시스템 접근을 강화하는 것 외에도 AID_INET그룹은 사용자가 AF_INET/AF_INET6 소켓을 열 수 있도록 하는 

권한을 부여하는 것 처럼 보조그룹을 사용하여 프로세스에 추가 권한을 부여할 수도 있다.

또 다른 경우 에는 권한이 'Linux Capability'를 부여하는 형태로 나타날 수 있다.
AID_INET_ADMIN그룹은 CAP_NET_ADMIN의 Capability를 부여하여 사용자가 네트워크 인터페이스 및 라우팅 테이블 

구성을 설정할 수 있도록 허용하는 것이 이러한 형태라고 할 수 있다.

Android v4.3이상에서는 위와 같은 Capability를 사용을 더 늘리게 되는데, /system/bin/run-as바이너리의 UID루트를 

수정하여 높은 권한의 리소스에 접근하는 것을 막는 등 다양하게 응용 되었다.

'Linux Capability'에 대한 자세한 정보는 Linux커널의 Documentation/security/credentials.txt 및 Capability 설명서 페이지에서 찾아볼 수 있다.


App이 실행되면 UID,GID 및 보조그룹이 새로 생성된 프로세스에 할당된다. 

고유한 UID/GID로 실행하면 운영체제가 커널에서 더 낮은 수준의 제한을 적용할 수 있으며, 런타임에서 App간 상호작용을 제어할 수 있도록 한다. 이것이 Android SandBox의 핵심이다.

 

아래 [그림2-3]은 HTC One V에서 ps명령어를 입력한 모습이다.

맨 왼쪽에서 2번째에 위치한 UID들이 각 App마다 고유한 것을 확인할 수 있다.

 

[그림2-3] ps Command on HTC One V

App은 Application Package의 특수 지시문을 통해 UID를 공유할 수도 있다. 

자세한 내용은 '주요 응용 프로그램 구성 요소'에서 설명하도록 한다.

내부적으로 프로세스에 대해 표시되는 UID/GID는 실제로 이러한 값을 설정하고 가져오는데 사용되는 

'POSIX'기능 중 getpwuid( )과 같은 안드로이드 특정 구현에 의해 제공된다.

[?]getpwuid: Bionic라이브러리에서 stubs.cpp에 정의되어 있다.

 

[그림2-4] getpwuid( )

getpwuid( )는 android_id_to_passwd, app_id_to_passwd와 같은 Android 관련 기능을 호출한다.
그런 다음 'Unix Password 구조체'를 AID정보로 채운다.
android_id_to_passwd( )는 android_i info_to_passwd( )를 호출하여 이를 수행한다.

 

[그림2-5] android_i info_to_passwd( )

 

2-2 Android 권한

안드로이드 권한 모델은 API권한파일 시스템 권한IPC권한 3가지의 관점으로 나눌 수 있다.
때때로, 이들 각각 얽힐 때가 있는데 앞에서 언급했듯이 일부 높은 수준의 사용 권한은 낮은 수준의 운영 체제 기능으로 다시 매핑된다.  여기에는 소켓 열기, Bluetooth장치 및 특정 파일 시스템 경로와 같은 작업이 포함될 수있다.

 

App사용자의 권한과 보조 그룹을 결정하기 위해 Android는 App Package의 'AndroidManifest.xml'파일에 지정된 상위 수준 권한을 처리한다. (Manifest 및 권한에 대해서는 '주요 애플리케이션 구성 요소'섹션에서 자세히 설명하도록 한다.)
App의 사용 권한은 설치시 Package Manifest에서 추출되고, '/data/system/packages.xml'에 저장된다.
그런 다음 이 항목을 사용하여 App프로세스의 인스턴스 생성시 적절한 권한을 부여한다.
[그림2-6]은 Chrome패키지의 Packages.xml의 저장된 App의 고유한 userID와 권한을 보여준다.

 

[그림2-7] Packages.xml in Chrome_Package

그룹에 대한 접근 권한 설정은 '/etc/permissions/platform.xml'에 저장된다. 

이것은 응용 프로그램에 설정할 보조그룹ID를 결정하는데 사용된다.
[그림2-7]은 이러한 설정 중 일부를 보여준다.

 

[그림2-7] /etc/permissions/platform.xml

Package항목에 정의된 권한은 나중에 두 가지 방법 중 하나로 적용된다.
첫번째는 주어진 메소드 호출 시 완료되며 런타임에 의해 적용된다.
두번째는 라이브러리 또는 커널 자체의 OS레벨에서 적용된다.


[API권한]
API권한에는 Android API/Framework 및 경우에 따라 타사 Framework에서 상위 수준 기능에 대한 접근을 

제어하는데 사용되는 권한이 포함된다. READ_PHONE_STATE를 예로 들 수 있는데,

'Android Documentation'에서 '전화상태에 대한 읽기 전용 접근'을 허용하는 것으로 정의되어 있다.
따라서, 이 권한을 요청하여 해당 권한이 부여된 App은 전화정보를 쿼리하는 것과 관련된 다양한 메소드를 호출할 수 있게된다.
메소드에는 'getDeviceSoftwareVersion','getDeviceId'등의 TeleponyManager클래스의 메소드가 있다.

앞서 언급했듯이 일부 API 사용권한은 커널 수준 메커니즘에 해당된다.
예를 들어, INTERNET권한이 부여되면 요청한 App의 UID가 INET그룹의 구성원으로 추가된다.(GID 3003)
이 그룹의 멤버쉽은 사용자에게 HttpURLConnection 객체 생성과 같은 상위 레벨 API기능에 필요한 AF_INET/AF_INET6 소켓을 여는 기능을 제공한다.
4장에서 API권한에 관련된 몇가지 문제점에 대해서 다루도록 한다.

[파일 시스템 사용권한]
Android의 어플리케이션 샌드박스는 Unix 파일 시스템 권한으로 지원된다. 
App의 고유한 UID/GID는 기본적으로 파일 시스템의 해당 데이터 저장소 경로에만 접근할 수 있다.
[그림2-8]의 디렉터리 목록을 UID/GID(두번째와 세번째 줄)에 유의해서 보도록 하자.

 

[그림2-8] App 디렉터리 목록

 

따라서, 어플리케이션에서 만든 파일에는 적절한 파일 사용권한이 설정된다.
다음 [그림2-9]는 어플리케이션의 데이터 디렉터리를 보여준다.
하위 디렉터리 및 파일에 대한 소유권과 실행권한은 어플리케이션의 UID/GID에 대해서만 설정된다.

 

[그림2-9] Application /data

SD카드 또는 기타 외부 저장소와 같은 공유 리소스에 접근할때는 특정 보조그룹(GID)이 사용된다. 
아래 그림에서 mount와 ls 명령의 출력을 확인해보길 바란다.

 

[그림2-10] mount GID

여기서 SD카드가 sdcard_rw그룹에 해당하는 'GID1015'로 마운트 되었음을 알수 있다.
WRITE_EXTERNAL_STORAGE권한을 요청하는 App은 이 그룹에 UID를 추가하여 이 경로에 대한 쓰기권한을 부여한다.

[IPC권한]
IPC권한은 API권한과 일부 겹치지만 App구성요소 간의 통신과 직접 관련된 권한이다.
이러한 사용권한의 선언 및 적용은 런타임,라이브러리 함수, Application 직접 수행과 같이 다양한 수준에서 발생할 수 있다.
특히, IPC권한은 Android의 바인더 IPC메커니즘을 기반으로 하는 주요 Android App 구성요소에 적용된다.
이러한 구성 요소와 바인더 자체에 대한 자세한 내용은 뒷부분에서 설명하도록 한다.


3. Android 구성 요소 자세히 알아보기

이 섹션에서는 애플리케이션, Android 프레임 워크, DalvikVM, 사용자 공간 기본 코드 및 관련 서비스 지원, 

Linux커널에 대한 Android 보안 구성요소를 자세히 살펴볼 것이다.
해당 내용들은 다음 장(Access Android Device)에 대한 기초적인 설명이며, 구성 요소를 공격 하는데 중요한 지식이 될 것이다.

 

3-1. Android 애플리케이션

Android 애플리케이션의 보안을 진단하고 공격하는 방법을 이해하려면 우선 애플리케이션에 대해서 이해해야 한다.
Android 보안 구성요소, 애플리케이션 런타임, IPC 메커니즘 지원에 대해서 설명하도록 한다.

애플리케이션은 일반적으로 사전 설치(Pre-Install), 사용자 설치(User-Install) 두 가지로 나뉜다.
사전 설치된 애플리케이션에는 Googld, OEM(Original Equipment Manufacturer), 캘린더, 이메일, 브라우저 등 

이동 통신사나 제조사에서 제공하는 애플리케이션이 포함된다. 이러한 앱의 패키지는 '/system/app'에 존재한다.
이렇게 사전설치된 앱들은 높은 권한 또는 기능을 가질 수 있으므로 유심히 봐야할 필요가 있다.

사용자 설치된 애플리케이션은 Google Play, 직접 설치(ADB,PM)를 통해 설치된 애플리케이션이다.
이렇게 사용자 설치된 앱과 사전 설치된 앱의 업데이트는 '/data/app'에 존재한다.

Android는 여러가지 목적을 위해 애플리케이션을 공개키로 암호화한다.
먼저 Android는 특수한 'Platform Key'를 사용하여 사전 설치된 앱을 서명한다.
해당 Platform Key로 서명된 앱은 시스템 사용자 권한을 가질 수 있다는 특징이 있다.

사용자가 직접설치하는 앱은 각 개발사마다의 Key로 서명된다.
사전 설치된 앱과 사용자가 설치한 앱 모두 서명을 통해서 앱이 무단으로 수정되는 것을 방지한다.

[주요 애플리케이션 구성 요소]
Android 애플리케이션은 여러 가지 구성요소를 가지고 있지만, 해당 섹션에서는 Android버전에 관계없이 대부분의

애플리케이션에서 확인할 수 있는 구성요소에 대해서 설명하도록 한다.

항목은 Android Manifest, Intent, Activities, Broadcast Receivers, Service, Content Providers가 있다.
이 중 Activity, Broadcast Receiver, Service, Content Provider는 'IPC Endpoint'를 나타내며 흥미로운 보안 속성이 있다.

 

> Android Manifest.xml  
모든 Android 애플리케이션 패키지(APK)에는 'Android Manifest.xml' 파일이 포함되어야 한다.
이 XML파일에는 다음을 포함한 앱에 대한 정보가 명시되어야 한다.

   

    ■ 고유한 패키지 이름
    ■ Activity, Service, Broadcast Receiver, Instrumentation Definition
    ■ 권한 정의
    ■ 공유UID정보, 기본 설치 위치 및 UI정보

Android Manifest.xml에서 특히 흥미로운 부분 중 하나는 공유 UID정보이다.
'공유 UID'란, 두 개의 애플리케이션에서 동일한 사용자 식별자를 지정할 수 있다는 것이다.
이 경우 두 앱은 동일한 UID에서 실행되는데, 이를 통해 두 앱은 잠재적으로 서로의 리소스에 접근할 수 있게 된다.
Android Manifest.xml은 Eclipse 또는 Android Studio와 같은 개발 환경에서 자동으로 생성되며,

Build 과정에서 일반 텍스트 XML파일이 이진 XML파일로 변환된다.

 

> Intent
앱 간 통신의 핵심은 Intent이다.
수행 할 작업, 수행 할 대상 구성요소, 추가 플래그 또는 기타 지원 정보 (수신자에게 중요할 수 있음)에 대한 

정보가 들어있는 메시지 개체이다.
메일의 링크를 눌러 브라우저를 실행하고, 메시지 앱에서 SMS가 도착했음을 알리고, 

애플리케이션을 설치/제거 하는 등 거의 모든 작업은 시스템에 Intent가 전달되는 것과 관련이 있다.
이는 애플리케이션 구성요소가 서로 프로그래밍 방식으로 상호작용하여 기능을 호출하고 데이터들을 공유할 수 있는 IPC 또는 RPC(Remote Procedure Call)기능과 유사하다.
Low-Level(파일 시스템,AID 등)에서 샌드 박스를 적용하면 애플리케이션은 일반적으로 이 API를 통해 상호작용한다.
사용자가 메시지 전송 또는 수신에 대한 권한 요구 사항을 지정하는 경우, Android 런타임은 모니터 역할을 하여 

Intent에 대한 권한 검사를 시행한다.
AndroidManifest.xml에서 특정 구성 요소를 선언할 때, End-Point가 처리하는 기준을 'Intent-filter'로 지정할 수 있다. Intent-filter는 '암시적 Intent'라고 하고도 하는데, 특정 대상을 지정하지 않고 Intent를 처리할 때 사용된다.
예를 들어 AndroidManifest.xml에 사용자 지정권한 'com.wiley.permission.INSTALL_WIDGET'과 

이 권한을 사용하여 'InstallWidgetActivity'시작을 제한하는 활동 'com.wiley.Mymission.InstallWidgetActivity'가 

있다고 가정해보자

[그림3-1] Intent-filter 설정

여기에 권한 선언과 Activity 선언이 있으며, 권한의 ProtectionLevel속성은 'signature'로 설정되어 있다.
이렇게 하면 처음에 이 권한을 정의한 앱과 동일한 키로 서명한 앱만 권한을 요청할 수 있고, 다른 앱은 제한되게 된다.

 

> Activities
Activity는 간단히 말해서 앱에서 '사용자에게 보여지는 구성요소' 또는 UI를 말한다.
기본 Activity 클래스를 기반으로 하는 Activity는 관련 UI요소와 함께 창으로 구성된다.
Activity의 Low-Level관리는 적절하게 이름이 지정된 Activity Manager에 의해 처리되며,

앱 사이에서 또는 앱 내부에서 Activity를 호출하기 위해 전송된 Intent도 Activity Manager에서 처리된다.
이러한 Activity은 앱의 Manifest 내부에서 정의되며, 다음과 같다.

[그림3-2] Activity 정의

여기에서는 스타일/UI정보, 화면 방향 등에 대한 지정자와 함께 Activity를 확인할 수 있다.
LaunchMode속성은 활동이 시작되는 방식에 영향을 주기 때문에 주의 깊게 볼 필요가 있다.
해당 경우는 값이 'singleTask'로 설정되어 있는데, 이는 특정 활동의 인스턴스가 한 번에 하나만 존재하 수 있음을 

나타낸다. 각 호출마다 별도의 인스턴스를 시작하는 것과 반대인 경우이다.
애플리케이션의 인스턴스는 Activity를 호출한 Intent를 수신하고 처리한다.

 

> Broadcast Receivers
IPC End-Point의 다른 유형은 Broadcast Receiver이다.
Receiver는 앱이 설정한 'Intent-filter'에서 확인할 수 있는데, 특정 기준과 일치하게 되면 Intent를 수신하게 된다.
예를 들어, SMS메시지와 관련된 Intent를 수신하려는 앱은 Manifest에 과 일치하는 Intent-filter를 사용하여 Receiver를 등록한다.

[그림3-3] Receiver 등록

Broadcast Receiver에 대한 권한 요구사항을 설정하면 Intent를 해당 End-Point로 보낼 수 있는 App을 제한할 수 있다.

 

Receiver는 개발단계에서 RegisterReceiver()를 사용하여 런타임에 등록할 수 있다. 이 방법을 오버로드하여
수신자에 대한 권한 제한을 설정할 수도 있다.

 

> Service
서비스는 사용자가 앱과 직접 상호작용하지 않아도 백그라운드에서 실행되는 앱의 구성요소를 말한다.
Android 서비스의 간단한 예로 'SmsReceiverService', 'BluetoothOppService'가 있다.
이러한 서비스들은 다른 Android앱 구성요소와 같이 백그라운드에서 실행되지만 Intent를 보내고 받음으로써

IPC기능을 활용할 수 있다.
서비스는 애플리케이션의 Manifest에 선언해야한다. 다음은 Intent-filter가 있는 서비스에 대한 간단한 정의이다.

[그림3-4] Service 정의

서비스는 일반적으로 모든 Intent로 시작,중지 또는 바인드 될 수 있다.
바인드의 경우, 추가 IPC 또는 RPC 프로시저 세트를 호출자가 사용할 수 있다.
이 절차는 서비스 구현에 따라 다르며, "Kernel"섹션에서 설명할 '바인더 서비스'를 더 많이 활용한다.

 

> Content Providers
Content Provider는 공유 데이터 저장소에 대한 구조화된 인터페이스 역할을 한다.
예를 들어, 연락처 공급자와 일정 공급자는 다른 앱에서 액세스 할 수 있는데 Content Provider는 각각의 항목들을

적절한 권한으로 관리한다.
또한, 앱은 고유한 Content Provider를 생성하고 선택적으로 다른 앱에 노출 시킬 수 있다.

이러한 Provider가 제공하는 데이터는 일반적으로 SQLite Database 또는 파일 시스템 경로(미디어 플레이어 인덱싱, MP3파일 공유경로 등)에 의해 백업된다.
다른 앱 구성 요소와 마찬가지로 Content Provider를 읽고 쓰는 기능은 권한으로 제한 될 수 있다.
다음 AndroidManifest.xml파일의 내용은 Content Provider권한 제한에 대한 내용이다.

[그림3-5] Content Provider 권한 제한

위 App은 Provider기능을 구현하는 클래스에 해당하는 MyProvider라는 Provider를 선언한다.
그 뒤, 'com.wiley.example.permission.WRITE'의 writePermission을 선언하여 해당 사용자 지정 권한이 있는 앱만

해당 Provider에 Write 할 수 있음을 나타낸다.
마지막으로, 이 Provider가 수행할 권한 또는 Content URI(Uniform Resource Identifier)를 지정한다.
Content URI는 'content://[authorityname]/'의 형식을 취하며, 추가 경로 / 인수정보를 포함 할 수 있다. (예: content://comwiley.example.data/foo)
4장에서는 이러한 IPC Endpoint 중 일부를 발견하고 공격하는 방법을 보여준다.

 

[Android Framework]
앱과 런타임 사이의 연결고리인 Android Framework는 개발자가 일반적인 작업을 수행할 수 있도록 패키지 및 클래스를 제공한다. 
이러한 작업에는 UI요소 관리공유 데이터 저장소 액세스, 앱 구성 요소간에 메시지 전달이 포함될 수 있다.

즉, DalvikVM 내부에서 실행되는 코드들이 포함된다. 
프레임워크 패키지는 'android.content'또는 'android.telephony'와 같은 android.* 네임스페이스 내의 패키지이다. 
또한, Android는 많은 표준 Java클래스(java.* 및 javax.* 네임스페이스)와 Apache HTTP클라이언트 라이브러리 및

SAX XML파서와 같은 추가적인 타사 패키지를 제공한다. 
그리고 Android Framework에는 클래스에서 제공하는 많은 기능들을 관리하고 용이하게 사용하는데 도움이 되는 

서비스가 포함되어 있다. 
Framework Manager는 시스템 초기화 후, System_server('Zygote'섹션에서 설명)에 의해 시작된다.

아래 그림은 Framework Manager 중 일부와 그에 대한 설명 및 역할을 보여준다. 

[그림3-6] Framework Manager

아래 그림에서 ps명령어에 -t 옵션과 system_server PID(376)을 지정하여 출력된 결과를 확인해보면, 
Framework Manager 중 일부가 system_server프로세스 내에서 Thread로 나타나는 것을 볼 수 있다. 

[그림3-7] Framework Manager 프로세스 확인


[Dalvik Virtual Machine]
DalvikVM은 스택 기반이 아닌 레지스터 기반 시스템이다. 
Dalvik은 Java기반이라고 말하지만 Google이 Java로고를 사용하지 않고,

Android 애플리케이션 모델이 JSR(Java사양 요구사항)과 관련이 없으므로 Java기반이라고 할 수 없다. 
Android 애플리케이션 개발자에게 DalvikVM은 Java처럼 보이고 느껴질 수 있지만 전혀 그렇지 않다. 
전반적인 개발 프로세스는 다음과 같다. 


    [1] 구문적으로 Java와 유사한 모양의 개발자 코드 
    [2] 소스코드는 .class파일로 컴파일 된다. (Java와 유사) 
    [3] 컴파일된 .class파일은 Dalvik Bytecode로 변환된다. (.Smali) 
    [4] 모든 .class파일이 단일 Dalvik 실행파일(.DEX)파일로 결합된다. 
    [5] Bytecode는 DalvikVM에 의해 로드되고 해석된다. 


DalvikVM은 레지스터 기반 가상머신으로 약 64,000개의 가상 레지스터를 가지고 있다. 
그러나, 전부 사용하는 것이 아닌 16개 또는 256개만 사용하는 것이 가장 일반적이다. 
이러한 레지스터는 VM메모리에서 마이크로 프로세서의 레지스터 기능을 시뮬레이션 하는 메모리 위치로 지정된다. 
실제 마이크로 프로세서와 마찬가지로 DalvikVM은 이러한 레지스터를 사용하여 상태를 유지한다. 
DalvikVM은 낮은 메모리, 낮은 프로세서 속도를 가진 임베디드 시스템의 제약 조건을 위해 속도와 효율성을 

염두에 두고 설계되었다. 


가상 머신은 결국 CPU의 기본 레지스터 머신의 추상화라고 할 수 있으며, 이는 본질적으로 효율성 손실을 

의미하므로 Google은 이러한 영향을 최소화 하려고 했다. 
이러한 제약 조건을 최대한 활용하기 위해 가상 시스템에서 해석하기 전에 DEX파일이 최적화된다.

Android 앱 내부에서 시작된 DEX파일의 경우, 일반적으로 애플리케이션을 처음 시작할 때 한번만 발생한다. 
이 최적화 프로세스의 결과는 최적화된 DEX파일(ODEX)이다. 

ODEX파일은 DalvikVM의 다른 버전이나 장치간에 이식성이 없다. 
JavaVM과 유사하게 DalvikVM은 JNI(Java Native Interface)를 사용하여 Low-Level의 원시코드를 사용한다. 
이 기능을 통해 Dalvik코드에서 Native Code를 호출할 수 있다. 
DalvikVM, DEX파일 형식 및 Android의 JNI에 대한 자세한 내용은 공식 Dalvik설명서 
(http://milk.com/kodebase/dalvik-docs-mirror/docs/)를 참고하길 바란다. 

> Zygote 
Android 기기 부팅시 시작되는 프로세스 중 하나는 Zygote 프로세스이다. 
Zygote는 Android Framework에서 사용하는 추가 서비스를 시작하고 라이브러리를 로드한다. 
그런 다음 Zygote프로세스를 복제하거나 분기하여 각 Dalvik프로세스의 로더 역할을 한다. 
이 최적화는 Dalvik프로세스(앱 포함)를 시작할 때, 자원이 많이 소모되는 Android Framework프로세스 로드 및 

종속성 작업을 반복하지 않아도 된다. 


결과적으로 주요 라이브러리, 클래스 및 힙 구조가 DalvikVM 인스턴스간에 공유된다. 

Zygote의 다음 작업은 system_server프로세스를 시작하는 것이다. 
이 프로세스는 시스템AID에서 높은 권한으로 실행되는 모든 핵심 서비스를 제공한다. 
차례로 system_server는 위 [그림3-6]에서 소개한 모든 Android Framework 서비스를 시작한다. 

 

Zygote는 초기 시작 후, RPC 및 IPC를 통해 다른 Dalvik프로세스에 대한 라이브러리 접근을 제공한다. 

이것은 Android 앱 구성 요소를 호스팅하는 프로세스가 실제로 시작되는 메커니즘이다. 

 

system_server프로세스는 매우 중요하므로 프로세스를 종료하면 장치가 재부팅 되는 것처럼 보인다.
하지만, 장치의 Dalvik 하위 시스템만 실제로 재부팅 되는 것이다. 

 

[유저 영역 Native Code]
Native code는 운영체제 유저 영역에서 Android의 많은 부분들을 구성한다. 
이 계층은 '라이브러리'와 '시스템 서비스' 두 가지 요소로 구성된다. 
해당 섹션에서는 두 요소와 그에 속하는 많은 구성 요소에 대해 좀 더 자세히 설명할 것이다. 

 

> 라이브러리
Android Framework의 상위 레벨 클래스에 의존하는 대부분의 Low-Level단의 기능들(Memory)은

공유 라이브러리에 의해 구현되고, JNI를 통해 액세스할 수 있다.


이러한 라이브러리 중 다수는 다른 유닉스 계열 운영 체제에서 사용되는 것과 동일한 오픈소스 프로젝트들이다. 

예를 들어, SQLite는 로컬 데이터베이스 기능을 제공하고, WebKit은 내장 가능한 웹 브라우저 엔진을 제공하며, FreeType은 비트맵 및 벡터 글꼴 렌더링을 제공한다.  
공급 업체별 라이브러리, 즉 디바이스에 고유한 하드웨어를 지원하는 라이브러리는 '/vendor/lib'

(또는 /system/vendor/lib)에 위치해 있다. 
여기에는 그래픽 장치, GPS 송수신기, 라디오에 대한 Low-Level단의 자원을 활용할 수 있는 API가 포함되어 있다. 


Vendor에서 제공한 라이브러리가 아닌 경우에는 '/system/lib'에 위치해 있으며, 
보통 외부 프로젝트가 존재한다. 
   

    ■ libexif: JPEG EXIF 처리 라이브러리 
    libexpat: Expat XML Parser 
    libaudioalsa / libtinyalsa: ALSA 오디오 라이브러리 
    libbluetooth: BlueZ Linux Bluetooth 라이브러리 
    libdbus: D-Bus IPC 라이브러리 


위 목록들은 Android에 포함된 수많은 라이브러리 중 일부에 불과하다. 
Android4.3에는 200개가 넘는 공유 라이브러리가 있다. 
그러나 모든 기본 라이브러리가 표준은 아니다.  
Bionic을 그 예로 들 수 있는데, Bionic은 BSD C 런타임 라이브러리에서 파생된 것으로 작은 용량, 

최적화 문제, GNU Public License(GPL)와 관련된 라이센스 문제를 피하기 위해 사용되었다. 
그러나 Bionic의 구현이 완벽하지 않았고, 많은 코드가 Native code(C)로 구현되어 있었다. 
또한, C런타임의 설치공간을 줄이기 위해 Android 개발자는 사용자 정의 동적 링커 및 Thread API를 구현하였고, 

이러한 문제 때문에 메모리 손상 취약점이 발생하기 쉬웠다. 

추후에 이 Layer는 Android 취약점을 분석할 때 흥미로운 영역으로 여겨진다. 

 

> Core Services 
Core Service는 기본 OS환경 및 Android 구성 요소를 설정하는 서비스이다. 
이러한 서비스는 'init'과 같은 유저 영역을 제일 먼저 초기화 하는 것부터 'adbd' 및 'debuggerd'와 같은 중요한 디버깅 기능을 제공하는 등 다양한 서비스를 제공한다.  일부 Core Service는 하드웨어 또는 버전별로 다를 수 있다. 
해당 섹션에서는 모든 서비스를 소개하지 않고, 일부 Core 서비스만 다루도록 하겠다.


>> init  

Linux시스템에서 Android와 마찬가지로 Linux커널에 의해 첫번째로 시작되는 프로세스는 'init'이며,

일련의 명령을 실행하여 유저 영역 환경을 초기화한다. 
Android가 일반 Linux시스템과 다른점은 'init의 사용자 정의'를 사용한다는 것이다. 

Android는 '/etc/init.d'에서 쉘 스크립트를 실행하는 대신 '/init.rc'에 있는 지시문을 기반으로 명령을 실행한다. 
지시문은 기기별로 '/init.[HW].rc'라는 파일에 있을 수 있으며, 여기서 [HW]는 해당 기기의 하드웨어 이름이다. 
다음은 'HTC One V'의 /init.rc 내용에 대한 그림이다. 

[그림 3-8] HTC Oen V /init.rc 

이 init스크립트는 다음을 포함하여 몇 가지 작업을 지정한다. 
     서비스 지시문을 통해 부팅시 시작해야하는 서비스 또는 데몬 시작 
     각 서비스 항목 아래의 들여쓰기된 인수에 따라 서비스를 실행할 사용자 및 그룹지정 
     속성 서비스를 통해 노출되는 시스템 전체 속성 및 구성 옵션 설정 
     'on'지시문을 통해 시스템 속성 수정, 파일 시스템 마운트와 같은 특정 이벤트 발생 시, 실행할 동작, 명령 등록 

 

>>Property Service 

Android의 초기화 과정에는 속성 서비스가 있다. 
이 서비스는 영구(re-boot까지) 메모리 매핑 'key-value'구성 기능을 제공한다. 
많은 OS 및 프레임 워크 구성 요소는 네트워크 인터페이스 구성, 라디오 옵션 및 보안 관련 설정과 같은 항목을 

포함하여 이러한 속성에 의존한다. 

속성은 다양한 방법으로 검색하고 설정할 수 있다. 
명령행 유틸리티인 'getprop', 'setprop'을 사용할 수 있으며, libcutils의 'property_get','property_set'을 

통해 Native code에서 설정할 수도 있다. 
또는, 'android.os.SystemProperties'클래스를 사용하여 설정 가능하다.(앞서 언급한 기본 함수를 호출함) 
속성 서비스의 개요는 다음 그림에 나와있다. 

[그림 3-9] 속성 서비스 개요

Android장치(여기에서는 HTC One V)에서 getprop명령을 실행하면 DalvikVM옵션, 현재 배경화면,

네트워크 인터페이스 구성 및 Vendor별 업데이트 URL이 포함된 출력이 표시된다. 

[그림3-10] getprop 명령 실행

'읽기 전용'으로 설정된 일부 속성은 'root'권한으로도 변경할 수 없다. (일부 장치 별 예외가 있음) 

이들은 'ro'접두사로 지정된다. 

[그림3-11] ro접두사로 지정된 속성

다음 3장에서 Property Service와 보안에 대한 추가적인 정보를 소개하겠다.  

 

>> Radio Interface Layer 

RIL(Radio Interface Layer)는 디바이스에 전화 기능을 가능하게끔 해주는 구성요소이다.

RIL이 없으면 Android장치에서 전화를 걸거나 문자를 보내고 받는 행위가 불가능 하다.

또한 Wi-Fi없이 인터넷에 액세스하는 것이 불가능 해진다. 
따라서, 셀룰러 데이터 또는 전화 기능이 있는 모든 Android기기에서 해당 구성요소 'RIL'이 필요하다. 
해당 내용은 다뤄야할 내용이 많기 때문에 11장에서 자세히 설명하도록 한다.

 

>> Debuggerd 

Android의 기본 충돌보고 기능은 'Debuggerd'라는 데몬을 중심으로 이루어진다. 
Debuggerd데몬이 시작되면 Android의 로깅 기능에 대한 연결이 활성화 되고,  'Abstruct Namespace Socket'에서

라이언트 수신 대기가 시작된다. 


각 프로그램이 시작되면 링커는 특정 신호를 처리하기 위해 신호처리기를 설치하고, 신호가 발생하게 되면 커널에서 'debugger_signal_handler'를 실행한다. 이 핸들러 함수는 'DEBUGGER_SOCKET_NAME'에 정의되어 있으며,

위에서 언급한 소켓에 연결된다.

연결이 완료되면 링커는 디버거에 대상 프로세스가 충돌했음을 알린다. 
이는 디버거에게 충돌 보고서를 작성해야 한다는 것을 알리는 역할을 한다. 

 

>> ADB 

Android Debugging Bridge(ADB)는 Android 디바이스의 adbd데몬, Host Workstation, ADB Server, ADB Client

구성되어 있다. 

서버는 'Java Debug Wrie Protocol'을 통해 클라이언트와 대상 장치에서 실행되는 데몬 간의 연결을 관리하여

Shell실행과 같은 작업을 원할하게 한다. 

 

ADB는 클라이언트 연결을 위해 'TCP/5037port'에서 수신대기를 하고 있으며, 'adb devices'명령어를 통해 서버와

연결된 디바이스를 나열할 수 있다. 

'adb shell'명령어를 통해서 디바이스에서 Shell을 실행할 수 있다. 

[그림3-12] adb devices / adb shell 실행

Shell을 실행한 뒤, pgrep을 통해 adbd데몬이 실행되고 있음을 확인할 수 있다. 

[그림3-13] adbd데몬 프로세스 확인

ADB는 Android장치 및 에뮬레이터로 개발하는데에 있어서 중추적인 역할을 한다. 
따라서, 앞으로 분석을 진행하면서 ADB를 많이 사용할 것이다. 
'http://developer.android.com/tools/help/adb.html'에서 ADB명령어에 대한 자세한 정보를 찾을 수 있다. 

 

>> Volume Daemon 

Volume Daemon(vold)은 Android에서 다양한 파일 시스템을 mount/unmount하는 역할을 한다. 
예를 들어, SD카드가 삽입되면 vold는 SD카드 파일 시스템의 오류(ex.fsck Launch)를 확인하고, 

카드를 적절한 경로(ex./mnt/sdcard)에 마운트하여 해당 이벤트를 처리한다. 
사용자가 SD카드를 꺼내게 되면 vold는 대상 볼륨을 마운트 해제 작업을 진행하여 이벤트를 처리한다. 

 

vold는 ASEC(Android Secure Container)파일 mount/unmount 처리역할도 하게 되는데,

FAT와 같은 안전하지 않은 파일 시스템에 저장될 때, 앱 패키지를 암호화하는데 사용된다. 
앱 로딩시 Loopback장치를 통해 '/mnt/asec'에 마운트 되며, Opaque Binary Blobs(OBBs)도 vold에 의해 mount/unmount된다. 

OBBs는 공유키로 암호화된 데이터를 저장하기 위해 앱과 함께 제공된다. 
ASEC과 다른점은 OBBs의 mount/unmount는 시스템이 아닌 앱에서 수행된다는 것이다. 
다음 그림은 SuperSecretKey를 공유키로 사용하여 OBBs를 작성하는 법을 나타낸다. 

[그림3-14] SuperSecretKey를 이용한 OBBs 작성

vold는 루트권한으로 실행되므로 공격자 입장에서 매력적인 대상이다. 
다음 3장에서는 vold서비스를 이용한 권한 상승 공격에 대한 세부 정보를 소개하도록 하겠다. 

 

>> Other Services 

아래 표는 필수적인 서비스는 아니지만, Android기기에서 제공하는 추가적인 기능을 소개하고 있다. 
각 서비스들의 권한, 설명들을 확인할 수 있으며 기기마다 차이가 있을 수 있다. 
또한, 시스템의 init.rc파일에 의해 서비스들이 특별하게 지정될 수 있다. 

[그림3-15] 서비스 목록-1 
[그림3-16] 서비스 목록-2

앞에서 언급했듯이 위 표는 모든 서비스가 포함되어 있지 않다. 
다양한 장치의 프로세스 목록, init.rc 및 파일 시스템을 Nexus시리즈 기기와 비교하면 더 많은 서비스들이 나타나는 것을 확인할 수 있다. 

 

[Kernel]
Android는 모두가 익히 알고있는 리눅스 커널을 베이스로 이루어져 있다. 
하지만 일반적으로 알고 있는 리눅스 커널과 Android커널은 약간의 차이점이 있다. 
해당 섹션에서는 이러한 차이점들 중 보안과 관련된 변경사항에대해 설명할 것이다. 

> Android Fork 
초기에 Google은 Android가 Linux커널 Mainline tree와 호환성이 좋지 않아 많은 부분을 수정해야 했고,

이 때문에 Android중심의 Fork를 만들게 되었다. 
여기에는 파일시스템 지원, 네트워킹 조정, 프로세스와 메모리 관리 기능들이 포함된 약 250개의 패치가 포함되어 있다. 
2012년 3월 Linux커널 관리자는 Android전용 커널 수정 사항을 Mainline tree에 병합하였고, 

아래 그림은 커널의 추가/변경 사항을 나타낸다. 
이 섹션 뒷부분에서 이 중 몇가지에 대해 추가로 설명하도록 하겠다. 

[그림3-17] 안드로이드 커널 추가/변경 사항

 

> Binder 
아마 Android Linux 커널에서 가장 중요한 요소 중 하나가 Binder인것을 알고 있을 것이다. 
Binder는 OpenBinder를 기반으로하는 IPC메커니즘이다. 
Android의 Binder는 비교적 작지만(약 4,000줄의 소스코드), Android의 많은 기능에서 중추적인 역할을 한다. 
간단히 말하자면, Binder 커널 드라이버는 모든 Binder 아키텍처의 사용을 용이하게 해준다. 
Binder는 하나의 아키텍처이며, 'Client-Server'방식으로 동작한다. 
따라서, 프로세스가 '원격'에서 메소드를 동기적으로 호출할 수 있다. 

 

Binder아키텍처는 세부사항을 추상화하여 원격 메소드 호출을 마치 로컬함수를 호출한 것처럼 보이게 한다. 
다음 그림은 Binder의 커뮤니케이션 흐름을 나타낸다. 

[그림3-18] Binder 커뮤니케이션 흐름

또한, Binder는 호출 프로세스를 식별하는 수단으로 PID 및 UID정보를 사용하여 수신자가 액세스 제어에 대한

결정을 내릴 수 있도록 한다. 
일반적으로 'Binder.getCallingUid', 'Binder.getCallingPid'와 같은 메소드를 호출하거나, 'checkCallingPermission' 

상위 레벨의 메소드를 통해 해당 작업을 진행한다. 
실제로 이러한 예는 'ACCESS_SURFACE_FLINGER'권한에서 볼 수 있는데, 해당 권한은 그래픽 시스템 사용자에게만 

부여되며 Surface Flinger 그래픽 서비스의 Binder IPC Interface에 대한 접근을 허용한다. 

다음 그림을 보면 해당 권한을 부여할 때, 'Binder.getCallingUid', 'Binder.getCallingPid'를 통해 UID와 PID를

확인하는 것을 볼 수 있다. 

[그림3-19] 메소드를 이용한 UID,PID 확인

> ashmem 
익명 공유 메모리(Ahmless Shared Memory)는 리눅스 커널 중 안드로이드에서 추가된 요소이다. 

ashmem드라이버는 기본적으로 파일 기반의 Reference Counting 공유메모리 인터페이스를 제공한다. 

Reference Counting이란, 개체, 메모리 블록과 같은 리소스에 대한 참조, 포인터 또는 핸들 수를 저장하는 기술이다.

일반적으로 더 이상 참조되지 않는 객체를 할당/해제하는 수단으로 사용된다. 

'Surface Flinger','Audio Flinger', 'System Server', 'DalvikVM'과 같은 Android의 주요 구성 요소에서 널리 사용된다. 

 

ashmem은 사용 가능한 시스템 전체 메모리가 적을 때, 자동으로 메모리 캐시를 축소하고 메모리 영역을 회수하도록

설계 되었으므로 메모리가 적은 환경에 적합하다. 
Low-Level에서 ashmem을 사용하는 방법은 간단하다. 
'ashmem_create_region( )'을 호출하고 반환된 File Descriptor에서 mmap()을 사용하면 된다. 
아래는 그 예시를 보여준다. 

[그림3-20] ashmem_create_region( )

Android Framework에서는 ashmem드라이버 주위의 wrapper역할을 하는 'MemoryFile'클래스를 제공한다. 
또한, 프로세스는 바인더 기능을 사용하여 나중에 이러한 메모리 개체를 공유하고 바인더의 보안 기능을 활용하여 

액세스를 제한할 수 있다. 

미리 얘기를 하나 하자면, ashmem은 2011년 초에 심각한 결함의 원인이 되어 Android 속성을 통한 권한 상승을 

허용했던 적이 있다. 
이에 대한 자세한 설명은 다음 3장에서 하도록 하겠다. 

> pmem 
또 다른 Android 전용 커스텀 드라이버는 'pmem'으로, 1MB에서 16MB(이는 구현에 따라 달라짐)이상의 물리적으로 

연속적인 대용량 메모리를 관리한다. 
이 영역은 유저 영역 프로세스와 다른 커널 드라이버(예: GPU드라이버)간에 공유되므로 특별하다. 
ashmem과 달리 pmem드라이버는 다른 모든 참조가 닫힐 때까지 파일 프로세스 디스크립터를 pmem메모리 힙에 

보유해야 한다. 

> Logger 
Android의 커널은 여전히 자체 Linux기반 커널 로깅 메커니즘을 유지하지만, 'Logger'라고 하는 다른 로깅 하위 시스템도 사용한다. 
이 드라이버는 로그 버퍼를 보는데 사용되는 'logcat'명령을 지원한다. 

정보 유형에 따라 메인,라디오,이벤트,시스템의 4가지 개별 로그 버퍼를 제공한다. 

아래 그림은 Logger를 지원하는 로그 이벤트 및 구성 요소의 흐름을 보여준다. 

[그림3-21] Logger 시스템 흐름

보통 main버퍼에 가장 많은 양의 log가 저장되며, 저장되는 데이터는 응용 프로그램 관련 이벤트의 소스들이다.  
애플리케이션은 일반적으로 'android.util.Log'클래스에서 메소드를 호출한다. 
여기서 호출된 메소드는 로그 항목 우선 순위 레벨에 해당한다. 
(예: 'informational'의 Log.i메소드, 'debug'의 Log.d메소드, 'error'의 Log.e메소드) 

system버퍼는 시스템 프로세스에 의해 생성된 시스템 전체 이벤트에 대한 많은 정보의 소스이기도 하다. 

이러한 프로세스는 'android.util.Slog'클래스의 println_native메소드를 사용한다. 
이 메소드는 차례로 특정 버퍼에 로깅하는 고유 코드를 호출한다. 
main버퍼와 system 버퍼가 기본 소스인 logcat명령을 사용하면 로그 메시지를 검색할 수 있다. 
다음 그림에서는 'adb -d logcat'을 실행하여 연결된 디바이스에서 발생하는 상황을 확인하는 모습이다. 

[그림3-22] adb -d logcat 실행

위와 같이 logcat명령을 다양하게 활용하여 프로세스와 전체 시스템 상태를 모니터할 수 있다. 

> Paranoid Networking 
Android 커널은 호출 프로세스의 보조 그룹 멤버쉽(Paranoid Networking으로 알려진 커널 수정 버전)을 기반으로 

네트워크 작동을 제한한다. 

High-Level에서는 AID와 GID를 응용 프로그램 수준의 권한 선언과 요청에 맵핑하는 것과 관련이 있다. 
예를 들어, 'android.permission.INTERNET' 매니페스트 권한은 'AID_INET' AID 또는 GID '3003'에 맵핑된다. 
이러한 그룹과 ID, 해당 기능에 대한 정의는 커널 소스 트리 '/include/linux/android_aid.h'에 정의되어 있으며,

다음 그림에 설명되어 있다. 

[그림3-23] Paranoid Networking 권한 그룹

'/system/core/include/private/android_filesystem_config.h'의 AOSP 소스 저장소에서 추가 Android 특정 그룹ID를 찾을 수 있다.


4. 복잡한 보안 시스템에 따른 Exploit 난이도 상승

Andorid 운영체제 개발자는 Android의 디자인과 아키텍처를 위한 매우 복잡한 시스템을 만들었다. 

Android는 최소한의 특권 원칙을 고수하도록 디자인 되었는데,

디자인 컨셉은 '어떤 특정 구성 요소라도 절대적으로 필요한 것들에만 접근할 수 있어야 한다'고 명시되어 있다. 
이러한 디자인은 보안을 향상 시키는 역할을 하지만 그만큼 복잡성을 증가시킨다. 
이 책 전체에서 이러한 원칙이 실제로 어떻게 사용되는지 확인 할 수 있다. 

프로세스 격리 및 권한 축소는 보안 시스템 설계에서 초석이 되는 기술이다. 
이러한 기술의 복잡성으로 인해 개발자와 공격자 모두에게 큰 벽으로 다가간다. 
공격자는 Exploit Code를 작성할 때, 이러한 복잡성을 완전히 이해하기 위해 시간을 할애해야 하고, 하나의 취약점을 

악용하는 것만으로는 시스템을 완벽히 장악할 수 없다. 
따라서, 공격자는 목표를 달성하기 위해 하나가 아닌 여러 개의 취약점을 이용하여 Exploit Code를 작성해야 하고 

그만큼 높은 난이도로 다가갈 것이다. 
이에 대한 실제 사례는 'diaggetroot Exploit'이 있는데, 해당 Exploit은 root권한을 얻기 위해 여러 취약점을 활용했다. 
해당 Exploitd에 대해서는 3장에서 자세히 설명하도록 한다.

 


Summary 

이 장에서는 Android의 보안 설계 및 아키텍처에 대한 개요를 설명했다. 
Android의 샌드박스와 권한 모델에 대해 소개하였고, Android의 특수한 Unix UID/GID맵핑(AID)구현과 시스템 전체에 

적용되는 제한 및 기능이 그 내용이다. 

그리고 애플리케이션, Android 프레임 워크, DalvikVM, User영역의 Native Code, Linux커널을 포함하여 Android의 

논리적 계층을 다루었고, 각 계층에 대한 주요 구성요소 중 특히 보안 관련 구성요소를 중점적으로 다뤘다. 

또한, Android개발자들이 리눅스 커널에 적용한 중요한 추가사항과 수정사항을 강조하였다. 
Android의 전체 디자인에 대한 High-Level의 적용 범위는 나머지 챕터를 진행하는데 도움이 될 것이며, 해당 챕터에서 다뤘던 구성요소와 레이어에 대해 더 자세히 알아볼 수 있을 것이다. 

다음 장에서는 Android기기를 완전히 제어하는 방법과 이유에 대해 설명하고, 특정 취약성을 이용한 과거의 기법과 

일반적으로 사용하는 기법에 대해서도 설명하도록 하겠다.