zoukankan      html  css  js  c++  java
  • DexExtractor的原理分析和使用说明

    本文博客链接:http://blog.csdn.net/qq1084283172/article/details/53557894

    周末有空就写下博客了,今天来扯一扯Android平台的脱壳工具DexExtractor。DexExtractor工具的使用比较简单,脱壳的原理也比较简单,工具的作者bunnyrene讲这个android脱壳工具只要是针对bangbang (Bangcle)和ijiami加固的脱壳工具,应该是这两类加固的免费版吧。之前在分析android病毒的时候使用过,但是有时候脱壳还是不成功,需要人工手工脱壳来完成或者说这个工具需要进一步完善一下,不管怎么说谢谢作者大牛。


    i.DexExtractor脱壳工具的使用说明和讨论链接

    看雪论坛:http://bbs.pediy.com/showthread.php?t=201799

    github地址:https://github.com/bunnyblue/DexExtractor


    ii.作者编译好的镜像文件system.img的下载地址

    网盘地址:http://pan.baidu.com/s/1jG3WQMU


    iii.DexExtractor脱壳工具的使用说明截图





    iiii.通过阅读DexExtractor作者提供的使用说明,写下需要注意的地方:

    1.DexExtractor脱壳工具的原理是修改了android源码的DexFile.cpp的dexFileParse函数也就是原来的脱壳点函数处进行dexdump的处理,作者提供了Android 4.4---api 19版本系统脱壳的system.img文件(推荐android模拟器用)和libdvm.so文件(android模拟器和android真机都可以使用)。



    2.由于DexExtractor工具需要不断的向sdcard写文件,因此特别是android模拟器使用该脱壳工具一定设置Android模拟的sdcard的空间大小。

    3.由于DexExtractor工具需要不断的向sdcard写文件,因此被脱壳的apk需要有向sdcard写文件的权限<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

    4.DexExtractor工具的system.img文件(Android 4.4.2版本)使用比较简单--直接替换Android 4.4.2版本系统的system.img文件文件即可,Android模拟器的system.img文件的替换比较简单,Android真机的替换可能需要是Android真机进入recovery模式进行替换;DexExtractor工具的libdvm.so文件使用--需要使用abd的push命令将libdvm.so推送到android系统中然后在su权限将libdvm.so文件拷贝或者备份到Android系统的/system/lib/libdvm.so或者Android真机在root的情况下,使用rootexplore.apk(RE管理器工具)libdvm.so文件拷贝到手机系统的/system/lib/libdvm.so下,替换掉原来Android系统的的/system/lib/libdvm.so文件,并赋予刚才拷贝替换的/system/lib/libdvm.so文件以0775权限然后重启Android真机即可。

    adb push xxx/libdvm.so /data/local/tmp/libdvm.so
    adb shell
    su
    mount -r -w -o remount/system
    mount -o remount,rw /system
    dd if=/system/lib/libdvm.so of=/data/local/tmp/libdvm.bak
    rm /system/lib/libdvm.so 
    cat /data/local/tmp/libdvm.so >/system/lib/libdvm.so
    chmod 0775 /system/lib/libdvm.so
    mount -o remount,ro /system
    exit
    exit
    adb reboot


    iiiii.使用DexExtractor工具的system.img文件配置Android 4.4.2的android模拟器进行脱壳实验

    使用前提条件

    1.如果是android模拟器使用脱壳镜像文件system.img,一定要配置sdcard参数

    2.需要脱壳的apk如果没有写权限,需要添加上写sdcard的权限
    如:
    apk没有写权限的反编译了加上write权限

    说明:
    <!--往sdcard写入数据权限 -->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <!--sdcard创建/删除文件权限 -->
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>

    需要使用的权限:
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    #如果脱壳apk没有文件的写权限,反编译以后加上sdcard文件的写权限,然后重新打包apk程序。


    DexExtractor脱壳实例(使用Android模拟器):

    1.找到Android 4.4.2对应的API 19的系统文件的目录,如下:

    E:BaiduYunDownloadadt-bundle-windows-x86_64-20140702sdksystem-imagesandroid-19defaultarmeabi-v7a
    备份原来的system.img文件,然后将修改的system.img文件解压后拷贝到这个目录里。

    2.在android模拟器上创建API为19的android模拟器,千万不能忘了为模拟器添加sdcard的内存空间参数。

    3.用反编译工具查看被脱壳的apk是否有-----写文件的权限<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>没有就添加上写文件的权限并重新打包apk程序

    4.adb install xxx.apk 安装需要脱壳的apk程序到上面创建的android模拟器上。

    5.打开logcat的logcat 监视log  "被加固的包名" 和 "dvmtag" ,当看到 "create file end",说明脱壳成功;从eclipse中导出log日志文件并保存。(这里请参考作者提供的脱壳成功的说明)



    6.adb pull  /sdcard/classes_xxx.dex 从android模拟器的sdcard中导出脱壳后但是经过base64加密的dex文件
    示例:
    adb  pull  /sdcard/tx.qq898507339.bzy9_classes_5528.dex

    7.脱壳后的dex文件被Base64编码了,需要解码。 
    解码dex文件:
    java -jar Decoder.jar  dex目录  
    java -jar Decoder.jar   xxxx x.qq898507339.bzy9_classes_5528.dex

    ======================================================================================================
    java环境的正确配置

    安装JDK,比如目录在C:Java

    为了方便java程序的开发,需要配置一下环境变量,右击我的电脑->属性->高级->环境变量->用户变量中单击[新建(N)]添加以下环境变量

    (假定你的JDK安装路径为C:Javajdk1.6.0_30)

    JAVA_HOME
    C:Javajdk1.6.0_30

    PATH
    C:Javajdk1.6.0_30in

    CLASSPATH
    .;%JAVA_HOME%libdt.jar;%JAVA_HOME%lib ools.jar;(注前面的点号和分号一定不能丢,还有中间的,后面的分号也不要丢了)

    说明:CLASSPATH可以再增加一些第三方的jar文件,方便手工编译和运行程序。
    ======================================================================================================


    iiiiii.DexExtractor脱壳工具的代码分析:

    DexExtractor脱壳工具的脱壳原理是修改了android系统的dvm虚拟机模块的代码/dalvik/libdex/DexFile.cpp文件的dexFileParse函数,在系统调用dexFileParse函数之前将加固释放出的原始dex文件从内存dump出来。


    但是呢,由于一些加固如梆梆加固,会对dex的内存dump脱壳进行检测,具体的就是hook修改当前进程的read、write读写相关的函数,一旦检测到read、write读写相关的函数的操作中有对dex文件的dump行为会有对抗的处理,防止dex的内存dump,因此呢,DexExtractor脱壳工具的作者为了过掉这种内存dump的对抗,需要先将原始的dex文件数据进行base64加密然后进行写文件到sdcard中进行输出,当pull导出拿到base64加密的dex文件时还需要进行base64的解密才能获取到原始的dex文件,具体的脱壳功能见DexHacker.cpp文件。

    //
    //  DexHacker.cpp
    //  
    //
    //  Created by BunnyBlue on 6/23/15.
    //
    //
    
    #include "DexHacker.h"
    void DexHacker::writeDex2Encoded(unsigned char *data, size_t length){
        
    #ifdef CODE_DVM
        ALOGE("--pacthed--  inject  .dex length %d  flag=%d",length,flags);
       
        char dexbuffer[64]={0};
        
        char dexbufferNamed[128]={0};
        char bufferProcess[256]={0};
    
    	// 获取当前进程的名称字符串
        bufferProcess= getProcessName(bufferProcess);
        sprintf(dexbuffer, "classes_%d", length);
        strcat(dexbufferNamed,"/sdcard/");
        
        if (bufferProcess!=NULL) {
         strcat(dexbufferNamed, bufferProcess);
            strcat(dexbufferNamed, dexbuffer);
        }else{
              ALOGE("--pacthed-- , FAULT pid not  found
    ");
            return;
        }
        
        // strcat(dexbufferNamed,dexbuffer);
        strcat(dexbufferNamed,".dex");
        
        ALOGE("--pacthed-- , %s
    ", dexbufferNamed);
        ALOGE("--pacthed--  debug dalvikParse   find dex try write file  ");
        
        // 删除原来存在的文件
        int status = remove(dexbufferNamed);
        if( status == 0 )
            ALOGE("%s file deleted successfully.
    ",dexbufferNamed);
        else
        {
            ALOGE("Unable to delete the file
    ");
            
        }
        
        // 申请内存缓冲区备份信息
        u1* buffer_data_dest=(u1*)malloc((length+1)*sizeof(u1));
        // 拷贝内存中的dex文件的数据到内存缓冲区buffer_data_dest中备份
        memcpy(buffer_data_dest, data, length);
        
        // 创建文件
        FILE *fp = fopen(dexbufferNamed,"wb");
        if(NULL==fp) {
    		
            ALOGE("--pacthed-- , can't create file ! maybe  you need mount sdcard again!");
            ALOGE( "%s data %s
    ", strerror(errno),data);
            
        } else {
    		
            ALOGE("--pacthed--   create file  %s ",dexbufferNamed);
            int dex_lem_local = length>2048? 1024:length;
            
            //  申请内存空间保存base64加密后的dex文件的数据
            unsigned char *dst=(unsigned char*)malloc(length*2.5);
            unsigned long dlen=length*2.5;
            
            // 将原始的dex文件的数据进行base64加密
            base64_encode(dst, &dlen, data, length);
            // 将base64加密后的dex文件的数据进行写文件输出到sdcard中
            fwrite(dst, dlen, 1, fp);
            
            
            
            //fwrite(data, sizeof(u1), length, fp);
            ALOGE("--pacthed--  create file  end ");
            
            //fflush(fp);
            fclose(fp);
            fp = NULL;
        }
        free(buffer_data_dest);
    #else 
        
        char dexbuffer[64]={0};
        char dexbufferNamed[128]={0};
        sprintf(dexbuffer, "classes_%d", length);
        //strcat(dexbufferNamed,");
        strcat(dexbufferNamed,dexbuffer);
        strcat(dexbufferNamed,".dex");
       
        int status = remove(dexbufferNamed);
     
        FILE *fp = fopen(dexbufferNamed,"wb");
        if(NULL==fp){
            
        } else {
           
            unsigned char *dst=(unsigned char*)malloc(length*2.5);
            unsigned long dlen=length*2.5;
            base64_encode(dst, &dlen, data, length);
            
            fwrite(dst, dlen, 1, fp);
            //fflush(fp);
            fclose(fp);
            fp = NULL;
        }
        
    #endif
    }
    
    
    void DexHacker::writeEncodedDex2Dex(const char *encodedDex){
    	
        FILE *srcDexFile=fopen(encodedDex,"rb");
        std::string outDexFile(encodedDex);
        outDexFile.append(".read.dex");
        
        
        FILE *outFile=fopen(outDexFile.c_str(), "wb");
        
        if (srcDexFile!=NULL) {
            fseek(srcDexFile,0,SEEK_END);
            long fsize =ftell(srcDexFile);
            rewind(srcDexFile);
            
            std::cout<<sizeof(char)<<"
    xxxxxxxx"<<fsize;
            unsigned  char *list=(unsigned char*)malloc(sizeof(char)*fsize);
            unsigned long  numread =fread(list,sizeof(char),fsize,srcDexFile);
            // blue_dump_data(list, (unsigned long )fsize);
            unsigned char *dst=(unsigned char*)malloc(numread);
            unsigned long dlen=numread;
            base64_decode(dst, &dlen, list, numread);
            
            fclose(srcDexFile);
            
            int ret=fwrite(dst, 1, dlen, outFile);
            fclose(outFile);
            //   std::cout<<"
    "<<repeate<<"numread"<<numread; 
        }
        
    }
    
    char* itoa(int i, char b[]){
    	
        char const digit[] = "0123456789";
        char* p = b;
        if(i<0){
            *p++ = '-';
            i *= -1;
        }
        int shifter = i;
        do{ //Move to where representation ends
            ++p;
            shifter = shifter/10;
        }while(shifter);
        *p = '';
        do{ //Move back, inserting digits as u go
            *--p = digit[i%10];
            i = i/10;
        }while(i);
        return b;
    }
    
    
    // 获取当前进程的名称
    char * DexHacker::getProcessName(char * buffer){
    	
        char path_t[256]={0};
    	// char buffer[512]={0} ;
     
    	// 获取当前进程的pid
        pid_t pid=getpid();
        char str[15];
        sprintf(str, "%d", pid);
        memset(path_t, 0 , sizeof(path_t));
        strcat(path_t, "/proc/");
        strcat(path_t, str);
        strcat(path_t, "/cmdline");
        
        //LOG_ERROR("zhw", "path:%s", path_t);
        int fd_t = open(path_t, O_RDONLY);
        if(fd_t>0){
    		
            int read_count = read(fd_t, buffer, BUFLEN);
            if(read_count>0){
            
                return buffer;
            }
        }
        
        return NULL;
    }
    


    iiiiii.DexExtractor脱壳工具作者提供的文件的说明





    关于DexExtractor脱壳工具的自行修改和扩展:根据自己的脱壳思路,编写额外的脱壳代码文件,添加自选Android系统版本的DexFile.cpp文件并将额外的脱壳代码文件添加到编译配置文件Android.mk中,然后在DexFile.cpp文件路径下进行android源码的局部模块的编译,具体编译参考见http://blog.csdn.net/qq1084283172/article/details/53365659


    iiiiii.DexExtractor脱壳工具的其他代码文件

    /*
     * Copyright (C) 2008 The Android Open Source Project
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    /*
     * Access the contents of a .dex file.
     */
    
    #include "DexFile.h"
    #include "DexOptData.h"
    #include "DexProto.h"
    #include "DexCatch.h"
    #include "Leb128.h"
    #include "sha1.h"
    #include "ZipArchive.h"
    
    #include <zlib.h>
    
    #include <stdlib.h>
    #include <stddef.h>
    #include <string.h>
    #include <fcntl.h>
    #include <errno.h>
    #include "DexHacker.cpp"
    
    /*
     * Verifying checksums is good, but it slows things down and causes us to
     * touch every page.  In the "optimized" world, it doesn't work at all,
     * because we rewrite the contents.
     */
    static const bool kVerifyChecksum = false;
    static const bool kVerifySignature = false;
    
    /* (documented in header) */
    char dexGetPrimitiveTypeDescriptorChar(PrimitiveType type) {
        const char* string = dexGetPrimitiveTypeDescriptor(type);
    
        return (string == NULL) ? '' : string[0];
    }
    
    /* (documented in header) */
    const char* dexGetPrimitiveTypeDescriptor(PrimitiveType type) {
        switch (type) {
            case PRIM_VOID:    return "V";
            case PRIM_BOOLEAN: return "Z";
            case PRIM_BYTE:    return "B";
            case PRIM_SHORT:   return "S";
            case PRIM_CHAR:    return "C";
            case PRIM_INT:     return "I";
            case PRIM_LONG:    return "J";
            case PRIM_FLOAT:   return "F";
            case PRIM_DOUBLE:  return "D";
            default:           return NULL;
        }
    
        return NULL;
    }
    
    /* (documented in header) */
    const char* dexGetBoxedTypeDescriptor(PrimitiveType type) {
        switch (type) {
            case PRIM_VOID:    return NULL;
            case PRIM_BOOLEAN: return "Ljava/lang/Boolean;";
            case PRIM_BYTE:    return "Ljava/lang/Byte;";
            case PRIM_SHORT:   return "Ljava/lang/Short;";
            case PRIM_CHAR:    return "Ljava/lang/Character;";
            case PRIM_INT:     return "Ljava/lang/Integer;";
            case PRIM_LONG:    return "Ljava/lang/Long;";
            case PRIM_FLOAT:   return "Ljava/lang/Float;";
            case PRIM_DOUBLE:  return "Ljava/lang/Double;";
            default:           return NULL;
        }
    }
    
    /* (documented in header) */
    PrimitiveType dexGetPrimitiveTypeFromDescriptorChar(char descriptorChar) {
        switch (descriptorChar) {
            case 'V': return PRIM_VOID;
            case 'Z': return PRIM_BOOLEAN;
            case 'B': return PRIM_BYTE;
            case 'S': return PRIM_SHORT;
            case 'C': return PRIM_CHAR;
            case 'I': return PRIM_INT;
            case 'J': return PRIM_LONG;
            case 'F': return PRIM_FLOAT;
            case 'D': return PRIM_DOUBLE;
            default:  return PRIM_NOT;
        }
    }
    
    /* Return the UTF-8 encoded string with the specified string_id index,
     * also filling in the UTF-16 size (number of 16-bit code points).*/
    const char* dexStringAndSizeById(const DexFile* pDexFile, u4 idx,
            u4* utf16Size) {
        const DexStringId* pStringId = dexGetStringId(pDexFile, idx);
        const u1* ptr = pDexFile->baseAddr + pStringId->stringDataOff;
    
        *utf16Size = readUnsignedLeb128(&ptr);
        return (const char*) ptr;
    }
    
    /*
     * Format an SHA-1 digest for printing.  tmpBuf must be able to hold at
     * least kSHA1DigestOutputLen bytes.
     */
    const char* dvmSHA1DigestToStr(const unsigned char digest[], char* tmpBuf);
    
    /*
     * Compute a SHA-1 digest on a range of bytes.
     */
    static void dexComputeSHA1Digest(const unsigned char* data, size_t length,
        unsigned char digest[])
    {
        SHA1_CTX context;
        SHA1Init(&context);
        SHA1Update(&context, data, length);
        SHA1Final(digest, &context);
    }
    
    /*
     * Format the SHA-1 digest into the buffer, which must be able to hold at
     * least kSHA1DigestOutputLen bytes.  Returns a pointer to the buffer,
     */
    static const char* dexSHA1DigestToStr(const unsigned char digest[],char* tmpBuf)
    {
        static const char hexDigit[] = "0123456789abcdef";
        char* cp;
        int i;
    
        cp = tmpBuf;
        for (i = 0; i < kSHA1DigestLen; i++) {
            *cp++ = hexDigit[digest[i] >> 4];
            *cp++ = hexDigit[digest[i] & 0x0f];
        }
        *cp++ = '';
    
        assert(cp == tmpBuf + kSHA1DigestOutputLen);
    
        return tmpBuf;
    }
    
    /*
     * Compute a hash code on a UTF-8 string, for use with internal hash tables.
     *
     * This may or may not be compatible with UTF-8 hash functions used inside
     * the Dalvik VM.
     *
     * The basic "multiply by 31 and add" approach does better on class names
     * than most other things tried (e.g. adler32).
     */
    static u4 classDescriptorHash(const char* str)
    {
        u4 hash = 1;
    
        while (*str != '')
            hash = hash * 31 + *str++;
    
        return hash;
    }
    
    /*
     * Add an entry to the class lookup table.  We hash the string and probe
     * until we find an open slot.
     */
    static void classLookupAdd(DexFile* pDexFile, DexClassLookup* pLookup,
        int stringOff, int classDefOff, int* pNumProbes)
    {
        const char* classDescriptor =
            (const char*) (pDexFile->baseAddr + stringOff);
        const DexClassDef* pClassDef =
            (const DexClassDef*) (pDexFile->baseAddr + classDefOff);
        u4 hash = classDescriptorHash(classDescriptor);
        int mask = pLookup->numEntries-1;
        int idx = hash & mask;
    
        /*
         * Find the first empty slot.  We oversized the table, so this is
         * guaranteed to finish.
         */
        int probes = 0;
        while (pLookup->table[idx].classDescriptorOffset != 0) {
            idx = (idx + 1) & mask;
            probes++;
        }
        //if (probes > 1)
        //    ALOGW("classLookupAdd: probes=%d", probes);
    
        pLookup->table[idx].classDescriptorHash = hash;
        pLookup->table[idx].classDescriptorOffset = stringOff;
        pLookup->table[idx].classDefOffset = classDefOff;
        *pNumProbes = probes;
    }
    
    /*
     * Create the class lookup hash table.
     *
     * Returns newly-allocated storage.
     */
    DexClassLookup* dexCreateClassLookup(DexFile* pDexFile)
    {
        DexClassLookup* pLookup;
        int allocSize;
        int i, numEntries;
        int numProbes, totalProbes, maxProbes;
    
        numProbes = totalProbes = maxProbes = 0;
    
        assert(pDexFile != NULL);
    
        /*
         * Using a factor of 3 results in far less probing than a factor of 2,
         * but almost doubles the flash storage requirements for the bootstrap
         * DEX files.  The overall impact on class loading performance seems
         * to be minor.  We could probably get some performance improvement by
         * using a secondary hash.
         */
        numEntries = dexRoundUpPower2(pDexFile->pHeader->classDefsSize * 2);
        allocSize = offsetof(DexClassLookup, table)
                        + numEntries * sizeof(pLookup->table[0]);
    
        pLookup = (DexClassLookup*) calloc(1, allocSize);
        if (pLookup == NULL)
            return NULL;
        pLookup->size = allocSize;
        pLookup->numEntries = numEntries;
    
        for (i = 0; i < (int)pDexFile->pHeader->classDefsSize; i++) {
            const DexClassDef* pClassDef;
            const char* pString;
    
            pClassDef = dexGetClassDef(pDexFile, i);
            pString = dexStringByTypeIdx(pDexFile, pClassDef->classIdx);
    
            classLookupAdd(pDexFile, pLookup,
                (u1*)pString - pDexFile->baseAddr,
                (u1*)pClassDef - pDexFile->baseAddr, &numProbes);
    
            if (numProbes > maxProbes)
                maxProbes = numProbes;
            totalProbes += numProbes;
        }
    
        ALOGV("Class lookup: classes=%d slots=%d (%d%% occ) alloc=%d"
             " total=%d max=%d",
            pDexFile->pHeader->classDefsSize, numEntries,
            (100 * pDexFile->pHeader->classDefsSize) / numEntries,
            allocSize, totalProbes, maxProbes);
    
        return pLookup;
    }
    
    
    /*
     * Set up the basic raw data pointers of a DexFile. This function isn't
     * meant for general use.
     */
    void dexFileSetupBasicPointers(DexFile* pDexFile, const u1* data) {
        DexHeader *pHeader = (DexHeader*) data;
    
        pDexFile->baseAddr = data;
        pDexFile->pHeader = pHeader;
        pDexFile->pStringIds = (const DexStringId*) (data + pHeader->stringIdsOff);
        pDexFile->pTypeIds = (const DexTypeId*) (data + pHeader->typeIdsOff);
        pDexFile->pFieldIds = (const DexFieldId*) (data + pHeader->fieldIdsOff);
        pDexFile->pMethodIds = (const DexMethodId*) (data + pHeader->methodIdsOff);
        pDexFile->pProtoIds = (const DexProtoId*) (data + pHeader->protoIdsOff);
        pDexFile->pClassDefs = (const DexClassDef*) (data + pHeader->classDefsOff);
        pDexFile->pLinkData = (const DexLink*) (data + pHeader->linkOff);
    }
    
    /*
     * Parse an optimized or unoptimized .dex file sitting in memory.  This is
     * called after the byte-ordering and structure alignment has been fixed up.
     *
     * On success, return a newly-allocated DexFile.
     */
    DexFile* dexFileParse(const u1* data, size_t length, int flags)
    {
    
    //******************************添加的脱壳代码**************************
    	// 构建脱壳工具实例
    	DexHacker mDexHacker;
    	// 从内存dump dex文件
    	mDexHacker.writeDex2Encoded(data,(unsigned int)length);
    
    //******************************常规手动脱壳点**************************
    
        DexFile* pDexFile = NULL;
        const DexHeader* pHeader;
        const u1* magic;
        int result = -1;
    
        if (length < sizeof(DexHeader)) {
            ALOGE("too short to be a valid .dex");
            goto bail;      /* bad file format */
        }
    
        pDexFile = (DexFile*) malloc(sizeof(DexFile));
        if (pDexFile == NULL)
            goto bail;      /* alloc failure */
        memset(pDexFile, 0, sizeof(DexFile));
    
        /*
         * Peel off the optimized header.
         */
        if (memcmp(data, DEX_OPT_MAGIC, 4) == 0) {
            magic = data;
            if (memcmp(magic+4, DEX_OPT_MAGIC_VERS, 4) != 0) {
                ALOGE("bad opt version (0x%02x %02x %02x %02x)",
                     magic[4], magic[5], magic[6], magic[7]);
                goto bail;
            }
    
            pDexFile->pOptHeader = (const DexOptHeader*) data;
            ALOGV("Good opt header, DEX offset is %d, flags=0x%02x",
                pDexFile->pOptHeader->dexOffset, pDexFile->pOptHeader->flags);
    
            /* parse the optimized dex file tables */
            if (!dexParseOptData(data, length, pDexFile))
                goto bail;
    
            /* ignore the opt header and appended data from here on out */
            data += pDexFile->pOptHeader->dexOffset;
            length -= pDexFile->pOptHeader->dexOffset;
            if (pDexFile->pOptHeader->dexLength > length) {
                ALOGE("File truncated? stored len=%d, rem len=%d",
                    pDexFile->pOptHeader->dexLength, (int) length);
                goto bail;
            }
            length = pDexFile->pOptHeader->dexLength;
        }
    
        dexFileSetupBasicPointers(pDexFile, data);
        pHeader = pDexFile->pHeader;
    
        if (!dexHasValidMagic(pHeader)) {
            goto bail;
        }
    
        /*
         * Verify the checksum(s).  This is reasonably quick, but does require
         * touching every byte in the DEX file.  The base checksum changes after
         * byte-swapping and DEX optimization.
         */
        if (flags & kDexParseVerifyChecksum) {
            u4 adler = dexComputeChecksum(pHeader);
            if (adler != pHeader->checksum) {
                ALOGE("ERROR: bad checksum (%08x vs %08x)",
                    adler, pHeader->checksum);
                if (!(flags & kDexParseContinueOnError))
                    goto bail;
            } else {
                ALOGV("+++ adler32 checksum (%08x) verified", adler);
            }
    
            const DexOptHeader* pOptHeader = pDexFile->pOptHeader;
            if (pOptHeader != NULL) {
                adler = dexComputeOptChecksum(pOptHeader);
                if (adler != pOptHeader->checksum) {
                    ALOGE("ERROR: bad opt checksum (%08x vs %08x)",
                        adler, pOptHeader->checksum);
                    if (!(flags & kDexParseContinueOnError))
                        goto bail;
                } else {
                    ALOGV("+++ adler32 opt checksum (%08x) verified", adler);
                }
            }
        }
    
        /*
         * Verify the SHA-1 digest.  (Normally we don't want to do this --
         * the digest is used to uniquely identify the original DEX file, and
         * can't be computed for verification after the DEX is byte-swapped
         * and optimized.)
         */
        if (kVerifySignature) {
            unsigned char sha1Digest[kSHA1DigestLen];
            const int nonSum = sizeof(pHeader->magic) + sizeof(pHeader->checksum) +
                                kSHA1DigestLen;
    
            dexComputeSHA1Digest(data + nonSum, length - nonSum, sha1Digest);
            if (memcmp(sha1Digest, pHeader->signature, kSHA1DigestLen) != 0) {
                char tmpBuf1[kSHA1DigestOutputLen];
                char tmpBuf2[kSHA1DigestOutputLen];
                ALOGE("ERROR: bad SHA1 digest (%s vs %s)",
                    dexSHA1DigestToStr(sha1Digest, tmpBuf1),
                    dexSHA1DigestToStr(pHeader->signature, tmpBuf2));
                if (!(flags & kDexParseContinueOnError))
                    goto bail;
            } else {
                ALOGV("+++ sha1 digest verified");
            }
        }
    
        if (pHeader->fileSize != length) {
            ALOGE("ERROR: stored file size (%d) != expected (%d)",
                (int) pHeader->fileSize, (int) length);
            if (!(flags & kDexParseContinueOnError))
                goto bail;
        }
    
        if (pHeader->classDefsSize == 0) {
            ALOGE("ERROR: DEX file has no classes in it, failing");
            goto bail;
        }
    
        /*
         * Success!
         */
        result = 0;
    
    bail:
        if (result != 0 && pDexFile != NULL) {
            dexFileFree(pDexFile);
            pDexFile = NULL;
        }
        return pDexFile;
    }
    
    /*
     * Free up the DexFile and any associated data structures.
     *
     * Note we may be called with a partially-initialized DexFile.
     */
    void dexFileFree(DexFile* pDexFile)
    {
        if (pDexFile == NULL)
            return;
    
        free(pDexFile);
    }
    
    /*
     * Look up a class definition entry by descriptor.
     *
     * "descriptor" should look like "Landroid/debug/Stuff;".
     */
    const DexClassDef* dexFindClass(const DexFile* pDexFile,
        const char* descriptor)
    {
        const DexClassLookup* pLookup = pDexFile->pClassLookup;
        u4 hash;
        int idx, mask;
    
        hash = classDescriptorHash(descriptor);
        mask = pLookup->numEntries - 1;
        idx = hash & mask;
    
        /*
         * Search until we find a matching entry or an empty slot.
         */
        while (true) {
            int offset;
    
            offset = pLookup->table[idx].classDescriptorOffset;
            if (offset == 0)
                return NULL;
    
            if (pLookup->table[idx].classDescriptorHash == hash) {
                const char* str;
    
                str = (const char*) (pDexFile->baseAddr + offset);
                if (strcmp(str, descriptor) == 0) {
                    return (const DexClassDef*)
                        (pDexFile->baseAddr + pLookup->table[idx].classDefOffset);
                }
            }
    
            idx = (idx + 1) & mask;
        }
    }
    
    
    /*
     * Compute the DEX file checksum for a memory-mapped DEX file.
     */
    u4 dexComputeChecksum(const DexHeader* pHeader)
    {
        const u1* start = (const u1*) pHeader;
    
        uLong adler = adler32(0L, Z_NULL, 0);
        const int nonSum = sizeof(pHeader->magic) + sizeof(pHeader->checksum);
    
        return (u4) adler32(adler, start + nonSum, pHeader->fileSize - nonSum);
    }
    
    /*
     * Compute the size, in bytes, of a DexCode.
     */
    size_t dexGetDexCodeSize(const DexCode* pCode)
    {
        /*
         * The catch handler data is the last entry.  It has a variable number
         * of variable-size pieces, so we need to create an iterator.
         */
        u4 handlersSize;
        u4 offset;
        u4 ui;
    
        if (pCode->triesSize != 0) {
            handlersSize = dexGetHandlersSize(pCode);
            offset = dexGetFirstHandlerOffset(pCode);
        } else {
            handlersSize = 0;
            offset = 0;
        }
    
        for (ui = 0; ui < handlersSize; ui++) {
            DexCatchIterator iterator;
            dexCatchIteratorInit(&iterator, pCode, offset);
            offset = dexCatchIteratorGetEndOffset(&iterator, pCode);
        }
    
        const u1* handlerData = dexGetCatchHandlerData(pCode);
    
        //ALOGD("+++ pCode=%p handlerData=%p last offset=%d",
        //    pCode, handlerData, offset);
    
        /* return the size of the catch handler + everything before it */
        return (handlerData - (u1*) pCode) + offset;
    }
    
    /*
     * Round up to the next highest power of 2.
     *
     * Found on http://graphics.stanford.edu/~seander/bithacks.html.
     */
    u4 dexRoundUpPower2(u4 val)
    {
        val--;
        val |= val >> 1;
        val |= val >> 2;
        val |= val >> 4;
        val |= val >> 8;
        val |= val >> 16;
        val++;
    
        return val;
    }
    

    //
    //  DexHacker.h
    //  
    //
    //  Created by BunnyBlue on 6/23/15.
    //
    //
    
    #ifndef ____DexHacker__
    #define ____DexHacker__
    #include <iostream>
    #include<string.h>
    #include<stdio.h>
    #include "base64.h"
    #include <sys/types.h>
    #include <unistd.h>
    #include <stdio.h>
    #include <fcntl.h>
    #define BUFLEN 1024
    
    class DexHacker{
    public:
        void  writeDex2Encoded(unsigned char * data,size_t length);
        void  writeEncodedDex2Dex(const char *dexPath);
        char * getProcessName(char * buffer);
    };
    #endif /* defined(____DexHacker__) */
    

    /**
     * file base64.h
     *
     * rief RFC 1521 base64 encoding/decoding
     *
     *  Copyright (C) 2006-2010, Brainspark B.V.
     *
     *  This file is part of PolarSSL (http://www.polarssl.org)
     *  Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
     *
     *  All rights reserved.
     *
     *  This program is free software; you can redistribute it and/or modify
     *  it under the terms of the GNU General Public License as published by
     *  the Free Software Foundation; either version 2 of the License, or
     *  (at your option) any later version.
     *
     *  This program is distributed in the hope that it will be useful,
     *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     *  GNU General Public License for more details.
     *
     *  You should have received a copy of the GNU General Public License along
     *  with this program; if not, write to the Free Software Foundation, Inc.,
     *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
     */
    #define  POLARSSL_BASE64_C
    #define POLARSSL_SELF_TEST
    #ifndef POLARSSL_BASE64_H
    #define POLARSSL_BASE64_H
    
    #include <string.h>
    
    #define POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL               -0x002A  /**< Output buffer too small. */
    #define POLARSSL_ERR_BASE64_INVALID_CHARACTER              -0x002C  /**< Invalid character in input. */
    
    #ifdef __cplusplus
    extern "C" {
    #endif
    
    /**
     * rief          Encode a buffer into base64 format
     *
     * param dst      destination buffer
     * param dlen     size of the buffer
     * param src      source buffer
     * param slen     amount of data to be encoded
     *
     * 
    eturn         0 if successful, or POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL.
     *                 *dlen is always updated to reflect the amount
     *                 of data that has (or would have) been written.
     *
     * 
    ote           Call this function with *dlen = 0 to obtain the
     *                 required buffer size in *dlen
     */
    int base64_encode( unsigned char *dst, size_t *dlen,
                       const unsigned char *src, size_t slen );
    
    /**
     * rief          Decode a base64-formatted buffer
     *
     * param dst      destination buffer
     * param dlen     size of the buffer
     * param src      source buffer
     * param slen     amount of data to be decoded
     *
     * 
    eturn         0 if successful, POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL, or
     *                 POLARSSL_ERR_BASE64_INVALID_CHARACTER if the input data is
     *                 not correct. *dlen is always updated to reflect the amount
     *                 of data that has (or would have) been written.
     *
     * 
    ote           Call this function with *dlen = 0 to obtain the
     *                 required buffer size in *dlen
     */
    int base64_decode( unsigned char *dst, size_t *dlen,
                       const unsigned char *src, size_t slen );
        int base64_self_test( int verbose );
    
    
    #ifdef __cplusplus
    }
    #endif
    
    #endif /* base64.h */
    

    /*
     *  RFC 1521 base64 encoding/decoding
     *
     *  Copyright (C) 2006-2013, Brainspark B.V.
     *
     *  This file is part of PolarSSL (http://www.polarssl.org)
     *  Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
     *
     *  All rights reserved.
     *
     *  This program is free software; you can redistribute it and/or modify
     *  it under the terms of the GNU General Public License as published by
     *  the Free Software Foundation; either version 2 of the License, or
     *  (at your option) any later version.
     *
     *  This program is distributed in the hope that it will be useful,
     *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     *  GNU General Public License for more details.
     *
     *  You should have received a copy of the GNU General Public License along
     *  with this program; if not, write to the Free Software Foundation, Inc.,
     *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
     */
    
    #define POLARSSL_BASE64_C
    #define POLARSSL_SELF_TEST
    
    #if defined(POLARSSL_BASE64_C)
    
    #include "base64.h"
    
    #if defined(_MSC_VER) && !defined(EFIX64) && !defined(EFI32)
    #include <basetsd.h>
    typedef UINT32 uint32_t;
    #else
    #include <inttypes.h>
    #endif
    
    static const unsigned char base64_enc_map[64] =
    {
        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
        'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
        'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
        'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
        'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
        'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
        '8', '9', '+', '/'
    };
    
    static const unsigned char base64_dec_map[128] =
    {
        127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
        127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
        127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
        127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
        127, 127, 127,  62, 127, 127, 127,  63,  52,  53,
         54,  55,  56,  57,  58,  59,  60,  61, 127, 127,
        127,  64, 127, 127, 127,   0,   1,   2,   3,   4,
          5,   6,   7,   8,   9,  10,  11,  12,  13,  14,
         15,  16,  17,  18,  19,  20,  21,  22,  23,  24,
         25, 127, 127, 127, 127, 127, 127,  26,  27,  28,
         29,  30,  31,  32,  33,  34,  35,  36,  37,  38,
         39,  40,  41,  42,  43,  44,  45,  46,  47,  48,
         49,  50,  51, 127, 127, 127, 127, 127
    };
    
    /*
     * Encode a buffer into base64 format
     */
    int base64_encode( unsigned char *dst, size_t *dlen,
                       const unsigned char *src, size_t slen )
    {
        size_t i, n;
        int C1, C2, C3;
        unsigned char *p;
    
        if( slen == 0 )
            return( 0 );
    
        n = (slen << 3) / 6;
    
        switch( (slen << 3) - (n * 6) )
        {
            case  2: n += 3; break;
            case  4: n += 2; break;
            default: break;
        }
    
        if( *dlen < n + 1 )
        {
            *dlen = n + 1;
            return( POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL );
        }
    
        n = (slen / 3) * 3;
    
        for( i = 0, p = dst; i < n; i += 3 )
        {
            C1 = *src++;
            C2 = *src++;
            C3 = *src++;
    
            *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
            *p++ = base64_enc_map[(((C1 &  3) << 4) + (C2 >> 4)) & 0x3F];
            *p++ = base64_enc_map[(((C2 & 15) << 2) + (C3 >> 6)) & 0x3F];
            *p++ = base64_enc_map[C3 & 0x3F];
        }
    
        if( i < slen )
        {
            C1 = *src++;
            C2 = ((i + 1) < slen) ? *src++ : 0;
    
            *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
            *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
    
            if( (i + 1) < slen )
                 *p++ = base64_enc_map[((C2 & 15) << 2) & 0x3F];
            else *p++ = '=';
    
            *p++ = '=';
        }
    
        *dlen = p - dst;
        *p = 0;
    
        return( 0 );
    }
    
    /*
     * Decode a base64-formatted buffer
     */
    int base64_decode( unsigned char *dst, size_t *dlen,
                       const unsigned char *src, size_t slen )
    {
        size_t i, n;
        uint32_t j, x;
        unsigned char *p;
    
        for( i = n = j = 0; i < slen; i++ )
        {
            if( ( slen - i ) >= 2 &&
                src[i] == '
    ' && src[i + 1] == '
    ' )
                continue;
    
            if( src[i] == '
    ' )
                continue;
    
            if( src[i] == '=' && ++j > 2 )
                return( POLARSSL_ERR_BASE64_INVALID_CHARACTER );
    
            if( src[i] > 127 || base64_dec_map[src[i]] == 127 )
                return( POLARSSL_ERR_BASE64_INVALID_CHARACTER );
    
            if( base64_dec_map[src[i]] < 64 && j != 0 )
                return( POLARSSL_ERR_BASE64_INVALID_CHARACTER );
    
            n++;
        }
    
        if( n == 0 )
            return( 0 );
    
        n = ((n * 6) + 7) >> 3;
    
        if( dst == NULL || *dlen < n )
        {
            *dlen = n;
            return( POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL );
        }
    
       for( j = 3, n = x = 0, p = dst; i > 0; i--, src++ )
       {
            if( *src == '
    ' || *src == '
    ' )
                continue;
    
            j -= ( base64_dec_map[*src] == 64 );
            x  = (x << 6) | ( base64_dec_map[*src] & 0x3F );
    
            if( ++n == 4 )
            {
                n = 0;
                if( j > 0 ) *p++ = (unsigned char)( x >> 16 );
                if( j > 1 ) *p++ = (unsigned char)( x >>  8 );
                if( j > 2 ) *p++ = (unsigned char)( x       );
            }
        }
    
        *dlen = p - dst;
    
        return( 0 );
    }
    
    #if defined(POLARSSL_SELF_TEST)
    
    #include <string.h>
    #include <stdio.h>
    
    static const unsigned char base64_test_dec[64] =
    {
        0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
        0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
        0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
        0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
        0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
        0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
        0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
        0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
    };
    
    static const unsigned char base64_test_enc[] =
        "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
        "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
    
    /*
     * Checkup routine
     */
    int base64_self_test( int verbose )
    {
        size_t len;
        const unsigned char *src;
        unsigned char buffer[128];
    
        if( verbose != 0 )
            printf( "  Base64 encoding test: " );
    
        len = sizeof( buffer );
        src = base64_test_dec;
    
        if( base64_encode( buffer, &len, src, 64 ) != 0 ||
             memcmp( base64_test_enc, buffer, 88 ) != 0 )
        {
            if( verbose != 0 )
                printf( "failed
    " );
    
            return( 1 );
        }
    
        if( verbose != 0 )
            printf( "passed
      Base64 decoding test: " );
    
        len = sizeof( buffer );
        src = base64_test_enc;
    
        if( base64_decode( buffer, &len, src, 88 ) != 0 ||
             memcmp( base64_test_dec, buffer, 64 ) != 0 )
        {
            if( verbose != 0 )
                printf( "failed
    " );
    
            return( 1 );
        }
    
        if( verbose != 0 )
            printf( "passed
    
    " );
    
        return( 0 );
    }
    
    #endif
    
    #endif
    

    # Copyright (C) 2008 The Android Open Source Project
    #
    # Licensed under the Apache License, Version 2.0 (the "License");
    # you may not use this file except in compliance with the License.
    # You may obtain a copy of the License at
    #
    #      http://www.apache.org/licenses/LICENSE-2.0
    #
    # Unless required by applicable law or agreed to in writing, software
    # distributed under the License is distributed on an "AS IS" BASIS,
    # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    # See the License for the specific language governing permissions and
    # limitations under the License.
    
    LOCAL_PATH:= $(call my-dir)
    
    dex_src_files := 
    	CmdUtils.cpp 
    	DexCatch.cpp 
    	DexClass.cpp 
    	DexDataMap.cpp 
    	DexDebugInfo.cpp 
    	DexFile.cpp 
    	DexInlines.cpp 
    	DexOptData.cpp 
    	DexOpcodes.cpp 
    	DexProto.cpp 
    	DexSwapVerify.cpp 
    	DexUtf.cpp 
    	InstrUtils.cpp 
    	Leb128.cpp 
    	OptInvocation.cpp 
    	sha1.cpp 
    	SysUtil.cpp 
    	ZipArchive.cpp
    	base64.c
    
    dex_include_files := 
    	dalvik 
    	external/zlib 
    	external/safe-iop/include
    
    ##
    ##
    ## Build the device version of libdex
    ##
    ##
    ifneq ($(SDK_ONLY),true)  # SDK_only doesn't need device version
    
    include $(CLEAR_VARS)
    LOCAL_CFLAGS += -DCODE_DVM -fpermissive
    LOCAL_CXXFLAGS += -DCODE_DVM -fpermissive
    LOCAL_CPPFLAGS += -DCODE_DVM -fpermissive
    #LOCAL_CFLAGS += -UNDEBUG -DDEBUG=1
    LOCAL_SRC_FILES := $(dex_src_files)
    LOCAL_C_INCLUDES += $(dex_include_files)
    LOCAL_STATIC_LIBRARIES := liblog
    LOCAL_MODULE_TAGS := optional
    LOCAL_MODULE := libdex
    include $(BUILD_STATIC_LIBRARY)
    
    endif # !SDK_ONLY
    
    
    ##
    ##
    ## Build the host version of libdex
    ##
    ##
    include $(CLEAR_VARS)
    LOCAL_CFLAGS += -DCODE_DVM
    LOCAL_CXXFLAGS += -DCODE_DVM -fpermissive
    LOCAL_CPPFLAGS += -DCODE_DVM -fpermissive
    LOCAL_SRC_FILES := $(dex_src_files)
    LOCAL_C_INCLUDES += $(dex_include_files)
    LOCAL_STATIC_LIBRARIES := liblog
    LOCAL_MODULE_TAGS := optional
    LOCAL_MODULE := libdex
    include $(BUILD_HOST_STATIC_LIBRARY)
    

    好啦,忙了一下午,一点点的积累和进步.........





  • 相关阅读:
    RHEL 6.3 详细安装教程
    如何利用sendmail发送外部邮件?
    阿里云API网关(14)流控策略
    阿里云API网关(13)请求身份识别:客户端请求签名和服务网关请求签名
    OpenID Connect 是什么?
    OpenID Connect + OAuth2.0
    OAuth是什么?
    OpendID是什么?
    【华为无线路由器】连接【广电光纤入户设备】宽带上网
    windows7.0旗舰版安装后控制面板自带的Microsoft程序
  • 原文地址:https://www.cnblogs.com/csnd/p/11800664.html
Copyright © 2011-2022 走看看