Android DEX加壳

此文的源码测试过,除了下面这个问题之外,基本没有什么大问题:

package com.android.dexunshell;

import java.io.IOException;
import java.net.URL;
import java.util.Enumeration;

import com.eebbk.mingming.k7utils.ReflectUtils;

import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;

import dalvik.system.DexClassLoader;
import dalvik.system.DexFile;

public class DynamicDexClassLoder extends DexClassLoader {
     private static final String TAG = DynamicDexClassLoder.class.getName();
     private int cookie;
     private Context mContext;

     /**
      * 原构造
      *
      * @param dexPath
      * @param optimizedDirectory
      * @param libraryPath
      * @param parent
      */
     public DynamicDexClassLoder(String dexPath, String optimizedDirectory,
                        String libraryPath, ClassLoader parent) {
               super(dexPath, optimizedDirectory, libraryPath, parent);
     }

     /**
      * 直接从内存加载 新构造
      *
      * @param dexBytes
      * @param libraryPath
      * @param parent
      * @throws Exception
      */

     public DynamicDexClassLoder(Context context, byte[] dexBytes,
                        String libraryPath, ClassLoader parent, String oriPath,
                        String fakePath) {
               super(oriPath, fakePath, libraryPath, parent);
               setContext(context);
               setCookie(NativeTool.loadDex(dexBytes, dexBytes.length));
     }

     private void setCookie(int kie) {
               cookie = kie;
     }

     private void setContext(Context context) {
               mContext = context;
     }

     private String[] getClassNameList(int cookie) {
               return (String[]) ReflectUtils.invokeStaticMethod(DexFile.class,
                                 "getClassNameList", new Class[] { int.class },
                                 new Object[] { cookie });
     }

     private Class defineClass(String name, ClassLoader loader, int cookie) {
               return (Class) ReflectUtils.invokeStaticMethod(DexFile.class,
                                 "defineClass", new Class[] { String.class, ClassLoader.class,
                                                    int.class }, new Object[] { name, loader, cookie });
     }

     @Override
     protected Class<?> findClass(String name) throws ClassNotFoundException {
               Log.d(TAG, "findClass-" + name);
               Class<?> cls = null;

               String as[] = getClassNameList(cookie);
               for (int z = 0; z < as.length; z++) {
                        if (as[z].equals(name)) {
                                 cls = defineClass(as[z].replace('.', '/'),
                                                    mContext.getClassLoader(), cookie);
                                 break;
                        } else {
                                 defineClass(as[z].replace('.', '/'), mContext.getClassLoader(),
                                                    cookie);
                        }
               }

               if (null == cls) {
                        cls = super.findClass(name);
               }

               return cls;
     }

     @Override
     protected URL findResource(String name) {
               Log.d(TAG, "findResource-" + name);
               return super.findResource(name);
     }

     @Override
     protected Enumeration<URL> findResources(String name) {
               Log.d(TAG, "findResources ssss-" + name);
               return super.findResources(name);
     }

     @Override
     protected synchronized Package getPackage(String name) {
               Log.d(TAG, "getPackage-" + name);
               return super.getPackage(name);
     }

     @Override
     protected Class<?> loadClass(String className, boolean resolve)
                        throws ClassNotFoundException {
               Log.d(TAG, "loadClass-" + className + " resolve " + resolve);
               Class<?> clazz = super.loadClass(className, resolve);
               if (null == clazz) {
                        Log.e(TAG, "loadClass fail,maybe get a null-point exception.");
               }
               return clazz;
     }

     @Override
     protected Package[] getPackages() {
               Log.d(TAG, "getPackages sss-");
               return super.getPackages();
     }

     @Override
     protected Package definePackage(String name, String specTitle,
                        String specVersion, String specVendor, String implTitle,
                        String implVersion, String implVendor, URL sealBase)
                        throws IllegalArgumentException {
               Log.d(TAG, "definePackage" + name);
              return super.definePackage(name, specTitle, specVersion, specVendor,
                                 implTitle, implVersion, implVendor, sealBase);
     }
}

注意:函数findClass处的改动!

已经定义过的类不需要重新再定义,否则会导致app陷入无限循环,启动时有卡死状!

在做ndk dex加密时,壳与被加密程序在通常是捆绑在一个APK包中。如果APP中libs目录下有so库,此时需要重写findLibrary函数,从getClass().getClassLoader()获取路径!否则,你需要自己把.so文件存到手机某个地方,然后把路径返回给出来!

ndk解壳形式安全性比较高,但是内存加载dex所依赖的底层方法,只在4.0以上几个版本存在,5.0没有查询还是未知数,还没能满足通用性的要求,要需要进一步寻找方案。

Ref: http://taoyuanxiaoqi.com/2015/01/16/apkshell2/

posted @ 2020-03-16 10:27  opencoder  阅读(399)  评论(0编辑  收藏  举报