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 @   opencoder  阅读(400)  评论(0编辑  收藏  举报
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示