首页
社区
课程
招聘
[原创]软件保护壳技术专题 - 识别函数与数据区域
发表于: 2009-12-12 16:28 22278

[原创]软件保护壳技术专题 - 识别函数与数据区域

2009-12-12 16:28
22278
/*
 * 预读分析阶段,在分区处理是时进行,数据与代码区域
 * 范围的界定,纯数据区域返回TRUE,反之为FALSE
 */
INLINE  BOOL PredictBlockEnd(LPBYTE pMem, LPBYTE pCurr, DWORD dwSize, DWORD *pOutSize, PANALYZE_CONFIGURE pAnalyzeConfigure)
{
  BOOL bBlock = FALSE;
  DWORD dwOffset = 0;
  ud_t ud_obj;
  ud_init(&ud_obj);
  ud_set_mode(&ud_obj, 32);
  ud_set_syntax(&ud_obj, UD_SYN_INTEL);
  ud_set_input_buffer(&ud_obj, pCurr, dwSize);
  while (ud_disassemble(&ud_obj) != 0)
  {
    enum ud_mnemonic_code mnemonic = ud_obj.mnemonic;
    if ((mnemonic == UD_Inop) ||
      (mnemonic == UD_Iint3) ||
      ((mnemonic == UD_Iadd) &&
      (ud_obj.inp_ctr == 2) &&
      (*(WORD *)&(ud_obj.inp_sess) == 0)))
    {
      /*
       * 到达结束条件
       * 检查是否到达了用户定义代码的最小范围,如果没到直接视为数据
       * 如果大于等于则进入深入鉴别
       */
      if (dwOffset < pAnalyzeConfigure->bCodeMixSize)
      {
        bBlock = TRUE;
      }
      else
      {
        // 进入深度分析
        bBlock = DeepAnalyzeBlock(pMem, pCurr, dwOffset, pAnalyzeConfigure);
      }
      *pOutSize = dwOffset;
      return bBlock;
    }/* end if */
    dwOffset += ud_insn_len(&ud_obj);
  }

  // 这里做深度鉴别
  bBlock = DeepAnalyzeBlock(pMem, pCurr, dwSize, pAnalyzeConfigure);
  *pOutSize = dwOffset;
  return bBlock;
}

/*
 * 进行分区处理
 * 以NOP,INT3,0,无效指令编码字符进行分区标志
 * 遇到NOP或者INT3,0,无效指令编码则将扫描过的区域
 * 作为一个区块摘出,继续查询,如果其后的数据有很长
 * 一段为连续的 NOP,INT3,0字节则将此视做绝对无效区域,
 * 在扫描过程中,如果遇到无效指令直接忽略当作这个区域
 * 的一部分如果遇到有效指令,则进入预分析阶段,尝试向前
 * 分析如果分析的指令长度小于最小代码长度则直接忽略.如果
 * 大于则将此区域继续分析,往返以上流程.直到完毕
 */
INLINE PPROCEDURE FormatBlock(LPBYTE pMem, LPBYTE pStart, DWORD dwSize, PANALYZE_CONFIGURE pAnalyzeConfigure)
{
  DWORD dwImageBase = GetNtHeader(pMem)->OptionalHeader.ImageBase;
  PPROCEDURE pBlock, *pCurrBlockPoint = NULL;
  pCurrBlockPoint = &pBlock;
  DWORD dwBlockEndSignCount = 0, dwOffset = 0;

  ud_t ud_obj;
  ud_init(&ud_obj);
  ud_set_mode(&ud_obj, 32);
  ud_set_syntax(&ud_obj, UD_SYN_INTEL);
  ud_set_input_buffer(&ud_obj, pStart, dwSize);

  while (ud_disassemble(&ud_obj) != 0)
  {
    enum ud_mnemonic_code mnemonic = ud_obj.mnemonic;
    if ((mnemonic == UD_Inop) ||
      (mnemonic == UD_Iint3) ||
      ((mnemonic == UD_Iadd) &&
      (ud_obj.inp_ctr == 2) &&
      (*(WORD *)&(ud_obj.inp_sess) == 0)))
    {
      dwBlockEndSignCount += ud_insn_len(&ud_obj);
    }
    else
    {
      /*
       * 遇到有效指令了
       * 现在该进入预读分析阶段,这里还有一个判断
       * 标志是剩余长度,如果其后的长度小于最小代码
       * 长度直接将这段代码视作为数据
       */
      DWORD dwRemainSize = dwSize - dwOffset;
      LPBYTE pCurr = pStart + dwOffset;
      if (dwRemainSize >= pAnalyzeConfigure->bCodeMixSize)
      {
        /*
         * 进入预读分析阶段
         * 在这里开始判断,如果预读处理分析的结果为单纯的数据块则
         * 与先前分析的区域进行合并
         * 否则单独为前面分析的块分配内存
         */
        DWORD dwOutSize = 0;
        if (PredictBlockEnd(pMem, pCurr, dwRemainSize, &dwOutSize, pAnalyzeConfigure) == TRUE)
        {
          // 进行合并
          dwBlockEndSignCount += dwOutSize;
        }
        else
        {
          /*
           * 判断上一组区块标记是否为0如果不为则分配空间存储它
           */
          if (dwBlockEndSignCount != 0)
          {
            (*pCurrBlockPoint) = __new__(PROCEDURE, 1);
            memset((*pCurrBlockPoint), 0, sizeof(PROCEDURE));
            (*pCurrBlockPoint)->bBlock = TRUE;//代码区域
            (*pCurrBlockPoint)->pFileStartAddress = pCurr - dwBlockEndSignCount;
            (*pCurrBlockPoint)->dwMemoryStartAddress = dwImageBase + Raw2Rva(pMem, (DWORD)((*pCurrBlockPoint)->pFileStartAddress - pMem));
            (*pCurrBlockPoint)->dwSize = dwBlockEndSignCount;
            pCurrBlockPoint = &((*pCurrBlockPoint)->pNext);
            dwBlockEndSignCount = 0;//清空标志记录计数
          }
          // 设定此段为代码区域
          (*pCurrBlockPoint) = __new__(PROCEDURE, 1);
          memset((*pCurrBlockPoint), 0, sizeof(PROCEDURE));
          (*pCurrBlockPoint)->bBlock = FALSE;//代码区域
          (*pCurrBlockPoint)->pFileStartAddress = pCurr;
          (*pCurrBlockPoint)->dwMemoryStartAddress = dwImageBase + Raw2Rva(pMem, (DWORD)(pCurr - pMem));
          (*pCurrBlockPoint)->dwSize = dwOutSize;
          pCurrBlockPoint = &((*pCurrBlockPoint)->pNext);
        }

        // 重新设定反汇编指针
        pCurr += dwOutSize;
        dwOffset += dwOutSize;
        dwRemainSize -= dwOutSize;//剩余长度
        ud_set_input_buffer(&ud_obj, pCurr, dwRemainSize);
        continue;
      }
      else
      {
        // 进入到这里就是进入到分析的末尾
        (*pCurrBlockPoint) = __new__(PROCEDURE, 1);
        memset((*pCurrBlockPoint), 0, sizeof(PROCEDURE));
        (*pCurrBlockPoint)->bBlock = TRUE;//表示有可能是数据
        dwBlockEndSignCount += dwRemainSize;
        (*pCurrBlockPoint)->dwSize = dwBlockEndSignCount;
        (*pCurrBlockPoint)->pFileStartAddress = pCurr;
        (*pCurrBlockPoint)->dwMemoryStartAddress = dwImageBase + Raw2Rva(pMem, (DWORD)(pCurr - pMem));
        pCurrBlockPoint = &((*pCurrBlockPoint)->pNext);
        dwBlockEndSignCount = 0;//清空标志记录计数
      }
    }
    dwOffset += ud_insn_len(&ud_obj);
  }

  /*
   * 处理组后一个纯区域块
   * 两种情况造成这种现象
   * 1) 整个分析的数据都是纯数据区
   * 2) 被分析的数据最后一个区域是纯数据区
   */
  if (dwBlockEndSignCount != 0)
  {
    LPBYTE pBlockZoon = NULL;
    // 第一种情况
    if (dwBlockEndSignCount == dwSize)
    {
      pBlockZoon = pStart;
    }
    else
    {
      pBlockZoon = pStart + dwSize - dwBlockEndSignCount;
    }
    (*pCurrBlockPoint) = __new__(PROCEDURE, 1);
    memset((*pCurrBlockPoint), 0, sizeof(PROCEDURE));
    (*pCurrBlockPoint)->bBlock = TRUE;//表示有可能是数据
    (*pCurrBlockPoint)->dwSize = dwBlockEndSignCount;
    (*pCurrBlockPoint)->pFileStartAddress = pBlockZoon;
    (*pCurrBlockPoint)->dwMemoryStartAddress = dwImageBase + Raw2Rva(pMem, (DWORD)(pBlockZoon - pMem));
    pCurrBlockPoint = &((*pCurrBlockPoint)->pNext);
    dwBlockEndSignCount = 0;//清空标志记录计数
  }

  return pBlock;
}

/*
 * 进行预分析,识别出数据
 * 如果分析出不是数据
 */  
INLINE PPROCEDURE AnalyzeData(LPBYTE pMem, LPBYTE pCurr, DWORD dwSize, PPROCEDURE pProcedureList, PPROGRAM pParents)
{
  PANALYZE_CONFIGURE pAnalyzeConfigure = &(pParents->AnalyzeConfigure);
  DWORD dwImageBase = GetNtHeader(pMem)->OptionalHeader.ImageBase;
  // 如果此块的长度小于用户指定长度
  if (dwSize < pAnalyzeConfigure->bCodeMixSize)
  {
    PPROCEDURE pBlock = __new__(PROCEDURE, 1);
    memset(pBlock, 0, sizeof(PROCEDURE));
    pBlock->bBlock = TRUE;
    pBlock->pFileStartAddress = pCurr;
    pBlock->dwMemoryStartAddress = dwImageBase + Raw2Rva(pMem, (DWORD)(pCurr - pMem));
    pBlock->dwSize = dwSize;
    pBlock->pNext = NULL;

    PPROCEDURE *pCurrMainPoint = &pProcedureList;
    while (*pCurrMainPoint != NULL) pCurrMainPoint = &((*pCurrMainPoint)->pNext);
    *pCurrMainPoint = pBlock;
    return pProcedureList;
  }

  /*
   * 开始对这个块进行有效的分区
   * 分区完毕后对链中的代码块进行函数帧分析
   * 初次分析
   */
  PPROCEDURE pFormatBlockList = FormatBlock(pMem, pCurr, dwSize, pAnalyzeConfigure);

  /*
   * 遍历此链表进行分析
   * 如果遇到代码块则进入并开始代码分析
   */
  PPROCEDURE pCurrBlock = pFormatBlockList;

  while (pCurrBlock != NULL)
  {
    if (pCurrBlock->bBlock == FALSE)//为代码块
    {
      // 进行分析
      PPROCEDURE pProcedure = GetProcFrame(pMem, pCurrBlock->pFileStartAddress, pCurrBlock->dwSize, pParents);
      /*
       * 调用Procedure2Procedure过后形成的函数链中存在两种函数,一种是函数存在在已有的
       * 未知区域中,一种是在做第一次扫描时分析到的函数
       */
      DWORD dwCount = Procedure2Procedure(pMem, pProcedureList, pProcedure);
    }
    else
    {
      // 直接连接到主链
      PPROCEDURE *pCurrMainPoint = &pProcedureList;
      while (*pCurrMainPoint != NULL) pCurrMainPoint = &((*pCurrMainPoint)->pNext);
      *pCurrMainPoint = __new__(PROCEDURE, 1);
      memcpy(*pCurrMainPoint, pCurrBlock, sizeof(PROCEDURE));
      (*pCurrMainPoint)->pNext = NULL;
    }
    pCurrBlock = pCurrBlock->pNext;
  }

  // 销毁分析链
  ReleaseProcedureList(&pFormatBlockList);
  return pProcedureList;
}

/*
 * 找寻所有不在链上的内存区域,并归结到链上
 */
INLINE PPROCEDURE AnalyzeProcedurePass1DiscoveryUnknowZoon(LPBYTE pMem, PPROCEDURE pProcedureList, PPROGRAM pParents)
{
  PPROCEDURE pCurrProcedure = pProcedureList;
  LPBYTE pStart = pMem + GetEntryPointSection(pMem)->PointerToRawData, pCurr = pStart;
  DWORD dwCodeSize = GetEntryPointSection(pMem)->Misc.VirtualSize;
  PPROCEDURE pUnknowProcedureList = NULL;
  LPBYTE pNow = NULL;
  DWORD dwCurrSize = 0, dwBlockSize = 0, dwRemainSize = 0;

  g_pAnalyzeDataDispatcher = MakeAnalyzeDataFromInstructionDispatcher();

_new_analyze:
  while (pCurrProcedure != NULL)
  {
    pNow = pCurrProcedure->pFileStartAddress;
    dwCurrSize = pCurrProcedure->dwSize;

    if (pCurr == pNow)//如果相当则直接略过
    {
      pCurr += dwCurrSize;
      dwRemainSize -= dwCurrSize;
    }
    else if (pCurr < pNow)//分析这个代码块
    {
      dwBlockSize = (DWORD)(pNow - pCurr);
      dwRemainSize -= dwBlockSize;
      goto _handler;
    }
    pCurrProcedure = pCurrProcedure->pNext;
  }

  // 判断是否到达末尾
  if (dwRemainSize != 0)
  {
    dwBlockSize = dwRemainSize;
    goto _handler;
  }

  // 释放派遣表
  DestroyDispatcherList(&g_pAnalyzeDataDispatcher);
  return pProcedureList;

// 这里为处理函数所在
_handler:
  /*
   * 这里的处理和前一次处理有个区别就是不知道当前这个区域是
   * 数据还是代码,所有首先要做数据鉴别
   */
  pUnknowProcedureList = AnalyzeData(pMem, pCurr, dwBlockSize, pProcedureList, pParents);
  pProcedureList = SortProcedureList(pProcedureList);//排序
  // 重新设定所有初始值,然后重新来过
  pCurr = pStart;
  dwRemainSize = dwCodeSize;//重新设定长度
  pUnknowProcedureList = NULL;
  pCurrProcedure = pProcedureList;
  __PrintProcedureListCount__(pProcedureList);
  goto _new_analyze;//重新进入新的一次分析
}

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

上传的附件:
收藏
免费 7
支持
分享
最新回复 (32)
雪    币: 7651
活跃值: (523)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
2
好文章啊,继续顶~~
2009-12-12 16:32
0
雪    币: 414
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
此文章需要收藏品读~~
2009-12-12 18:25
0
雪    币: 168
活跃值: (152)
能力值: ( LV11,RANK:180 )
在线值:
发帖
回帖
粉丝
4
这个专题一直跟踪到现在,应该继续顶~
2009-12-12 21:07
0
雪    币: 433
活跃值: (1870)
能力值: ( LV17,RANK:1820 )
在线值:
发帖
回帖
粉丝
5
膜拜玩命版主大人……
2009-12-12 21:18
0
雪    币: 1844
活跃值: (35)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
6
进入观摩精华帖
2009-12-12 22:29
0
雪    币: 47147
活跃值: (20450)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
7
确实,能坚持下来不容易,感谢玩命!
2009-12-12 22:38
0
雪    币: 7309
活跃值: (3788)
能力值: (RANK:1130 )
在线值:
发帖
回帖
粉丝
8
如果不是2次加密,直接用PDB
2009-12-12 23:03
0
雪    币: 390
活跃值: (15)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
9
太强大了,玩命版主大人
2009-12-13 02:59
0
雪    币: 1708
活跃值: (586)
能力值: ( LV15,RANK:670 )
在线值:
发帖
回帖
粉丝
10
支持玩命大哥
2009-12-13 10:23
0
雪    币: 347
活跃值: (30)
能力值: ( LV9,RANK:420 )
在线值:
发帖
回帖
粉丝
11
玩命大人

太强悍了

膜拜
2009-12-13 13:41
0
雪    币: 99
活跃值: (219)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
:eek想不顶都难
2009-12-13 14:03
0
雪    币: 348
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
学习楼主的精神!
2009-12-13 21:02
0
雪    币: 112
活跃值: (48)
能力值: ( LV9,RANK:320 )
在线值:
发帖
回帖
粉丝
14
来学习大哥新作,,顶起
2009-12-14 10:36
0
雪    币: 1022
活跃值: (31)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
15
玩命太强了~
2009-12-14 10:59
0
雪    币: 351
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
mark..
2009-12-14 17:47
0
雪    币: 201
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
比较高深,俺不太懂,不过还是支持下哈哈
2009-12-14 17:57
0
雪    币: 139
活跃值: (126)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
18
神经网络主要是做非线性分析和解决模式识别的一些问题,在代码和数据的甄别上我感觉倒是不好应用---当然我的理解可以是错的。样本的收集不是小问题,而且你如何提高神经网络的训练速度?它的慢是出了名的。
2009-12-15 04:20
0
雪    币: 11121
活跃值: (158)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
强帖,挂个号。
2009-12-15 07:58
0
雪    币: 102
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
膜拜楼主,努力学习
2009-12-15 11:15
0
雪    币: 124
活跃值: (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
21
好贴,收藏~~
2009-12-15 14:28
0
雪    币: 7115
活跃值: (639)
能力值: (RANK:1290 )
在线值:
发帖
回帖
粉丝
22
其实识别代码与数据就是一个模糊识别。 样本这个 嘿嘿 就是我的一个比较核心的东西了。 我学习的不是具体的样本。而是规则的样本。这个收集的少的多。 因为想投一些国际的核心期刊。周期会比较长。最少也要半年以后,如果幸运的入稿的话。我就贴到论坛上再一起探讨。
2009-12-15 16:03
0
雪    币: 303
活跃值: (41)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
23
玩命的帖子终于出来了。
规则,假设太多了,要是能少些规则,假设,做到通用些就强悍了。
2009-12-16 01:44
0
雪    币: 557
活跃值: (10)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
24
楼主太玩命了~~~

可惜自己基础不行 暂时看不懂
2009-12-16 20:34
0
雪    币: 115
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
25
怒赞 玩命博士
2009-12-16 23:10
0
游客
登录 | 注册 方可回帖
返回
//