安卓 dex 通用脫殼技術研究(二)


0x03 DexHunter代碼分析

DexHunter 實現中,只需要修改一處文件:dalvik\vm\native\dalvik_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);
}

 

代碼未完,下一篇繼續;


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM