看雪论坛
发新帖
1

[原创]百度加固逆向分析—dex还原

scxc 2017-6-30 13:49 3166

上回说过要再写一篇文章,这里跟大家分享一下百度壳DEX的dump与修复。

下面开始:

一、如何获取dex

    首先,我们知道动态加载的dex必然会调用dalvik/vm/DvmDex.cpp中以下两个函数任意一个:

    dvmDexFileOpenFromFd  从文件描述符获取DexFile结构体

    dvmDexFileOpenPartial    从内存获取DexFile结构体

    百度这里用的是dvmDexFileOpenFromFd,通过这个函数我们得到了pDexFile

int 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;
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;
};

通过pDexFile->baseAddr 获取到dex加载的基址。

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;
};

通过pDexFile->pHeader->fileSize 获取到dex文件大小。

int fd = open("/sdcard/dump.dex", O_CREAT | O_WRONLY, 0666);
write(fd, pDexFile->baseAddr, pDexFile->pHeader->fileSize);
close(fd);

这时我们已经得到dex了。

二、百度壳对dex做了什么?

     1、修改DexClassDef中的classDataOff字段保存的偏移为负偏移

      

   

2、classdata数据清空

      

三、这么做如何让系统正常解析?

       百度的把classdata的数据保存在/data/data/xxxx/.1/1.jar包中,会在加载dex之前先分配空间给jar包,所以他的偏移为负值,内存结构如下图:

      

四、还原DEX

      1、获取到pDexFile后,我们遍历pDexFile->pClassDefs调用dexGetClassData获取到ClassData。将ClassData经过writeLeb128函数编码,写入到文件classdata并记录每个class的大小(此处参考Dexhunter做法)

   #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[i].type == 0x2000)   //0x2000代表classdata
		{
			cls_dat_off = pMaps->list[i].offset;  //获取classdata起始偏移
			break;
		}
	}
	log("classdata_offset:0x%x\n", cls_dat_off);
	log("0,");     //记录classdata的偏移用的log
	for (u4 i = 0; i<classDefsSize; i++)
	{
		const u1* data = dexGetClassData(g_pDexFile, &pClassDefs[i]);
		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中的偏移。

5、运行完后我们已经获取到正确的dex,我们将out.dex拖入JEB 已经可以正常解析。

六、附件说明

      额 附件不让上传了,大家看下思路就好


本主题帖已收到 0 次赞赏,累计¥0.00
最新回复 (38)
ddddddfx 2017-6-30 14:13
2
我顶啊 
1
scxc 2017-6-30 14:16
3
ddddddfx 我顶啊
你这太划水了吧。。
2
地狱怪客 2017-6-30 14:33
4
太厉害了
1
zfdyq 2017-6-30 14:35
5
这个厉害了!膜拜!
不知世事 2017-6-30 14:39
6
不错,赞
hanhaochi 2017-6-30 14:47
7
厉害了……等我涉及到这些,我天天去烦你……
1
scxc 2017-6-30 14:51
8
hanhaochi 厉害了……等我涉及到这些,我天天去烦你……[em_19]
韩大神最近在玩什么?
Youngs 2017-6-30 14:58
9
厉害了!叼叼叼!!
欧阳峰峰 2017-6-30 15:18
10
大神,onCreate流程研究了没?  invoke-static  {v1,  p0,  v0},  Lcom/baidu/protect/A;-&gt;V(ILjava/lang/Object;[Ljava/lang/Object;)V,这个函数,流程混淆的没法看了
clumsybirda 2017-6-30 15:47
11
看见楼上的评论白高兴了唉,oncreate都没还原怎么能叫dex还原呢,白高兴一场!
1
scxc 2017-6-30 16:48
12
欧阳峰峰 大神,onCreate流程研究了没? invoke-static {v1, p0, v0}, Lcom/baidu/protect/A;->V(ILjava/lang/Object;[Ljava ...
这个函数是在我分析的idb中的0x2CA4D。混淆我没看,可以hook  malloc函数看看他放了什么进去。
Loopher 2017-7-1 11:07
13
叼叼叼
Lostself 2017-7-1 16:55
14
66666
1
scxc 2017-7-3 11:42
15
欧阳峰峰 大神,onCreate流程研究了没? invoke-static {v1, p0, v0}, Lcom/baidu/protect/A;->V(ILjava/lang/Object;[Ljava ...
你可以分析下0x3292C到0x329DC中间内容。其他都没用的。。
smehod 2017-7-3 14:47
16
厉害!
欧阳峰峰 2017-7-3 21:16
17
谢大神,onCreate差不多分析完了
1
scxc 2017-7-4 11:06
18
欧阳峰峰 谢大神,onCreate差不多分析完了
别叫大神了,我是渣渣。看雪的大佬太多。
王小东 2017-7-4 15:05
19
谢大神,onCreate差不多分析完了
ugene 2017-7-5 14:32
20
太厉害了
繁华皆成空 2017-7-6 18:01
21
看来百度用了2代壳+vmp
1
scxc 2017-7-6 19:25
22
繁华皆成空 [em_4][em_4]看来百度用了2代壳+vmp
没有vmp只有混淆
欧阳锋锋 2017-7-6 20:00
23
有vmp有混淆,跟360的一样,通过jni解释的
1
scxc 2017-7-6 20:41
24

欧阳锋锋 有vmp有混淆,跟360的一样,通过jni解释的[em_48]

好吧  我还没分析里面流程  没看到呢 dalvik指令的解释器不能算vmp吧? 这种跟邦邦企业版的vmp差的还挺大吧

欧阳锋锋 2017-7-6 23:16
25
先前分析棒棒企业版的,就是内存加载加类抽取加这种vmp,各大加固厂商宣传的vmp也是这种实现原理,没看到哪家是不依赖dalvik,真正自己实现一套指令的,难道现在棒棒实现了?企业版和免费的,在dex的加载执行上区别是不大的,无非是在对so的处理上,保护强度大些
1
scxc 2017-7-7 00:01
26

欧阳锋锋 先前分析棒棒企业版的,就是内存加载加类抽取加这种vmp,各大加固厂商宣传的vmp也是这种实现原理,没看到哪家是不依赖dalvik,真正自己实现一套指令的,难道现在棒棒实现了?企业版和免费的,在dex的 ...

有没有样本呀。我看看跟我看的一样吗。libdexvmp.so?

无边 2017-7-7 01:34
27
大哥,来个测试样本apk啊。
cugtaotao 2017-7-7 17:32
28
支持一个,分析的很不错。看来类抽取的加固方案也不是很安全。目前正在实现类抽取的加固方案,有兴趣的加我QQ409842321一起交流研究。
1
houjingyi 2017-9-10 00:04
29
6666666666666
看雪猫猫 6天前
30
大神用的什么工具~~~透露下啊
clumsybirda 6天前
31
这样太水了吧,这个负偏移不是很早以前的事情了吗,早就oncreate了哎,为啥这样的帖子一而再再而三的出现呢,不懂哦!
1
scxc 5天前
32
我是很水 爱看看 不看滚 谢谢
clumsybirda 4天前
33
scxc 我是很水 爱看看 不看滚 谢谢[em_37]
发到文章再这里你是想让别人夸奖你呢,还是讨论技术的,如果你只是想让人夸奖你,那么联系我,删掉帖子,如果是讨论技术请好好的看下别人的技术点评
clumsybirda 4天前
34
欧阳锋锋 有vmp有混淆,跟360的一样,通过jni解释的[em_48]
并没像360哪有的vmp那么难,这个只是简单的负偏移罢了,2015年早就有人说过了  参考这篇文章http://bbs.pediy.com/thread-206441.htm  ,根本不用这么麻烦,随便改一下dalvik源码随便dump出dex,原理参考dexhunter原理,他这个demo是百度很早以前加固的样本是百度去年的加固了,不是最新的抽取oncreate丢到native运行的。
clumsybirda 4天前
35
繁华皆成空 [em_4][em_4]看来百度用了2代壳+vmp
并没像360哪有的vmp那么难,这个只是简单的负偏移罢了,2015年早就有人说过了  参考这篇文章http://bbs.pediy.com/thread-206441.htm  ,根本不用这么麻烦,随便改一下dalvik源码随便dump出dex,原理参考dexhunter原理,他这个demo是百度很早以前加固的样本是百度去年的加固了,不是最新的抽取oncreate丢到native运行的。
clumsybirda 4天前
36
王小东 谢大神,onCreate差不多分析完了
并没像360哪有的vmp那么难,这个只是简单的负偏移罢了,2015年早就有人说过了    参考这篇文章http://bbs.pediy.com/thread-206441.htm    ,根本不用这么麻烦,随便改一下dalvik源码随便dump出dex,原理参考dexhunter原理,他这个demo是百度很早以前加固的样本是百度去年的加固了,不是最新的抽取oncreate丢到native运行的。
clumsybirda 4天前
37
地狱怪客 太厉害了[em_20]
并没像360哪有的vmp那么难,这个只是简单的负偏移罢了,2015年早就有人说过了    参考这篇文章http://bbs.pediy.com/thread-206441.htm    ,根本不用这么麻烦,随便改一下dalvik源码随便dump出dex,原理参考dexhunter原理,他这个demo是百度很早以前加固的样本是百度去年的加固了,不是最新的抽取oncreate丢到native运行的。
clumsybirda 4天前
38
没意思搬砖去,楼主不要激动,我不是针对你,是说目前论坛大部分都是这样的文章,,没有一个发布修复dalvik指令虚拟化,然后修复oncreate的文章,全是把以前别人的蛋炒饭再重新包装炒热之后再发布一次。除了欧阳锋锋  的文章还有点意思,其余的全是水的不能再水
1
scxc 4天前
39
.
返回



©2000-2017 看雪学院 | Based on Xiuno BBS | 微信公众号:ikanxue
Time: 0.018, SQL: 15 / 京ICP备10040895号-17