首先感谢天草老师,这些天跟他学习到了不少东西。这个其实是他布置的作业,给大家分享下成果。
      PEArmor这个壳特点:1、aplib压缩 2、IAT加密 3、程序Call和Jmp跳入壳里然后解密执行真api(不知道密届术语)。壳分两层外壳,第一层解压出第二层外壳,然后跳入第二层外壳去执行(第二层开始处大量花),第二层解压出各个段,接着还原IAT,再根据加密表把程序代码里的 call和jmp指向外壳,跳向oep。
    首先我找第一层壳的入口,找需要解压二层外壳所需要的相关数据的偏移,解压二层外壳。

代码:
  //*************************************************************************
  //搜索特征码,在壳第一层找真正壳代码入口。
  //*************************************************************************
  BYTE szPCode1[] = "\x5D\x81\xED\x05\x00\x00\x00\x8D\x75\x3D\x56";
  shellstart = searchMem(pPEImage,szPCode1,sizeof(szPCode1));
  if (shellstart == NULL)
  {
    return FALSE;
  }

BYTE * FistPackBaseAddr = NULL;
  DWORD  dwFirstPackSize = 0;   
  HANDLE hFistPackTempMem = 0;
//*************************************************************************
//    解压第二层外壳
 //*************************************************************************
     __try
     {
       FistPackBaseAddr = shellstart - 0xAF;
       dwFirstPackSize  = GETDWORD(FistPackBaseAddr + 0x82);
       hFistPackTempMem = VirtualAlloc(NULL,dwFirstPackSize, MEM_COMMIT, PAGE_READWRITE);
       aP_depack_asm((PVOID)(GETDWORD(FistPackBaseAddr+0x7e)+FistPackBaseAddr),(PVOID)hFistPackTempMem);
     }
     __except(EXCEPTION_EXECUTE_HANDLER)
     {
       VirtualFree(hFistPackTempMem,dwFirstPackSize,MEM_RELEASE);
       return FALSE;
     }

//*************************************************************************
//搜索特征码,在壳第二层找真正壳代码入口(跳过无数花,准确定位,同时也确认是当前版本的壳)。
//*************************************************************************

     BYTE szPCode2[] = "\xE8\x00\x00\x00\x00\x5A\x83\xEA\x05\x5D\xB9\x03\x00\x00\x00";
     
     shellstart2 = searchMem((BYTE *)hFistPackTempMem,szPCode2,sizeof(szPCode2));
     
     if (shellstart2 == NULL)
     {
       return FALSE;
     }
      接下来就是要解压PE的各个区段的真真数据了。
代码:
BOOL CPEArmor046UnPack::unPackEachSection()
{

     __try
     {
       DWORD dwOffset = 0x2ED;
       while (GETDWORD(shellstart2 + dwOffset)!=0)
       {
         DWORD dwCurrentSectionSize = GETDWORD(shellstart2 + dwOffset);
         HANDLE hEachSectionTempMem = VirtualAlloc(NULL,dwCurrentSectionSize, MEM_COMMIT, PAGE_READWRITE);
         DWORD dwEachSectionPackDataAddr = GETDWORD(shellstart2 + dwOffset + 0x4) + (DWORD)pImage;
         aP_depack_asm((PVOID)(dwEachSectionPackDataAddr),(PVOID)hEachSectionTempMem);
         memcpy((PVOID)dwEachSectionPackDataAddr,(PVOID)hEachSectionTempMem,dwCurrentSectionSize);
         VirtualFree(hEachSectionTempMem,dwCurrentSectionSize,MEM_RELEASE);
         dwOffset += 0xC;
       }
     }
     
     __except(EXCEPTION_EXECUTE_HANDLER)
     {
       return FALSE;
     }
     return TRUE;
}
       分析IAT,找出修复IAT需要的数据存入Vector。
代码:
BOOL CPEArmor046UnPack::analyzeImportTable()
{

        
  __try{
    
    BOOL blApiStrShuffle  = GETDWORD(shellstart2 + 0x2B8) == 1?TRUE:FALSE;
    
    
    if (blApiStrShuffle)  //IAT加密方式1
    {
      DWORD dwOrgImportaddr  = GETDWORD(shellstart2 + 0x2c0) + (DWORD)shellstart2;
      while (TRUE)
      {
        if (GETDWORD((PDWORD)(dwOrgImportaddr))==0)
        {
          break;
        }
        STOrgImport stOrgImportDataTemp ;
        stOrgImportDataTemp.dwThunkTable = GETDWORD((PDWORD)(dwOrgImportaddr));
        stOrgImportDataTemp.strdllName.assign((char *)(dwOrgImportaddr+5));
        stOrgImportDataTemp.dwApiNumber = GETDWORD((PBYTE)(dwOrgImportaddr + 5 + GETBYTE((PBYTE)(dwOrgImportaddr + 4)) + 1));
        dwOrgImportaddr = dwOrgImportaddr + 5 + GETBYTE(dwOrgImportaddr + 4) +5;
        BOOL blIsApiOrd = GETBYTE(dwOrgImportaddr)==0?TRUE:FALSE;
        stOrgImportDataTemp.isOrd = blIsApiOrd;
        if (blIsApiOrd) //序号
        {
          for (int i = 0 ; i < stOrgImportDataTemp.dwApiNumber;i++)
          {
            DWORD dwApiOrg = GETDWORD(dwOrgImportaddr+1);
            stOrgImportDataTemp.vecApiOrd.push_back(dwApiOrg);
            dwOrgImportaddr = dwOrgImportaddr + 1 + sizeof(DWORD) + 1;
          }
        }
        else  //APi名
        {
          for (int i = 0 ; i < stOrgImportDataTemp.dwApiNumber;i++)
          {
            string strApiName;
            strApiName.assign((char *)(dwOrgImportaddr+1));
            stOrgImportDataTemp.vecApiName.push_back(strApiName);
            dwOrgImportaddr = dwOrgImportaddr + 1 + GETBYTE(dwOrgImportaddr)+1;
          }
        }
        
        vecImport.push_back(stOrgImportDataTemp);
        
      }
      
    }
    else  // IAT不自定义存储格式的 (IAT加密方式2)
    {
      DWORD dwDllBase = GETDWORD(shellstart2 + 0x2c0) + (DWORD)pImage;
      
      DWORD dwApiOrdOrName = NULL;
      DWORD dwIatAddr = NULL;
      while(TRUE)
      {
        
        DWORD dwDllNameAddr = GETDWORD((PBYTE)dwDllBase + 0xc);
        if (dwDllNameAddr != 0)
        {
          
          dwDllNameAddr = dwDllNameAddr + (DWORD)pImage; //dllname
          
          
          if (GETDWORD(dwDllBase) !=0)
          {
            dwApiOrdOrName = GETDWORD(dwDllBase) + (DWORD)pImage;
            dwIatAddr = GETDWORD(dwDllBase + 0x10)+(DWORD)pImage;
          }
          else
          {
            dwApiOrdOrName = GETDWORD(dwDllBase + 0x10) + (DWORD)pImage;
            dwIatAddr = GETDWORD(dwDllBase + 0x10)+(DWORD)pImage;
          }
          
          
          STOrgImport stOrgImportDataTemp;
          if (GETDWORD(dwApiOrdOrName) & 0x80000000)
          {
            stOrgImportDataTemp.isOrd = TRUE;
          }
          else
          {
            stOrgImportDataTemp.isOrd = FALSE;
          }
          stOrgImportDataTemp.dwThunkTable = dwIatAddr - (DWORD)pImage;
          stOrgImportDataTemp.strdllName.assign((char *)dwDllNameAddr);
          
          
          
          while(TRUE)
          {
            if (GETDWORD(dwApiOrdOrName) == 0)
            {
              dwDllBase = dwDllBase + 0x14;
              
              vecImport.push_back(stOrgImportDataTemp);
              break;
            }
            else
            {
              //处理
              
              if ( GETDWORD(dwApiOrdOrName) & 0x80000000 )
              {
                DWORD dwOrd = GETDWORD(dwApiOrdOrName) & 0x7fffffff;
                stOrgImportDataTemp.vecApiOrd.push_back(dwOrd);
              }
              else
              {
                DWORD dwApiNameAddr = (GETDWORD(dwApiOrdOrName) + 2 ) + (DWORD)pImage;
                string strApiName;
                strApiName.assign((char *)dwApiNameAddr);
                stOrgImportDataTemp.vecApiName.push_back(strApiName);
              }
              
              dwApiOrdOrName = dwApiOrdOrName + 0x4;
              
              dwIatAddr = dwIatAddr + 0x4;
            }
          }
          
          
        }
        else
        {
          break;
        }
      }
    }
    }
    __except(EXCEPTION_EXECUTE_HANDLER)
    {
      return FALSE;
    }
    return TRUE;
}
         根据分析的数据修复IAT。
代码:
BOOL CPEArmor046UnPack::fixImportTable()
{

  __try{
    
    DWORD dwDLLNumber = vecImport.size();
    BYTE * NewImportAddrSave = this->addNewImportSectionAddr;
    BYTE * temppoint = (BYTE *)(this->addNewImportSectionAddr+(dwDLLNumber + 1) * sizeof(IMAGE_IMPORT_DESCRIPTOR));
    for(vector<STOrgImport>::iterator it = vecImport.begin(); it != vecImport.end();++it)
    {
      
      IMAGE_IMPORT_DESCRIPTOR STNewIID = {0};
      string strDllName = it->strdllName;
      strDllName.copy((char *)temppoint,strDllName.length(),0);//复制到新增区域
      // fill IID struct
      STNewIID.FirstThunk = it->dwThunkTable;
      STNewIID.Name = (DWORD)(temppoint-pImage);
      STNewIID.OriginalFirstThunk=0;
      
      
      temppoint += strDllName.length() + 1 + 2; //加三个零
      
      PDWORD iat = (PDWORD)(STNewIID.FirstThunk + (DWORD)pImage);
      
      //序号方式处理
      if (it->isOrd)
      {
        for(vector<DWORD>::iterator itapi = it->vecApiOrd.begin(); itapi != it->vecApiOrd.end();++itapi)
        {
          *iat = *itapi | 0x80000000;
          iat++;
        }
      }
      else //APi名字方式处理
      {
        for(vector<string>::iterator itapi = it->vecApiName.begin(); itapi != it->vecApiName.end();++itapi)
        {
          itapi->copy((char *)temppoint,(*itapi).length());
          
          *iat = temppoint - 2 - pImage;
          iat++;
          temppoint += (*itapi).length() + 1 + 2;//加三个零
        }
        
      }
      *iat = 0;
      
      memcpy((PVOID)NewImportAddrSave,(PVOID)&STNewIID,sizeof(IMAGE_IMPORT_DESCRIPTOR));
      NewImportAddrSave += sizeof(IMAGE_IMPORT_DESCRIPTOR);
    }
    
    ((PIMAGE_NT_HEADERS)pPEImage)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = this->addNewImportSectionAddr - pImage;
  }
  __except(EXCEPTION_EXECUTE_HANDLER)
  {
    return FALSE;
  }
  return TRUE;
}
        修复壳里的Call和Jmp。按hying的说法,这里叫特殊代码处理
代码:
BOOL CPEArmor046UnPack::fixSpecialApiEncode()
{

  
  __try{
    
    DWORD ApiIsEncode = GETDWORD(shellstart2 + 0x2BC);
    
    if (ApiIsEncode == 1) //是否特殊代码处理 FF 15 或 FF 25
    {
      
      //修复Api 
      
      DWORD dwDecodeTable =  GETDWORD(shellstart2 + 0x2c4) + (DWORD)shellstart2;
      while ( (*(PDWORD)dwDecodeTable) != 0)
      {
        DWORD dwDecodeVal = *(PDWORD)dwDecodeTable;
        
        dwDecodeVal = dwDecodeVal  << 1;
        dwDecodeVal = dwDecodeVal >> 1;
        
        if( ( *((PBYTE)dwDecodeTable+3) ) == 0x80 )
        {
          //25ff
          DWORD dwDecodeIAT = *(PDWORD)(dwDecodeTable + 4);
          dwDecodeVal = dwDecodeVal - (DWORD)pe.ImageBase() + (DWORD)pImage;
          *((PWORD)(dwDecodeVal - 6)) = 0x25ff;
          *((PDWORD)(dwDecodeVal - 4)) = dwDecodeIAT;
        }
        else
        {
          DWORD dwDecodeIAT = *(PDWORD)(dwDecodeTable + 4);
          dwDecodeVal = dwDecodeVal - (DWORD)pe.ImageBase() + (DWORD)pImage;
          *((PWORD)(dwDecodeVal - 6)) = 0x15ff;
          *((PDWORD)(dwDecodeVal - 4)) = dwDecodeIAT;
        }
        dwDecodeTable = dwDecodeTable + 8;
      }
      
    }
  }
  __except(EXCEPTION_EXECUTE_HANDLER)
  {
    return FALSE;
  }
  return TRUE;
}
         修复OEP。
代码:
BOOL CPEArmor046UnPack::fixOEP()
{
  
  __try
  {
    
    DWORD oep = GETDWORD(shellstart2 + 0x2C8);
    *(PDWORD((DWORD)pPEImage + 0x28)) = oep;
    
    fixSpecialApiEncode();
  }
  __except(EXCEPTION_EXECUTE_HANDLER)
  {
    return FALSE;
  }
  return TRUE;
}
         
          最后dump就OK了。只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!

上传的附件 PEArmorperfectionUnpackOOP.rar[解压密码:pediy.com]