zoukankan      html  css  js  c++  java
  • 安卓 dex 通用脱壳技术研究(二)

    0x03 DexHunter代码分析

    DexHunter 实现中,只需要修改一处文件:dalvikvm ativedalvik_system_DexFile.cpp

    下面是BeyondCompare比对:

     首先看一下DexHunter的设计原理:

     

    APP 启动时,通过freature string定位dex在内存中位置,并读取classdef块之前的内存为part1,读取classdef之后的内存为data。遍历class_def_item结构,生成文件classdef,并通过code_item_off判断具体的类方法是否在dex范围内,若不在,则写extra文件。

     

    描述几个问题:

    • 从哪里dump出dex文件

    dex文件打开时

    类加载时

    类初始化时

    类方法调用时

    DexHunter中,我们关注,ClassLoader.loadClass->Dalvik_dalvik_system_DexFile_defineClassNative这个函数,它实现了类的加载,实现过程如下:

     

    选择脱壳的时机应是在APP的第一个类加载的时候,为什么呢?

    1. 类加载之前,类的内容是在内存当中的

    2. 当类初始化时,该内存的内容可能会被动态修改

    3. 在一个类方法被调用前,code_item或指令肯定是可用的

    那如何做呢?

    我们要主动加载并初始化所有的类;

    因此,我们代码的注入点,应该是Dalvik_dalvik_system_DexFile_defineClassNative()函数的clazz = dvmDefineClass(pDvmDex, descriptor, loader);语句之前;即在APP加载第一个类之前完成;通过dvmDefineClass主动遍历class_def_item加载每个类,并调用dvmIsClassInitialized和dvmInitClass函数初始化之。

    初始化完成之后,内存中的就是将执行的代码,像梆梆加固针对每个方法进行的加密,会在运行时解密、运行完成后清理内存并再次加密,通过这种方法就可以过掉;因为我们模拟了这样一次调用过程;

    下面是我加入注释的代码:

    //------------------------added begin----------------------//
    
    #include <asm/siginfo.h>
    #include "libdex/DexClass.h"
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <sys/mman.h>
    
    static char dexname[100]={0};   //feature string
    static char dumppath[100]={0};  //dump的文件路径
    static bool readable=true;
    
    static pthread_mutex_t read_mutex;
    static bool flag=true;
    static pthread_mutex_t mutex;
    static bool timer_flag=true;
    static timer_t timerId;
    
    struct arg{
        DvmDex* pDvmDex;
        Object * loader;
    }param;
    
    void timer_thread(sigval_t)
    {
        timer_flag=false;
        timer_delete(timerId);
        ALOGI("GOT IT time up");
    }
    
    void* ReadThread(void *arg){
        FILE *fp = NULL;
        while (dexname[0]==0||dumppath[0]==0) {
            fp=fopen("/data/dexname", "r");
            if (fp==NULL) {
                sleep(1);
                continue;
            }
            fgets(dexname,99,fp);   //读feature string
            dexname[strlen(dexname)-1]=0;
            fgets(dumppath,99,fp);
            dumppath[strlen(dumppath)-1]=0;	//取dump路径 
            fclose(fp);
            fp=NULL;
        }
    
        struct sigevent sev;
    
        sev.sigev_notify=SIGEV_THREAD;
        sev.sigev_value.sival_ptr=&timerId;
        sev.sigev_notify_function=timer_thread;
        sev.sigev_notify_attributes = NULL;
    
        timer_create(CLOCK_REALTIME,&sev,&timerId);
    
        struct itimerspec ts;
        ts.it_value.tv_sec=5;
        ts.it_value.tv_nsec=0;
        ts.it_interval.tv_sec=0;
        ts.it_interval.tv_nsec=0;
    
        timer_settime(timerId,0,&ts,NULL);
    
        return NULL;
    }
    
    /*
        这里是class_data_item的前4项,称为ClassDataHeader
        Dex File->class_defs->class_def_item(class_data_offset)->class_data_item->ClassDataHeader 
    */
    void ReadClassDataHeader(const uint8_t** pData, DexClassDataHeader *pHeader) 
    {
        pHeader->staticFieldsSize = readUnsignedLeb128(pData);
        pHeader->instanceFieldsSize = readUnsignedLeb128(pData);
        pHeader->directMethodsSize = readUnsignedLeb128(pData);
        pHeader->virtualMethodsSize = readUnsignedLeb128(pData);
    }
    
    /*
        下面两个函数,分别读class_data_item Header下的内容,分Field和Method
    */
    void ReadClassDataField(const uint8_t** pData, DexField* pField) 
    {
        pField->fieldIdx = readUnsignedLeb128(pData);
        pField->accessFlags = readUnsignedLeb128(pData);
    }
    
    void ReadClassDataMethod(const uint8_t** pData, DexMethod* pMethod) 
    {
        pMethod->methodIdx = readUnsignedLeb128(pData);
        pMethod->accessFlags = readUnsignedLeb128(pData);
        pMethod->codeOff = readUnsignedLeb128(pData);
    }
    
    /*
        解析class_data_item结构,使用到上面3个函数,分别解析,Header、Field和Method部分
    */
    DexClassData* ReadClassData(const uint8_t** pData) 
    {
    
        DexClassDataHeader header;
    
        if (*pData == NULL) {
            return NULL;
        }
    
        //读取 class_data_item的Header
        ReadClassDataHeader(pData, &header);
    
        size_t resultSize = sizeof(DexClassData) + (header.staticFieldsSize * sizeof(DexField)) + (header.instanceFieldsSize * sizeof(DexField)) + (header.directMethodsSize * sizeof(DexMethod)) + (header.virtualMethodsSize * sizeof(DexMethod));
    
        DexClassData* result = (DexClassData*) malloc(resultSize); //result指向class_data_item并返回
    
        if (result == NULL) {
            return NULL;
        }
    
        uint8_t* ptr = ((uint8_t*) result) + sizeof(DexClassData);  //指向class_data_item的staic_fields偏移
    
        result->header = header;
    
        //以下依次读class_data_item的staticFields,instanceFields,directMethods和virtualMethods域大小————————begain
        if (header.staticFieldsSize != 0) {
            result->staticFields = (DexField*) ptr;
            ptr += header.staticFieldsSize * sizeof(DexField);
        } else {
            result->staticFields = NULL;
        }
    
        if (header.instanceFieldsSize != 0) {
            result->instanceFields = (DexField*) ptr;
            ptr += header.instanceFieldsSize * sizeof(DexField);
        } else {
            result->instanceFields = NULL;
        }
    
        if (header.directMethodsSize != 0) {
            result->directMethods = (DexMethod*) ptr;
            ptr += header.directMethodsSize * sizeof(DexMethod);
        } else {
            result->directMethods = NULL;
        }
    
        if (header.virtualMethodsSize != 0) {
            result->virtualMethods = (DexMethod*) ptr;
        } else {
            result->virtualMethods = NULL;
        }
        //以下依次读class_data_item的staticFields,instanceFields,directMethods和virtualMethods域大小————————end
        
        
    
        //以下依次读staticFields,instanceFields,directMethods,virtualMethods域内容————————begain
        for (uint32_t i = 0; i < header.staticFieldsSize; i++) {
            ReadClassDataField(pData, &result->staticFields[i]);
        }
    
        for (uint32_t i = 0; i < header.instanceFieldsSize; i++) {
            ReadClassDataField(pData, &result->instanceFields[i]);
        }
    
        for (uint32_t i = 0; i < header.directMethodsSize; i++) {
            ReadClassDataMethod(pData, &result->directMethods[i]);
        }
    
        for (uint32_t i = 0; i < header.virtualMethodsSize; i++) {
            ReadClassDataMethod(pData, &result->virtualMethods[i]);
        }
        //以下依次读staticFields,instanceFields,directMethods,virtualMethods域内容————————end
    
        return result;
    }
    
    
    /*
        class_data_item中的一些域是用LEB128算法编码的
    */
    void writeLeb128(uint8_t ** ptr, uint32_t data)
    {
        while (true) {
            uint8_t out = data & 0x7f;
            if (out != data) {
                *(*ptr)++ = out | 0x80;
                data >>= 7;
            } else {
                *(*ptr)++ = out;
                break;
            }
        }
    }
    
    /*
        此函数读取class_data_item,并将内容用writeLeb128转码后返回
    */
    uint8_t* EncodeClassData(DexClassData *pData, int& len)
    {
        len=0;
    
        len+=unsignedLeb128Size(pData->header.staticFieldsSize);
        len+=unsignedLeb128Size(pData->header.instanceFieldsSize);
        len+=unsignedLeb128Size(pData->header.directMethodsSize);
        len+=unsignedLeb128Size(pData->header.virtualMethodsSize);
    
        if (pData->staticFields) {
            for (uint32_t i = 0; i < pData->header.staticFieldsSize; i++) {
                len+=unsignedLeb128Size(pData->staticFields[i].fieldIdx);
                len+=unsignedLeb128Size(pData->staticFields[i].accessFlags);
            }
        }
    
        if (pData->instanceFields) {
            for (uint32_t i = 0; i < pData->header.instanceFieldsSize; i++) {
                len+=unsignedLeb128Size(pData->instanceFields[i].fieldIdx);
                len+=unsignedLeb128Size(pData->instanceFields[i].accessFlags);
            }
        }
    
        if (pData->directMethods) {
            for (uint32_t i=0; i<pData->header.directMethodsSize; i++) {
                len+=unsignedLeb128Size(pData->directMethods[i].methodIdx);
                len+=unsignedLeb128Size(pData->directMethods[i].accessFlags);
                len+=unsignedLeb128Size(pData->directMethods[i].codeOff);
            }
        }
    
        if (pData->virtualMethods) {
            for (uint32_t i=0; i<pData->header.virtualMethodsSize; i++) {
                len+=unsignedLeb128Size(pData->virtualMethods[i].methodIdx);
                len+=unsignedLeb128Size(pData->virtualMethods[i].accessFlags);
                len+=unsignedLeb128Size(pData->virtualMethods[i].codeOff);
            }
        }
    
        uint8_t * store = (uint8_t *) malloc(len);
    
        if (!store) {
            return NULL;
        }
    
        uint8_t * result=store;
    
        writeLeb128(&store,pData->header.staticFieldsSize);
        writeLeb128(&store,pData->header.instanceFieldsSize);
        writeLeb128(&store,pData->header.directMethodsSize);
        writeLeb128(&store,pData->header.virtualMethodsSize);
    
        if (pData->staticFields) {
            for (uint32_t i = 0; i < pData->header.staticFieldsSize; i++) {
                writeLeb128(&store,pData->staticFields[i].fieldIdx);
                writeLeb128(&store,pData->staticFields[i].accessFlags);
            }
        }
    
        if (pData->instanceFields) {
            for (uint32_t i = 0; i < pData->header.instanceFieldsSize; i++) {
                writeLeb128(&store,pData->instanceFields[i].fieldIdx);
                writeLeb128(&store,pData->instanceFields[i].accessFlags);
            }
        }
    
        if (pData->directMethods) {
            for (uint32_t i=0; i<pData->header.directMethodsSize; i++) {
                writeLeb128(&store,pData->directMethods[i].methodIdx);
                writeLeb128(&store,pData->directMethods[i].accessFlags);
                writeLeb128(&store,pData->directMethods[i].codeOff);
            }
        }
    
        if (pData->virtualMethods) {
            for (uint32_t i=0; i<pData->header.virtualMethodsSize; i++) {
                writeLeb128(&store,pData->virtualMethods[i].methodIdx);
                writeLeb128(&store,pData->virtualMethods[i].accessFlags);
                writeLeb128(&store,pData->virtualMethods[i].codeOff);
            }
        }
    
        free(pData);
        return result;
    }
    
    uint8_t* codeitem_end(const u1** pData)
    {
        uint32_t num_of_list = readUnsignedLeb128(pData);
        for (;num_of_list>0;num_of_list--) {
            int32_t num_of_handlers=readSignedLeb128(pData);
            int num=num_of_handlers;
            if (num_of_handlers<=0) {
                num=-num_of_handlers;
            }
            for (; num > 0; num--) {
                readUnsignedLeb128(pData);
                readUnsignedLeb128(pData);
            }
            if (num_of_handlers<=0) {
                readUnsignedLeb128(pData);
            }
        }
        return (uint8_t*)(*pData);
    }

    代码未完,下一篇继续;

  • 相关阅读:
    mybatis中#{}和${}的区别 (二)
    JAVA分布式架构的演变及解决方案
    mybatis中的#和$的区别
    https
    vue3的组件v-model初探1
    前端性能优化
    HTTP请求的完全过程
    http缓存详解,http缓存推荐方案
    vscode-setting备份
    Mac电脑在finder中添加- 右键打开vscode
  • 原文地址:https://www.cnblogs.com/gm-201705/p/9864107.html
Copyright © 2011-2022 走看看