[안드로이드 모의해킹] apk파일 코드패치와 무결성 검사

직접 연구하여 작성한 자료입니다. 공식 출처가 명시되지 않은 자료의 무단 복제, 사용을 금지합니다.
공격 기법은 학습용, 허가된 환경에서 실습 바랍니다. 실 운영망 대상 공격은 처벌받습니다. (정보통신망법 제48조 1항)

1. 개요

안드로이드 설치파일(apk)이 무결성검증을 하지 않는다면 악성코드가 앱을 변조하거나 침해하는 등의 위협이 발생할 수 있다.

일반적으로 안드로이드 앱은 Google Play 스토어를 통해서 배포되거나 개발자가 제공하는 공식 웹페이지에서 다운로드 받을 수 있다. 하지만 공식 채널이 아닌 방법으로 앱을 다운로드하는 경우 무결성 검증이 이루어지지 않을 수 있다. 이 경우 해커가 악성코드를 포함하고 있는 앱을 배포하여 사용자의 단말기에 악성코드를 설치하게 할 수 있다.

악성코드가 앱을 변조하는 경우에는, 사용자의 민감한 정보를 탈취하거나, 앱이 수행하는 기능을 조작하여 악의적인 행동을 할 수 있다. 또는 루팅(rooting)이나 권한상승 등을 통해서 다른 앱의 데이터나 서비스에 접근할 수 있다.

따라서 안드로이드 설치파일의 무결성 검증을 실시해야 하며, 사용자는 공식적인 채널을 통해 앱을 다운로드하거나 신뢰할 수 있는 출처에서만 앱을 설치해야 한다.

이번 포스트에서는 직접 APK파일을 디컴파일하고 코드패치하여 앱의 무결성 검증 여부를 판단한다.

2. 전체 과정(Overview)

코드패치는 다음의 과정으로 진행된다. 실행파일(apk)이 준비되고 코드가 수정된파일이 단말기에 설치될 때까지의 과정이다.

Code Patch 전체 과정

  1. 디컴파일 : 앱의 소스코드, 리소스 등을 분석하기 위한 과정이다.
  2. 디컴파일된 코드 수정 : 디컴파일된 코드를 수정한다. 수정할 코드를 찾고, 변경해야 하는 부분을 수정한다.
  3. 수정된 코드를 컴파일 : 디컴파일된 코드를 수정한 후, 컴파일러를 이용해 다시 바이트 코드로 컴파일한다. 이 때, 반드시 수정한 코드만 컴파일하도록 주의한다. 불필요한 코드를 포함하면 앱의 크기가 증가하고 실행 속도가 느려진다.
  4. apk 파일 생성 : 컴파일된 코드를 apk 파일로 패키징한다.
  5. 서명(Signing) : apk 파일에 서명을 추가한다. 서명은 apk 파일의 무결성을 검증하고, 앱의 신원을 보장하는 역할을 한다. 서명하지 않으면 Android 시스템에서 앱을 실행할 수 없다.
    취약점이 제 3자에 의한 변조앱 배포로 인해 발생하는 경우이기 때문에 진단자가 서명용 key를 생성한 후 서명한다.
  6. 변조한 앱 설치 및 실행확인

3. 디컴파일

안드로이드 앱파일(.apk)의 디컴파일 과정은 다음과 같다.

  1. apk 파일을 압축해제하여 안드로이드 매니페스트 파일, 리소스 파일, dex 파일 등을 추출한다.
  2. dex 파일을 다시 디컴파일(도구: jadx, jd-gui)하여 Java 코드를 추출한다.
  3. 추출한 Java 코드를 분석하여 앱의 기능, 로직, 알고리즘 등을 분석한다.

앱 파일의 디컴파일 과정을 통해 앱의 소스코드, 리소스 등을 분석할 수 있으므로, 악성 코드를 삽입하거나 민감한 정보를 탈취할 수 있는 보안 취약점을 찾을 수 있다.

4. dex & dalvik byte code

dex 파일은 안드로이드 앱의 실행 파일로, Dalvik 가상 머신에서 실행된다. dex 파일은 Java 클래스 파일을 Dalvik 가상 머신에서 실행하기 위한 형태로 변환된 바이트 코드이다.

dex 파일을 디컴파일하면 smali 코드를 얻을 수 있다. smali 코드는 Dalvik 바이트 코드를 인간이 이해하기 쉬운 형태로 변환한 것이다. smali 코드는 쉽게 이해할 수 있도록 사람이 읽기 편한 형태의 언어로 작성되어 있다. 예를 들어, Java 코드와 smali 코드를 비교하면 다음과 같다.

[JAVA 코드]

public int add(int a, int b) {
    return a + b;
}

[smali 코드]

.method public add(II)I
    .registers 3
    .param p1, "a"    # I
    .param p2, "b"    # I
    .prologue
    add-int v0, p1, p2
    return v0
.end method

 

반면에 Dalvik 바이트 코드는 기계가 실행하기 쉬운 형태의 코드이다. Dalvik 바이트 코드는 dex 파일의 실제 실행 코드입니다. dex 파일이 Dalvik 바이트 코드를 포함하고 있으며, 이 코드가 Dalvik 가상 머신에서 실행된다.

따라서, dex 파일의 디컴파일을 통해 얻어지는 smali 코드는 Java 코드와 비슷한 구조를 가지며, Dalvik 바이트 코드는 기계가 실행하기 쉬운 형태의 코드이다.

다시 정리하면, smali코드는 인간이 분석하기 쉬운 코드 / Dalvik 바이트 코드는 기계가 실행하기 쉬운 코드이다.

5. 코드 패치(Code Patch)

코드패치는 인증로직 우회, 루팅 탐지 우회 등 여러 부분에 적용이 가능하기 때문에 여러 앱들을 분석하면서 컴파일 해보면 된다. 소개할 예제는 무결성 취약점 항목 진단 시 쉽게 적용할 수 있는 "toast message" 코드를 삽입하는 방법을 다룬다.

디컴파일 후 JAVA파일과 smali 파일의 파일 구조는 같기 때문에 AndroidManifest.xml 파일에서 분석한 MainActivity가 포함된 smali 파일을 분석한다.

앞선 포스트([안드로이드 모의해킹] Activity Lifecycle 분석)에서 다룬대로 Activity 생명주기를 가지고 있으며 각각 여러 콜백 함수(onStart(), onResume(), onPause(), onStop(), onCreate() 등)를 통해 관리된다. 해당 Activity의 생명주기들은 smali 코드에서도 확인할 수 있다. 다음 코드는 onCreate()의 smali 코드 예제를 보여준다.

.method protected onCreate(Landroid/os/Bundle;)V
    .registers 2
    .param p1, "savedInstanceState"    # Landroid/os/Bundle;

    .prologue
    const/4 v0, 0x1

    invoke-super {p0, p1}, Landroid/support/v7/app/AppCompatActivity;->onCreate(Landroid/os/Bundle;)V

    # 이하 생략

위 smali 코드에서, onCreate() 함수는 .method으로 시작하며, 파라미터로 Bundle 객체를 받는다. 이어서, invoke-super를 통해 AppcompatActivity 클래스의 onCreate() 함수를 호출한다. 진단 시에는 모든 메소드 하나하나를 자세하게 분석할 필요는 없지만 중요 로직에 대해서는 정확하게 분석할 수 있으면 된다.

5.1. Toast Message smali code 삽입

Toast Message Smali Code

Toast Message를 사용하는 이유는 인자를 하나만 받아서 실행하는 메소드면서, 앱 실행 시 동작 변화를 간단하게 살펴볼 수 있기 때문에 사용하였다. 코드 패치 후 앱 실행 시 Toast Message가 나타나는지 확인하면 된다.

smali 코드는 위에서 부터 한 줄(line)씩 실행되므로 onCreate() 콜백 함수의 시작 부분에 아래의 코드를 삽입하면 된다.

 

const/4 v0, 0x1

const-string v1, "Integrity Check"

invoke-static {p0, v1, v0}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;

move-result-object v0

invoke-virtual {v0}, Landroid/widget/Toast;->show()V

APK Studio로 편집한 경우 꼭 저장(Ctrl+S) 후에 다시 컴파일 해주도록 한다.

6. 컴파일(Compile)

수정이 완료된 코드를 포함하여 컴파일, 리패키징한다.

apktool d C:\Android\CodePatch\app-release.apk

apktool b C:\Android\CodePatch\[리패키징 파일 경로] -o [리패키징 후 앱이름].apk

리패키징 후 결과파일(.apk)을 설치하면 설치가 되지 않는다. 서명이 되지 않았기 때문이다.

7. 앱 서명(Signing)

서명되지 않은 앱은 안드로이드 시스템에 설치될 수 없다. 서명은 apk의 무결성을 검증하고 앱의 신원을 보장하는 역할을 한다.

다음 포스트([안드로이드] UberSigner로 apk 서명하기)에서 UberSigner를 이용하여 패치한 앱을 직접 서명할 수 있다.

참고
취약점 진단의 관점에서 안드로이드 개발자가 앱 출시에 사용하는 서명 키와 해커가 앱을 리패키징할 때 사용하는 서명 키는 목적이 다르다.

안드로이드 개발자가 앱 출시에 사용하는 서명 키는 공식적으로 발급받은 서명 키로써, 해당 앱이 개발자에 의해 만들어졌음을 인증하는 역할을 한다. 이 서명 키는 개발자의 개인키로 생성된다. 개발자는 이 서명 키를 사용하여 앱을 서명하여 Google Play 스토어와 같은 앱 스토어에 출시할 수 있다. 이 서명키는 개발자가 지정한 패키지 이름과 일치하는지 검증하는 데 사용된다.

반면에 해커가 앱을 리패키징할 때 사용하는 서명 키는 악성 코드를 포함한 앱을 생성하는 데 사용된다. 해커는 앱을 분석하여 보안 취약점을 찾은 후 이를 이용하여 앱에 악성 코드를 삽입한다. 이후, 해커는 리패키징된 앱을 다시 서명하여 원래 앱과 같은 이름으로 앱 스토어에 업로드하거나 다른 경로로 배포한다. 이때, 해커가 사용하는 서명 키는 원래 앱의 서명 키와 다른 서명 키이다. 앱을 사용하는 사용자는 변조된 앱을 정상앱인 것처럼 사용하게 되며, 악성코드가 사용자 몰래 실행될 수 있다.

8. 취약점 진단 기준 및 보안대책

위의 방법으로 패치된 앱을 실행했을 때 (양호)무결성 검증 로직이 동작하여 경고 메시지를 띄우거나 바로 앱을 종료하는 경우 무결성 검증을 하고 있다고 판단할 수 있다. (취약)무결성 검증이 없는 경우, 변조하거나 삽입한 코드가 그대로 실행되는 경우 취약으로 진단할 수 있다.

보안대책으로는 코드 패치가 불가능하도록 코드 난독화, 암호화를 적용하는 방법이 있고 서명 키를 확인하는 방법, APK파일의 해쉬 또는 중요 로직의 해쉬값을 검사하는 방법이 있다.

9. 참고&출처

 

 

반응형