http://blog.csdn.net/lifeshow/article/details/32914081
Android平台的动态调试一直以来是个困扰我等Coder的头疼问题,特别是对于本地的动态调试支持,可以说是“弱智”级别的,不知道Google的新版NDK和新出的Android Studio对这块支持如何,让我们拭目以待。
言归正传,我这里采用的是cygwin+ndk-gdb的调试模式,灵感来自于XDA的一篇博文(点击打开链接),平台和原文作者不同:
1、Win7 64
2、NDK r9d x86_64
3、Android 4.2.2
4、cygwin 64
5、IDA pro 6.1
话不多话,开始正题,调试步骤如下:
1、环境搭建这类的各位可以自行Google之,这里就不多说了。
2、首先我们随便找个网站,下载游戏的APK包。Android的APK包的正式发布版本是取消了debug属性的,在调试之前,我们还需要做些准备工作。
3、用apktool解包apk文件,然后修改AndroidManifest.xml,在重新打包,再用signapk签名。
4、为ndk-gdb调试做准备工作,这个上面那篇博文已经写得很详细,这里不再赘述。说明一点:我们调试的目标是.\libs\armeabi\libgame.so,这个so是游戏主库文件。
准备好后的目录结构大致如下:
5、好了,准备工作完毕,开始我们的调试之旅!
首先,安装我们重新打包的apk到手机,然后进入cygwin shell,进入本地的游戏解包后的目录。这里要重点说明一点:由于一些兼容性问题,我们不能直接使用google原来的ndk-gdb调试脚本,需要做一些修改:
我这里直接给DATA_DIR赋值为app目录:/data/data/com.umonistudio.tile。这步骤很重要,否则你会遇到run-as之类的错误,导致无法继续调试!
好了,终于准备完毕了,切换到cygwin shell,开始调试,如果没有问题的话,就会顺利进入gdb提示符,我的输出如下:
- $ ndk-gdb --verbose --start --nowait
- Android NDK installation path: /cygdrive/e/Tools/android-ndk-r9d-windows-x86_64/ android-ndk-r9d
- Using default adb command: /cygdrive/e/Tools/adt-bundle-windows-x86_64-20131030/ adt-bundle-windows-x86_64-20131030/sdk/platform-tools/adb
- ADB version found: Android Debug Bridge version 1.0.31
- Using ADB flags:
- Using JDB command: /cygdrive/e/Tools/Java/jdk1.7.0_15/bin/jdb
- Using auto-detected project path: .
- Found package name: com.umonistudio.tile
- ABIs targetted by application: armeabi
- Device API Level: 17
- Device CPU ABIs: armeabi-v7a armeabi
- Compatible device ABI: armeabi
- Using gdb setup init: ./libs/armeabi/gdb.setup
- Using toolchain prefix: /cygdrive/e/Tools/android-ndk-r9d-windows-x86_64/android-ndk-r9
- Using app out directory: ./obj/local/armeabi
- Found debuggable flag: true
- Found data directory: '/data/data/com.umonistudio.tile'
- Found device gdbserver: /data/data/com.umonistudio.tile/lib/gdbserver
- Found first launchable activity: .tile
- Launching activity: com.umonistudio.tile/.tile
- ## COMMAND: adb_cmd shell am start -n com.umonistudio.tile/.tile
- Starting: Intent { cmp=com.umonistudio.tile/.tile }
- ## COMMAND: adb_cmd shell sleep 2
- Found running PID: 8706
- Launched gdbserver succesfully.
- Setup network redirection
- ## COMMAND: adb_cmd shell run-as com.umonistudio.tile /data/data/com.umonistudio .tile/lib/gdbserver +debug-socket --attach 8706
- ## COMMAND: adb_cmd forward tcp:5039 localfilesystem:/data/data/com.umonistudio. tile/debug-socket
- Attached; pid = 8706
- Listening on Unix socket debug-socket
- ## COMMAND: adb_cmd pull /system/bin/app_process obj/local/armeabi/app_process
- 2384 KB/s (21980 bytes in 0.009s)
- Pulled app_process from device/emulator.
- ## COMMAND: adb_cmd pull /system/bin/linker obj/local/armeabi/linker
- 3246 KB/s (63176 bytes in 0.019s)
- Pulled linker from device/emulator.
- ## COMMAND: adb_cmd pull /system/lib/libc.so obj/local/armeabi/libc.so
- 4186 KB/s (424460 bytes in 0.099s)
- Pulled libc.so from device/emulator.
- GNU gdb (GDB) 7.3.1-gg2
- Copyright (C) 2011 Free Software Foundation, Inc.
- License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
- This is free software: you are free to change and redistribute it.
- There is NO WARRANTY, to the extent permitted by law. Type "show copying"
- and "show warranty" for details.
- This GDB was configured as "--host=x86_64-pc-mingw32msvc --target=arm-linux-android".
- For bug reporting instructions, please see:
- <http://source.android.com/source/report-bugs.html>.
- Warning: E:\works\apktools\biecaibaikuaier_an_debug_sign/system/core/include/cutils: No such file or directory.
- Remote debugging from host 0.0.0.0
- 0x400f44b8 in epoll_wait () from E:/works/apktools/biecaibaikuaier_an_debug_sign/obj/local/armeabi/libc.so
- warning: Could not load shared library symbols for 108 libraries, e.g. libstdc++.so.
- Use the "info sharedlibrary" command to see the complete listing.
- Do you need "set solib-search-path" or "set sysroot"?
- warning: Breakpoint address adjusted from 0x400b4ab7 to 0x400b4ab6.
- (gdb)
这里需要说明一点,我输入的调试命令:ndk-gdb --verbose --start --nowait,加了一个nowait参数:如果不加nowait会在libgame.so这个目标so加载前,gdb就断下来,导致我们无法调试目标库。
好了,我们在gdb命令号输入:
- (gdb) info shared
- From To Syms Read Shared Object Library
- 0x400b2280 0x400bb418 Yes (*) E:/works/apktools/biecaibaikuaie r_an_debug_sign/obj/local/armeabi/linker
- 0x400df830 0x4012e294 Yes (*) E:/works/apktools/biecaibaikuaie r_an_debug_sign/obj/local/armeabi/libc.so
- No libstdc++.so
- No libm.so
- No liblog.so
- No libcutils.so
- No libgccdemangle.so
- No libcorkscrew.so
- No libz.so
- No libutils.so
- No libbinder.so
- No libemoji.so
- No libjpeg.so
- No libexpat.so
- No libm4u.so
- No libstlport.so
- No libnetutils.so
- No libbwc.so
- No libhardware.so
- No libsync.so
- No libui.so
- No libGLES_trace.so
- No libEGL.so
- No libGLESv2.so
- No libion.so
- No libdpframework_os.so
- No libdpframework_plat.so
- No libdpframework.so
- No libgui.so
- No libcamera_client.so
- No libcam.utils.so
- No libaed.so
- No libcameracustom.so
- No libcam_camera_exif.so
- No libnativehelper.so
- No libmatv_cust.so
- No libcamdrv.so
- No libimageio.so
- No libcam.campipe.so
- No libGdmaScalerPipe.so
- No libSwJpgCodec.so
- No libvcodec_oal.so
- No libsched.so
- No libvcodec_utility.so
- No libmp4enc_xa.ca7.so
- No libvcodecdrv.so
- No libJpgDecPipe.so
- No libmhalImageCodec.so
- No libalmkdrv.so
- No libskia.so
- No libtinyxml.so
- No libandroidfw.so
- No libgabi++.so
- No libicuuc.so
- No libicui18n.so
- No libsqlite.so
- No libdvm.so
- No libGLESv1_CM.so
- No libETC1.so
- No libwpa_client.so
- No libhardware_legacy.so
- No libsonivox.so
- No libcrypto.so
- No libssl.so
- No libstagefright_foundation.so
- No libspeexresampler.so
- No libaudioutils.so
- No libmedia_native.so
- No libmedia.so
- No libusbhost.so
- No libharfbuzz.so
- No libhwui.so
- No libmtkbtextadpa2dp.so
- No libextjsr82.so
- No libandroid_runtime.so
- No libjavacore.so
- No libdrmframework.so
- No libdrmmtkwhitelist.so
- No libdrmmtkutil.so
- No libdrmframework_jni.so
- No libstagefright_memutil.so
- No libstagefright_omx.so
- No libstagefright_yuv.so
- No libvorbisidec.so
- No libstagefright_enc_common.so
- No libstagefright_avc_common.so
- No libstagefright.so
- No libmtp.so
- No libexif.so
- No libstagefright_amrnb_common.so
- No libmtk_drvb.so
- No libamr_wrap.so
- No libmedia_jni.so
- No libbcinfo.so
- No libbcc.so
- No libRS.so
- No librs_jni.so
- No libandroid.so
- No libchromium_net.so
- No libwebcore.so
- 0x5dd4a500 0x5dfb591c Yes (*) E:/works/apktools/biecaibaikuaie r_an_debug_sign/obj/local/armeabi/libgame.so
- No libsoundpool.so
- No libsrv_um.so
- No libIMGegl.so
- No libEGL_mtk.so
- No libusc.so
- No libGLESv1_CM_mtk.so
- No libGLESv2_mtk.so
- No libpvrANDROID_WSEGL.so
- No libpvr2d.so
- No gralloc.mt6589.so
- (*): Shared library is missing debugging information.
可以看到我们的目标库已经成功加载,地址0x5dd5a500---0x5dfb591c,终于可以开始愉快的玩耍了
这里我们打开IDA,查看libgame.so的反汇编,找到GameOver::initscore(int,bool)这个函数:
先说明下这个函数的作用:在游戏结束后,显示当前局的分数!我们看下其函数名导出为:_ZN8GameOver9initScoreEib。好了,我们在GDB输入:
- (gdb) br _ZN8GameOver9initScoreEib
- Breakpoint 1 at 0x5dd4c612
- (gdb) info b
- Num Type Disp Enb Address What
- 1 breakpoint keep y 0x5dd4c612 <GameOver::initScore(int, bool)+26>
- (gdb) disas 0x5dd4c612,+20
- Dump of assembler code from 0x5dd4c612 to 0x5dd4c626:
- 0x5dd4c612 <_ZN8GameOver9initScoreEib+26>: cmp r1, #0
- 0x5dd4c614 <_ZN8GameOver9initScoreEib+28>: beq.n 0x5dd4c61a <_ZN8GameOver9initScoreEib+34>
- 0x5dd4c616 <_ZN8GameOver9initScoreEib+30>: ldr r3, [pc, #284] ; (0x5dd4c734 <_ZN8GameOver9initScoreEib+316>)
- 0x5dd4c618 <_ZN8GameOver9initScoreEib+32>: str r3, [sp, #4]
- 0x5dd4c61a <_ZN8GameOver9initScoreEib+34>: adds r4, r5, #0
- 0x5dd4c61c <_ZN8GameOver9initScoreEib+36>: adds r4, #252 ; 0xfc
- 0x5dd4c61e <_ZN8GameOver9initScoreEib+38>: bl 0x5dde73d4 <_ZN7cocos2d13CCUserDefault17sharedUserDefaultEv>
- 0x5dd4c622 <_ZN8GameOver9initScoreEib+42>: ldr r2, [r4, #32]
- 0x5dd4c624 <_ZN8GameOver9initScoreEib+44>: ldr r3, [pc, #272] ; (0x5dd4c738 <_ZN8GameOver9initScoreEib+320>)
- End of assembler dump.
- (gdb)
对照IDA反汇编,可以看到是断在了函数的内部,当然我们可以调整断点到函数入口,这里主要是为了演示,就不做调整。
好了,断点下好了,我们开始游戏,选择“街机”模式开始游戏,然后点几下,再随便点个白块儿让游戏结束。
看看gdb的输出窗口:
- (gdb) c
- Continuing.
- [New Thread 8720]
- [Switching to Thread 8720]
- Breakpoint 1, 0x5dd4c612 in GameOver::initScore(int, bool) () from E:/works/apktools/biecaibaikuaier_an_debug_sign/obj/local/armeabi/libgame.so
- (gdb) info registers
- r0 0x65cf59f8 1708087800
- r1 0x0 0
- r2 0x6e0aeb37 1846209335
- r3 0x4013d1f4 1075040756
- r4 0x65cf5af4 1708088052
- r5 0x65cf59f8 1708087800
- r6 0x7 7
- r7 0x5dde3b2d 1574845229
- r8 0x5e1c2c70 1578904688
- r9 0x5e0c2f3c 1577856828
- r10 0x5cdd5a88 1558010504
- r11 0x5e1c2c84 1578904708
- r12 0x5e088afc 1577618172
- sp 0x5e1c2af8 0x5e1c2af8
- lr 0x5dd4ca0f 1574226447
- pc 0x5dd4c612 0x5dd4c612 <GameOver::initScore(int, bool)+26>
- cpsr 0x30 48
- (gdb)set $r6=99999
YES,成功断下!输入info registers查看当前寄存器状态,注意查看r6寄存器,值为0x7(我刚才点了7个黑块儿)。我们开始个好玩的东西,gdb输入:set $r6=99999,然后让游戏继续,看看有什么 !!!
总结一下:
这里主要是演示了下Android平台下,对于无源码的第三方动态库的汇编级调试过程(不针对任何游戏,不用于任何商业目的),目前google官方的调试工具对native调试支持不好,希望后面google能对这块给力些。上面所涉及的内容只用于技术交流之用处,不用于任何商业目的。