[技术]Android APK一键脱壳(腾讯乐固、360加固)
概述
现在使用Proguard进行混淆的代码,也很容易被破解,所以就出现了加固工具,让反编译的难度更大。但是有了加固技术,就会有反加固技术,正所谓道高一尺魔高一丈。
经过加固后的apk,通过dex2jar
反编译:
腾讯乐固:
360加固:
从上面可以看出,经过加固后的apk,通过常规方法反编译无法获取到源码。
下载工具
脱壳工具FDex2
通过Hook ClassLoader的loadClass方法,反射调用getDex方法取得Dex(com.android.dex.Dex类对象),在将里面的dex写出。
下载地址:
VirtualXposed
脱壳
Step1:
将VirtualXposed
、FDex2
和需要脱壳的应用都安装到手机上。
Step2:
启动VirtualXposed
,并在VirtualXposed
中安装FDex2
:
Step3:
在VirtualXposed
中激活FDex2
:
Step4:
在VirtualXposed
中安装要脱壳的应用,方法和Step2一样。
Step5:
启动VirtualXposed
中的FDex2
,并配置要脱壳的应用。
Step6:
在VirtualXposed
中运行要脱壳的应用。
Step7:
脱壳后的dex文件:
导出脱壳的dex文件:
root设备:
adb root adb pull /data/user/0/iv.va.exposed/virtual/data/user/0/{packageName} {电脑上的目录}
未root设备:
在VirtualXposed
中,设置–>高级设置–>文件管理,安装文件管理器,然后通过文件管理器进入到指定的目录,通过分享
功能发到电脑上。
Step8:
通过dex2jar
对 脱壳的dex进行反编译:
从上图就可以看到脱壳后的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("文件写出失败"); } } }
褡裢
2020年9月15日 18:39
你好 我拖出来的文件夹之比/data/data/pkgName 里面的东西多了三个文件夹:/lib、/.jiagu、 /.oabugaij 没有找到dex文件……请问是哪里出问题了吗?
adb pull /data/user/0/io.va.exposed/virtual/data/user/0/pkgName
褡裢
2020年9月15日 18:15
你好,显示“这台设备不支持本软件” 已root的oppo手机,请问这个软件现在适配哪些手机啊?
niu
2019年11月6日 18:35
然而未ROOT设备 打不开要脱壳的应用