Skip to content

Instantly share code, notes, and snippets.

@chitacan
Last active September 4, 2018 08:13
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save chitacan/11200703 to your computer and use it in GitHub Desktop.
Save chitacan/11200703 to your computer and use it in GitHub Desktop.
AOSP 4.4_r1 의 네이티브 코드를 gdb 로 디버깅 해보자!!

hack aosp with gdb

AOSP 4.4_r1 의 네이티브 코드를 gdb 로 디버깅 해보자!!

  • 안드로이드 어플리케이션을 실행할 때 사용되는 네이티브 코드(libbinder등) 은 어떻게 디버깅 할 수 있을까?
  • 안드로이드 단말이나 에뮬레이터의 /system/bin/ 아래에 있는 바이너리들(service, am, pm 등등) 어떻게 디버깅할 수 있을까?

준비물

  • 단말이나 에뮬레이터를 타겟으로 잘(!?) 빌드된 AOSP
  • AOSP 로 빌드된 소스가 포팅된 단말이나, 에뮬레이터

첫 시도

칸드로이드 슬로우부트 님의 문서 9 페이지부터 참고해서 진행했다.

우선 단말이나 에뮬레이터에서 gdbserver 를 실행하고 디버깅 하고자 하는 네이티브 코드를 담고 있는 pid를 인자로 전달.

$ gdbserver :5039 --attach <pid_of_process>

호스트 pc 에서 adb forward 를 통해 호스트의 5039 포트가 단말의 5039로 전달되도록 설정하고 arm-eabi-gdb 를 실행하였다. 이때 디버그 심볼의 경로를 명시.

$ adb forward tcp:5039 tcp:5039
$ cd android/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin
$ ./arm-eabi-gdb ~/workspace/android-4.4_r1/out/target/product/generic/symbols/system/lib/<symbol>

gdb 가 시작되면 패스를 설정하고 target 을 설정한다.

(gdb) set solib-absolute-prefix ~/workspace/android-4.4_r1/out/target/product/generic/symbols
(gdb) set solib-search-path ~/workspace/android-4.4_r1/out/target/product/generic/symbols/system/lib/
(gdb) target remote :5039
(gdb) c

하지만, 마지막에 c (continue) 실행이후 심볼을 찾지 못했다는 메시지와 함께 더이상 진행되지 않았다. 이게 성공한다고 하더라도, 매번 gdb 를 연결할 때마다, 이렇게 경로를 명시해야 된다면 😱

gdbclient 활용

환경

  • ubuntu 12.04, AOSP 4.4_r1
  • aosp_arm-eng 타겟으로 빌드 완료

aosp-env 참고!!

gdbclient 연결하기

build/envsetup.shgdbclient명령어가 있다. 이 명령어를 활용하면 앞서 설정했던 경로나 gdb 바이너리를 선택하는 과정을 스크립트를 통해 자동화 시켜준다.

gdbclient 는 언제부터 작성된 거지? build/envsetup.shblame 해보니 꽤 오래전부터 존재했다는 것을 알 수 있다.

gdbclient 를 사용하기 위해서는 build/envsetup 을 로드하고, 빌드 타겟까지 lunch 를 통해 지정되어 있어야 한다. 빌드 타겟설정시 선언되는 경로가 gdbclient 에서 사용하기 때문이다.

$ . build/envsteup.sh
$ lunch 

gdbclient 를 시작하기 전 단말이나 에뮬레이터에서 gdbserver 를 시작해야 한다. 시작할때 이미 실행된 프로세스에 gdbserver 를 붙이기 위해서는 --attach 옵션을 통해 pid를 전달하자.

$ gdbserver :5039 --attach <pid_of_process>

$ adb forward --list
$ adb forward tcp:5039 tcp:5039
$ gdbclient

gdbclient 명령어를 살펴보면 필요한 설정들이 다 있다. 전달된 인자에 따라서 adb forward 설정이나, adb shell gdbserver 실행까지 다해준다. 그리고 gdbclient.cmds 를 열어 필요한 경로 설정도 다해준다. gdbclient 는 실행할 때 기본값으로 app_process 심볼을 가져온다.

시스템 서비스 도구 디버깅!!

adb shell 로 쉘에 진입했을 때, 시스템 서비스를 컨트롤 할 수 있는 도구들(am, pm, wm 등등)을 gdb 로 디버깅할 수 있다. 이 도구들의 코드는 frameworks/base/cmds 또는 frameworks/native/cmds 에서 찾을 수 있다.

이 도구들의 코드는 시스템 서비스를 만들거나 해킹하고자 할때 좋은 출발점이 될 것 같다.

$ adb shell
> gdbserver localhost:5039 service list

$ adb forward tcp:5039 tcp:5039
$ gdbclient service

gdbclient 에 인자(service)를 주지 않으면 app_process 를 디버깅하도록 설정되니 주의하자. 이건 build/envsetup.sh 에서 찾을 수 있다.

service list 는 현재 안드로이드 운영체제에서 실행되고 있는 시스템 서비스의 리스트를 출력하는 명령어이다.

gdb 가 실행되면, service 바이너리의 main 함수에 브레이크 포인트를 걸고 c (continue)명령을 입력하면 frameworks/native/cmds/service/service.cppmain 함수에서 멈추는 것을 알 수 있다. 이제 n(next) 를 입력해가면서 이 소스를 한줄한줄 디버깅할 수 있다.

(gdb) b main
(gdb) c
reakpoint 1, main (argc=2, argv=0xbeecfaf4)
at frameworks/native/cmds/service/service.cpp:70
70      {
(gdb) l
(gdb) n

진행되는 과정을 영상으로 확인하고 싶다면 여기로!!

브라우저의 영문 폰트가 고정폭 폰트로 설정되어 있어야 잘 보입니다 😄

app_process

신기한건, 앞선 예제에서 service 를 인자로 주지않고, gdbclient 를 실행하면 libbinder 에 포함된 코드도 디버깅이 된다는거. 왜 그런 것일까?

app_process 를 컴파일 하면서 libbinder.so 가 링크되기 때문. 이 내용은 frameworks/base/cmds/app_process/Android.mk 에 보면 shared library 형태로 libbinder 를 사용하는 것을 확인할 수 있다.

참고

  • http://www.unknownroad.com/rtfm/gdbtut/gdbtoc.html 여기에 꼭 필요한 내용만 잘 정리되어 있다.
  • lunch 를 실행하면 path에 android/prebuilt/linux-x86/toolchain/arm-eabi-*/bin 가 추가되어 arm-eabi-gdb, arm-eabi-gdbtui 를 사용할 수 있게된다. arm-eabi-gdbtui 는 화면을 나눠 위쪽엔 코드가, 아래쪽엔 gdb 명령창이 나온다.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment