原文 :https://lichao890427.github.io/wiki/android%20reverse%20engineering/php
Android程序的特色相比在於使用混淆方式打包,將包名、類名、函數名改爲不易看懂的字母,從而使生成的apk小不少(android studio提供了release編譯方式,使用proguard混淆),所以反編譯apk最多的工做在於重構這些名稱,這一點和pc上一致,對於android native程序(jni)則和pc上基本一致,不一樣之處在於常見的是arm彙編。html
對於apk的反編譯,因爲資源和xml都進行了編碼,所以反編譯時必然要解析相應的resource.arsc/AndroidManifest.xml等文件,對於作過保護處理的apk一般會在這裏作手腳干擾Apktool、dex2jar等反編譯工具所以頗有必要掌握編譯、調試這些工具源碼的方法(見「如何編譯、調試apktool和dex2jar」)java
輕量級反編譯,反編譯jar/class等java字節碼文件(能力通常),提供簡單的搜索能力python
dex2jar是一個工具包,反編譯dex和jar,還提供了一些其它的功能,每一個功能使用一個bat批處理或 sh 腳原本包裝,只需在Windows 系統中調用 bat文件、在Linux 系統中調用 sh 腳本便可。在bat中調用相應的jar主類完成特定功能,例如d2j-dex2jar.bat中的內容是:@"%~dp0d2j_invoke.bat" com.googlecode.dex2jar.tools.Dex2jarCmd %*
。經常使用的有dex2jar jar2dex dex2smali smali2dex
linux
Android package,android安裝程序文件,本質上是壓縮包,解壓獲得classes.dex、resources.arsc、AndroidManifest.xml、so文件以及資源文件android
aapt d xmltree 1.apk AndroidManifest.xml
N: android=http://schemas.android.com/apk/res/android
E: manifest (line=2)
A: android:versionCode(0x0101021b)=(type 0x10)0x1
A: android:versionName(0x0101021c)="1.0" (Raw: "1.0")
A: package="com.ibotpeaches.issue767" (Raw: "com.ibotpeaches.issue767")
A: platformBuildVersionCode=(type 0x10)0x17 (Raw: "23")
A: platformBuildVersionName="6.0-2438415" (Raw: "6.0-2438415")
E: uses-sdk (line=0)
A: android:minSdkVersion(0x0101020c)=(type 0x10)0x16
A: android:targetSdkVersion(0x01010270)=(type 0x10)0x17
E: application (line=3)
A: android:theme(0x01010000)=@0x7f090083
A: android:label(0x01010001)=@0x7f060015
A: android:icon(0x01010002)=@0x7f030000
A: android:debuggable(0x0101000f)=(type 0x12)0xffffffff
A: android:allowBackup(0x01010280)=(type 0x12)0xffffffff
A: android:supportsRtl(0x010103af)=(type 0x12)0xffffffff
E: activity (line=4)
A: android:theme(0x01010000)=@0x7f090030
A: android:label(0x01010001)=@0x7f060015
A: android:name(0x01010003)="com.ibotpeaches.issue767.MainActivity" (Raw
: "com.ibotpeaches.issue767.MainActivity")
E: intent-filter (line=5)
E: action (line=6)
A: android:name(0x01010003)="android.intent.action.MAIN" (Raw: "andr
oid.intent.action.MAIN")
E: category (line=7)
A: android:name(0x01010003)="android.intent.category.LAUNCHER" (Raw:
"android.intent.category.LAUNCHER")
E: meta-data (line=10)
A: android:name(0x01010003)="large.int.value" (Raw: "large.int.value")
A: android:value(0x01010024)="9999999999999999999999" (Raw: "99999999999
99999999999")
查看xml => aapt d xmltree 1.apk AndroidManifest.xml
查看resource => aapt d resources 1.apk (resource.arsc)ios
Dalvik Executable,Dalvik可執行文件,從java class文件轉換而來的字節碼,Classes.Dex經過dex2jar轉換成java字節碼(有損),或者dex2smali轉換成darvik彙編(無損)——smali字節碼,其形式以下 c++
Java Archive,java歸檔文件,能夠直接解壓獲得class文件git
dex轉odex:/system/bin/dexopt
dexopt-wrapper 1.apk 1.odexgithub
Android歸檔文件,壓縮包格式,包含
Linux動態連接庫文件,包含arm64 arm mips mips64 x86 x86-64幾個平臺
設備通訊、調試工具,經常使用法:
adb devices 列出當前設備
adb –s d24eb3ab [命令] 指定設備執行命令
adb push 源 目標 非root機器能夠設置路徑爲/data/local/tmp
adb pull 源 目標
adb shell 執行終端
adb logcat 查看日誌(/system/logcat爲服務器)
adb jdwp 查看遠程jdwp進程
adb forward tcp:主機端口 tcp:遠程端口 把主機端口消息轉發手機端口(端口對應進程) 用於ida調試
adb forward tcp:主機端口 jdwp:遠程進程ID 把主機端口消息轉發手機jdwp進程 用於jdb調試
adb install [apkpath] 安裝apk
adb uninstall [packagename] 卸載apk 注意會完全清理,刪除/data/app下的備份apk
adb remount 將/system從新映射爲讀寫,以便進行系統區文件操做
adb root 使adb以root方式啓動,便於push/pull/remount
APK資源管理工具,用於增刪查改APK中的文件、資源等,對於分析編譯後的Resource.arsc, AndroidManifest.xml格式較有價值,一般也能夠用winrar對apk/jar進行解壓
打印xml樹 aapt d xmltree 1.apk AndroidManifest.xml
打印資源 aapt d resources 1.apk
添加文件 aapt a 1.apk AndroidManifest.xml
刪除文件 aapt r 1.apk AndroidManifest.xml
Android遠程命令,am執行調試、運行功能,pm執行安裝、卸載功能
am start -D -n "b.myapp/b.myapp.MainActivity" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER
am startservice -n com.android.music/com.android.music.MediaPlaybackService
am force-stop com.example.administrator.myapplication
am kill com.example.administrator.myapplication
am kill all
adb shell am broadcast -a com.android.test
pm install –r 1.apk
pm uninstall packagename
pm list package
pm list package com.qihoo
pm disable packagename
(禁用後,圖標消失,對該應用的操做都無效)在android studio中能夠採用運行調試或進程附加方式調試,支持條件斷點、一次斷點、對單線程下斷,有6種斷點:
TypeCh | TypEn | Description |
---|---|---|
行斷點 | Java Line Breakpoints | 在(java/c)源碼某行下斷 |
Java類成員變量訪問斷點 | Java Field Watchpoints | 相似於內存訪問斷點,在讀和寫java類成員變量時斷下 |
Java類方法斷點 | Java Method Breakpoints | 在進入java層函數或退出函數時斷下 |
Java異常斷點 | Java Exception Breakpoints | 發生java層捕獲或未捕獲異常時斷下 |
異常斷點 | Exception Breakpoints | 拋異常或捕獲異常時斷下 |
符號斷點 | Symbolic Breakpoints | (c/java)符號斷點 |
應用市場有不少這種軟件,須要Root權限。解決沒有USB數據線的狀況下的調試
C:\Users\Administrator>adb connect 192.168.0.103:5555
connected to 192.168.0.103:5555
此時能夠用adt調試
不須要調試的通常過程 :使用反編譯工具獲得源代碼,修改調試標識,修改機器碼,最後回編譯簽名:
反編譯apk:apktool d file.apk –o path
回編譯apk:apktool b path –o file.apk
java -jar apktool.jar d -d input.apk -o out
,加上-d選項以後反編譯出的文件後綴爲.java,而不是.smali,每一個.java文件立馬都僞形成了一個類,語句全都是「a=0;」這一句,smali語句成爲註釋,作這些都是爲了後面欺騙idea、eclipse、android studio這些ide的apktool b –d path –o input.apk
java –jar signapk.jar testkey.x509.pem testkey.pk8 input.apk output.apk
點評:這種方式只能夠用來分析加密很弱的App,前提是apktool能夠成功反編譯
jdb是一個支持java代碼級調試的工具,它是由java jdk提供的,能夠設置斷點、查看堆棧、計算表達式、動態修改類字節碼、調試&跟蹤、修改變量值、線程操做,斷點包括:(源碼)行斷點、符號斷點、成員變量訪問斷點。每一個java程序(windows/ios/android)均可以用jdwp協議進行調試,Android Studio/Eclipse的調試也是創建在該協議基礎之上,下面以實例說明:
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); findViewById(R.id.ok).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.b.com")); intent.setClassName("com.android.browser","com.android.browser.BrowserActivity"); startActivity(intent); } }); } }
adb shell am start -D -n "b.myapp/b.myapp.MainActivity" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER
<1> main[1] where
[1] android.app.Activity.startActivity (Activity.java:3,490)
[2] b.myapp.MainActivity$1.onClick (MainActivity.java:21)
[3] android.view.View.performClick (View.java:4,084)
[4] android.view.View$PerformClick.run (View.java:16,966)
[5] android.os.Handler.handleCallback (Handler.java:615)
[6] android.os.Handler.dispatchMessage (Handler.java:92)
[7] android.os.Looper.loop (Looper.java:137)
[8] android.app.ActivityThread.main (ActivityThread.java:4,745)
[9] java.lang.reflect.Method.invokeNative (本機方法)
<1> main[1] print intent
intent = "Intent { act=android.intent.action.VIEW dat=http://www.b.com cmp=
com.android.browser/.BrowserActivity }"
<1> main[1] use D:\Android\sdk\sources\android-18 //參考設備android版本
<1> main[1] use D:\test\MyApplication\app\src\main\java
<1> main[1] list
3,421 * @hide Implement to provide correct calling token.
3,422 */
3,423 public void startActivityAsUser(Intent intent, UserHandle user) {
3,424 startActivityAsUser(intent, null, user);
3,425 => }
3,426
3,427 /**
3,428 * @hide Implement to provide correct calling token.
3,429 */
3,430 public void startActivityAsUser(Intent intent, Bundle options, User
Handle user) {
> use D:\test\MyApplication\app\src\main\java
stop at b.myapp.MainActivity:18
正在延遲斷點b.myapp.MainActivity:18。
將在加載類後設置。
> resume
已恢復全部線程。
> 設置延遲的斷點b.myapp.MainActivity:18
斷點命中: "線程=<1> main", b.myapp.MainActivity.onCreate(), 行=18 bci=12
18 int j = 0;
只要鏈接到jdb就會致使app運行起來,此時若是想斷在初始化這部分就沒有辦法了,不過jdb提供初始命令腳本
echo suspend > jdb.ini
jdb -connect com.sun.jdi.SocketAttach:hostname=127.0.0.1,port=8601
此時,app仍然處於等調試器狀態,而蟲子已經變綠,此時能夠下斷點,而後resume恢復全部線程 附加後會變綠色蟲子
> > stop in b.myapp.MainActivity.onCreate(android.os.Bundle)
正在延遲斷點b.myapp.MainActivity.onCreate(android.os.Bundle)。
將在加載類後設置。
>resume
已恢復全部線程。
斷點命中: "線程=<1> main", b.myapp.MainActivity.onCreate(), 行=13 bci=0
<1> main[1] where
[1] b.myapp.MainActivity.onCreate (MainActivity.java:13)
[2] android.app.Activity.performCreate (Activity.java:5,372)
[3] android.app.Instrumentation.callActivityOnCreate (Instrumentation.java:1,1
04)
[4] android.app.ActivityThread.performLaunchActivity (ActivityThread.java:2,25
8)
[5] android.app.ActivityThread.handleLaunchActivity (ActivityThread.java:2,350
)
[6] android.app.ActivityThread.access$700 (ActivityThread.java:160)
[7] android.app.ActivityThread$H.handleMessage (ActivityThread.java:1,317)
[8] android.os.Handler.dispatchMessage (Handler.java:99)
[9] android.os.Looper.loop (Looper.java:137)
[10] android.app.ActivityThread.main (ActivityThread.java:5,454)
stop in:斷點
step:步入(源碼行)
stepi:單入(指令)
step up:執行到返回
cont:恢復運行
next:步過
輸出表達式:print/eval
jdb最大缺點在於難用,因此有人用python封裝了一次,工具名AndBug
Usage: gdbserver [OPTIONS] COMM PROG [ARGS ...]
gdbserver [OPTIONS] --attach COMM PID
gdbserver [OPTIONS] --multi COMM
隱藏用法:gdbserver [OPTIONS] +SOCKETFILE --attach PID 會在本地創建socket文件通訊
Options:
--debug Enable general debugging output.
--remote-debug Enable remote protocol debugging output.
--version Display version information and exit.
--wrapper WRAPPER -- Run WRAPPER to start new programs.
--once Exit after the first connection has closed.
使用方式:
啓動模式遠程調試:gdbserver --debug --remote-debug :23946 /system/test.out [參數]
附加模式遠程:gdbserver –debug –remote-debug –attach :23946 1234
Adb forward tcp:23946 tcp:23946 轉發端口
IDA中選擇Remote GDB Debugger附加便可
usage: strace [-CdDffhiqrtttTvVxx] [-a column] [-e expr] ... [-o file]
[-p pid] ... [-s strsize] [-u username] [-E var=val] ...
[command [arg ...]]
or: strace -c [-D] [-e expr] ... [-O overhead] [-S sortby] [-E var=val] ...
[command [arg ...]]
-c --統計每一系統調用的所執行的時間,次數和出錯的次數等.
-C -- like -c but also print regular output while processes are running
-f --跟蹤由fork調用所產生的子進程.
-F --嘗試跟蹤vfork調用.在-f時,vfork不被跟蹤.
-i --輸出系統調用的入口指針
-q --禁止輸出關於脫離的消息
-r --打印出相對時間關於,,每個系統調用
-T --顯示每一調用所耗的時間
-v --輸出全部的系統調用.一些調用關於環境變量,狀態,輸入輸出等調用因爲使用頻繁,默認不輸出
-x --以十六進制形式輸出非標準字符串
-a設置返回值的輸出位置.默認 爲40.
-e expr -指定一個表達式,用來控制如何跟蹤.: option=[!]all or option=[!]val1[,val2]...
options: trace, abbrev, verbose, raw, signal, read, or write
-o file --將strace的輸出寫入文件filename
-O overhead -- set overhead for tracing syscalls to OVERHEAD usecs
-p pid --跟蹤指定的進程pid.
-D -- run tracer process as a detached grandchild, not as parent
-s strsize --指定輸出的字符串的最大長度.默認爲32.文件名一直所有輸出
-S sortby -- sort syscall counts by: time, calls, name, nothing (default time)
-u username --以username 的UID和GID執行被跟蹤的命令
-E var=val -- put var=val in the environment for command
-E var -- remove var from the environment for command
使用方式:
Strace –f ProcessA 啓動跟蹤
Strace –f –p 234 附加跟蹤
-e trace=file -e trace=process -e trace=network
該程序是一個shell腳本,執行過程以下:
adb shell am start -D -n com.example.hellojni/.HelloJni 啓動app並等待調試器
ps | grep hellojni 獲得PID 3569
adb shell run-as com.example.hellojni /data/data/com.example.hellojni/lib/gdbserver +debug-socket --attach (3569)PID
將PID與文件映射創建調試連接(c層)
adb forward tcp:5039 localfilesystem:/data/data/com.example.hellojni/debug-socket將調試連接和本地端口創建連接(c層)
adb forward tcp:65534 jdwp:(3569)PID 將本地端口和進程創建鏈接(java層)
jdb -connect com.sun.jdi.SocketAttach:hostname=localhost,port=65534 使用jdb調試java層
arm-linux-androideabi-gdb.exe
target remote :5039 使用gdb調試c層
set breakpoint pending on
(使用前關掉騰訊的AndroidServer.exe,不然連不上!!!),在工程目錄下(有AndroidManifest.xml),命令行運行%NDK_ROOT%\ndk-gdb-py.cmd --start --verbose
,輸出下面字符即爲成功:
Android NDK installation path: D:/Android/AndroidNDK/android-ndk-r10e
ADB version found: Android Debug Bridge version 1.0.32
Using ADB flags:
Using auto-detected project path: .
Found package name: com.example.hellojni
ABIs targetted by application: arm64-v8a armeabi armeabi-v7a armeabi-v7a-hard mips mips64 x86 x86_64
Device API Level: 19
Device CPU ABIs: armeabi-v7a armeabi
Compatible device ABI: armeabi-v7a
Using gdb setup init: ./libs/armeabi-v7a/gdb.setup
Using toolchain prefix: D:/Android/AndroidNDK/android-ndk-r10e/toolchains/arm-linux-androideabi-4.8/prebuilt/windows/bin/arm-linux-androideabi
Using app out directory: ./obj/local/armeabi-v7a
Found debuggable flag: true
Found device gdbserver: /data/data/com.example.hellojni/lib/gdbserver
Found data directory: '/data/data/com.example.hellojni'
Found first launchable activity: .HelloJni
Launching activity: com.example.hellojni/.HelloJni
## COMMAND: adb_cmd shell am start -D -n com.example.hellojni/.HelloJni
## COMMAND: adb_cmd shell sleep 2.000000
Found running PID: 9139
## COMMAND: adb_cmd shell run-as com.example.hellojni /data/data/com.example.hellojni/lib/gdbserver --attach +debug-socket 9139 [BACKGROUND]
Launched gdbserver succesfully.
Setup network redirection
## COMMAND: adb_cmd forward tcp:5039 localfilesystem:/data/data/com.example.hellojni/debug-socket
Attached; pid = 9139
Listening on Unix socket debug-socket
## COMMAND: adb_cmd pull /system/bin/app_process ./obj/local/armeabi-v7a/app_process
79 KB/s (9488 bytes in 0.117s)
Pulled app_process from device/emulator.
## COMMAND: adb_cmd pull /system/bin/linker ./obj/local/armeabi-v7a/linker
585 KB/s (63596 bytes in 0.106s)
Pulled linker from device/emulator.
## COMMAND: adb_cmd pull /system/lib/libc.so ./obj/local/armeabi-v7a/libc.so
1184 KB/s (310584 bytes in 0.256s)
Pulled /system/lib/libc.so from device/emulator.
Set up JDB connection, using jdb command: C:\Program Files\Java\jdk1.8.0_66\bin\jdb.exe
## COMMAND: adb_cmd forward tcp:65534 jdwp:9139
--------------------./obj/local/armeabi-v7a/gdb.setup---------------
GNU gdb (GDB) 7.7
Copyright (C) 2014 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=i586-pc-mingw32msvc --target=arm-linux-android".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://source.android.com/source/report-bugs.html>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word".
Remote debugging from host 9.11.5.0
warning: Could not load shared library symbols for 112 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"?
0x400daa80 in __futex_syscall3 () from D:\Android\AndroidNDK\android-ndk-r10e\samples\hello-jni\obj\local\armeabi-v7a\libc.so
(gdb)
點評:該工具要求環境極爲苛刻且不穩定,不建議使用
操做步驟:
gdbserver --attach *:111 1234
adb forward tcp:111 tcp:111
target remote 127.0.0.1:111
(gdb) set solib-search-path C:/Users/lichao/2/
Reading symbols from C:\Users\lichao\2\linker...(no debugging symbols found)...done.
Loaded symbols for C:\Users\lichao\2\linker
Reading symbols from C:\Users\lichao\2\libc.so...(no debugging symbols found)...done.
Loaded symbols for C:\Users\lichao\2\libc.so
Reading symbols from C:\Users\lichao\2\libstdc++.so...(no debugging symbols found)...done.
Loaded symbols for C:\Users\lichao\2\libstdc++.so
Reading symbols from C:\Users\lichao\2\libm.so...(no debugging symbols found)...done.
Loaded symbols for C:\Users\lichao\2\libm.so
Reading symbols from C:\Users\lichao\2\liblog.so...(no debugging symbols found)...done.
Loaded symbols for C:\Users\lichao\2\liblog.so
Reading symbols from C:\Users\lichao\2\libcutils.so...(no debugging symbols found)...done.
Loaded symbols for C:\Users\lichao\2\libcutils.so
Reading symbols from C:\Users\lichao\2\libgccdemangle.so...(no debugging symbols found)...done.
Loaded symbols for C:\Users\lichao\2\libgccdemangle.so
Reading symbols from C:\Users\lichao\2\libcorkscrew.so...(no debugging symbols found)...done.
(gdb) bt
#0 0x400e50e0 in fork () from C:\Users\lichao\2\libc.so
#1 0x76886ca0 in Java_com_example_hellojni_HelloJni_stringFromJNI () from C:\Users\lichao\2\libhello-jni.so
#2 0x416b8350 in dvmPlatformInvoke () from C:\Users\lichao\2\libdvm.so
#3 0x416e8fd2 in dvmCallJNIMethod(unsigned int const*, JValue*, Method const*, Thread*) () from C:\Users\lichao\2\libdvm.so
#4 0x416ea9ba in dvmResolveNativeMethod(unsigned int const*, JValue*, Method const*, Thread*) () from C:\Users\lichao\2\libdvm.so
#5 0x416c1828 in dvmJitToInterpNoChain () from C:\Users\lichao\2\libdvm.so
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
(gdb) list
adb push gdb /data/bin
adb shell
./data/bin/gdb
GNU gdb 6.7
Copyright (C) 2007 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=arm-none-linux-gnueabi --target=".
(gdb)
點評:該方法速度快,但很差查看符號
adb push android_server /data/local/tmp/
cd /data/local/tmp/
chmod 755 android_server
./android_server
adb forward tcp:23946 tcp:23946
Remote ARMLinux/Android debugger
,端口23946,調試便可,成功之後顯示Accepting connection from 127.0.0.1...
./gdbserver –attach :1234 [pid]
adb forward tcp:1234 tcp:1234
arm-linux-androideabi-gdb.exe
target remote :1234
set step-mode on
set disassemble-next on
catch load 1.so
0xb6cdf480 in __epoll_pwait () from E:\aaa\libc.so
=> 0xb6cdf480 <__epoll_pwait+28>: 1e ff 2f 91 bxls lr
(gdb) bt
#0 0xb6cdf480 in __epoll_pwait () from E:\aaa\libc.so
#1 0xb6cb70ca in epoll_pwait () from E:\aaa\libc.so
#2 0xb6cb70d8 in epoll_wait () from E:\aaa\libc.so
#3 0xb6f06bd6 in android::Looper::pollInner(int) () from E:\aaa\libutils.so
#4 0xb6f06e52 in android::Looper::pollOnce(int, int*, int*, void**) () from E:\aaa\libutils.so
#5 0xb6e4d41c in android::NativeMessageQueue::pollOnce(_JNIEnv*, _jobject*, int) () from E:\aaa\libandroid_runtime.so
#6 0x732e056e in ?? ()
GikDbg 是一款移動平臺的彙編級調試器,它基於 OllyDbg ,GDB 以及 LLVM 實現而來。OllyDbg 現已普遍用於 PC 平臺軟件安全領域,GikDbg 是 OllyDbg 向移動平臺轉移的產物,它能夠協助您完成諸如應用調試分析,應用安全評估,應用漏洞挖掘等移動安全領域。What features can GikDbg support? http://gikir.com/product.php
GikDbg for IOS
GikDbg for Android
gikdbg.art-Gikir Debugger for Android RunTime, 是Android平臺的32位彙編級調試器。此處的Android RunTime既指DVM RunTime又指ART RunTime,所以無論是運行dalvik虛擬機仍是運行本地代碼的art都可以使用gikdbg.art進行程序的二進制調試分析。不一樣之處在於dalvik虛擬機的運行時只能調試so動態庫,而art運行時不只能調試so動態庫,還能調試系統鏡像oat,可執行程序dex這樣的文件。另外,gikdbg-Gikir Debugger for iPhone OS,是調試越獄蘋果設備的32位彙編級調試器,同窗們莫搞混淆了哈,它須要一些複雜點的服務端和客戶端的配置,而gikdbg.art在正常狀況下是不須要手工配置的,因此別去找android server了。對於靜態分析,能夠執行/ART Debug/View/ELF Data…,/ART Debug/View/ELF Code…兩個菜單打開本地so,oat,dex文件。
Step 0.前置說明
手機端:Android模擬器,Android 4.4.2 ART 運行時;(真機與DVM運行時是同樣的)
PC端:ParallelDesktop虛擬機,Windows 8.0,gikdbg.art v1.0.build140601.3;
PS:非root環境的設備因爲權限的緣由會有不少問題,不推薦使用!
Step 1.鏈接設備
運行模擬器,打開gikdbg.art.exe,執行/ART Debug/Device菜單,咱們就能夠來到以下界面:
若是模擬器已經運行了,可是設備列表中沒有,則等待一段時間後執行右鍵的Refresh菜單。而後雙擊或者右鍵Login就能夠登錄選中的設備了。對於第一次Login該設備,會詢問你是否上傳依賴的文件到/data/local,這一步若是否認了的話將不能使用調試功能。上傳文件這個步驟目前已知的問題是對於非root的設備,每每由於權限的緣由上傳不成功,通常狀況下/data/local/tmp目錄沒有問題,可是有些設備又沒有/data/local/tmp目錄,所以咱們只有設置/data/local爲目標路徑,這個問題目前還不知道好的解決辦法。概括一下就是:非root的機器沒法在其/data/local下建立咱們依賴的文件夾以及上傳文件,若是咱們將其遷移至/data/local/tmp這個目錄下,又有部分設備沒有這個文件夾,就更沒有辦法上傳了。
對於這類上傳失敗的同窗,能夠想辦法手工將$(GIKDBG.ART)/adb/android/gdb傳至/data/local/gikir_android-xxxx/gdb這個位置,其中xxxx是GUID。
若是尚未安裝該apk文件的,則能夠在ADB Shell中執行$install –r命令選擇gikdebugee.apk進行安裝.
Step 2.選擇進程
登錄成功後執行,確保模擬器的gikdebugee.apk運行正常,而後執行/ART Debug/File/Attach就能夠獲得以下進程列表,選中咱們的gikdebugee進程,雙擊或者執行Attach按鈕
以後咱們就會看到以下加載輸出:
等gdb加載完畢以後咱們就能夠進入熟悉的CPU主窗口了:
Step 3.選擇模塊
咱們的目的是調試apk裏面的so動態庫,所以執行/ART Debug/View/Module切換到模塊列表,選中咱們要調試的模塊,雙擊它
Step 4.擊中斷點
本例中找到要調試的函數getNativeString,咱們能夠用CTRL+F查找到它,找到以後F2下斷點,F9運行它,而後在設備中操做按鈕則該方法將被斷點擊中,F8運行3步
adb push %NDK%\prebuilt\android-arm\gdbserver\gdbserver /system/bin
chmod 777 /system/bin/gdbserver
adb push test.out /system/bin
chmod 777 /system/bin/test.out
gdbserver :2345 /system/bin/test.out(若附加調試則提供進程號)
adb forward tcp:2345 tcp:2345
gdb >
gdb > target remote :2345
用ida分析so,並在JNI_OnLoad下斷點,動態附加後,ida會自動rebase,使用gdb 的catch load命令捕獲
參照前幾節
adb shell am start -D -n com.example.hellojni/.HelloJni 啓動app並等待調試器
ps | grep hellojni 獲得PID 3569
adb shell run-as com.example.hellojni /data/data/com.example.hellojni/lib/gdbserver +debug-socket --attach (3569)PID
將PID與文件映射創建調試連接(c層)
adb forward tcp:5039 localfilesystem:/data/data/com.example.hellojni/debug-socket將調試連接和本地端口創建連接(c層)
adb forward tcp:65534 jdwp:(3569)PID 將本地端口和進程創建鏈接(java層)
jdb -connect com.sun.jdi.SocketAttach:hostname=localhost,port=65534 使用jdb調試java層
arm-linux-androideabi-gdb.exe
target remote :5039 使用gdb調試c層
set breakpoint pending on
am start -D -n com.example.hellojni/.HelloJni
gdbserver --attach :1234 10863
adb forward tcp:1234 tcp:1234
arm-linux-androideabi-gdb Target remote :1234
root@ja3gchnduos:/ # am start -D -n com.example.hellojni/.HelloJni
Starting: Intent { cmp=com.example.hellojni/.HelloJni }
root@ja3gchnduos:/ # ps | grep hello
u0_a165 10863 3593 869292 16088 ffffffff 40077a08 S com.example.hellojni
root@ja3gchnduos:/ # gdbserver --attach :1234 10863
Attached; pid = 10863
Listening on port 1234
set solib-search-path c:/1
catch load libhello-jni.so
Catchpoint 1
Inferior loaded C:\Users\lichao\sumsing\libhello-jni.so
0x40036b8c in rtld_db_dlactivity () from C:\Users\lichao\sumsing\linker
Android底層爲linux層,gdb用於調試linux應用層,而kgdb用於調試linux內核層
kgdb的android版本下載:http://github.com/dankex/kgdb-android
經常使用Hook框架:
360手機衛士在非root狀況下卸載後彈出瀏覽器。因而有2種常見可能,一種是intent跳轉,一種是執行am命令,後者能夠在java層和jni層實現,若是是java層考慮進行hook,jni層考慮修改am.jar
將/system/bin/am更名,發現沒法彈窗,因而肯定是經過第二種方式實現,爲了肯定調用層級,嘗試修改(反編譯成smali->加入logcat輸出打印回溯棧和接收參數->回編譯)/system/framework/am.jar,(能夠經過本身再另外一個app中實現一樣的功能,經過反編譯獲得smali代碼)再次反編譯後內容以下:
public static void main(String[] args) {
String v0 = "";
int v3 = args.length;
int v2;
for(v2 = 0; v2 < v3; ++v2) {
v0 = String.valueOf(v0) + " " + args[v2];
}
Log.d("my god", v0);
Log.d("my god", Log.getStackTraceString(new Throwable()));
}
在卸載瞬間拿到輸出:
start -n com.android.browser/.BrowserActivity -a android.intent.action.VIEW -d http://shouji.360.cn/web/uninstall/uninstall.html?u=100&id=76bb84de8f53b53f57dd3cedfe966091&v=6.3.1.1048&s=1&model=SE0gTk9URSAxTFRF&sdk=19&ch=200222&wid=9fa298f35aec4232c26048442f36dc59 --user 0
java.lang.Throwable
at com.android.commands.am.Am.main(Am.java:30)
at com.android.internal.os.RuntimeInit.nativeFinishInit(Native Method)
at com.android.internal.os.RuntimeInit.main(RuntimeInit.java:245)
at dalvik.system.NativeStart.main(Native Method)
發現命令行是 am start –n com.android.browser/.BrowserActivity -a android.intent.action.VIEW
經過字符串搜索,定位到java層關鍵代碼,使用android hook框架cydia substrate,掛鉤java.lang.Runtime類的exec函數,定位到調用棧:
content:/data/user/0/com.qihoo360.mobilesafe/files/so_libs/um.0.2 com.qihoo360.mobilesafe --execute am start -n com.android.browser/.BrowserActivity -a android.intent.action.VIEW -d http://shouji.360.cn/web/uninstall/uninstall.html?u=100\&id=7b55c26b779bd111dfed8b02bb00131c\&v=5.5.0.1041\&s=1\&model=TmV4dXMgUw\&sdk=19\&at=KTvooEkhHMzgJ13AXfMkJINnhrmyyNdu\&ch=200222 --user 0
java.lang.Throwable
at com.example.emptytest.Main$1$1.invoked(Main.java:68)
at com.saurik.substrate.MS$2.invoked(MS.java:68)
at java.lang.Runtime.exec(Native Method)
at egv.a(360MobileSafe:257)
at egv.a(360MobileSafe:66)
at com.qihoo360.mobilesafe.ui.index.MobileSafeApplication.p(360MobileSafe:1223)
at com.qihoo360.mobilesafe.ui.index.MobileSafeApplication.onCreate(360MobileSafe:799)
啓動不久,360啓動linux程序/data/data/com.qihoo360.mobilesafe/com.qihoo360.mobilesafe/files/so_libs/um.0.2
,並將彈窗任務以參數形式傳遞給該程序,程序中對/data/data/com.qihoo360.mobilesafe文件夾的刪除操做進行掛鉤,以實現卸載後彈窗機制
(gdb) disass /r 0x401148b8,0x40114900
Dump of assembler code from 0x401148b8 to 0x401148c8:
=> 0x401148b8: 0c 70 a0 e1 mov r7, r12
0x401148bc: 01 0a 70 e3 cmn r0, #4096 ; 0x1000
0x401148c0: 1e ff 2f 91 bxls lr
0x401148c4: 00 00 60 e2 rsb r0, r0, #0
0x401148c8: 0e 70 00 ea b 0x40130908
End of assembler dump.
print expr
print 」%d」 a
dprintf 動態插入printf函數
dprintf location,format string,arg1,arg2,...
info registers
info args
info locals
x
set *(unsigned int*)0x800000000=0x00000000
break [PROBE_MODIFIER] [LOCATION] [thread THREADNUM] [if CONDITION] clear [LOCATION]
break *0x4000000 絕對地址
break 12 行號
break func1 函數
clear *0x40000000
clear 12
clear func1
tbreak [PROBE_MODIFIER] [LOCATION] [thread THREADNUM] [if CONDITION]
break func1 thread1 if i==0
watch/awatch/ rwatch [-l|-location] EXPRESSION 變化/讀寫/讀斷點
(若是EXPRESSION不是絕對地址,則須要用-l計算表達式)
watch *0x40000000==0x90909090
watch –l *$pc
watch i (有源碼,變量i的值有變化時中止)
break-range START-LOCATION, END-LOCATION
break-range 1.c:5, 1.c:10 在1.c的第5行和第10行之間下斷
break-range +5, +10 在當前行+5和當前行+10之間下斷
普通硬斷 hbreak [PROBE_MODIFIER] [LOCATION] [thread THREADNUM] [if CONDITION]
臨時硬斷 thbreak [PROBE_MODIFIER] [LOCATION] [thread THREADNUM] [if CONDITION]
xbreak
普通補斷 catch [assert|catch|exception|exec|fork|load|rethrow|signal|syscall|throw|unload|vfork]
臨時捕斷 tcatch [assert|catch|exception|exec|fork|load|rethrow|signal|syscall|throw|unload|vfork]
如何使程序在so加載時刻斷下??(網上很多人用奇葩方式,仍是對gdb不瞭解)
catch load 1.so
strace [LOCATION] [IF CONDITION]
bt [N] 顯示N層調用棧
bt full 顯示所有調用棧
行爲 | 命令 |
---|---|
運行時中斷 | Ctrl+C |
結束程序 | kill |
單步步過 | next |
單步步入 | step |
單步步過(指令級) | nexti |
單步步入(指令級) | stepi |
繼續運行 | continue |
執行到當前函數指定位置 | advance |
分離進程 | detach |
強制跳轉 | jump |
reverse-continue reverse-next reverse-search reverse-stepi reverse-finish reverse-next reverse-step
info shared
能夠用於作二進制對比
(gdb) load C:/Users/lichao/2/libadnative.so 0x50000000
Loading section .interp, size 0x13 lma 0x50000134
Loading section .dynsym, size 0x1210 lma 0x50000148
Loading section .dynstr, size 0x2061 lma 0x50001358
Loading section .hash, size 0x8a8 lma 0x500033bc
Loading section .rel.dyn, size 0x10a0 lma 0x50003c64
Loading section .rel.plt, size 0x1b0 lma 0x50004d04
Loading section .plt, size 0x29c lma 0x50004eb4
Loading section .text, size 0xe7a0 lma 0x50005150
Loading section .ARM.extab, size 0x8e8 lma 0x500138f0
Loading section .ARM.exidx, size 0xd80 lma 0x500141d8
Loading section .rodata, size 0x11bc lma 0x50014f58
Loading section .data.rel.ro.local, size 0x738 lma 0x50018098
Loading section .fini_array, size 0x8 lma 0x500187d0
Loading section .init_array, size 0x14 lma 0x500187d8
Loading section .data.rel.ro, size 0x508 lma 0x500187f0
Loading section .dynamic, size 0xf8 lma 0x50018cf8
Loading section .got, size 0x210 lma 0x50018df0
Loading section .data, size 0x1c lma 0x50019000
Start address 0x0, load size 94044
Transfer rate: 188 KB/sec, 2541 bytes/write.
file c:/1.so
gcore
進程空間inferior,用於調試多個進程,fork函數會自動添加進程空間
操做 | 指令 |
---|---|
添加進程空間 | add-inferior |
複製進程空間 | clone-inferior 1 |
刪除進程空間 | remove-inferior 1 |
切換進程空間 | inferior 2 |
分離進程空間 | detach inferior 2 |
maintenance translate-address [address]
info functions [regex] 定位地址
info symbol address 定位文件
info variables [regex] 全局靜態符號
目標系統:! [command]
主機系統:shell [command]
info threads
info vtbl