• 基于dalvik模式下的Xposed Hook开发的某加固脱壳工具


    本文博客地址:http://blog.csdn.net/qq1084283172/article/details/77966109


    这段时间好好的学习了一下Android加固相关的知识和流程也大致把Android加固的一些思路理清楚了,不巧在博客上看到了这篇文章《某加固使用xposed脱壳》感觉还不错,正好有时间可以学习一下这款基于Xposed Hook框架开发的某加固脱壳工具,原作者的博客已经找不到但是作者已经给出了主要的实现代码,我在作者给出的原代码基础上稍微做了一下修改和优化并且在Android Nexus 5手机上测试某加固的脱壳,成功得到了某加固解密后的dex文件。在进行源码分析之前,你需要了解Xposed Hook框架模块编写相关的知识,还不了解的可以先看下我前面的博客《Xposed框架之函数Hook学习》。Android加固的实现是基于DexClassLoader的加载流程来实现的,具体详细的流程后面有时间再整理一下,因此这里使用Xposed Hook框架来脱某加固壳的工具也是基于DexClassLoader的加载流程来实现的。


    下图是DexClassLoader在整个java层的实现流程:




    DexClassLoader到openDexFileNative函数的整个流程下来,DexClassLoader的java层实现全部完成,openDexFileNative之后是由native层函数实现,暂时不关心;dex文件的加固是基于DexClassLoader的加载流程而来的,dex文件优化为odex文件后加载到apk进程的内存中返回是mCookie值,这个mCookie值就是dex文件加载到内存之后的镜像描述结构体指针DexOrJar* ,DexOrJar结构体的实现如下图所示:

    http://androidxref.com/4.4.4_r1/xref/dalvik/vm/native/dalvik_system_DexFile.cpp#DexOrJar

    /*
     * Internal struct for managing DexFile.
     */
    struct DexOrJar {
    	
    	// 描述的dex文件或者jar文件的路径
        char*       fileName;
    	// 是否是dex文件的标识
        bool        isDex;
        bool        okayToFree;
    	// 描述dex文件内存加载镜像odex文件的结构体
        RawDexFile* pRawDexFile;
    	// 描述内存加载后的jar文件的结构体
        JarFile*    pJarFile;
        u1*         pDexMemory; // malloc()ed memory, if any
    };

    openDexFileNative在native层对应的实现函数是 Dalvik_dalvik_system_DexFile_openDexFileNative。

    http://androidxref.com/4.4.4_r1/xref/dalvik/vm/native/dalvik_system_DexFile.cpp#151

    // 对应函数的注册结构体
    const DalvikNativeMethod dvm_dalvik_system_DexFile[] = {
        { "openDexFileNative",  "(Ljava/lang/String;Ljava/lang/String;I)I",
            Dalvik_dalvik_system_DexFile_openDexFileNative },
        { "openDexFile",        "([B)I",
            Dalvik_dalvik_system_DexFile_openDexFile_bytearray },
        { "closeDexFile",       "(I)V",
            Dalvik_dalvik_system_DexFile_closeDexFile },
        { "defineClassNative",  "(Ljava/lang/String;Ljava/lang/ClassLoader;I)Ljava/lang/Class;",
            Dalvik_dalvik_system_DexFile_defineClassNative },
        { "getClassNameList",   "(I)[Ljava/lang/String;",
            Dalvik_dalvik_system_DexFile_getClassNameList },
        { "isDexOptNeeded",     "(Ljava/lang/String;)Z",
            Dalvik_dalvik_system_DexFile_isDexOptNeeded },
        { NULL, NULL, NULL },
    };
    /*
     * private static int openDexFileNative(String sourceName, String outputName,
     *     int flags) throws IOException
     *
     * Open a DEX file, returning a pointer to our internal data structure.
     *
     * "sourceName" should point to the "source" jar or DEX file.
     *
     * If "outputName" is NULL, the DEX code will automatically find the
     * "optimized" version in the cache directory, creating it if necessary.
     * If it's non-NULL, the specified file will be used instead.
     *
     * TODO: at present we will happily open the same file more than once.
     * To optimize this away we could search for existing entries in the hash
     * table and refCount them.  Requires atomic ops or adding "synchronized"
     * to the non-native code that calls here.
     *
     * TODO: should be using "long" for a pointer.
     */
    static void Dalvik_dalvik_system_DexFile_openDexFileNative(const u4* args,
        JValue* pResult)
    {
        StringObject* sourceNameObj = (StringObject*) args[0];
        StringObject* outputNameObj = (StringObject*) args[1];
        DexOrJar* pDexOrJar = NULL;
        JarFile* pJarFile;
        RawDexFile* pRawDexFile;
        char* sourceName;
        char* outputName;
    
        if (sourceNameObj == NULL) {
            dvmThrowNullPointerException("sourceName == null");
            RETURN_VOID();
        }
    
        sourceName = dvmCreateCstrFromString(sourceNameObj);
        if (outputNameObj != NULL)
            outputName = dvmCreateCstrFromString(outputNameObj);
        else
            outputName = NULL;
    
        /*
         * We have to deal with the possibility that somebody might try to
         * open one of our bootstrap class DEX files.  The set of dependencies
         * will be different, and hence the results of optimization might be
         * different, which means we'd actually need to have two versions of
         * the optimized DEX: one that only knows about part of the boot class
         * path, and one that knows about everything in it.  The latter might
         * optimize field/method accesses based on a class that appeared later
         * in the class path.
         *
         * We can't let the user-defined class loader open it and start using
         * the classes, since the optimized form of the code skips some of
         * the method and field resolution that we would ordinarily do, and
         * we'd have the wrong semantics.
         *
         * We have to reject attempts to manually open a DEX file from the boot
         * class path.  The easiest way to do this is by filename, which works
         * out because variations in name (e.g. "/system/framework/./ext.jar")
         * result in us hitting a different dalvik-cache entry.  It's also fine
         * if the caller specifies their own output file.
         */
        if (dvmClassPathContains(gDvm.bootClassPath, sourceName)) {
            ALOGW("Refusing to reopen boot DEX '%s'", sourceName);
            dvmThrowIOException(
                "Re-opening BOOTCLASSPATH DEX files is not allowed");
            free(sourceName);
            free(outputName);
            RETURN_VOID();
        }
    
        /*
         * Try to open it directly as a DEX if the name ends with ".dex".
         * If that fails (or isn't tried in the first place), try it as a
         * Zip with a "classes.dex" inside.
         */
        if (hasDexExtension(sourceName)
                && dvmRawDexFileOpen(sourceName, outputName, &pRawDexFile, false) == 0) {
            ALOGV("Opening DEX file '%s' (DEX)", sourceName);
    
            pDexOrJar = (DexOrJar*) malloc(sizeof(DexOrJar));
            pDexOrJar->isDex = true;
            pDexOrJar->pRawDexFile = pRawDexFile;
            pDexOrJar->pDexMemory = NULL;
        } else if (dvmJarFileOpen(sourceName, outputName, &pJarFile, false) == 0) {
            ALOGV("Opening DEX file '%s' (Jar)", sourceName);
    
            pDexOrJar = (DexOrJar*) malloc(sizeof(DexOrJar));
            pDexOrJar->isDex = false;
            pDexOrJar->pJarFile = pJarFile;
            pDexOrJar->pDexMemory = NULL;
        } else {
            ALOGV("Unable to open DEX file '%s'", sourceName);
            dvmThrowIOException("unable to open DEX file");
        }
    
        if (pDexOrJar != NULL) {
            pDexOrJar->fileName = sourceName;
            addToDexFileTable(pDexOrJar);
        } else {
            free(sourceName);
        }
    
        free(outputName);
        RETURN_PTR(pDexOrJar);
    }

    基于Xposed Hook开发的某加固脱壳工具是使用Xposed Hook框架Hook掉 DexClassLoader加载dex文件流程中类dalvik.system.DexFile的方法loadDex函数,等到loadDex函数返回时拿到dex文件内存加载后的mCookie值,然后内存dump出mCookie值描述的dex文件的值。类dalvik.system.DexFile的loadDex函数的实现如下:

    http://androidxref.com/4.4.4_r1/xref/libcore/dalvik/src/main/java/dalvik/system/DexFile.java#141

        /**
         * Open a DEX file, specifying the file in which the optimized DEX
         * data should be written.  If the optimized form exists and appears
         * to be current, it will be used; if not, the VM will attempt to
         * regenerate it.
         *
         * This is intended for use by applications that wish to download
         * and execute DEX files outside the usual application installation
         * mechanism.  This function should not be called directly by an
         * application; instead, use a class loader such as
         * dalvik.system.DexClassLoader.
         *
         * @param sourcePathName
         *  Jar or APK file with "classes.dex".  (May expand this to include
         *  "raw DEX" in the future.)
         * @param outputPathName
         *  File that will hold the optimized form of the DEX data.
         * @param flags
         *  Enable optional features.  (Currently none defined.)
         * @return
         *  A new or previously-opened DexFile.
         * @throws IOException
         *  If unable to open the source or output file.
         */
        static public DexFile loadDex(String sourcePathName, String outputPathName,
            int flags) throws IOException {
    
            /*
             * TODO: we may want to cache previously-opened DexFile objects.
             * The cache would be synchronized with close().  This would help
             * us avoid mapping the same DEX more than once when an app
             * decided to open it multiple times.  In practice this may not
             * be a real issue.
             */
            return new DexFile(sourcePathName, outputPathName, flags);
        }

    1.某加固脱壳工具Xposed Hook模块的编写,xxx.yyy.zzz为需要被脱壳的apk应用的包名,Xposed Hook掉类dalvik.system.DexFile的方法loadDex函数,获取到dex文件内存加载后的mCookie值,然后进行内存dex文件的dump处理。

    package com.xposeddemo;
    
    import java.lang.reflect.Field;
    import dalvik.system.DexFile;
    import de.robv.android.xposed.IXposedHookLoadPackage;
    import de.robv.android.xposed.XC_MethodHook;
    import de.robv.android.xposed.XposedBridge;
    import de.robv.android.xposed.XposedHelpers;
    import de.robv.android.xposed.callbacks.XC_LoadPackage;
    import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam;
    
    
    public class Module implements IXposedHookLoadPackage {
    
    	// native方法在libnativelib.so库文件中实现
    	public native void dumpdex(int cookie);
    	
    	// 内部类
    	class dumpThread implements Runnable {
    		
    	    int cookide;
    	    public dumpThread(int cookide){
    	    	
    	    	// 保存dex文件的mCookie值
    	        this.cookide = cookide;
    	    }
    	
    	    @Override
    	    public void run() {
    	    	
    	        try {
    	        	
    	        	// 休眠5s 时间足够壳修复dex
    	            Thread.sleep(5000);
    	            
    	        } catch (InterruptedException e) {
    	        	
    	            e.printStackTrace();
    	        }
    	        
    	        // 从内存中dump出解密后的内存dex文件
    	        dumpdex(cookide);
    	    }
    	}
    
    	@Override
    	public void handleLoadPackage(LoadPackageParam lpparam) throws Throwable {
    		
    		// 判断是否是要Hook的包名(xxx.yyy.zzz为需要脱壳的apk的包名)
    		if (lpparam.packageName.equals("xxx.yyy.zzz")){
    			
    			XposedBridge.log("Loaded App:" + lpparam.packageName);
    			
    	    	// 加载动态库文件libnativelib.so
    	        System.load("/data/data/com.xposeddemo/lib/libnativelib.so");
    			
    			// 对类dalvik.system.DexFile的方法loadDex进行java Hook操作
    	        // 获取到需要脱壳apk解密dex文件加载后返回的mCookie值
    	        // 根据mCookie值进行内存dex文件的dump操作
    			loadhooklib(lpparam);
    		}
    	}
    	
    	 private void loadhooklib(XC_LoadPackage.LoadPackageParam lpparam) {
    		 
    		// 对类dalvik.system.DexFile的方法loadDex进行dalvik模式下的java Hook操作
    		// /libcore/dalvik/src/main/java/dalvik/system/DexFile.java
    		// static public DexFile loadDex(String sourcePathName, String outputPathName, int flags)
    		// http://androidxref.com/4.4.4_r1/xref/libcore/dalvik/src/main/java/dalvik/system/DexFile.java#141
            XposedHelpers.findAndHookMethod(DexFile.class.getName(), 
            		lpparam.classLoader, "loadDex", 
            		String.class, 
            		String.class, int.class,
            		new XC_MethodHook() {
        	
                    @Override
                    protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    	
                        if (!param.hasThrowable()) {
                        	
                            int falg = (Integer) param.args[2];
                            // 加载的dex文件的路径
                            String sourcePathName = (String) param.args[0];
                            // dex被优化后的odex文件的存放路径
                            String outputPathName = (String) param.args[1];
                            XposedBridge.log("sourcePathName:" + sourcePathName + " outputPathName:" 
                            				+ outputPathName + " falg:" + falg);
                            
                            // 获取dex文件被loadDex后返回的DexFile文件对象
                            Object object = param.getResult();
                            if (object instanceof DexFile) {
                            	
                            	// 通过类反射获取DexFile类的私有成员mCookie的调用Field
                                Field field = ((DexFile) object).getClass().getDeclaredField("mCookie");
                                // 设置有权限
                                field.setAccessible(true);
                                // 获取到DexFile类的私有成员mCookie的值
                                int cookie = field.getInt(object);
                                // 恢复权限
                                field.setAccessible(false);
                                System.out.println("cookie:" + String.format("%x", cookie));
                                
                                // 创建线程对需要脱壳的apk进程进行内存dex的dump操作
                                Thread thread = new Thread(new Module.dumpThread(cookie));
                                // 启动线程
                                thread.start();
                            }
                        }
                    }
                });
    	    }
    
    }


    2.内存dump函数实现在动态库文件libnativelib.so中实现,先通过jni函数反射调用java方法获取到手机设备的scard卡的文件路径,然后将内存dump的dex文件保存到手机设备的scard卡文件路径中。原作者在nativelib.cpp文件的源码实现中使用了C++的stl模板库函数,考虑到代码中字符串的处理比较简单,去掉了C++的stl模板库函数的使用,直接使用C语言的相关函数替换掉了,并且做了一些小调整;原作者在处理 code_off偏移超过dex文件大小的加固类型脱壳时比较暴力,直接保存三倍dex文件长度;如果dex文件内存dump时,想处理的精细一些可以参考一下dexHunter代码的实现。

    #include <jni.h>
    #include <stdio.h>
    #include <unistd.h>
    //#include <string>
    #include <android/log.h>
    #include "Object.h"
    
    //using std::string;
    
    char* getExternalStorageDirectory(JNIEnv* env);
    void printinfo(const char* tag, const char* fmt, ...);
    
    
    char* jstringTostring(JNIEnv* env, jstring str)
    {
        char* rtn = NULL;
        jclass clsstring = env->FindClass("java/lang/String");
        jstring strencode = env->NewStringUTF("utf-8");
        jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B");
        jbyteArray barr = (jbyteArray)env->CallObjectMethod(str, mid, strencode);
        jsize alen = env->GetArrayLength(barr);
        jbyte* ba = env->GetByteArrayElements(barr, JNI_FALSE);
        if (alen > 0)
        {
            rtn = (char*)malloc(alen + 1);
            memcpy(rtn, ba, alen);
            rtn[alen] = 0;
        }
        env->ReleaseByteArrayElements(barr, ba, 0);
    
        return rtn;
    }
    
    // 通过jni函数反射调用java方法获取到设备的scard卡的文件路径
    char* getExternalStorageDirectory(JNIEnv* env)
    {
        jclass Environment = env->FindClass("android/os/Environment");
        if (Environment != NULL)
        {
            //Messageprint::printinfo("util", "Environment class have found");
            jmethodID getExternalStorageDirectoryID = env->GetStaticMethodID(Environment,
            							"getExternalStorageDirectory", "()Ljava/io/File;");
            if (getExternalStorageDirectoryID != NULL)
            {
                jobject fileobject = env->CallStaticObjectMethod(Environment, getExternalStorageDirectoryID);
                jclass Fileclass = env->FindClass("java/io/File");
                jmethodID getAbsolutePathId = env->GetMethodID(Fileclass, "getAbsolutePath", "()Ljava/lang/String;");
                jstring jstringPath = (jstring)env->CallObjectMethod(fileobject, getAbsolutePathId);
                char* StorageDirectoryPath = jstringTostring(env, jstringPath);
                return StorageDirectoryPath;
            }
        }
    
        return NULL;
    }
    
    
    // 使用了stl的库函数
    #ifdef __cplusplus
    extern "C" {
    #endif
    
    // 调用native层实现的jni方法dumpdex
    JNIEXPORT void JNICALL Java_com_xposeddemo_Module_dumpdex(JNIEnv *env, jobject instance, jint cookie) {
    
    	DexOrJar* pDexOrJar = (DexOrJar*)cookie;
    	DvmDex* pDvmDex;
    	//打印dex文件的内存加载路径
    	printf("jni", pDexOrJar->fileName);
    
    	// 判断当前mCookie值是否是dex文件的
    	if (pDexOrJar->isDex)
    	{
    		// 得到内存加载的odex文件的信息结构体
    		pDvmDex = pDexOrJar->pRawDexFile->pDvmDex;
    	}
    	else
    	{
    		pDvmDex = pDexOrJar->pJarFile->pDvmDex;
    	}
    
    	// 获取到描述内存加载的odex文件信息的结构体DexFile
    	DexFile* dexFile = pDvmDex->pDexFile;
    	// 得到内存加载的odex文件的基地址(起始地址)
    	MemMapping mapping = pDvmDex->memMap;
    	printinfo("jni","MemMapping:addr:%x length:%x baseAddr:%x baseLength:%x",
    			 mapping.addr, mapping.length, mapping.baseAddr, mapping.baseLength);
    
    	// 通过jni函数反射调用java方法获取到设备的scard卡的文件路径
    	char* path = getExternalStorageDirectory(env);
    
    	char szBufferDexPath[128];
    	memset(szBufferDexPath, 0, sizeof(szBufferDexPath));
    	memcpy(szBufferDexPath, path, strlen(path));
    	// 拼接字符串得到dump的dex文件的路径
    	strcat(szBufferDexPath, "/xxxx.dex");
    	printinfo("dump dex path: %s", szBufferDexPath);
    
    	// F_OK = 0
    	if (!access(szBufferDexPath,  F_OK))
    	{
    		// 删除已经存在的文件
    		remove(szBufferDexPath);
    	}
    
    	// 创建新文件保存dump的dex文件
    	FILE* file = fopen(szBufferDexPath, "wb+");
    
    	// 保存三倍dex文件长度(比较暴力,可以参考dexhunter的实现代码进行优化)
    	fwrite(mapping.addr,mapping.length*3,1,file);
    
    	// 关闭文件
    	fclose(file);
    }
    
    #ifdef __cplusplus
    }
    #endif
    
    // 打印Log日志信息
    void printinfo(const char* tag, const char* fmt, ...)
    {
        va_list ap;
        char buf[1024];
    
        va_start(ap, fmt);
        vsnprintf(buf, 1024, fmt, ap);
        va_end(ap);
        __android_log_write(ANDROID_LOG_INFO, tag, buf);
    }


    3.jni目录需要的头文件 Object.h

    #ifndef HELPTOOLCLIENT_OBJECT_H
    #define HELPTOOLCLIENT_OBJECT_H
    #include <stddef.h>
    #include <cstdint>
    #include <pthread.h>
    
    typedef uint8_t             u1;
    typedef uint16_t            u2;
    typedef uint32_t            u4;
    typedef uint64_t            u8;
    typedef int8_t              s1;
    typedef int16_t             s2;
    typedef int32_t             s4;
    typedef int64_t             s8;
    
    /* fwd decl */
    struct DataObject;
    struct InitiatingLoaderList;
    struct ClassObject;
    struct StringObject;
    struct ArrayObject;
    struct Method;
    struct ExceptionEntry;
    struct LineNumEntry;
    struct StaticField;
    struct InstField;
    struct Field;
    struct RegisterMap;
    
    struct Object;
    union JValue
    {
        u1 z;
        s1 b;
        u2 c;
        s2 s;
        s4 i;
        s8 j;
        float f;
        double d;
        Object* l;
    };
    
    typedef void (*DalvikBridgeFunc)(const u4* args, JValue* pResult,
                                     const Method* method, struct Thread* self);
    
    enum AccessFlags
    {
        ACC_MIRANDA = 0x8000, // method (internal to VM)
        JAVA_FLAGS_MASK = 0xffff, // bits set from Java sources (low 16)
    };
    
    typedef void (*DalvikNativeFunc)(const u4* args, JValue* pResult);
    
    enum ClassFlags
    {
        CLASS_ISFINALIZABLE = (1 << 31), // class/ancestor overrides finalize()
        CLASS_ISARRAY = (1 << 30), // class is a "[*"
        CLASS_ISOBJECTARRAY = (1 << 29), // class is a "[L*" or "[[*"
        CLASS_ISCLASS = (1 << 28), // class is *the* class Class
    
        CLASS_ISREFERENCE = (1 << 27), // class is a soft/weak/phantom ref
        // only ISREFERENCE is set --> soft
                CLASS_ISWEAKREFERENCE = (1 << 26), // class is a weak reference
        CLASS_ISFINALIZERREFERENCE = (1 << 25), // class is a finalizer reference
        CLASS_ISPHANTOMREFERENCE = (1 << 24), // class is a phantom reference
    
        CLASS_MULTIPLE_DEFS = (1 << 23), // DEX verifier: defs in multiple DEXs
    
        /* unlike the others, these can be present in the optimized DEX file */
                CLASS_ISOPTIMIZED = (1 << 17), // class may contain opt instrs
        CLASS_ISPREVERIFIED = (1 << 16), // class has been pre-verified
    };
    #define EXPECTED_FILE_FLAGS 
        (ACC_CLASS_MASK | CLASS_ISPREVERIFIED | CLASS_ISOPTIMIZED)
    
    
    #define SET_CLASS_FLAG(clazz, flag) 
        do { (clazz)->accessFlags |= (flag); } while (0)
    
    #define CLEAR_CLASS_FLAG(clazz, flag) 
        do { (clazz)->accessFlags &= ~(flag); } while (0)
    
    #define IS_CLASS_FLAG_SET(clazz, flag) 
        (((clazz)->accessFlags & (flag)) != 0)
    
    #define GET_CLASS_FLAG_GROUP(clazz, flags) 
        ((u4)((clazz)->accessFlags & (flags)))
    
    enum MethodFlags
    {
        METHOD_ISWRITABLE = (1 << 31), // the method's code is writable
    };
    
    #define SET_METHOD_FLAG(method, flag) 
        do { (method)->accessFlags |= (flag); } while (0)
    
    #define CLEAR_METHOD_FLAG(method, flag) 
        do { (method)->accessFlags &= ~(flag); } while (0)
    
    #define IS_METHOD_FLAG_SET(method, flag) 
        (((method)->accessFlags & (flag)) != 0)
    
    #define GET_METHOD_FLAG_GROUP(method, flags) 
        ((u4)((method)->accessFlags & (flags)))
    
    enum ClassStatus
    {
        CLASS_ERROR = -1,
    
        CLASS_NOTREADY = 0,
        CLASS_IDX = 1, /* loaded, DEX idx in super or ifaces */
                CLASS_LOADED = 2, /* DEX idx values resolved */
                CLASS_RESOLVED = 3, /* part of linking */
                CLASS_VERIFYING = 4, /* in the process of being verified */
                CLASS_VERIFIED = 5, /* logically part of linking; done pre-init */
                CLASS_INITIALIZING = 6, /* class init in progress */
                CLASS_INITIALIZED = 7, /* ready to go */
    };
    #define CLASS_WALK_SUPER ((unsigned int)(3))
    #define CLASS_SMALLEST_OFFSET (sizeof(struct Object))
    #define CLASS_BITS_PER_WORD (sizeof(unsigned long int) * 8)
    #define CLASS_OFFSET_ALIGNMENT 4
    #define CLASS_HIGH_BIT ((unsigned int)1 << (CLASS_BITS_PER_WORD - 1))
    #define _CLASS_BIT_NUMBER_FROM_OFFSET(byteOffset) 
        (((unsigned int)(byteOffset) - CLASS_SMALLEST_OFFSET) / 
         CLASS_OFFSET_ALIGNMENT)
    #define CLASS_CAN_ENCODE_OFFSET(byteOffset) 
        (_CLASS_BIT_NUMBER_FROM_OFFSET(byteOffset) < CLASS_BITS_PER_WORD)
    #define CLASS_BIT_FROM_OFFSET(byteOffset) 
        (CLASS_HIGH_BIT >> _CLASS_BIT_NUMBER_FROM_OFFSET(byteOffset))
    #define CLASS_OFFSET_FROM_CLZ(rshift) 
        (((int)(rshift) * CLASS_OFFSET_ALIGNMENT) + CLASS_SMALLEST_OFFSET)
    
    struct InterfaceEntry
    {
        ClassObject* clazz;
        int* methodIndexArray;
    };
    
    struct Object
    {
        ClassObject* clazz;
        u4 lock;
    };
    
    #define DVM_OBJECT_INIT(obj, clazz_) 
        dvmSetFieldObject(obj, OFFSETOF_MEMBER(Object, clazz), clazz_)
    
    struct DataObject : Object
    {
        u4 instanceData[1];
    };
    
    struct StringObject : Object
    {
        u4 instanceData[1];
        int length() const;
        int utfLength() const;
        ArrayObject* array() const;
        const u2* chars() const;
    };
    
    struct ArrayObject : Object
    {
        u4 length;
        u8 contents[1];
    };
    
    struct InitiatingLoaderList
    {
        Object** initiatingLoaders;
        int initiatingLoaderCount;
    };
    
    struct Field
    {
        ClassObject* clazz; /* class in which the field is declared */
        const char* name;
        const char* signature; /* e.g. "I", "[C", "Landroid/os/Debug;" */
        u4 accessFlags;
    };
    
    struct StaticField : Field
    {
        JValue value; /* initially set from DEX for primitives */
    };
    
    struct InstField : Field
    {
        int byteOffset;
    };
    
    #define CLASS_FIELD_SLOTS   4
    enum PrimitiveType
    {
        PRIM_NOT = 0, /* value is a reference type, not a primitive type */
                PRIM_VOID = 1,
        PRIM_BOOLEAN = 2,
        PRIM_BYTE = 3,
        PRIM_SHORT = 4,
        PRIM_CHAR = 5,
        PRIM_INT = 6,
        PRIM_LONG = 7,
        PRIM_FLOAT = 8,
        PRIM_DOUBLE = 9,
    };
    
    // java类的描述结构体
    struct ClassObject : Object
    {
        u4 instanceData[CLASS_FIELD_SLOTS];
    
        const char* descriptor;
        char* descriptorAlloc;
        u4 accessFlags;
        u4 serialNumber;
    
        void* pDvmDex;
    
        ClassStatus status;
    
        ClassObject* verifyErrorClass;
    
        u4 initThreadId;
    
        size_t objectSize;
    
        ClassObject* elementClass;
        int arrayDim;
        PrimitiveType primitiveType;
    
        ClassObject* super;
    
        Object* classLoader;
    
        InitiatingLoaderList initiatingLoaderList;
    
        int interfaceCount;
        ClassObject** interfaces;
    
        int directMethodCount;
        Method* directMethods;
        int virtualMethodCount;
        Method* virtualMethods;
    
    
        int vtableCount;
        Method** vtable;
    
        int iftableCount;
        InterfaceEntry* iftable;
    
    
        int ifviPoolCount;
        int* ifviPool;
    
    
        int ifieldCount;
        int ifieldRefCount; // number of fields that are object refs
        InstField* ifields;
    
        u4 refOffsets;
    
        /* source file name, if known */
        const char* sourceFile;
    
        int sfieldCount;
        StaticField sfields[]; /* MUST be last item */
    };
    
    
    struct DexProto
    {
        const void * dexFile; /* file the idx refers to */
        u4 protoIdx; /* index into proto_ids table of dexFile */
    };
    
    struct Method
    {
        /* the class we are a part of */
        ClassObject* clazz;
        u4 accessFlags;
    
        u2 methodIndex;
    
        u2 registersSize; /* ins + locals */
        u2 outsSize;
        u2 insSize;
    
        /* method name, e.g. "<init>" or "eatLunch" */
        const char* name;
    
        DexProto prototype;
    
        const char* shorty;
    
        const u2* insns; /* instructions, in memory-mapped .dex */
    
    
        int jniArgInfo;
    
    
        DalvikBridgeFunc nativeFunc;
    
    
        bool fastJni;
    
    
        bool noRef;
    
    
        bool shouldTrace;
    
    
        const RegisterMap* registerMap;
    
        /* set if method was called during method profiling */
        bool inProfile;
    };
    
    enum
    {
        ACC_PUBLIC = 0x00000001, // class, field, method, ic
        ACC_PRIVATE = 0x00000002, // field, method, ic
        ACC_PROTECTED = 0x00000004, // field, method, ic
        ACC_STATIC = 0x00000008, // field, method, ic
        ACC_FINAL = 0x00000010, // class, field, method, ic
        ACC_SYNCHRONIZED = 0x00000020, // method (only allowed on natives)
        ACC_SUPER = 0x00000020, // class (not used in Dalvik)
        ACC_VOLATILE = 0x00000040, // field
        ACC_BRIDGE = 0x00000040, // method (1.5)
        ACC_TRANSIENT = 0x00000080, // field
        ACC_VARARGS = 0x00000080, // method (1.5)
        ACC_NATIVE = 0x00000100, // method
        ACC_INTERFACE = 0x00000200, // class, ic
        ACC_ABSTRACT = 0x00000400, // class, method, ic
        ACC_STRICT = 0x00000800, // method
        ACC_SYNTHETIC = 0x00001000, // field, method, ic
        ACC_ANNOTATION = 0x00002000, // class, ic (1.5)
        ACC_ENUM = 0x00004000, // class, field, ic (1.5)
        ACC_CONSTRUCTOR = 0x00010000, // method (Dalvik only)
        ACC_DECLARED_SYNCHRONIZED =
        0x00020000, // method (Dalvik only)
        ACC_CLASS_MASK =
        (ACC_PUBLIC | ACC_FINAL | ACC_INTERFACE | ACC_ABSTRACT
         | ACC_SYNTHETIC | ACC_ANNOTATION | ACC_ENUM),
        ACC_INNER_CLASS_MASK =
        (ACC_CLASS_MASK | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC),
        ACC_FIELD_MASK =
        (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC | ACC_FINAL
         | ACC_VOLATILE | ACC_TRANSIENT | ACC_SYNTHETIC | ACC_ENUM),
        ACC_METHOD_MASK =
        (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC | ACC_FINAL
         | ACC_SYNCHRONIZED | ACC_BRIDGE | ACC_VARARGS | ACC_NATIVE
         | ACC_ABSTRACT | ACC_STRICT | ACC_SYNTHETIC | ACC_CONSTRUCTOR
         | ACC_DECLARED_SYNCHRONIZED),
    };
    
    bool dvmIsPublicMethod(const Method* method)
    {
        return (method->accessFlags & ACC_PUBLIC) != 0;
    }
    
    bool dvmIsPrivateMethod(const Method* method)
    {
        return (method->accessFlags & ACC_PRIVATE) != 0;
    }
    
    bool dvmIsStaticMethod(const Method* method)
    {
        return (method->accessFlags & ACC_STATIC) != 0;
    }
    
    bool dvmIsSynchronizedMethod(const Method* method)
    {
        return (method->accessFlags & ACC_SYNCHRONIZED) != 0;
    }
    
    bool dvmIsDeclaredSynchronizedMethod(const Method* method)
    {
        return (method->accessFlags & ACC_DECLARED_SYNCHRONIZED) != 0;
    }
    
    bool dvmIsFinalMethod(const Method* method)
    {
        return (method->accessFlags & ACC_FINAL) != 0;
    }
    
    bool dvmIsNativeMethod(const Method* method)
    {
        return (method->accessFlags & ACC_NATIVE) != 0;
    }
    
    bool dvmIsAbstractMethod(const Method* method)
    {
        return (method->accessFlags & ACC_ABSTRACT) != 0;
    }
    
    bool dvmIsSyntheticMethod(const Method* method)
    {
        return (method->accessFlags & ACC_SYNTHETIC) != 0;
    }
    
    bool dvmIsMirandaMethod(const Method* method)
    {
        return (method->accessFlags & ACC_MIRANDA) != 0;
    }
    
    bool dvmIsConstructorMethod(const Method* method)
    {
        return *method->name == '<';
    }
    
    /* Dalvik puts private, static, and constructors into non-virtual table */
    bool dvmIsDirectMethod(const Method* method)
    {
        return dvmIsPrivateMethod(method) ||
               dvmIsStaticMethod(method) ||
               dvmIsConstructorMethod(method);
    }
    
    /* Get whether the given method has associated bytecode. This is the
    * case for methods which are neither native nor abstract. */
    bool dvmIsBytecodeMethod(const Method* method)
    {
        return (method->accessFlags & (ACC_NATIVE | ACC_ABSTRACT)) == 0;
    }
    
    bool dvmIsProtectedField(const Field* field)
    {
        return (field->accessFlags & ACC_PROTECTED) != 0;
    }
    
    bool dvmIsStaticField(const Field* field)
    {
        return (field->accessFlags & ACC_STATIC) != 0;
    }
    
    bool dvmIsFinalField(const Field* field)
    {
        return (field->accessFlags & ACC_FINAL) != 0;
    }
    
    bool dvmIsVolatileField(const Field* field)
    {
        return (field->accessFlags & ACC_VOLATILE) != 0;
    }
    
    bool dvmIsInterfaceClass(const ClassObject* clazz)
    {
        return (clazz->accessFlags & ACC_INTERFACE) != 0;
    }
    
    bool dvmIsPublicClass(const ClassObject* clazz)
    {
        return (clazz->accessFlags & ACC_PUBLIC) != 0;
    }
    
    bool dvmIsFinalClass(const ClassObject* clazz)
    {
        return (clazz->accessFlags & ACC_FINAL) != 0;
    }
    
    bool dvmIsAbstractClass(const ClassObject* clazz)
    {
        return (clazz->accessFlags & ACC_ABSTRACT) != 0;
    }
    
    bool dvmIsAnnotationClass(const ClassObject* clazz)
    {
        return (clazz->accessFlags & ACC_ANNOTATION) != 0;
    }
    
    bool dvmIsPrimitiveClass(const ClassObject* clazz)
    {
        return clazz->primitiveType != PRIM_NOT;
    }
    
    /* linked, here meaning prepared and resolved */
    bool dvmIsClassLinked(const ClassObject* clazz)
    {
        return clazz->status >= CLASS_RESOLVED;
    }
    
    /* has class been verified? */
    bool dvmIsClassVerified(const ClassObject* clazz)
    {
        return clazz->status >= CLASS_VERIFIED;
    }
    
    
    
    
    bool dvmIsClassInitialized(const ClassObject* clazz)
    {
        return (clazz->status == CLASS_INITIALIZED);
    }
    
    /* annotation constants */
    enum
    {
        kDexVisibilityBuild = 0x00, /* annotation visibility */
                kDexVisibilityRuntime = 0x01,
        kDexVisibilitySystem = 0x02,
    
        kDexAnnotationByte = 0x00,
        kDexAnnotationShort = 0x02,
        kDexAnnotationChar = 0x03,
        kDexAnnotationInt = 0x04,
        kDexAnnotationLong = 0x06,
        kDexAnnotationFloat = 0x10,
        kDexAnnotationDouble = 0x11,
        kDexAnnotationString = 0x17,
        kDexAnnotationType = 0x18,
        kDexAnnotationField = 0x19,
        kDexAnnotationMethod = 0x1a,
        kDexAnnotationEnum = 0x1b,
        kDexAnnotationArray = 0x1c,
        kDexAnnotationAnnotation = 0x1d,
        kDexAnnotationNull = 0x1e,
        kDexAnnotationBoolean = 0x1f,
    
        kDexAnnotationValueTypeMask = 0x1f, /* low 5 bits */
                kDexAnnotationValueArgShift = 5,
    };
    
    /* map item type codes */
    enum
    {
        kDexTypeHeaderItem = 0x0000,
        kDexTypeStringIdItem = 0x0001,
        kDexTypeTypeIdItem = 0x0002,
        kDexTypeProtoIdItem = 0x0003,
        kDexTypeFieldIdItem = 0x0004,
        kDexTypeMethodIdItem = 0x0005,
        kDexTypeClassDefItem = 0x0006,
        kDexTypeMapList = 0x1000,
        kDexTypeTypeList = 0x1001,
        kDexTypeAnnotationSetRefList = 0x1002,
        kDexTypeAnnotationSetItem = 0x1003,
        kDexTypeClassDataItem = 0x2000,
        kDexTypeCodeItem = 0x2001,
        kDexTypeStringDataItem = 0x2002,
        kDexTypeDebugInfoItem = 0x2003,
        kDexTypeAnnotationItem = 0x2004,
        kDexTypeEncodedArrayItem = 0x2005,
        kDexTypeAnnotationsDirectoryItem = 0x2006,
    };
    
    /* auxillary data section chunk codes */
    enum
    {
        kDexChunkClassLookup = 0x434c4b50, /* CLKP */
                kDexChunkRegisterMaps = 0x524d4150, /* RMAP */
    
                kDexChunkEnd = 0x41454e44, /* AEND */
    };
    
    /* debug info opcodes and constants */
    enum
    {
        DBG_END_SEQUENCE = 0x00,
        DBG_ADVANCE_PC = 0x01,
        DBG_ADVANCE_LINE = 0x02,
        DBG_START_LOCAL = 0x03,
        DBG_START_LOCAL_EXTENDED = 0x04,
        DBG_END_LOCAL = 0x05,
        DBG_RESTART_LOCAL = 0x06,
        DBG_SET_PROLOGUE_END = 0x07,
        DBG_SET_EPILOGUE_BEGIN = 0x08,
        DBG_SET_FILE = 0x09,
        DBG_FIRST_SPECIAL = 0x0a,
        DBG_LINE_BASE = -4,
        DBG_LINE_RANGE = 15,
    };
    
    enum
    {
        kSHA1DigestLen = 20,
        kSHA1DigestOutputLen = kSHA1DigestLen * 2 + 1
    };
    
    
    /*
    * Direct-mapped "header_item" struct.
    */
    struct DexHeader
    {
        u1 magic[8]; /* includes version number */
        u4 checksum; /* adler32 checksum */
        u1 signature[kSHA1DigestLen]; /* SHA-1 hash */
        u4 fileSize; /* length of entire file */
        u4 headerSize; /* offset to start of next section */
        u4 endianTag;
        u4 linkSize;
        u4 linkOff;
        u4 mapOff;
        u4 stringIdsSize;
        u4 stringIdsOff;
        u4 typeIdsSize;
        u4 typeIdsOff;
        u4 protoIdsSize;
        u4 protoIdsOff;
        u4 fieldIdsSize;
        u4 fieldIdsOff;
        u4 methodIdsSize;
        u4 methodIdsOff;
        u4 classDefsSize;
        u4 classDefsOff;
        u4 dataSize;
        u4 dataOff;
    };
    
    /*
    * Direct-mapped "map_item".
    */
    struct DexMapItem
    {
        u2 type; /* type code (see kDexType* above) */
        u2 unused;
        u4 size; /* count of items of the indicated type */
        u4 offset; /* file offset to the start of data */
    };
    
    /*
    * Direct-mapped "map_list".
    */
    struct DexMapList
    {
        u4 size; /* #of entries in list */
        DexMapItem list[1]; /* entries */
    };
    
    /*
    * Direct-mapped "string_id_item".
    */
    struct DexStringId
    {
        u4 stringDataOff; /* file offset to string_data_item */
    };
    
    /*
    * Direct-mapped "type_id_item".
    */
    struct DexTypeId
    {
        u4 descriptorIdx; /* index into stringIds list for type descriptor */
    };
    
    /*
    * Direct-mapped "field_id_item".
    */
    struct DexFieldId
    {
        u2 classIdx; /* index into typeIds list for defining class */
        u2 typeIdx; /* index into typeIds for field type */
        u4 nameIdx; /* index into stringIds for field name */
    };
    
    /*
    * Direct-mapped "method_id_item".
    */
    struct DexMethodId
    {
        u2 classIdx; /* index into typeIds list for defining class */
        u2 protoIdx; /* index into protoIds for method prototype */
        u4 nameIdx; /* index into stringIds for method name */
    };
    
    /*
    * Direct-mapped "proto_id_item".
    */
    struct DexProtoId
    {
        u4 shortyIdx; /* index into stringIds for shorty descriptor */
        u4 returnTypeIdx; /* index into typeIds list for return type */
        u4 parametersOff; /* file offset to type_list for parameter types */
    };
    
    /*
    * Direct-mapped "class_def_item".
    */
    struct DexClassDef
    {
        u4 classIdx; /* index into typeIds for this class */
        u4 accessFlags;
        u4 superclassIdx; /* index into typeIds for superclass */
        u4 interfacesOff; /* file offset to DexTypeList */
        u4 sourceFileIdx; /* index into stringIds for source file name */
        u4 annotationsOff; /* file offset to annotations_directory_item */
        u4 classDataOff; /* file offset to class_data_item */
        u4 staticValuesOff; /* file offset to DexEncodedArray */
    };
    
    /*
    * Direct-mapped "type_item".
    */
    struct DexTypeItem
    {
        u2 typeIdx; /* index into typeIds */
    };
    
    /*
    * Direct-mapped "type_list".
    */
    struct DexTypeList
    {
        u4 size; /* #of entries in list */
        DexTypeItem list[1]; /* entries */
    };
    
    typedef struct DexMapId
    {
        u2 type; /*Section type*/
    
        u2 unused; /*unused*/
        u4 size; /* section size*/
        u4 offset; /* section offset */
    } DexMapId;
    
    /*
    * Direct-mapped "code_item".
    *
    * The "catches" table is used when throwing an exception,
    * "debugInfo" is used when displaying an exception stack trace or
    * debugging. An offset of zero indicates that there are no entries.
    */
    struct DexCode
    {
        u2 registersSize;
        u2 insSize;
        u2 outsSize;
        u2 triesSize;
        u4 debugInfoOff; /* file offset to debug info stream */
        u4 insnsSize; /* size of the insns array, in u2 units */
        u2 insns[1];
        /* followed by optional u2 padding */
        /* followed by try_item[triesSize] */
        /* followed by uleb128 handlersSize */
        /* followed by catch_handler_item[handlersSize] */
    };
    
    /*
    * Direct-mapped "try_item".
    */
    struct DexTry
    {
        u4 startAddr; /* start address, in 16-bit code units */
        u2 insnCount; /* instruction count, in 16-bit code units */
        u2 handlerOff; /* offset in encoded handler data to handlers */
    };
    
    /*
    * Link table.  Currently undefined.
    */
    struct DexLink
    {
        u1 bleargh;
    };
    
    
    /*
    * Direct-mapped "annotations_directory_item".
    */
    struct DexAnnotationsDirectoryItem
    {
        u4 classAnnotationsOff; /* offset to DexAnnotationSetItem */
        u4 fieldsSize; /* count of DexFieldAnnotationsItem */
        u4 methodsSize; /* count of DexMethodAnnotationsItem */
        u4 parametersSize; /* count of DexParameterAnnotationsItem */
        /* followed by DexFieldAnnotationsItem[fieldsSize] */
        /* followed by DexMethodAnnotationsItem[methodsSize] */
        /* followed by DexParameterAnnotationsItem[parametersSize] */
    };
    
    /*
    * Direct-mapped "field_annotations_item".
    */
    struct DexFieldAnnotationsItem
    {
        u4 fieldIdx;
        u4 annotationsOff; /* offset to DexAnnotationSetItem */
    };
    
    /*
    * Direct-mapped "method_annotations_item".
    */
    struct DexMethodAnnotationsItem
    {
        u4 methodIdx;
        u4 annotationsOff; /* offset to DexAnnotationSetItem */
    };
    
    /*
    * Direct-mapped "parameter_annotations_item".
    */
    struct DexParameterAnnotationsItem
    {
        u4 methodIdx;
        u4 annotationsOff; /* offset to DexAnotationSetRefList */
    };
    
    /*
    * Direct-mapped "annotation_set_ref_item".
    */
    struct DexAnnotationSetRefItem
    {
        u4 annotationsOff; /* offset to DexAnnotationSetItem */
    };
    
    /*
    * Direct-mapped "annotation_set_ref_list".
    */
    struct DexAnnotationSetRefList
    {
        u4 size;
        DexAnnotationSetRefItem list[1];
    };
    
    /*
    * Direct-mapped "annotation_set_item".
    */
    struct DexAnnotationSetItem
    {
        u4 size;
        u4 entries[1]; /* offset to DexAnnotationItem */
    };
    
    /*
    * Direct-mapped "annotation_item".
    *
    * NOTE: this structure is byte-aligned.
    */
    struct DexAnnotationItem
    {
        u1 visibility;
        u1 annotation[1]; /* data in encoded_annotation format */
    };
    
    /*
    * Direct-mapped "encoded_array".
    *
    * NOTE: this structure is byte-aligned.
    */
    struct DexEncodedArray
    {
        u1 array[1]; /* data in encoded_array format */
    };
    
    /*
    * Lookup table for classes.  It provides a mapping from class name to
    * class definition.  Used by dexFindClass().
    *
    * We calculate this at DEX optimization time and embed it in the file so we
    * don't need the same hash table in every VM.  This is slightly slower than
    * a hash table with direct pointers to the items, but because it's shared
    * there's less of a penalty for using a fairly sparse table.
    */
    struct DexClassLookup
    {
        int size; // total size, including "size"
        int numEntries; // size of table[]; always power of 2
        struct
        {
            u4 classDescriptorHash; // class descriptor hash code
            int classDescriptorOffset; // in bytes, from start of DEX
            int classDefOffset; // in bytes, from start of DEX
        } table[1];
    };
    
    /*
    * Header added by DEX optimization pass.  Values are always written in
    * local byte and structure padding.  The first field (magic + version)
    * is guaranteed to be present and directly readable for all expected
    * compiler configurations; the rest is version-dependent.
    *
    * Try to keep this simple and fixed-size.
    */
    struct DexOptHeader
    {
        u1 magic[8]; /* includes version number */
    
        u4 dexOffset; /* file offset of DEX header */
        u4 dexLength;
        u4 depsOffset; /* offset of optimized DEX dependency table */
        u4 depsLength;
        u4 optOffset; /* file offset of optimized data tables */
        u4 optLength;
    
        u4 flags; /* some info flags */
        u4 checksum; /* adler32 checksum covering deps/opt */
    
        /* pad for 64-bit alignment if necessary */
    };
    
    #define DEX_OPT_FLAG_BIG            (1<<1)  /* swapped to big-endian */
    
    #define DEX_INTERFACE_CACHE_SIZE    128     /* must be power of 2 */
    
    /*
    * Structure representing a DEX file.
    *
    * Code should regard DexFile as opaque, using the API calls provided here
    * to access specific structures.
    */
    struct DexFile
    {
        /* directly-mapped "opt" header */
        const DexOptHeader* pOptHeader;
    
        /* pointers to directly-mapped structs and arrays in base DEX */
        const DexHeader* pHeader;
        const DexStringId* pStringIds;
        const DexTypeId* pTypeIds;
        const DexFieldId* pFieldIds;
        const DexMethodId* pMethodIds;
        const DexProtoId* pProtoIds;
        const DexClassDef* pClassDefs;
        const DexLink* pLinkData;
    
        /*
        * These are mapped out of the "auxillary" section, and may not be
        * included in the file.
        */
        const DexClassLookup* pClassLookup;
        const void* pRegisterMapPool; // RegisterMapClassPool
    
        /* points to start of DEX file data */
        const u1* baseAddr;
    
        /* track memory overhead for auxillary structures */
        int overhead;
    
        /* additional app-specific data structures associated with the DEX */
        //void*               auxData;
    };
    
    
    struct MemMapping
    {
        void* addr; /* start of data */
        size_t length; /* length of data */
    
        void* baseAddr; /* page-aligned base address */
        size_t baseLength; /* length of mapping */
    };
    
    struct DvmDex
    {
        /* pointer to the DexFile we're associated with */
        DexFile* pDexFile;
    
        /* clone of pDexFile->pHeader (it's used frequently enough) */
        const DexHeader* pHeader;
    
        /* interned strings; parallel to "stringIds" */
        struct StringObject** pResStrings;
    
        /* resolved classes; parallel to "typeIds" */
        struct ClassObject** pResClasses;
    
        /* resolved methods; parallel to "methodIds" */
        struct Method** pResMethods;
    
        /* resolved instance fields; parallel to "fieldIds" */
        /* (this holds both InstField and StaticField) */
        struct Field** pResFields;
    
        /* interface method lookup cache */
        struct AtomicCache* pInterfaceCache;
    
        /* shared memory region with file contents */
        bool isMappedReadOnly;
        MemMapping memMap;
    
        jobject dex_object;
    
        /* lock ensuring mutual exclusion during updates */
        pthread_mutex_t modLock;
    };
    
    struct JarFile
    {
        u4* Nocare[9];
        char* cacheFileName;
        DvmDex* pDvmDex;
    };
    
    struct RawDexFile
    {
        char* cacheFileName;
        struct DvmDex* pDvmDex; //DvmDex*
    };
    
    struct DexOrJar
    {
        char* fileName;
        bool isDex;
        bool okayToFree;
        RawDexFile* pRawDexFile;
        JarFile* pJarFile;
        u1* pDexMemory; // malloc()ed memory, if any
    };
    #endif //HELPTOOLCLIENT_OBJECT_H

    4.当前工程ndk编译需要的配置文件Android.mk

    LOCAL_PATH := $(call my-dir)
    
    include $(CLEAR_VARS)
    
    LOCAL_MODULE    := nativelib
    LOCAL_SRC_FILES := nativelib.cpp
    
    # 支持log日志打印需要加载链接的库    
    LOCAL_LDLIBS += -L$(SYSROOT)/usr/lib -llog    
    
    include $(BUILD_SHARED_LIBRARY)

    5.使用当前Xposed Hook工具进行某加固脱壳的测试结果。




    使用JEB工具反编译脱壳成功后的odex文件,结果如下图:




    总之呢,这个工具对付一般免费版的某数字加固保、某加密、某梆梆加固还是可以的,企业估计不行还需要修改和优化,有兴趣的可以测试一下其他的免费版的加固产品,可以把样本和结果反馈下,我修改一下。


    重要参考:

    某加固使用xposed脱壳




  • 相关阅读:
    java 深入技术三(List)
    java 深入技术二(Collection)
    java开发JDBC连接数据库详解
    数据库基础和JDBC
    java 深入技术一
    java入门 第三季4
    java入门 第三季3
    04-1. 水仙花数(20)
    04-0. 求符合给定条件的整数集(15)
    03-4. 成绩转换(15)
  • 原文地址:https://www.cnblogs.com/csnd/p/11800578.html
Copyright © 2020-2023  润新知