Android Device를 이용한 동적 디버깅

스마트폰 2013. 4. 26. 04:23 Posted by TEAMCR@K

본 문서는 Android APK 파일을 Device에서 동적 디버깅 방법에 대해 작성 하였습니다.

안드로이드 기반 동적 디버깅 환경 구축(emulator): http://teamcrak.tistory.com/342

 

테스트 환경은 아래와 같습니다.

  • OS: Window 7
  • Java version: jdk6
  • APKTools: 1.4.1
  • NetBeans IDE: 7.3
  • APK Sign tool
  • Galaxy S2

APKTool 1.4.1 버전 사용 이슈

APK Tool 1.4.1 이상 버전부터 디버그모드(-d) 일 때 java파일이 생성되지 않아 동적 디버깅을 할 수 없다고 합니다.

http://i5on9i.blogspot.kr/2012/10/smali-apk-debugger.html

 

우선 APKTool 1.4.1 다운로드 합니다.

APKTool 1.4.1: https://android-apktool.googlecode.com/files/apktool1.4.1.tar.bz2

기존 APKTool을 사용하고 있었다면 다음경로의 파일을 삭제해야 에러가 발생하지 않습니다.

C:\Users\<USER_NAME>\apktool\framework\1.apk

다운로드 후 디버깅옵션으로 smali code를 생성합니다.

apktool.bat d –d <file>.apk

[그림1] APKTool 을 이용한 smali code 생성

 

AndroidManifest.xml 파일에서 아래 항목을 추가해줍니다.

Android:debuggable="true" //디버깅 허용

-------------------------------------------------------------------------------------------------------

<intent -filter="-filter">

<action android:name="android.intent.action.MAIN">

// 테스크의 첫 액티비티로 액티비티를 시작한다.

<category android:name="android.intent.category.LAUNCHER">

//액티비티가 어플리케이션의 런처에 표시되고 테스크의 첫 액티비티가 될 수 있다.

</intent>

 

[그림2] AndroidManifest.xml 패치

 

추가 및 패치하기 전 DDMS 화면을 보면 attach 할 수 있는 프로세스가 없습니다.

[그림3] attach 프로세스 유무 확인

 

다시 apktool로 패키징 후 코드사인 합니다.

[그림4] 패치후 리패키징

 

패치 된 APK 설치 전 디바이스에서 환경설정 > 개발자 옵션 > USB디버깅 체크해줍니다.

[그림5] USB 디버깅 모드

 

어플리케이션 설치 후 연결된 디바이스에서 attach 할 수 있는 프로세스를 확인할 수 있습니다.

[그림6] 접근 가능한 프로세스 확인

 

NetBeans 7.3 버전들 다운로드 후 설치합니다.

NetBeans Download: https://netbeans.org/downloads/

NetBeans 설정은 다음과 같이 진행합니다.

[그림7] 새 프로젝트 작성

 

[그림8] 프로젝트 위치 지정

 

APKTool 1.4.1 로 디코딩 한 smali 경로를 설정해 줍니다.

[그림9] smali code 위치 설정

 

[그림10] API Level에 맞춰 라이브러리를 설정

 

[그림11] API Level에 맞춰 라이브러리 추가

 

[그림12] 테스트로 작성된 어플리케이션 실행

 

Debug > Attach Debugger 를 선택합니다.

[그림13] Attach Debugger

 

[그림14] 호스트, 포트 입력

 

Attach 에 성공하면 형광색 아이콘이 생겨 디바이스에서 디버깅을 시작할 수 있습니다.

[그림15] 디버깅 시작

 

지금까지 디버깅 환경 설정을 살펴보았습니다.

이제부터 실제로 디버깅을 시작하기 위해 어플리케이션 실행 시부터 디버깅 할 수 있는 방법에 대해 알아보겠습니다.

디버깅을 어플리케이션이 시작과 동시에 하기 위해서 smali code에서 onCreate 메소드 호출 시 'invoke-static {}, Landroid/os/Debug;->waitForDebugger()V' 를 삽입해 줍니다.

[그림16] 디버깅 대기를 위한 코드패치

 

코드 패치 + 리패키징 + 코드사인 후 어플리케이션을 설치합니다.

어플리케이션을 실행하게 되면 DDMS 에서 붉은색 아이콘이 생성되며 attach 전까지 대기하게 됩니다.

[그림17] 디버깅 대기

 

[그림18] 디버깅 전 화면

 

NETBeans에서 attach 하기 전 ctrl+shift+F8 단축키를 눌러 bp를 설정합니다.

[그림19] break point 설정

 

Attach 시 debugging wait 에서 벗어나 호출된 함수에서 break point 가 걸리게 됩니다.

[그림20] break point 지점 확인

 

[그림21] 라인별로 smali code, java code를 보며 디버깅을 시작

 

[그림22] 어플리케이션 시작

 

버튼 이벤트 발생 시 break point를 설정하여 디버깅 할 수 있습니다.

Ctrl+shift+F8 단축키를 이용하여 break point 지점을 설정합니다.

[그림23] 버튼 이벤트 메소드 확인

 

[그림24] 버튼 이벤트 동작

 

[그림25] 동작 지점 확인

 

[그림26] 디버깅 메뉴를 이용하여 분석

 

이상으로 디바이스에서 APK 동적 디버깅 환경을 살펴 보았습니다.

 

마지막으로 APK 동적 디버깅 순서 정리하면 아래와 같습니다.

  1. APKTool을 이용한 디코딩 (Apktool d –d <file>.apk)
  2. Device 설정(USB디버깅 모드) 및AndroidManifest.xml 수정
  3. MainActivity에 debugging wait 함수 추가
  4. 어플리케이션 리패키징 및 코드사인 후 설치
  5. NETBeans설정 후 호출되는 Method break point 설정
  6. Attach Debug 후 디버깅을 시작

 

 

참고자료

http://d-kovalenko.blogspot.kr/2012/08/breakpoints-in-smali-code.html

http://d-kovalenko.blogspot.kr/2012/08/debugging-smali-code-with-apk-tool-and.html

http://dztall.blogspot.kr/2011/01/blog-post.html

http://i5on9i.blogspot.kr/2012/10/smali-apk-debugger.html

http://code.google.com/p/android-apktool/issues/detail?id=339

 



본 문서는 안드로이드(Android) 기반에서의 APK 동적 디버깅 기법에 대해 작성하였습니다. 해당 내용은 아래와 같이 2개의 주제로 나눠 연재하겠습니다.

 

1. '안드로이드 기반 동적 디버깅 환경 구축'
2. '안드로이드 APP Code Patch 기법'



안드로이드 동적 디버깅 환경 구축


1. 디버깅 환경
Android 동적 디버깅 환경에서 필요한 Tool은 APKTools와 Netbeans IDE, Android개발환경, APK Sign환경이 구축되어 있어야 합니다. APKTools를 이용하여 APK파일을 디버그 모드로 디코딩 하면 Class단위로 java파일이 생성되며 java파일안에는 smali코드가 주석처리 되어 있습니다.
Netbeans는 IDE중 주석문에도 breakpoint를 설정할 수 있기 때문에 동적 디버깅 시 이용하며, APK Sign환경은 APK 수정 후 배포 전에 사인할 때 사용합니다.

동적 디버깅 시 필요한 Tool들의 역할입니다.



2.동적 디버깅 절차
동적 디버깅 절차는 다음과 같습니다.
1.    APK Tools를 이용하여 디버깅 모드로 덤프 (-d 옵션사용)
2.    APK Tools를 이용하여 디버깅 모드로 덤프한 것을 디버깅모드로 다시 패키징 (동적 디버깅을 위함)
3.    디버깅 모드로 패키징 한 APK파일을 sign하여 AVD에 실행
4.    Netbeans를 이용하여 1번에서 덤프했던 코드를 프로젝트 추가
5.    DDMS를 이용하여 대상 APP에 대한 포트를 열어줌.
6.    Netbeans 메뉴에서 Debug -> Attach Debugger -> Select JPDA 를 통해 host와 port를 설정하여 원격 디버깅 연결
7.    분석할 부분에 bp설정
8.    에뮬레이터에서 이벤트를 줘서 bp설정부분의 라인이 실행하게 유도
9.    Line by Line으로 동적 디버깅 시작

APK Tools를 이용하여 디버그모드로 APK파일을 디코딩 합니다. 디코딩 후 파일을 확인해 보면 확장자는 .java 이지만 파일의 내용에는 smali코드가 주석으로 처리 되어 있는 것을 확인 할 수 있습니다.

                                                             [그림 1] 디버그 모드로 디코딩



out폴더에 결과 파일들이 생성된 것을 확인 할 수 있으며, java파일이 생성되었지만 함수 몸체는 smali 코드로 구성되어 있는 것을 확인 할 수 있습니다.

                                                                       [그림 2] 디코딩 결과


동적 디버깅을 위하여 디코딩 된 파일을 다시 디버깅 모드로 패키징 합니다.

                                                              [그림 3] 디버깅 모드로 패키징


패키징 결과 out폴더 및에 dist라는 폴더가 생성되며 그 안에 새로운 APK파일이 생성된 것을 확인 할 수 있습니다.

                                                                 [그림 4] 패키징 결과



디버깅 모드로 패키징 된 APK파일을 설치하고 실행하기 위하여 APK Sign Tool을 이용하여 사인합니다.

                                                                      [그림 5] 사인하기


사인이 완료되어 새로운 파일이 생성된 것을 확인 할 수 있습니다.

                                                                        [그림 6] 사인 결과


사인이 완료 되면 AVD에 설치 후 실행합니다.

                                                                        [그림 7] AVD에 설치(Install)


설치 후 실행하여 제대로 설치 되었는지 확인합니다.

                                                                [그림 8] AVD설치 확인


디버그 모드로 디코딩 된 파일을 Netbeans에서 프로젝트로 추가합니다. 프로젝트에 추가 할 시에는 메뉴아이콘에서 두 번째 위치한 버튼을 이용하여 프로젝트를 추가합니다. [New Project] -> [java] -> [Java Project with Existing Source]를 선택하여 Next를 클릭합니다.

                                                      [그림 9] New Project 선택


다음은 덤프 했었던 경로를 설정하여 Next를 클릭합니다.

                                                  [그림 10] 프로젝트 경로 설정


프로젝트 경로를 설정한 후 코드가 있는 경로를 설정하여 코드를 프로젝트에 추가합니다.
 

                                                   [그림 11] 소스코드 추가


프로젝트 추가 후 Android의 버전에 맞게 android.jar파일을 추가해 주어야 합니다. Android.jar파일은 Android관련 API를 호출 할 때 참조되는 Library이므로 꼭 추가가 필요합니다. 추가 시 실행하였던 AVD의 버전에 맞추어 추가를 합니다.
 

                                                     [그림 12] Library 추가

                                                  [그림 13] android.jar추가



android.jar와 코드를 프로젝트에 추가하였으니 제대로 추가되었는지 확인합니다.

                                                                 [그림 14] 프로젝트 확인


DDMS에서 현재 동작하고 있는 APP중 방금 디버그 모드로 패킹되어 설치된 APP를 선택하여 열린 PORT번호를 확인합니다. 화면에서는 8700번이 open되 있는 것을 확인 할 수 있습니다.

                                                     [그림 15] 디버깅 대상 원격 포트확인


포트가 확인 되었으면 Netbeans에서 원격 디버깅을 위한 세팅을 합니다.

                                                   [그림 16] Attach Debbuger 메뉴 선택

                                                   [그림 17] JPDA선택


디버거 선택 후 host와 port정보를 설정해야 합니다. local에서 디버깅을 할 것이기 때문에 host에는 127.0.0.1, port에는 앞에서 확인한 8700으로 설정합니다.

                                                         [그림 18] 원격 디버깅 환경 설정


원격 디버깅을 위한 설정이 끝나면 디버깅관련 기능을 사용할 수 있습니다. 원격 디버깅을 위한 연결이 맺어 졌는 지 확인합니다. DDMS에서는 버그 모양이 앞에 표시 되며, Netbeans에서는 대상 프로그램을 pause시킬 수 있으므로 이 기능을 이용하여 연결이 정상적인지 확인 가능합니다.

                                                 [그림 19] DDMS에서 디버깅연결 확인


디버깅을 위한 연결이 맺어 졌기 때문에 bp설정을 하여 분석을 시작 할 수 있습니다. 다른 IDE같은 경우 주석문에 bp설정을 할 수 없지만 Netbeans에서는 Alt + Shift + F8번을 이용하여 line break point를 이용하여 bp 설정이 가능합니다.
원격 디버깅으로 중간에 디버거에 Attach 되었기 때문에 처음부터 프로그램의 분석이 필요하다면 bp를 첫 부분에 설정한 후 프로그램을 다시 시작하여 처음 부분부터 분석이 가능합니다.


                                               [그림 20] break point 설정


                                                               [그림 21] break point 설정

이렇게 디버거 연결이 완료 됩니다.

이제 안드로이드 에물레이터에서 실행을 하면서 각 단계마다 변하는 값들을 조작할 수 있으며, 이 내용은 "제 2부 안드로이드 APP Code Patch" 를 통해 알아가도록 하겠습니다.

참고 자료
[1] http://code.google.com/p/android-apktool/wiki/SmaliDebugging
[2] http://www.youtube.com/watch?v=P_Zyf7jFbx4
[3] http://code.google.com/p/android-apktool/issues/detail?id=88&colspec=ID Stars Type Status Priority Milestone Owner Summary
[4] http://pastebin.com/ge39wRZS