Android APK脫殼

概述

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

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

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

騰訊樂固加固:
在這裏插入圖片描述
360加固
在這裏插入圖片描述
能夠發現,通過加固處理由,反編譯是沒法直接獲取到源碼的,代碼的結構以下圖所示:
在這裏插入圖片描述app

工具

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

  • FDex2
  • VirtualXposed

不過,須要說明的是,此技術在Android9.0及以上版本是行不通的,而且VirtualXposed有軟件版本限制。工具

FDex2

下載地址:
連接: https://pan.baidu.com/s/10ZfD... 提取碼: asu1加密

VirtualXposed

VirtualXposed:無需root手機便可使用Xposed框架
下載連接:
https://vxposed.com/spa

脫殼

首先,將VirtualXposed、FDex2和須要脫殼的應用都安裝到手機上。而後,啓動VirtualXposed,並在VirtualXposed中安裝FDex2。
在這裏插入圖片描述
而後,在VirtualXposed中選擇模塊管理激活FDex2。
在這裏插入圖片描述
在VirtualXposed中安裝要脫殼的應用,具體和上面的步驟同樣。而後,啓動VirtualXposed中的FDex2,並配置要脫殼的應用。
在這裏插入圖片描述
在VirtualXposed中運行要脫殼的應用,脫殼後的dex文件以下圖:
在這裏插入圖片描述
而後,使用adb pull命令將脫殼後的dex文件導出到電腦。code

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的原理。

相關文章
相關標籤/搜索