Android逆向分析筆記


layout: wiki
title: Android逆向分析筆記
categories: Reverse_Engineering
description: Android逆向分析筆記
keywords:
url: https://lichao890427.github.io/ https://github.com/lichao890427/


概述

分析步驟

通用逆向分析步驟

  • 1.了解該模塊正向編程相關(guān)方法
  • 2.使用apktool解密apk,得到資源、jni模塊等文件
  • 3.從apk提取出dex文件,使用dex2jar轉(zhuǎn)換成jar文件,再用java逆向工具得到j(luò)ava源碼 dex->jar->java
  • 4.根據(jù)特征(字符串、常量、包名類(lèi)名方法名、manifest文件、布局文件等方式)或調(diào)試手段定位到關(guān)鍵代碼
  • 5.分析變量含義類(lèi)型、函數(shù)邏輯、模塊流程
  • 6.對(duì)變量、函數(shù)、類(lèi)進(jìn)行標(biāo)注、恢復(fù)成高級(jí)語(yǔ)言 ->c

??Android程序的特點(diǎn)相比在于使用混淆方式打包,將包名、類(lèi)名、函數(shù)名改成不易看懂的字母,從而使生成的apk小很多(android studio提供了release編譯方式,使用proguard混淆),因此反編譯apk最多的工作在于重構(gòu)這些名稱(chēng),這一點(diǎn)和pc上一致,對(duì)于android native程序(jni)則和pc上基本一致,不同之處在于常見(jiàn)的是arm匯編。

安卓上APK調(diào)試步驟:

  • 1.Apk(debuggable)或系統(tǒng)(ro.debuggable=1)設(shè)置為可調(diào)試
  • 2.在虛擬機(jī)中啟動(dòng)服務(wù)端(adbd/android_server)
  • 3.在主機(jī)端連接客戶(hù)端調(diào)試器(IDA/jdb/adt),設(shè)置斷點(diǎn)

安卓上linux程序調(diào)試步驟:

  • 1.在虛擬機(jī)中啟動(dòng)服務(wù)端(gdb_server/linux_server)
  • 2.在主機(jī)端連接客戶(hù)端調(diào)試器(IDA/gdb_for_windows),設(shè)置斷點(diǎn)

??對(duì)于apk的反編譯,由于資源和xml都進(jìn)行了編碼,因此反編譯時(shí)必然要解析相應(yīng)的resource.arsc/AndroidManifest.xml等文件,對(duì)于做過(guò)保護(hù)處理的apk通常會(huì)在這里做手腳干擾Apktool、dex2jar等反編譯工具因此很有必要掌握編譯、調(diào)試這些工具源碼的方法(見(jiàn)“如何編譯、調(diào)試apktool和dex2jar”)

分析工具

  • 集成IDE:APK改之理、JD-GUI、JEB(1.4破解 2.0)、jadx
  • 解壓(apk, jar):WinRar
  • 解析資源:apktool
  • 反編譯引擎(jar, class):dex2jar工具集、jd-core(JD-GUI,JD-Eclipse反編譯核心)、fernflower(Android Studio反編 、procyon
  • 回編譯:aapt、dex2jar工具集
  • 調(diào)試器:IDA、jdb、adt等
  • 輔助工具:DDMS 如果是虛擬機(jī)可以看到所有進(jìn)程

APK改之理

  • 整合&提供了全套解壓、反編譯代碼和資源、回編譯、簽名功能,強(qiáng)大的正則搜索,修改smali字節(jié)碼等功能
  • 集成ApkTool、Dex2jar、JD-GUI工具
  • 可視化操作,全自動(dòng)的反編譯、回編譯、簽名Apk
  • 正則表達(dá)式搜索資源及源碼

JD-GUI

輕量級(jí)反編譯,反編譯jar/class等java字節(jié)碼文件(能力一般),提供簡(jiǎn)單的搜索能力

JEB

  • 反編譯apk/jar工具(能力較強(qiáng))
  • 強(qiáng)大的正向、反向索引,一定程度重命名能力,一定搜索能力
  • 支持注釋、插件
  • 交互式可視化操作,全自動(dòng)的反編譯
  • 支持重命名

Dex2jar工具集

??dex2jar是一個(gè)工具包,反編譯dex和jar,還提供了一些其它的功能,每個(gè)功能使用一個(gè)bat批處理或 sh 腳本來(lái)包裝,只需在Windows 系統(tǒng)中調(diào)用 bat文件、在Linux 系統(tǒng)中調(diào)用 sh 腳本即可。在bat中調(diào)用相應(yīng)的jar主類(lèi)完成特定功能,例如d2j-dex2jar.bat中的內(nèi)容是:@"%~dp0d2j_invoke.bat" com.googlecode.dex2jar.tools.Dex2jarCmd %*。常用的有dex2jar jar2dex dex2smali smali2dex

  • d2j-apk-sign用來(lái)為apk 文件簽名。命令格式:d2j-apk-sign xxx.apk 。
  • d2j-asm-verify 用來(lái)驗(yàn)證jar 文件。命令格式:d2j-asm-verify -d xxx.jar。
  • d2j-dex2jar 用來(lái)將dex 文件轉(zhuǎn)換成jar 文件。命令格式:d2j-dex2jar xxx.apk
  • d2j-dex-asmifier 用來(lái)驗(yàn)證dex 文件。命令格式:d2j-dex-asmifier xxx.dex。
  • d2j-dex-dump 用來(lái)轉(zhuǎn)存dex 文件的信息。命令格式:d2j-dex-dump xxx.apk out.jar 。
  • d2j-init-deobf 用來(lái)生成反混淆jar 文件時(shí)的初始化配置文件。
  • d2j-jar2dex 用來(lái)將jar 文件轉(zhuǎn)換成 dex 文件。命令格式:d2j-jar2dex xxx.apk。
  • d2j-jar2jasmin 用來(lái)將jar 文件轉(zhuǎn)換成jasmin 格式的文件。命令格式:d2j-jar2jasmin xxx.jar
  • d2j-jar-access 用來(lái)修改jar 文件中的類(lèi)、方法以及字段的訪(fǎng)問(wèn)權(quán)限。
  • d2j-jar-remap 用來(lái)重命名jar 文件中的包、類(lèi)、方法以及字段的名稱(chēng)。
  • d2j-jasmin2jar 用來(lái)將jasmin 格式的文件轉(zhuǎn)換成 jar 文件。命令格式:d2j-jasmin2jar dir dex2jar為d2j-dex2jar 的副本。
  • dex-dump為d2j-dex-dump 的副本

Apktool反編譯&打包工具

  • 反編譯apk:apktool d file.apk –o path
  • 回編譯apk:apktool b path –o file.apk

常見(jiàn)文件格式

Apk

??Android package,android安裝程序文件,本質(zhì)上是壓縮包,解壓得到classes.dex、resources.arsc、AndroidManifest.xml、so文件以及資源文件

  • Resources.arsc資源描述文件
  • Classes.dex所有代碼編譯過(guò)得darvik字節(jié)碼文件,可能會(huì)有多個(gè)
  • AndroidManifest.xml 編譯過(guò)的AndroidManifest.xml文件

使用aapt解析xml

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)

Dex

??Dalvik Executable,Dalvik可執(zhí)行文件,從java class文件轉(zhuǎn)換而來(lái)的字節(jié)碼,Classes.Dex通過(guò)dex2jar轉(zhuǎn)換成java字節(jié)碼(有損),或者dex2smali轉(zhuǎn)換成darvik匯編(無(wú)損)——smali字節(jié)碼,其形式如下
[圖片上傳失敗...(image-9ed308-1516409604717)]

Jar

??Java Archive,java歸檔文件,可以直接解壓得到class文件

Odex

dex轉(zhuǎn)odex:/system/bin/dexopt
dexopt-wrapper 1.apk 1.odex

Aar

??Android歸檔文件,壓縮包格式,包含

  • /AndroidManifest.xml (強(qiáng)制) 未編譯的
  • /classes.jar (強(qiáng)制)
  • /res/ (強(qiáng)制)
  • /R.txt (強(qiáng)制)
  • /assets/ (可選)
  • /libs/*.jar (可選)
  • /jni/<abi>/*.so (可選)
  • /proguard.txt (可選)
  • /lint.jar (可選)

So

??Linux動(dòng)態(tài)鏈接庫(kù)文件,包含arm64 arm mips mips64 x86 x86-64幾個(gè)平臺(tái)

工具轉(zhuǎn)換圖

[圖片上傳失敗...(image-e2645e-1516409604717)]

Android設(shè)備上重要目錄

  • /system/app/1.apk 系統(tǒng)應(yīng)用
  • /data/app/1.apk 用戶(hù)應(yīng)用
  • /data/data/[pkgname] 應(yīng)用數(shù)據(jù)(so,database,…)
  • /data/dalvik-cache 存放dex

Java層

常用工具

adb

??設(shè)備通信、調(diào)試工具,常用法:

adb devices 列出當(dāng)前設(shè)備
adb –s d24eb3ab [命令]      指定設(shè)備執(zhí)行命令
adb push 源 目標(biāo)            非root機(jī)器可以設(shè)置路徑為/data/local/tmp
adb pull 源 目標(biāo)
adb shell                   執(zhí)行終端
adb logcat                  查看日志(/system/logcat為服務(wù)器)
adb jdwp                    查看遠(yuǎn)程jdwp進(jìn)程
adb forward tcp:主機(jī)端口     tcp:遠(yuǎn)程端口       把主機(jī)端口消息轉(zhuǎn)發(fā)手機(jī)端口(端口對(duì)應(yīng)進(jìn)程)   用于ida調(diào)試
adb forward tcp:主機(jī)端口     jdwp:遠(yuǎn)程進(jìn)程ID    把主機(jī)端口消息轉(zhuǎn)發(fā)手機(jī)jdwp進(jìn)程   用于jdb調(diào)試 
adb install [apkpath]       安裝apk
adb uninstall [packagename] 卸載apk 注意會(huì)徹底清理,刪除/data/app下的備份apk
adb remount                 將/system重新映射為讀寫(xiě),以便進(jìn)行系統(tǒng)區(qū)文件操作
adb root                    使adb以root方式啟動(dòng),便于push/pull/remount

aapt

??APK資源管理工具,用于增刪查改APK中的文件、資源等,對(duì)于分析編譯后的Resource.arsc, AndroidManifest.xml格式較有價(jià)值,通常也可以用winrar對(duì)apk/jar進(jìn)行解壓

打印xml樹(shù) aapt d xmltree 1.apk AndroidManifest.xml
打印資源    aapt d resources 1.apk
添加文件    aapt a 1.apk AndroidManifest.xml
刪除文件    aapt r 1.apk AndroidManifest.xml

am & pm

??Android遠(yuǎn)程命令,am執(zhí)行調(diào)試、運(yùn)行功能,pm執(zhí)行安裝、卸載功能

  • 啟動(dòng)應(yīng)用:am start -D -n "baidu.myapp/baidu.myapp.MainActivity" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER
  • 啟動(dòng)服務(wù):am startservice -n com.android.music/com.android.music.MediaPlaybackService
  • 強(qiáng)制停止包:am force-stop com.example.administrator.myapplication
  • 強(qiáng)制結(jié)束包進(jìn)程:am kill com.example.administrator.myapplication am kill all
  • 發(fā)送廣播:adb shell am broadcast -a com.android.test
  • 安裝應(yīng)用:pm install –r 1.apk
  • 卸載應(yīng)用:pm uninstall packagename
  • 列出所有安裝包:pm list package
  • 查看是否以指定名為前綴的包存在:pm list package com.qihoo
  • 禁用應(yīng)用:pm disable packagename (禁用后,圖標(biāo)消失,對(duì)該應(yīng)用的操作都無(wú)效)

有源碼調(diào)試APK

Android studio

??在android studio中可以采用運(yùn)行調(diào)試或進(jìn)程附加方式調(diào)試,支持條件斷點(diǎn)、一次斷點(diǎn)、對(duì)單線(xiàn)程下斷,有6種斷點(diǎn):

TypeCh TypEn Description
行斷點(diǎn) Java Line Breakpoints 在(java/c)源碼某行下斷
Java類(lèi)成員變量訪(fǎng)問(wèn)斷點(diǎn) Java Field Watchpoints 類(lèi)似于內(nèi)存訪(fǎng)問(wèn)斷點(diǎn),在讀和寫(xiě)java類(lèi)成員變量時(shí)斷下
Java類(lèi)方法斷點(diǎn) Java Method Breakpoints 在進(jìn)入java層函數(shù)或退出函數(shù)時(shí)斷下
Java異常斷點(diǎn) Java Exception Breakpoints 發(fā)生java層捕獲或未捕獲異常時(shí)斷下
異常斷點(diǎn) Exception Breakpoints 拋異常或捕獲異常時(shí)斷下
符號(hào)斷點(diǎn) Symbolic Breakpoints (c/java)符號(hào)斷點(diǎn)

Adb wifi

??應(yīng)用市場(chǎng)有很多這種軟件,需要Root權(quán)限。解決沒(méi)有USB數(shù)據(jù)線(xiàn)的情況下的調(diào)試

C:\Users\Administrator>adb connect 192.168.0.103:5555
connected to 192.168.0.103:5555
此時(shí)可以用adt調(diào)試

無(wú)源碼調(diào)試apk

??不需要調(diào)試的一般過(guò)程 :使用反編譯工具得到源代碼,修改調(diào)試標(biāo)識(shí),修改機(jī)器碼,最后回編譯簽名:

反編譯apk:apktool d file.apk –o path  
回編譯apk:apktool b path –o file.apk  

使用AndroidStudio和Apktool工具調(diào)試

  • 第一步,反編譯得到(占行)偽源碼:java -jar apktool.jar d -d input.apk -o out,加上-d選項(xiàng)之后反編譯出的文件后綴為.java,而不是.smali,每個(gè).java文件立馬都偽造成了一個(gè)類(lèi),語(yǔ)句全都是“a=0;”這一句,smali語(yǔ)句成為注釋?zhuān)鲞@些都是為了后面欺騙idea、eclipse、android studio這些ide的
  • 第二步,修改資源或者源碼(smali),修改AndroidManifest.xml調(diào)試標(biāo)識(shí),反編譯以后可以在dex中插入waitfordebugger或者Log.i的smali代碼來(lái)進(jìn)行相應(yīng)的控制
  • 第三步,回編譯(-d選項(xiàng))+簽名
    • 回編譯:apktool b –d path –o input.apk
    • 簽名: java –jar signapk.jar testkey.x509.pem testkey.pk8 input.apk output.apk
  • 第四步,新建android studio工程 ,將反編譯得到的smali文件夾中的源文件拷貝到源碼目錄(欺騙),回編譯的apk覆蓋目標(biāo)apk位置 ,刪除Edit configuration的Before launch,下斷點(diǎn)調(diào)試

點(diǎn)評(píng):這種方式只可以用來(lái)分析加密很弱的App,前提是apktool可以成功反編譯
[圖片上傳失敗...(image-519a4b-1516409604717)]

使用jdb調(diào)試

??jdb是一個(gè)支持java代碼級(jí)調(diào)試的工具,它是由java jdk提供的,可以設(shè)置斷點(diǎn)、查看堆棧、計(jì)算表達(dá)式、動(dòng)態(tài)修改類(lèi)字節(jié)碼、調(diào)試&跟蹤、修改變量值、線(xiàn)程操作,斷點(diǎn)包括:(源碼)行斷點(diǎn)、符號(hào)斷點(diǎn)、成員變量訪(fǎng)問(wèn)斷點(diǎn)。每個(gè)java程序(windows/ios/android)都可以用jdwp協(xié)議進(jìn)行調(diào)試,Android Studio/Eclipse的調(diào)試也是建立在該協(xié)議基礎(chǔ)之上,下面以實(shí)例說(shuō)明:

  • 第一步,開(kāi)發(fā)demo
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.baidu.com"));
                intent.setClassName("com.android.browser","com.android.browser.BrowserActivity");
                startActivity(intent);
            }
        });
    }
}
  • 第二步,啟動(dòng)jdb調(diào)試
adb shell am start -D -n "baidu.myapp/baidu.myapp.MainActivity" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER

[圖片上傳失敗...(image-3c2d4a-1516409604717)]

  • 第三步,開(kāi)始調(diào)試
    • 查看ddms中該進(jìn)程端口號(hào) 8600
    • 使用jdb調(diào)試:jdb -connect com.sun.jdi.SocketAttach:hostname=127.0.0.1,port=8600
    • 下斷點(diǎn):函數(shù)斷點(diǎn)stop in android.app.Activity.startActivity(android.content.Intent)
      行斷點(diǎn) stop at android.app.Activity:123,觸發(fā)斷點(diǎn)后顯示堆棧:
<1> main[1] where
  [1] android.app.Activity.startActivity (Activity.java:3,490)
  [2] baidu.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 (本機(jī)方法)

查看參數(shù)

<1> main[1] print intent
 intent = "Intent { act=android.intent.action.VIEW dat=http://www.baidu.com cmp=
com.android.browser/.BrowserActivity }"

設(shè)置源碼從而進(jìn)行逐行調(diào)試

<1> main[1] use D:\Android\sdk\sources\android-18       //參考設(shè)備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) {

行斷點(diǎn):

> use D:\test\MyApplication\app\src\main\java
stop at baidu.myapp.MainActivity:18
正在延遲斷點(diǎn)baidu.myapp.MainActivity:18。
將在加載類(lèi)后設(shè)置。
> resume
已恢復(fù)所有線(xiàn)程。
> 設(shè)置延遲的斷點(diǎn)baidu.myapp.MainActivity:18
斷點(diǎn)命中: "線(xiàn)程=<1> main", baidu.myapp.MainActivity.onCreate(), 行=18 bci=12
18            int j = 0;

初始斷點(diǎn)

??只要連接到j(luò)db就會(huì)導(dǎo)致app運(yùn)行起來(lái),此時(shí)如果想斷在初始化這部分就沒(méi)有辦法了,不過(guò)jdb提供初始命令腳本

  • 暫停所有線(xiàn)程: echo suspend > jdb.ini
  • 執(zhí)行調(diào)試:jdb -connect com.sun.jdi.SocketAttach:hostname=127.0.0.1,port=8601

??此時(shí),app仍然處于等調(diào)試器狀態(tài),而蟲(chóng)子已經(jīng)變綠,此時(shí)可以下斷點(diǎn),然后resume恢復(fù)所有線(xiàn)程
附加后會(huì)變綠色蟲(chóng)子

> > stop in baidu.myapp.MainActivity.onCreate(android.os.Bundle)
正在延遲斷點(diǎn)baidu.myapp.MainActivity.onCreate(android.os.Bundle)。
將在加載類(lèi)后設(shè)置。
>resume
已恢復(fù)所有線(xiàn)程。
斷點(diǎn)命中: "線(xiàn)程=<1> main", baidu.myapp.MainActivity.onCreate(), 行=13 bci=0

<1> main[1] where
  [1] baidu.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)

調(diào)試命令

    stop in:斷點(diǎn)
    step:步入(源碼行)
    stepi:單入(指令)
    step up:執(zhí)行到返回
    cont:恢復(fù)運(yùn)行
    next:步過(guò)
    輸出表達(dá)式:print/eval

jdb最大缺點(diǎn)在于難用,所以有人用python封裝了一次,工具名AndBug

無(wú)源碼調(diào)試dex

    1. 使用ida分析apk或者從apk中提取出的dex
    1. 設(shè)置調(diào)試選項(xiàng),包括包名和主類(lèi)名,參考反編譯的AndroidManifest
    1. 啟動(dòng)調(diào)試即可
      [圖片上傳失敗...(image-5e8db1-1516409604717)]
      [圖片上傳失敗...(image-47c4a-1516409604717)]

Linux層

常用工具

Gdbserver

Usage:  gdbserver [OPTIONS] COMM PROG [ARGS ...]
        gdbserver [OPTIONS] --attach COMM PID
        gdbserver [OPTIONS] --multi COMM
        隱藏用法:gdbserver [OPTIONS] +SOCKETFILE --attach PID           會(huì)在本地建立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.
使用方式:
啟動(dòng)模式遠(yuǎn)程調(diào)試:gdbserver --debug --remote-debug  :23946 /system/test.out [參數(shù)]     
附加模式遠(yuǎn)程:gdbserver –debug –remote-debug –attach  :23946 1234
    Adb forward tcp:23946 tcp:23946 轉(zhuǎn)發(fā)端口
IDA中選擇Remote GDB Debugger附加即可

Strace

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 --統(tǒng)計(jì)每一系統(tǒng)調(diào)用的所執(zhí)行的時(shí)間,次數(shù)和出錯(cuò)的次數(shù)等.
-C -- like -c but also print regular output while processes are running
-f --跟蹤由fork調(diào)用所產(chǎn)生的子進(jìn)程.
-F --嘗試跟蹤vfork調(diào)用.在-f時(shí),vfork不被跟蹤.
-i --輸出系統(tǒng)調(diào)用的入口指針
-q --禁止輸出關(guān)于脫離的消息
-r --打印出相對(duì)時(shí)間關(guān)于,,每一個(gè)系統(tǒng)調(diào)用
-T --顯示每一調(diào)用所耗的時(shí)間
-v --輸出所有的系統(tǒng)調(diào)用.一些調(diào)用關(guān)于環(huán)境變量,狀態(tài),輸入輸出等調(diào)用由于使用頻繁,默認(rèn)不輸出
-x --以十六進(jìn)制形式輸出非標(biāo)準(zhǔn)字符串
-a設(shè)置返回值的輸出位置.默認(rèn) 為40.
-e expr -指定一個(gè)表達(dá)式,用來(lái)控制如何跟蹤.: option=[!]all or option=[!]val1[,val2]...
   options: trace, abbrev, verbose, raw, signal, read, or write
-o file --將strace的輸出寫(xiě)入文件filename
-O overhead -- set overhead for tracing syscalls to OVERHEAD usecs
-p pid --跟蹤指定的進(jìn)程pid.
-D -- run tracer process as a detached grandchild, not as parent
-s strsize --指定輸出的字符串的最大長(zhǎng)度.默認(rèn)為32.文件名一直全部輸出
-S sortby -- sort syscall counts by: time, calls, name, nothing (default time)
-u username --以u(píng)sername 的UID和GID執(zhí)行被跟蹤的命令
-E var=val -- put var=val in the environment for command
-E var -- remove var from the environment for command

使用方式:
Strace –f ProcessA      啟動(dòng)跟蹤
Strace –f –p 234        附加跟蹤
    -e trace=file       -e trace=process    -e trace=network

有源碼so調(diào)試

Ndk-gdb

??該程序是一個(gè)shell腳本,執(zhí)行過(guò)程如下:

adb shell am start -D -n com.example.hellojni/.HelloJni     啟動(dòng)app并等待調(diào)試器
    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與文件映射建立調(diào)試鏈接(c層)
adb forward tcp:5039 localfilesystem:/data/data/com.example.hellojni/debug-socket將調(diào)試鏈接和本地端口建立鏈接(c層)
adb forward tcp:65534 jdwp:(3569)PID                                         將本地端口和進(jìn)程建立連接(java層)
jdb -connect com.sun.jdi.SocketAttach:hostname=localhost,port=65534          使用jdb調(diào)試java層
arm-linux-androideabi-gdb.exe                                           
    target remote :5039                                              使用gdb調(diào)試c層
    set breakpoint pending on

??(使用前關(guān)掉騰訊的AndroidServer.exe,否則連不上!!!),在工程目錄下(有AndroidManifest.xml),命令行運(yùn)行%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)

點(diǎn)評(píng):該工具要求環(huán)境極為苛刻且不穩(wěn)定,不建議使用

Gdb-Gdbserver

??操作步驟:

  • Android studio導(dǎo)入jni工程,
  • 拷貝.so到搜索路徑,pull /system/lib到搜索路徑,pull /system/linker到搜索路徑
  • 啟動(dòng)gdbserver (具體命令根據(jù)版本不同而變)
    gdbserver --attach *:111 1234
  • 轉(zhuǎn)發(fā)端口
    adb forward tcp:111 tcp:111
  • 連接本地調(diào)試器
    target remote 127.0.0.1:111
(gdb) set solib-search-path C:/Users/lichao26/2/
Reading symbols from C:\Users\lichao26\2\linker...(no debugging symbols found)...done.
Loaded symbols for C:\Users\lichao26\2\linker
Reading symbols from C:\Users\lichao26\2\libc.so...(no debugging symbols found)...done.
Loaded symbols for C:\Users\lichao26\2\libc.so
Reading symbols from C:\Users\lichao26\2\libstdc++.so...(no debugging symbols found)...done.
Loaded symbols for C:\Users\lichao26\2\libstdc++.so
Reading symbols from C:\Users\lichao26\2\libm.so...(no debugging symbols found)...done.
Loaded symbols for C:\Users\lichao26\2\libm.so
Reading symbols from C:\Users\lichao26\2\liblog.so...(no debugging symbols found)...done.
Loaded symbols for C:\Users\lichao26\2\liblog.so
Reading symbols from C:\Users\lichao26\2\libcutils.so...(no debugging symbols found)...done.
Loaded symbols for C:\Users\lichao26\2\libcutils.so
Reading symbols from C:\Users\lichao26\2\libgccdemangle.so...(no debugging symbols found)...done.
Loaded symbols for C:\Users\lichao26\2\libgccdemangle.so
Reading symbols from C:\Users\lichao26\2\libcorkscrew.so...(no debugging symbols found)...done.

(gdb) bt
#0  0x400e50e0 in fork () from C:\Users\lichao26\2\libc.so
#1  0x76886ca0 in Java_com_example_hellojni_HelloJni_stringFromJNI () from C:\Users\lichao26\2\libhello-jni.so
#2  0x416b8350 in dvmPlatformInvoke () from C:\Users\lichao26\2\libdvm.so
#3  0x416e8fd2 in dvmCallJNIMethod(unsigned int const*, JValue*, Method const*, Thread*) () from C:\Users\lichao26\2\libdvm.so
#4  0x416ea9ba in dvmResolveNativeMethod(unsigned int const*, JValue*, Method const*, Thread*) () from C:\Users\lichao26\2\libdvm.so
#5  0x416c1828 in dvmJitToInterpNoChain () from C:\Users\lichao26\2\libdvm.so
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
(gdb) list

無(wú)源碼調(diào)試So

使用Arm版Gdb在移動(dòng)端直接調(diào)試

  • 獲取arm版gdb
  • 把gdb下載到移動(dòng)端
    adb push gdb /data/bin
  • 執(zhí)行g(shù)db
    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) 

點(diǎn)評(píng):該方法速度快,但不好查看符號(hào)

IDA調(diào)試

  • 將android_server拷入/data/local/tmp/
    adb push android_server /data/local/tmp/
  • 修改可執(zhí)行權(quán)限,運(yùn)行
    cd /data/local/tmp/
    chmod 755 android_server
    ./android_server
  • 將模擬器端口轉(zhuǎn)發(fā)至pc端口 (另開(kāi)啟命令行)
    adb forward tcp:23946 tcp:23946
  • IDA中選擇Remote ARMLinux/Android debugger,端口23946,調(diào)試即可,成功以后顯示
    Accepting connection from 127.0.0.1...

Gdb-Gdbserver

  • 啟動(dòng)server
    ./gdbserver –attach :1234 [pid]
  • 轉(zhuǎn)發(fā)端口
    adb forward tcp:1234 tcp:1234
  • 啟動(dòng)client
    arm-linux-androideabi-gdb.exe
  • 連接server
    target remote :1234
  • 設(shè)置單步調(diào)試
    set step-mode on
  • 設(shè)置反匯編模式
    set disassemble-next on
  • 設(shè)置加載so斷點(diǎn)
    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

??GikDbg 是一款移動(dòng)平臺(tái)的匯編級(jí)調(diào)試器,它基于 OllyDbg ,GDB 以及 LLVM 實(shí)現(xiàn)而來(lái)。OllyDbg 現(xiàn)已廣泛用于 PC 平臺(tái)軟件安全領(lǐng)域,GikDbg 是 OllyDbg 向移動(dòng)平臺(tái)轉(zhuǎn)移的產(chǎn)物,它可以協(xié)助您完成諸如應(yīng)用調(diào)試分析,應(yīng)用安全評(píng)估,應(yīng)用漏洞挖掘等移動(dòng)安全領(lǐng)域。What features can GikDbg support? http://gikir.com/product.php

  • ELF / Mach-O executable file static analysis;
  • Android / iOS App dynamic debugging;
  • Android / iOS remote console;
  • ARM assembler;
  • ARM disassembler;
  • Device file uploading and downloading;
  • Built-in GDB and LLDB;
  • Support for memory breakpoint, software breakpoint, conditional breakpoint;
  • Support for multi-threaded debugging;
  • Support for assembly code level file patching.

GikDbg for IOS
[圖片上傳失敗...(image-600f30-1516409604717)]

GikDbg for Android
[圖片上傳失敗...(image-3266ab-1516409604718)]

??gikdbg.art-Gikir Debugger for Android RunTime, 是Android平臺(tái)的32位匯編級(jí)調(diào)試器。此處的Android RunTime既指DVM RunTime又指ART RunTime,因此不管是運(yùn)行dalvik虛擬機(jī)還是運(yùn)行本地代碼的art均可以使用gikdbg.art進(jìn)行程序的二進(jìn)制調(diào)試分析。不同之處在于dalvik虛擬機(jī)的運(yùn)行時(shí)只能調(diào)試so動(dòng)態(tài)庫(kù),而art運(yùn)行時(shí)不僅能調(diào)試so動(dòng)態(tài)庫(kù),還能調(diào)試系統(tǒng)鏡像oat,可執(zhí)行程序dex這樣的文件。另外,gikdbg-Gikir Debugger for iPhone OS,是調(diào)試越獄蘋(píng)果設(shè)備的32位匯編級(jí)調(diào)試器,同學(xué)們莫搞混淆了哈,它需要一些復(fù)雜點(diǎn)的服務(wù)端和客戶(hù)端的配置,而gikdbg.art在正常情況下是不需要手工配置的,所以別去找android server了。對(duì)于靜態(tài)分析,可以執(zhí)行/ART Debug/View/ELF Data…,/ART Debug/View/ELF Code…兩個(gè)菜單打開(kāi)本地so,oat,dex文件。

調(diào)試so

Step 0.前置說(shuō)明
手機(jī)端:Android模擬器,Android 4.4.2 ART 運(yùn)行時(shí);(真機(jī)與DVM運(yùn)行時(shí)是一樣的)
PC端:ParallelDesktop虛擬機(jī),Windows 8.0,gikdbg.art v1.0.build140601.3;
PS:非root環(huán)境的設(shè)備由于權(quán)限的原因會(huì)有很多問(wèn)題,不推薦使用!
Step 1.連接設(shè)備
運(yùn)行模擬器,打開(kāi)gikdbg.art.exe,執(zhí)行/ART Debug/Device菜單,我們就可以來(lái)到如下界面:  

[圖片上傳失敗...(image-77832b-1516409604718)]

如果模擬器已經(jīng)運(yùn)行了,但是設(shè)備列表中沒(méi)有,則等待一段時(shí)間后執(zhí)行右鍵的Refresh菜單。然后雙擊或者右鍵Login就可以登陸選中的設(shè)備了。對(duì)于第一次Login該設(shè)備,會(huì)詢(xún)問(wèn)你是否上傳依賴(lài)的文件到/data/local,這一步如果否定了的話(huà)將不能使用調(diào)試功能。上傳文件這個(gè)步驟目前已知的問(wèn)題是對(duì)于非root的設(shè)備,往往因?yàn)闄?quán)限的原因上傳不成功,一般情況下/data/local/tmp目錄沒(méi)有問(wèn)題,但是有些設(shè)備又沒(méi)有/data/local/tmp目錄,因此我們只有設(shè)置/data/local為目標(biāo)路徑,這個(gè)問(wèn)題目前還不知道好的解決辦法。歸納一下就是:非root的機(jī)器無(wú)法在其/data/local下創(chuàng)建我們依賴(lài)的文件夾以及上傳文件,如果我們將其遷移至/data/local/tmp這個(gè)目錄下,又有部分設(shè)備沒(méi)有這個(gè)文件夾,就更沒(méi)有辦法上傳了。
對(duì)于這類(lèi)上傳失敗的同學(xué),可以想辦法手工將$(GIKDBG.ART)/adb/android/gdb傳至/data/local/gikir_android-xxxx/gdb這個(gè)位置,其中xxxx是GUID。
如果還沒(méi)有安裝該apk文件的,則可以在ADB Shell中執(zhí)行$install –r命令選擇gikdebugee.apk進(jìn)行安裝.
Step 2.選擇進(jìn)程
登陸成功后執(zhí)行,確保模擬器的gikdebugee.apk運(yùn)行正常,然后執(zhí)行/ART Debug/File/Attach就可以得到如下進(jìn)程列表,選中我們的gikdebugee進(jìn)程,雙擊或者執(zhí)行Attach按鈕

[圖片上傳失敗...(image-cac399-1516409604718)]

之后我們就會(huì)看到如下加載輸出:

[圖片上傳失敗...(image-fbb4e8-1516409604718)]

等gdb加載完畢之后我們就可以進(jìn)入熟悉的CPU主窗口了:

[圖片上傳失敗...(image-337052-1516409604718)]

Step 3.選擇模塊
我們的目的是調(diào)試apk里面的so動(dòng)態(tài)庫(kù),因此執(zhí)行/ART Debug/View/Module切換到模塊列表,選中我們要調(diào)試的模塊,雙擊它

[圖片上傳失敗...(image-f54cff-1516409604718)]

Step 4.擊中斷點(diǎn)
 本例中找到要調(diào)試的函數(shù)getNativeString,我們可以用CTRL+F查找到它,找到之后F2下斷點(diǎn),F(xiàn)9運(yùn)行它,然后在設(shè)備中操作按鈕則該方法將被斷點(diǎn)擊中,F(xiàn)8運(yùn)行3步

[圖片上傳失敗...(image-37b010-1516409604718)]

調(diào)試Android上Linux程序

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(若附加調(diào)試則提供進(jìn)程號(hào))
adb forward tcp:2345 tcp:2345
gdb >
gdb > target remote :2345

技巧:如何在so入口下斷?

??用ida分析so,并在JNI_OnLoad下斷點(diǎn),動(dòng)態(tài)附加后,ida會(huì)自動(dòng)rebase,使用gdb 的catch load命令捕獲

Java層/Linux層聯(lián)合調(diào)試

有源碼聯(lián)合調(diào)試

參照前幾節(jié)

無(wú)源碼聯(lián)合調(diào)試

操作步驟

adb shell am start -D -n com.example.hellojni/.HelloJni     啟動(dòng)app并等待調(diào)試器
    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與文件映射建立調(diào)試鏈接(c層)
adb forward tcp:5039 localfilesystem:/data/data/com.example.hellojni/debug-socket將調(diào)試鏈接和本地端口建立鏈接(c層)
adb forward tcp:65534 jdwp:(3569)PID                                         將本地端口和進(jìn)程建立連接(java層)
jdb -connect com.sun.jdi.SocketAttach:hostname=localhost,port=65534          使用jdb調(diào)試java層
arm-linux-androideabi-gdb.exe                                           
    target remote :5039                                              使用gdb調(diào)試c層
    set breakpoint pending on

最簡(jiǎn)單的gdb中,斷在加載so時(shí)刻的方法

  • 1.以等待模式啟動(dòng)
    am start -D -n com.example.hellojni/.HelloJni
  • 2.Gdbserver鏈接該進(jìn)程(ps | grep hello)
    gdbserver --attach :1234 10863
  • 3.轉(zhuǎn)發(fā)端口
    adb forward tcp:1234 tcp:1234
  • 4.連接gdb
    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
  • 5.設(shè)置符號(hào)路徑(提前把/system/lib/*.so /system/bin/linker libhello-jni.so拷貝到目錄)
    set solib-search-path c:/1
  • 6.設(shè)置加載so斷點(diǎn)
    catch load libhello-jni.so
  • 7.執(zhí)行continue,使用android studio的attach使程序繼續(xù)運(yùn)行
  • 8.加載so時(shí)自動(dòng)斷下:
Catchpoint 1
  Inferior loaded C:\Users\lichao26\sumsing\libhello-jni.so
0x40036b8c in rtld_db_dlactivity () from C:\Users\lichao26\sumsing\linker
  • 9.用ida分析出onload要下斷點(diǎn)的偏移,b *addr下斷

Android linux內(nèi)核層調(diào)試

??Android底層為linux層,gdb用于調(diào)試linux應(yīng)用層,而kgdb用于調(diào)試linux內(nèi)核層
??kgdb的android版本下載:http://github.com/dankex/kgdb-android

使用Hook

常用Hook/Inject工具簡(jiǎn)介

??常用Hook框架:

  • Cydia Substrate
    • 支持Java層hook
    • 支持Jni層hook
    • 需要Root,且機(jī)型適配
    • 支持dalvik,不支持art
    • 閉源
  • Xposed https://github.com/rovo89/Xposed
    • 支持Java層hook
    • 需要Root,且機(jī)型適配
    • 支持dalvik/art
    • 開(kāi)源
  • Frida https://github.com/frida/frida
    • 需要Root
    • 支持Java層hook
    • 支持Jni層hook
    • 支持dalvik/art
    • 開(kāi)源
    • 任意時(shí)刻注入,簡(jiǎn)單易用,遠(yuǎn)程代碼即時(shí)編譯并注入運(yùn)行
  • Adbi https://github.com/evilsocket/arminject
    • 需要Root
    • 支持Jni層hook
    • 任意時(shí)刻注入,手工
    • 開(kāi)源

實(shí)例 360手機(jī)衛(wèi)士卸載后彈窗分析過(guò)程

現(xiàn)象

??360手機(jī)衛(wèi)士在非root情況下卸載后彈出瀏覽器。于是有2種常見(jiàn)可能,一種是intent跳轉(zhuǎn),一種是執(zhí)行am命令,后者可以在java層和jni層實(shí)現(xiàn),如果是java層考慮進(jìn)行hook,jni層考慮修改am.jar

文件注入

??將/system/bin/am改名,發(fā)現(xiàn)無(wú)法彈窗,于是確定是通過(guò)第二種方式實(shí)現(xiàn),為了確定調(diào)用層級(jí),嘗試修改(反編譯成smali->加入logcat輸出打印回溯棧和接收參數(shù)->回編譯)/system/framework/am.jar,(可以通過(guò)自己再另一個(gè)app中實(shí)現(xiàn)同樣的功能,通過(guò)反編譯得到smali代碼)再次反編譯后內(nèi)容如下:

 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)

發(fā)現(xiàn)命令行是 am start –n com.android.browser/.BrowserActivity -a android.intent.action.VIEW

定位關(guān)鍵代碼

??通過(guò)字符串搜索,定位到j(luò)ava層關(guān)鍵代碼,使用android hook框架cydia substrate,掛鉤java.lang.Runtime類(lèi)的exec函數(shù),定位到調(diào)用棧:

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)

結(jié)論

??啟動(dòng)不久,360啟動(dòng)linux程序/data/data/com.qihoo360.mobilesafe/com.qihoo360.mobilesafe/files/so_libs/um.0.2,并將彈窗任務(wù)以參數(shù)形式傳遞給該程序,程序中對(duì)/data/data/com.qihoo360.mobilesafe文件夾的刪除操作進(jìn)行掛鉤,以實(shí)現(xiàn)卸載后彈窗機(jī)制
[圖片上傳失敗...(image-8cf813-1516409604718)]

GDB調(diào)試

反匯編一段地址

(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.

表達(dá)式計(jì)算

print expr
    print ”%d” a
    
dprintf 動(dòng)態(tài)插入printf函數(shù)
    dprintf location,format string,arg1,arg2,...

查看寄存器

info registers

查看棧參數(shù)

info args

查看局部變量

info locals

查看內(nèi)存

x

修改內(nèi)存

set *(unsigned int*)0x800000000=0x00000000

斷點(diǎn)

break [PROBE_MODIFIER] [LOCATION] [thread THREADNUM] [if CONDITION]
clear [LOCATION]

break *0x4000000  絕對(duì)地址
break 12          行號(hào)
break func1       函數(shù)
clear *0x40000000
clear 12
clear func1

一次斷點(diǎn)

tbreak [PROBE_MODIFIER] [LOCATION] [thread THREADNUM] [if CONDITION]

條件/線(xiàn)程斷點(diǎn)

break func1 thread1 if i==0

觀察斷點(diǎn)

watch/awatch/ rwatch [-l|-location] EXPRESSION      變化/讀寫(xiě)/讀斷點(diǎn)
(如果EXPRESSION不是絕對(duì)地址,則需要用-l計(jì)算表達(dá)式)
watch *0x40000000==0x90909090
watch –l *$pc
watch i   (有源碼,變量i的值有變化時(shí)停止)

范圍斷點(diǎn)

break-range START-LOCATION, END-LOCATION
break-range 1.c:5, 1.c:10  在1.c的第5行和第10行之間下斷
break-range +5, +10 在當(dāng)前行+5和當(dāng)前行+10之間下斷

硬件斷點(diǎn)

普通硬斷 hbreak [PROBE_MODIFIER] [LOCATION] [thread THREADNUM] [if CONDITION]
臨時(shí)硬斷 thbreak [PROBE_MODIFIER] [LOCATION] [thread THREADNUM] [if CONDITION]

攔截當(dāng)前函數(shù)退出

xbreak

捕獲斷點(diǎn)

普通補(bǔ)斷 catch [assert|catch|exception|exec|fork|load|rethrow|signal|syscall|throw|unload|vfork]
臨時(shí)捕斷 tcatch [assert|catch|exception|exec|fork|load|rethrow|signal|syscall|throw|unload|vfork]

如何使程序在so加載時(shí)刻斷下??(網(wǎng)上不少人用奇葩方式,還是對(duì)gdb不了解)
catch load 1.so

跟蹤斷點(diǎn)

strace [LOCATION] [IF CONDITION]

查看調(diào)用棧

bt [N] 顯示N層調(diào)用棧
bt full 顯示全部調(diào)用棧

流程控制

行為 命令
運(yùn)行時(shí)中斷 Ctrl+C
結(jié)束程序 kill
單步步過(guò) next
單步步入 step
單步步過(guò)(指令級(jí)) nexti
單步步入(指令級(jí)) stepi
繼續(xù)運(yùn)行 continue
執(zhí)行到當(dāng)前函數(shù)指定位置 advance
分離進(jìn)程 detach
強(qiáng)制跳轉(zhuǎn) jump

反向調(diào)試

reverse-continue reverse-next reverse-search reverse-stepi reverse-finish reverse-next reverse-step

顯示當(dāng)前加載模塊

info shared

強(qiáng)制加載模塊

可以用于做二進(jìn)制對(duì)比

(gdb) load C:/Users/lichao26/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.

替換當(dāng)前調(diào)試模塊

file c:/1.so

進(jìn)程轉(zhuǎn)儲(chǔ)

gcore

進(jìn)程空間

??進(jìn)程空間inferior,用于調(diào)試多個(gè)進(jìn)程,fork函數(shù)會(huì)自動(dòng)添加進(jìn)程空間

操作 指令
添加進(jìn)程空間 add-inferior
復(fù)制進(jìn)程空間 clone-inferior 1
刪除進(jìn)程空間 remove-inferior 1
切換進(jìn)程空間 inferior 2
分離進(jìn)程空間 detach inferior 2

由地址獲對(duì)應(yīng)的符號(hào)

maintenance translate-address [address]

查找符號(hào)

info functions [regex]   定位地址
info symbol address      定位文件
info variables [regex]   全局靜態(tài)符號(hào)

執(zhí)行外部命令

目標(biāo)系統(tǒng):! [command]
主機(jī)系統(tǒng):shell [command]

顯示線(xiàn)程

info threads

打印c++對(duì)象虛表

info vtbl

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容