Android逆向入門(mén)流程

0.寫(xiě)在前面

本文是筆者自學(xué)筆記,以破解某目標(biāo)apk的方式進(jìn)行學(xué)習(xí),中間輔以原理性知識(shí),方便面試需求。
參考文章的原文鏈接會(huì)附在相應(yīng)流程位置,方便閱讀學(xué)習(xí)。

逆向分析流程.jpg

1.獲取目標(biāo)apk

第一步是拿到目標(biāo)安裝包文件,這一步很簡(jiǎn)單,可以在主流的第三方市場(chǎng)內(nèi)獲取,但是主流的第三方市場(chǎng)都要求應(yīng)用加固,為了之后方便,筆者常常去app的官網(wǎng)下載,或者去一些小市場(chǎng)下載,運(yùn)氣好的話能下載到他們的未加固版本。

2.確定逆向目標(biāo)

這個(gè)就看各自需求,比如有破解內(nèi)購(gòu),分析反逆向邏輯,crackme題目,查看競(jìng)品實(shí)現(xiàn)方式,確定好目標(biāo)再下手。

3.拖動(dòng)目標(biāo)文件到集成工具

直接拖apk到集成工具,如改之理,比如jadx,這里是為了檢查有沒(méi)有加固。
附上一些必要的開(kāi)發(fā)工具下載地址
http://www.itdecent.cn/p/b33eb2f5efa0

4.加固

這里判斷很好判斷,形如有StubShell的包,都是被加固了的。
那接下來(lái)就是要脫殼了。

4.1加固原理

脫殼之前,了解殼是什么(加固原理)。
http://www.itdecent.cn/p/cec7ef861ace

加殼
https://mp.weixin.qq.com/s/KELi6e6x4-svGP6Ef6r4jQ

殼的加載
https://mp.weixin.qq.com/s/AYZ7k75IlKLDbAIJZ2BelA

so的加載
https://mp.weixin.qq.com/s/BhGxnJrRnrYAEWJ7zDZKmQ

還可能涉及到,so指令膨脹(加花),指令抽取等防護(hù)。

4.2脫殼

接下來(lái)才是脫殼
脫殼還可能涉及到指令修復(fù)

殼的指令修復(fù)
https://mp.weixin.qq.com/s/-vrDvp3rbTKNIX-pAlamVw

4.2.1手脫

手脫的麻煩點(diǎn)就在于過(guò)各種檢測(cè),過(guò)完所有的檢測(cè)最終就是找到dex的內(nèi)存地址,最后運(yùn)行代碼進(jìn)行dump

鏈接是收集各種手工脫殼的帖子
http://www.itdecent.cn/p/3f6bcf364197

4.2.2機(jī)脫

實(shí)際上就是各種脫殼機(jī),原理就是
無(wú)論什么殼,最終都是要加載到內(nèi)存中,等apk已經(jīng)加載到內(nèi)存后,脫殼機(jī)把dex dump出來(lái)就行了,也就省去了手工脫殼的麻煩。

這里的原理可參考
Android中apk加固完善篇之內(nèi)存加載dex方案實(shí)現(xiàn)原理(不落地方式加載)
http://www.520monkey.com/archives/629

原理主要討論了兩個(gè)問(wèn)題
如果解密后有一個(gè)未加密的apk做中間產(chǎn)物,那就是落地方式,這個(gè)方式已經(jīng)被淘汰了,因?yàn)椴话踩?br> 如果不落地則可能出現(xiàn)加載兩次到內(nèi)存的效率問(wèn)題。

這里不深研,只提供一個(gè)脫殼機(jī),fdex2
看雪原帖(也說(shuō)了原理)
https://bbs.pediy.com/thread-224105.htm
52破解帖
https://www.52pojie.cn/forum.php?mod=viewthread&tid=758726&fromguid=hot
推薦另一個(gè)機(jī)脫dumpDex
https://github.com/WrBug/dumpDex

核心代碼,有空可以看
package com.ppma.xposed;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Method;

import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XSharedPreferences;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage;

public class MainHook implements IXposedHookLoadPackage {

    XSharedPreferences xsp;
    Class Dex;
    Method Dex_getBytes;
    Method getDex;
    String packagename;


    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
        xsp = new XSharedPreferences("com.ppma.appinfo", "User");
        xsp.makeWorldReadable();
        xsp.reload();
        initRefect();
        packagename = xsp.getString("packagename", null);
        XposedBridge.log("設(shè)定包名:"+packagename);
        if ((!lpparam.packageName.equals(packagename))||packagename==null) {
            XposedBridge.log("當(dāng)前程序包名與設(shè)定不一致或者包名為空");
            return;
        }
        XposedBridge.log("目標(biāo)包名:"+lpparam.packageName);
        String str = "java.lang.ClassLoader";
        String str2 = "loadClass";

        XposedHelpers.findAndHookMethod(str, lpparam.classLoader, str2, String.class, Boolean.TYPE, new XC_MethodHook() {
            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                super.afterHookedMethod(param);
                Class cls = (Class) param.getResult();
                if (cls == null) {
                    //XposedBridge.log("cls == null");
                    return;
                }
                String name = cls.getName();
                XposedBridge.log("當(dāng)前類名:" + name);
                byte[] bArr = (byte[]) Dex_getBytes.invoke(getDex.invoke(cls, new Object[0]), new Object[0]);
                if (bArr == null) {
                    XposedBridge.log("數(shù)據(jù)為空:返回");
                    return;
                }
                XposedBridge.log("開(kāi)始寫(xiě)數(shù)據(jù)");
                String dex_path = "/data/data/" + packagename + "/" + packagename + "_" + bArr.length + ".dex";
                XposedBridge.log(dex_path);
                File file = new File(dex_path);
                if (file.exists()) return;
                writeByte(bArr, file.getAbsolutePath());
            }
            } );
    }

    public void initRefect() {
        try {
            Dex = Class.forName("com.android.dex.Dex");
            Dex_getBytes = Dex.getDeclaredMethod("getBytes", new Class[0]);
            getDex = Class.forName("java.lang.Class").getDeclaredMethod("getDex", new Class[0]);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }

    }

    public  void writeByte(byte[] bArr, String str) {
        try {
            OutputStream outputStream = new FileOutputStream(str);
            outputStream.write(bArr);
            outputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
            XposedBridge.log("文件寫(xiě)出失敗");
        }
    }
}

4.3得到.dex文件

dex文件是什么
java,dex,smali,關(guān)系/區(qū)別又是什么
http://www.itdecent.cn/p/fb9aec070c0a
延展閱讀
dex直接得到smali,插入log代碼再回編譯dex
https://blog.csdn.net/jiangwei0910410003/article/details/79820040

涉及到兩個(gè)語(yǔ)句

java -jar baksmali.jar -o classes classes.dex 其中classes是反編譯dex之后的smali文件夾目錄

java -jar smali.jar classes -o classes.dex 其中classes是反編譯的smali目錄,classes.dex是回編譯之后的dex

5.集成工具分析

其實(shí)就是可以把剛才拿到的.dex拖進(jìn)來(lái)分析了

6.減少混淆干擾

apk在打包時(shí)會(huì)被混淆,文件名被替換成影響無(wú)意義的字母甚至漢字。
jdax通過(guò)以下設(shè)置來(lái)減少混淆干擾
https://segmentfault.com/a/1190000012180752

發(fā)散:proguard的源碼閱讀
http://www.itdecent.cn/p/734424a14eff

7.定位目標(biāo)

借助第三方工具
比如adb工具
https://blog.csdn.net/halibobo1998/article/details/50623929

或者有一部已經(jīng)root的機(jī)器(可以減少很多麻煩),使用layoutInspector去查布局找id

簡(jiǎn)單的就下一個(gè)第三方app 當(dāng)前activity

還可以通過(guò)搜索界面里的特殊字串來(lái)定目標(biāo)文件。
因?yàn)橘Y源字串無(wú)論怎么混淆,反編譯出來(lái)的public.xml一定有對(duì)應(yīng)的int值

8.分析業(yè)務(wù)邏輯

9.確定逆向方法

比如想通過(guò)xposed框架去hook某個(gè)結(jié)果,還是直接nop掉某個(gè)返回值。

10.使用apktool進(jìn)行反編譯

執(zhí)行代碼

apktool d -f 目標(biāo)apk路徑

這里可能遇到殼利用apktool漏洞對(duì)其進(jìn)行的干擾
http://www.520monkey.com/archives/808

11.得到.smali

smali語(yǔ)法
http://www.itdecent.cn/p/54e893ae28ea
空類的smali結(jié)構(gòu)
http://www.itdecent.cn/p/758bccaaa0a6

12.源碼調(diào)試

靜態(tài)調(diào)試
http://www.itdecent.cn/p/4359598a2c9b

動(dòng)態(tài)調(diào)試
http://www.itdecent.cn/p/90f495191a6a

動(dòng)態(tài)調(diào)試so
http://www.itdecent.cn/p/5617220cbb02

13.回編譯 app

執(zhí)行命令

apktool b -d 資源路徑 -o 輸出.apk

可能會(huì)遇到回編譯失敗的情況,比如低版本的apktool不認(rèn)識(shí)高Android版本的屬性,可以選擇升級(jí)apktool或者刪除該屬性值。

14.簽名

執(zhí)行命令

apksigner sign --ks testKey.jks --ks-key-alias testkey --ks-pass pass:123456 --key-pass pass:123456 --out output_sign.apk source.apk

參考

Android逆向分析筆記
https://lichao890427.github.io/wiki/android%20reverse%20engineering/#%E6%A6%82%E8%BF%B0

adb指令
http://www.itdecent.cn/p/85373d89bc81

bugly出的一篇反調(diào)總結(jié)
大部分方法都寫(xiě)過(guò),少部分如文件節(jié)點(diǎn),inotify,so hash檢測(cè)可以加以了解(就是我沒(méi)寫(xiě)過(guò))
https://mp.weixin.qq.com/s/uvrkAvbfWuDYf7SWX_dJBA

todo

還有smali,baksmali沒(méi)寫(xiě)上去,還有教我兄弟學(xué)逆向,臥槽還有好多。。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • afinalAfinal是一個(gè)android的ioc,orm框架 https://github.com/yangf...
    passiontim閱讀 15,835評(píng)論 2 45
  • ??Android系統(tǒng)由于其開(kāi)源的屬性,市場(chǎng)上針對(duì)開(kāi)源代碼定制的ROM參差不齊,在系統(tǒng)層面的安全防范和易損性都不一...
    道書(shū)簡(jiǎn)閱讀 9,673評(píng)論 0 23
  • 1、網(wǎng)絡(luò)請(qǐng)求——裸奔的數(shù)據(jù) 無(wú)論是網(wǎng)頁(yè)還是APP,都不可避免與后臺(tái)服務(wù)進(jìn)行訪問(wèn),可能從服務(wù)器獲取數(shù)據(jù)或者提交數(shù)據(jù)到...
    dfqin閱讀 10,271評(píng)論 0 16
  • 文/梅香 詞林正韻 冰雪消融陽(yáng)和煦,柳綠桃紅,芳菲隨風(fēng)吐,彩蝶聞香翩舞赴,南歸紫燕誰(shuí)家顧。 倩女思親花下駐。春意盈...
    流浪的狗尾巴草閱讀 510評(píng)論 2 6
  • 姓名:庹亞軍 公司:寧波貞觀電器有限公司 組別:第235期 利他一組 【日精進(jìn)打卡第 43天】 【知~學(xué)習(xí)】 《六...
    tyj小電工閱讀 305評(píng)論 0 0

友情鏈接更多精彩內(nèi)容