1. 程式人生 > >Android APK脫殼--騰訊樂固、360加固一鍵脫殼

Android APK脫殼--騰訊樂固、360加固一鍵脫殼

概述

現在使用Proguard進行混淆的程式碼,也很容易被破解,所以就出現了加固工具,讓反編譯的難度更大。但是有了加固技術,就會有反加固技術,正所謂道高一尺魔高一丈。

經過加固後的apk,通過dex2jar反編譯:

騰訊樂固:

legu.png

360加固:

360jiagu.png

從上面可以看出,經過加固後的apk,通過常規方法反編譯無法獲取到原始碼。

下載工具

脫殼工具FDex2

通過Hook ClassLoader的loadClass方法,反射呼叫getDex方法取得Dex(com.android.dex.Dex類物件),在將裡面的dex寫出。

下載地址:

連結:https://pan.baidu.com/s/1smxtinr 密碼:dk4v

VirtualXposed

VirtualXposed:無需root手機即可使用xp框架。

下載地址:

https://vxposed.com/

脫殼

Step1:

VirtualXposedFDex2需要脫殼的應用都安裝到手機上。

Step2:

啟動VirtualXposed,並在VirtualXposed中安裝FDex2:

vp-install-fdex2.gif

Step3:

VirtualXposed

中啟用FDex2:

active-fdex2.gif

Step4:

VirtualXposed中安裝要脫殼的應用,方法和Step2一樣。

Step5:

啟動VirtualXposed中的FDex2,並配置要脫殼的應用。

fdex2-config.png

Step6:

VirtualXposed中執行要脫殼的應用。

Step7:

脫殼後的dex檔案:

shelling-dex.png

匯出脫殼的dex檔案:

root裝置:

adb root
adb pull /data/user/0/iv.va.exposed/virtual/data/user/0/{packageName}   {電腦上的目錄}

未root裝置:

VirtualXposed中,設定-->高階設定-->檔案管理,安裝檔案管理器,然後通過檔案管理器進入到指定的目錄,通過分享功能發到電腦上。

Step8:

通過dex2jar對 脫殼的dex進行反編譯:

shelling-dex2jar.png

從上圖就可以看到脫殼後的dex檔案被成功的反編譯。

FDex2核心程式碼MainHook

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("檔案寫出失敗");
        }
    }
}

參考連結

  1. 【手機端】騰訊樂固,360加固一鍵脫殼
  2. 安卓xposed脫殼工具FDex2