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


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

102018.09.28 17:22:18字數 478閱讀 81,487

概述

現在使用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("文件寫出失敗"); } } } 

參考鏈接


免責聲明!

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



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