Android APK脫殼(轉)


轉https://zhuanlan.zhihu.com/p/70894166

概述

眾所周知,Android應用開發完成后,除了使用Google官方的混淆外,還需要使用一些第三方的安全軟件的加殼處理,比較出名的有騰訊樂固、360加固和愛加密等。我之前所在的公司,就是使用愛加密進行加殼處理的。

雖然加密后,讓軟件的安全性更高了,但並不是無懈可擊,一些反加固技術和脫殼技術應運而生。今天要說的就是騰訊樂固、360加固一鍵脫殼。

工程,經過加固后的apk,通過dex2jar反編譯效果是下面這樣的:

騰訊樂固加固:

360加固

可以發現,經過加固處理由,反編譯是無法直接獲取到源碼的,代碼的結構如下圖所示:

 

工具

要對Android的apk文件進行脫殼,需要使用的軟件有:

  • FDex2
  • VirtualXposed 不過,需要說明的是,此技術在Android9.0及以上版本是行不通的,並且VirtualXposed有軟件版本限制。

FDex2

下載地址: 鏈接:  提取碼: asu1

備用下載:https://089u.com/dir/3843664-40606878-902c5f

VirtualXposed

VirtualXposed:無需root手機即可使用Xposed框架 下載鏈接(國內需要梯子): 

脫殼

首先,將VirtualXposed、FDex2和需要脫殼的應用都安裝到手機上。然后,啟動VirtualXposed,並在VirtualXposed中安裝FDex2。

然后,在VirtualXposed中選擇模塊管理激活FDex2。

在VirtualXposed中安裝要脫殼的應用,具體和上面的步驟一樣。然后,啟動VirtualXposed中的FDex2,並配置要脫殼的應用。

在VirtualXposed中運行要脫殼的應用,脫殼后的dex文件如下圖:

然后,使用adb pull命令將脫殼后的dex文件導出到電腦。

adb pull /data/user/0/iv.va.exposed/virtual/data/user/0/{packageName}

最后,再通過dex2jar對 脫殼的dex進行反編譯。

 

FDex2核心代碼

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("設定包名:"+packagename);
        if ((!lpparam.packageName.equals(packagename))||packagename==null) {
            XposedBridge.log("當前程序包名與設定不一致或者包名為空");
            return;
        }
        XposedBridge.log("目標包名:"+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("當前類名:" + name);
                byte[] bArr = (byte[]) Dex_getBytes.invoke(getDex.invoke(cls, new Object[0]), new Object[0]);
                if (bArr == null) {
                    XposedBridge.log("數據為空:返回");
                    return;
                }
                XposedBridge.log("開始寫數據");
                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("文件寫出失敗");
        }
    }
}

通過Hook ClassLoader的loadClass方法,反射調用getDex方法取得Dex(com.android.dex.Dex類對象),再將里面的dex寫出,這就是Hook的原理。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM