百度加固逆向分析—dex還原

转https://awabest.com/thread-18663-1-1.html


一、如何獲取dex

首先,我們知道動態加載的dex必然會調用dalvik/vm/DvmDex.cpp中以下兩個函數任意一個:

dvmDexFileOpenFromFd 從文件描述符獲取DexFile結構體

dvmDexFileOpenPartial 從內存獲取DexFile結構體

百度這裡用的是dvmDexFileOpenFromFd,通過這個函數我們得到了pDexFile

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

26

27

28

29

30

31

32

33

34

35

36int dvmDexFileOpenFromFd(int fd, DvmDex** ppDvmDex)

{

DvmDex* pDvmDex;

DexFile* pDexFile;

MemMapping memMap;

int parseFlags = kDexParseDefault;

int result = -1;

if (gDvm.verifyDexChecksum)

parseFlags |= kDexParseVerifyChecksum;

if (lseek(fd, 0, SEEK_SET) < 0) {

ALOGE("lseek rewind failed");

goto bail;

}

if (sysMapFileInShmemWritableReadOnly(fd, &memMap) != 0) {

ALOGE("Unable to map file");

goto bail;

}

pDexFile = dexFileParse((u1*)memMap.addr, memMap.length, parseFlags);//这里获取了pDexFile

if (pDexFile == NULL) {

ALOGE("DEX parse failed");

sysReleaseShmem(&memMap);

goto bail;

}

pDvmDex = allocateAuxStructures(pDexFile);

if (pDvmDex == NULL) {

dexFileFree(pDexFile);

sysReleaseShmem(&memMap);

goto bail;

}

/* tuck this into the DexFile so it gets released later */

sysCopyMap(&pDvmDex->memMap, &memMap);

pDvmDex->isMappedReadOnly = true;

*ppDvmDex = pDvmDex;

result = 0;

bail:

return result;

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25struct 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;

};

通過pDexFile->baseAddr 獲取到dex加載的基址。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25struct 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;

};

通過pDexFile->pHeader->fileSize 獲取到dex文件大小。

1

2

3int fd = open("/sdcard/dump.dex", O_CREAT | O_WRONLY, 0666);

write(fd, pDexFile->baseAddr, pDexFile->pHeader->fileSize);

close(fd);

這時我們已經得到dex了。

二、百度殼對dex做了什麼?

1、修改DexClassDef中的classDataOff字段保存的偏移為負偏移

百度加固逆向分析—dex還原_第1张图片

2、將classdata數據清空

百度加固逆向分析—dex還原_第2张图片

三、這麼做如何讓系統正常解析?

百度的把classdata的數據保存在/data/data/xxxx/.1/1.jar包中,會在加載dex之前先分配空間給jar包,所以他的偏移為負值,內存結構如下圖:

百度加固逆向分析—dex還原_第3张图片

四、還原DEX

1、獲取到pDexFile後,我們遍歷pDexFile->pClassDefs調用dexGetClassData獲取到ClassData。將ClassData經過writeLeb128函數編碼,寫入到文件classdata並記錄每個class的大小(此處參考Dexhunter做法)

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

26

27

28

29

30

31

32

33

34

35

36

37

38#define log(...) \

{FILE *fp = fopen("/sdcard/dumpdex.log", "a+"); if (fp) {\

fprintf(fp, __VA_ARGS__);\

fclose(fp);}}

//因为log被hook了所以用写文件的形式保存log

void dump()

{

const DexClassDef* pClassDefs = pDexFile->pClassDefs;

u4 classDefsSize = pDexFile->pHeader->classDefsSize;

DexMapList* pMaps = (DexMapList*)(g_pDexFile->baseAddr + pDexFile->pHeader->mapOff);

u4 cls_dat_off = 0;

for (u4 i = 0; i < pMaps->size; i++)

{

if (pMaps->list.type == 0x2000)   //0x2000代表classdata

{

cls_dat_off = pMaps->list.offset;  //获取classdata起始偏移

break;

}

}

log("classdata_offset:0x%x\n", cls_dat_off);

log("0,");     //记录classdata的偏移用的log

for (u4 i = 0; i

{

const u1* data = dexGetClassData(g_pDexFile, &pClassDefs);

DexClassData *pData = ReadClassData(&data);

if (!pData) {

continue;

}

int fd = open("/sdcard/classdata", O_APPEND | O_CREAT | O_WRONLY, 0666);

int class_data_len = 0;

uint8_t *out = EncodeClassData(pData, class_data_len);

log("%d,", class_data_len);//记录classdata的偏移用的log

cls_dat_off += class_data_len;

write(fd, out, class_data_len);

close(fd);

}

log("\n");

}

以上ReadClassData、EncodeClassData函數用的Dexhunter的。感謝Dexhunter作者。

2、此時我們已經有了dump.dex、classdata、dumpdex.log中保存的偏移。

3、將classdata寫入到classdata偏移處。

4、通過程序修復classdef中的偏移。

百度加固逆向分析—dex還原_第4张图片

5、運行完後我們已經獲取到正確的dex,我們將out.dex拖入JEB 已經可以正常解析。

百度加固逆向分析—dex還原_第5张图片

你可能感兴趣的:(百度加固逆向分析—dex還原)