zoukankan      html  css  js  c++  java
  • 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的原理。

  • 相关阅读:
    android之手机震动Vibrate
    Android中Spinner下拉列表(使用ArrayAdapter和自定义Adapter实现) .
    用AutoCompleteTextView实现历史记录提示
    AutoCompleteTextView
    android学习笔记7--------MVC设计模式
    Android之MVC模式
    Android中常见的MVC模式
    //11个整数的手机号码正则式 phoneNumber(String number)
    YuvImage知识点总结
    运行项目的时候出现missing frature:WATCH
  • 原文地址:https://www.cnblogs.com/it-tsz/p/13692591.html
Copyright © 2011-2022 走看看