首页
社区
课程
招聘
[原创][开源]Win32控制台解析PE文件
发表于: 2015-11-25 18:54 12099

[原创][开源]Win32控制台解析PE文件

2015-11-25 18:54
12099
推荐下这个帖子 希望能帮助你更好理解
手查PE导出表:http://bbs.pediy.com/showthread.php?p=1403106#post1403106

手查PE重定向:http://bbs.pediy.com/showthread.php?t=206072

代码500行 除了必要的计算文件偏移必须要封装外  其它都在main函数内  我不是故意的...   真的...
部分效果截图:




---------------------------------
进入正题:

目前已解析的有:

  • 基本PE头信息
  • 区段
  • 目录

  • - 输出表
  •     - 输入表 
  •     - 资源  
  •     - 重定位

  • 位置计算器


  • 计算文件偏移(也算是最整个代码的核心吧):
    DWORD CalcOffset(DWORD Rva,PIMAGE_NT_HEADERS32  pNtH)
    {
      //PIMAGE_NT_HEADERS32 pnt=pNtH;
      PIMAGE_SECTION_HEADER pSecHTemp=IMAGE_FIRST_SECTION(pNtH);//区段头
      int index=0;
      
      while (!(Rva>=pSecHTemp->VirtualAddress&&
        Rva<pSecHTemp->VirtualAddress+pSecHTemp->SizeOfRawData))
      {
        //找完所有区段还没有找到
        if (index>pNtH->FileHeader.NumberOfSections)
        {      
          return Rva;
        }
        ++index;
        ++pSecHTemp;
      }
      v=Rva-pSecHTemp->VirtualAddress+pSecHTemp->PointerToRawData;;
      return v;
    }
    


    这部分代码依旧是计算文件偏移,重定位特需 和上面稍有些不同:
    DWORD RelCalcOffset(DWORD Rva,PIMAGE_NT_HEADERS32 pNtH,char *Tempbuf,PCHAR pName=NULL,PCHAR pData=NULL,int Flag=NULL)
    {
      //PIMAGE_NT_HEADERS32 pnt=pNtH;
      PIMAGE_SECTION_HEADER pSecHTemp=IMAGE_FIRST_SECTION(pNtH);//区段头
      int index=0;
    
      while (!(Rva>=pSecHTemp->VirtualAddress&&
        Rva<pSecHTemp->VirtualAddress+pSecHTemp->SizeOfRawData))
      {
        //找完所有区段还没有找到
        if (index>pNtH->FileHeader.NumberOfSections)
        {
          //  m_Section=L"部首";
          ////  DWORD a[5];
          //  _memccpy(&Address,pSecHTemp,6,24);
          //  //Address=(int);
          if (Flag==2)
          {
            return Rva-pNtH->OptionalHeader.ImageBase;
          }
          return Rva;
        }
        ++index;
        ++pSecHTemp;
      }
      //获取区段名
      if (pName!=NULL)
      {
        //return Rva-pNtH->OptionalHeader.ImageBase;
        memcpy(pName,pSecHTemp->Name,8);
      }
      v=Rva-pSecHTemp->VirtualAddress+pSecHTemp->PointerToRawData;;
      DWORD iiii=(long)Tempbuf+v;
      //获取数据
      if (pData!=NULL)
      {
        //if (Flag==NULL)
        //{
        //  return Rva-pNtH->OptionalHeader.ImageBase;
        //}
        if (Flag==2)
        {
          return Rva-pNtH->OptionalHeader.ImageBase;
        }
        //flag 为1时 
        memcpy(pData,PCHAR((long)Tempbuf+v),10);
      }
      return v;
    }
    


    打开并判断是否为PE文件:
      //TCHAR FileName[] = _T("C:\\Users\\Administrator\\Desktop\\PEText.exe");C:\Users\Administrator\Desktop\MFCLibrary1Dll.dll
       //  TCHAR FileName[] = _T("D:\\Program Files (x86)\\Tencent\\WeChat\\WeChat.exe");
      //TCHAR FileName[] = _T("D:\\Program Files\\Tencent\\QQ\\Bin\\QQScLauncher.exe");
      TCHAR FileName[] = _T("C:\\Users\\Administrator\\Desktop\\Inpaint.exe");
      //TCHAR FileName[] = _T("C:\\Users\\Administrator\\Desktop\\MFCLibrary1Dll.dll");‪
      char* buf = nullptr;
      //得到文件句柄
      HANDLE hFile = CreateFile(
        FileName, GENERIC_READ|GENERIC_WRITE,
        0,
        NULL,
        OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL,
        NULL);
      //得到文件大小
      DWORD dwFileSize = 
        GetFileSize(hFile, NULL);
      DWORD ReadSize = 0;
      buf = new char[dwFileSize];
      //将文件读取到内存
      ReadFile(hFile, buf, dwFileSize, &
        ReadSize, NULL);
      PIMAGE_DOS_HEADER pDosH=(PIMAGE_DOS_HEADER)buf;
      if(IMAGE_DOS_SIGNATURE!=pDosH->e_magic)
      {
        printf_s("不是DOS头");
        return 0;
      }
      printf_s("DOS头:0x%X\n",pDosH->e_magic);
      printf_s("EXE文件的偏移头:0x%X\n",pDosH->e_lfanew);
      //获取NT头
      PIMAGE_NT_HEADERS32 pNtH=(PIMAGE_NT_HEADERS32)(buf+pDosH->e_lfanew);  
      //PIMAGE_NT_HEADERS32 pNtH=(PIMAGE_NT_HEADERS32)buf;  
      if (pNtH->Signature!=IMAGE_NT_SIGNATURE)
      {
        printf_s("不是NT头");
        return 0;
      }
    


    基本PE头信息:
      printf_s("文件头:\n");
      printf_s("文件的运行平台:0x%X\n",pNtH->FileHeader.Machine);
      printf_s("区段的数量:0x%X\n",pNtH->FileHeader.NumberOfSections);
      printf_s("文件的创建时间:0x%X\n",pNtH->FileHeader.TimeDateStamp);
      printf_s("符号表偏移:0x%X\n",pNtH->FileHeader.PointerToSymbolTable);
      printf_s("符号个数:0x%X\n",pNtH->FileHeader.NumberOfSymbols);
      printf_s("扩展头大小:0x%X\n",pNtH->FileHeader.SizeOfOptionalHeader);
      printf_s("PE文件的一些属性:0x%X\n",pNtH->FileHeader.Characteristics);
      printf_s("---------------------------------------------------------\n");
      printf_s("扩展头:\n");
      printf_s("标志字:0x%X\n",pNtH->OptionalHeader.Magic);
      printf_s("所有代码区段总大小:0x%X\n",pNtH->OptionalHeader.SizeOfCode);
      printf_s("已初始化的数据总大小:0x%X\n",pNtH->OptionalHeader.SizeOfInitializedData);
      printf_s("未初始化的数据总大小:0x%X\n",pNtH->OptionalHeader.SizeOfUninitializedData);
      printf_s("入口点:0x%X\n",pNtH->OptionalHeader.AddressOfEntryPoint);
      printf_s("代码基址:0x%X\n",pNtH->OptionalHeader.BaseOfCode);
      printf_s("数据基址:0x%X\n",pNtH->OptionalHeader.BaseOfData);
      printf_s("镜像基址:0x%X\n",pNtH->OptionalHeader.ImageBase);
      printf_s("块对齐:0x%X\n",pNtH->OptionalHeader.SectionAlignment);
      printf_s("文件对齐:0x%X\n",pNtH->OptionalHeader.FileAlignment);
      printf_s("镜像大小:0x%X\n",pNtH->OptionalHeader.SizeOfImage);
      printf_s("部首大小:0x%X\n",pNtH->OptionalHeader.SizeOfHeaders);
      printf_s("校验和:0x%X\n",pNtH->OptionalHeader.CheckSum);
      printf_s("子系统:0x%X\n",pNtH->OptionalHeader.Subsystem);
      printf_s("DLL特征:0x%X\n",pNtH->OptionalHeader.DllCharacteristics);
      printf_s("栈可增长最大值:0x%X\n",pNtH->OptionalHeader.SizeOfStackReserve);
      printf_s("栈初始值:0x%X\n",pNtH->OptionalHeader.SizeOfHeapCommit);
      printf_s("堆可增长最大值:0x%X\n",pNtH->OptionalHeader.SizeOfHeapReserve);
      printf_s("堆初始值:0x%X\n",pNtH->OptionalHeader.SizeOfHeapCommit);
      printf_s("RVA数及大小:0x%X\n",pNtH->OptionalHeader.NumberOfRvaAndSizes);
    


    目录:
      printf_s("输出表  RVA:0x%X  SIZE:0x%X\n",pNtH->OptionalHeader.DataDirectory[0].VirtualAddress,
                          pNtH->OptionalHeader.DataDirectory[0].Size);
    
      printf_s("输入表  RVA:0x%X  SIZE:0x%X\n",pNtH->OptionalHeader.DataDirectory[1].VirtualAddress,
        pNtH->OptionalHeader.DataDirectory[1].Size);
    
      printf_s("资源  RVA:0x%X  SIZE:0x%X\n",pNtH->OptionalHeader.DataDirectory[2].VirtualAddress,
        pNtH->OptionalHeader.DataDirectory[2].Size);
    
      printf_s("异常处理程序表  RVA:0x%X  SIZE:0x%X\n",pNtH->OptionalHeader.DataDirectory[3].VirtualAddress,
        pNtH->OptionalHeader.DataDirectory[3].Size);
    
      printf_s("安全  RVA:0x%X  SIZE:0x%X\n",pNtH->OptionalHeader.DataDirectory[4].VirtualAddress,
        pNtH->OptionalHeader.DataDirectory[4].Size);
    
      printf_s("重定位  RVA:0x%X  SIZE:0x%X\n",pNtH->OptionalHeader.DataDirectory[5].VirtualAddress,
        pNtH->OptionalHeader.DataDirectory[5].Size);
    
      printf_s("版权  RVA:0x%X  SIZE:0x%X\n",pNtH->OptionalHeader.DataDirectory[6].VirtualAddress,
        pNtH->OptionalHeader.DataDirectory[6].Size);
      
      printf_s("全局指针  RVA:0x%X  SIZE:0x%X\n",pNtH->OptionalHeader.DataDirectory[7].VirtualAddress,
        pNtH->OptionalHeader.DataDirectory[7].Size);
      
      printf_s("线程局部存储初始化节(TLS)  RVA:0x%X  SIZE:0x%X\n",pNtH->OptionalHeader.DataDirectory[8].VirtualAddress,
        pNtH->OptionalHeader.DataDirectory[8].Size);
      
      printf_s("载入配置  RVA:0x%X  SIZE:0x%X\n",pNtH->OptionalHeader.DataDirectory[9].VirtualAddress,
        pNtH->OptionalHeader.DataDirectory[9].Size);
      
      printf_s("载入范围  RVA:0x%X  SIZE:0x%X\n",pNtH->OptionalHeader.DataDirectory[10].VirtualAddress,
        pNtH->OptionalHeader.DataDirectory[10].Size);
      
      printf_s("导入地址表(IAT)  RVA:0x%X  SIZE:0x%X\n",pNtH->OptionalHeader.DataDirectory[11].VirtualAddress,
        pNtH->OptionalHeader.DataDirectory[11].Size);
      
      printf_s("延迟输入  RVA:0x%X  SIZE:0x%X\n",pNtH->OptionalHeader.DataDirectory[12].VirtualAddress,
        pNtH->OptionalHeader.DataDirectory[12].Size);
      
      printf_s("COM信息  RVA:0x%X  SIZE:0x%X\n",pNtH->OptionalHeader.DataDirectory[13].VirtualAddress,
        pNtH->OptionalHeader.DataDirectory[13].Size);
      
      printf_s("保留  RVA:0x%X  SIZE:0x%X\n",pNtH->OptionalHeader.DataDirectory[14].VirtualAddress,
        pNtH->OptionalHeader.DataDirectory[14].Size);
    


    区段:
    PIMAGE_SECTION_HEADER pSecH=IMAGE_FIRST_SECTION(pNtH);
      int i=0;
      while (i<pNtH->FileHeader.NumberOfSections)
      {
        printf_s("名称 %s  ",pSecH->Name);
        printf_s("VOffset %08X  ",pSecH->VirtualAddress);
        printf_s("VSize %08X  ",pSecH->Misc.VirtualSize);
        printf_s("ROffset %08X  ",pSecH->PointerToRawData);
        printf_s("Rsize %08X  ",pSecH->SizeOfRawData);
        printf_s("标志 %08X  \n",pSecH->Characteristics);
        ++pSecH;
        i++;
      }
    


    输出表:
    PIMAGE_OPTIONAL_HEADER32 pOptH;//可选头
    //  PIMAGE_SECTION_HEADER pSecH;//区段头
      PIMAGE_DATA_DIRECTORY pDatD;//数据目录
      PIMAGE_EXPORT_DIRECTORY pExpD;// 导出表数据
      
      //获取可选头数据
      pOptH=&(pNtH->OptionalHeader);
      //获取数据目录
      pDatD=&(pOptH->DataDirectory[0]);
      //获取导出表数据
      pExpD=(PIMAGE_EXPORT_DIRECTORY)(buf+CalcOffset(pDatD->VirtualAddress,pNtH));
      //判断是否有导出函数
      if (pExpD->NumberOfFunctions==0)
      {
        printf_s("无导出函数");
      }
      //取出三个表的函数地址
      PDWORD pFunAddr=(PDWORD)(buf+CalcOffset(pExpD->AddressOfFunctions,pNtH));  //函数地址
      PDWORD pFunNameAddr=(PDWORD)(buf+CalcOffset(pExpD->AddressOfNames,pNtH));  //函数名地址
      PWORD pOrdinalAddr=(PWORD)(buf+CalcOffset(pExpD->AddressOfNameOrdinals,pNtH));//函数序号地址
      
      DWORD NumberOfFun=pExpD->NumberOfFunctions;
      DWORD NumberOfName=pExpD->AddressOfNames;  
      printf_s("函数偏移表地址:%08X\n",CalcOffset(pDatD->VirtualAddress,pNtH));
      printf_s("函数地址:%08X\n",pExpD->AddressOfFunctions);
      printf_s("函数名序号地址:%08X\n",pExpD->AddressOfNameOrdinals);
      printf_s("函数名称地址:%08X\n",pExpD->AddressOfNames);
      printf_s("基址:%08X\n",pExpD->Base);
      printf_s("特征值:%08X\n",pExpD->Characteristics);
      printf_s("名称:%08X\n",pExpD->Name);
    //  printf_s("名称:%08X",pExpD->);
      printf_s("函数数量:%08X\n",pExpD->NumberOfFunctions);
      printf_s("函数名数量:%08X\n",pExpD->NumberOfNames);
      for (DWORD i=0;i<NumberOfFun;i++)
      {
        
        //如果是无效函数 进行下一次
        if (!pFunAddr[i])
        {
          continue;
        }
        //此时为有效函数  在序号表查找是否有这个序号 用以判断是函数名导出函数序号导出
        DWORD j=0;
        for (;j<NumberOfName;j++)
        {
    
          if (i==pOrdinalAddr[j])
          {
            break;
          }
        }
        //size_t
        //找到了 这是一个函数名导出的函数
        if (j!=NumberOfName)
        {
        //  (PCHAR)(buf+CalcOffset(pFunNameAddr[j],pNtH));
          printf_s("序号:%d  ",pOrdinalAddr[j]+pExpD->Base);
          printf_s("RVA:%08X  ",pFunAddr[i]);
          printf_s("偏移:%08X  ",CalcOffset(pFunAddr[i],pNtH));
          printf_s("函数名:%s\n",(buf+CalcOffset(pFunNameAddr[j],pNtH)));
        }
        //没有找到  这是一个序号导出的函数 没有名字
        else
        {
          printf_s("%d",i+pExpD->Base);
          printf_s("%08X",pFunAddr[i]);
          if (strcmp((buf+CalcOffset(pFunNameAddr[i],pNtH)),"")==0)
          {
            printf_s("没有");
          }
          //else
          //{
          //  printf_s("%s\n",(buf+CalcOffset(pFunNameAddr[i],pNtH)));
          //}
          
        }
      }
    


    输入表:
    PIMAGE_IMPORT_DESCRIPTOR  pImpD;
      pDatD=&(pOptH->DataDirectory[1]);
      pImpD=(PIMAGE_IMPORT_DESCRIPTOR)(buf+CalcOffset(pDatD->VirtualAddress,pNtH));
      //第一层循环 每个导入的DLL依次解析
      while(pImpD->Name)
      {
        //DLL名称相关
        printf_s("DLL名称:%s  ",(buf+CalcOffset(pImpD->Name,pNtH)));
        printf_s("INT(输入名称表):%08X  ",pImpD->OriginalFirstThunk);
        printf_s("日期时间标志:%08X  ",pImpD->TimeDateStamp);
        printf_s("ForwarderChain:%08X  ",pImpD->ForwarderChain);
        printf_s("名称:%08X  ",pImpD->Name);
        printf_s("FirstThunk:%08X\n",pImpD->FirstThunk);
        //从获取的DLL导入函数地址表 IAT 计算偏移
        PIMAGE_THUNK_DATA32 pInt=(PIMAGE_THUNK_DATA32)(buf+CalcOffset(pImpD->FirstThunk,pNtH));
        
        //循环解析导入地址表IAT
        while(pInt->u1.Function)
        {
          
          DWORD ThunkOffest=CalcOffset(pImpD->OriginalFirstThunk,pNtH);
          //判断最高位是否为1 不为1按名称导入
          if (!IMAGE_SNAP_BY_ORDINAL32(pInt->u1.Ordinal))
          {
            
            //找到函数序号名地址 并将其取出  
            printf_s("ThunkRVA:%08X  ",pImpD->OriginalFirstThunk);
            printf_s("Thunk偏移:%08X  ",ThunkOffest);
            printf_s("Thunk值:%08X  ",pInt->u1.AddressOfData);
            PIMAGE_IMPORT_BY_NAME pFunName=(PIMAGE_IMPORT_BY_NAME)(buf+CalcOffset(pInt->u1.AddressOfData,pNtH));
            printf_s("提示:%04X  ",pFunName->Hint);
            printf_s("API名称:%s\n",pFunName->Name);
            //每次偏移四个字节
            pImpD->OriginalFirstThunk+=4;
            ThunkOffest+=4;
          }
          else
          {
            //找到函数序号名地址 并将其取出  
          //  PIMAGE_IMPORT_BY_NAME pFunName=(PIMAGE_IMPORT_BY_NAME)(buf+CalcOffset(pInt->u1.AddressOfData,pNtH));
            printf_s("ThunkRVA:%08X  ",pImpD->OriginalFirstThunk);
            printf_s("Thunk偏移:%08X  ",ThunkOffest);
            printf_s("Thunk值:%08X  ",pInt->u1.AddressOfData);
            printf_s("提示:-  ");
            printf_s("序号:%4xH  %4dD\n",pInt->u1.Ordinal&0x7fffffff,pInt->u1.Ordinal&0x7fffffff);
          }
          pInt++;
        }
        system("pause");
        pImpD++;
      }
    


    资源:
    //获取资源表
       pDatD=&(pOptH->DataDirectory[2]);
       PIMAGE_RESOURCE_DIRECTORY pResD=(PIMAGE_RESOURCE_DIRECTORY)(buf+CalcOffset(pDatD->VirtualAddress,pNtH));
       DWORD ReSize=pResD->NumberOfIdEntries+pResD->NumberOfNamedEntries;
       PIMAGE_RESOURCE_DIRECTORY_ENTRY pResDE=(PIMAGE_RESOURCE_DIRECTORY_ENTRY)((long)pResD+sizeof(IMAGE_RESOURCE_DIRECTORY));
       
       char ResourceName[15][16]={"鼠标指针","位图","图标","菜单","对话框",
                    "字符串列表","字体目录","字体","快捷键","非格式化资源",
                    "消息列表","鼠标指针组","图标组","版本信息"};
       printf_s("第一层[名称条目]->:%04X   ",pResDE->NameIsString);  
       printf_s("第一层[ID条目]->:%04X   \n",ReSize);    
       for (DWORD FirstOrder=0;FirstOrder<ReSize;FirstOrder++)
       {
         //第一层 假如是字符串标识
         if (pResDE->NameIsString==1)
         {
           PIMAGE_RESOURCE_DIR_STRING_U pREsDStrU=(PIMAGE_RESOURCE_DIR_STRING_U)((long)pResD+pResDE->NameOffset);
           printf_s("资源类型名:%s",pREsDStrU->NameString);
         }
         //假如是一直类型 用序号作为标识
         else
         {
           switch (pResDE->Name)
           {
           case 0x1:
             printf_s("第一层:%s\n",ResourceName[0]);
             break;        
           case 0x2:        
             printf_s("第一层:%s\n",ResourceName[1]);
             break;        
           case 0x3:        
             printf_s("第一层:%s\n",ResourceName[2]);
             break;        
           case 0x4:        
             printf_s("第一层:%s\n",ResourceName[3]);
             break;        
           case 0x5:        
             printf_s("第一层:%s\n",ResourceName[4]);
             break;        
           case 0x6:        
             printf_s("第一层:%s\n",ResourceName[5]);
             break;        
           case 0x7:        
             printf_s("第一层:%s\n",ResourceName[6]);
             break;        
           case 0x8:        
             printf_s("第一层:%s\n",ResourceName[7]);
             break;        
           case 0x9:        
             printf_s("第一层:%s\n",ResourceName[8]);
             break;        
           case 0xA:        
             printf_s("第一层:%s\n",ResourceName[9]);
             break;        
           case 0xB:        
             printf_s("第一层:%s\n",ResourceName[10]);
             break;        
           case 0xC:        
             printf_s("第一层:%s\n",ResourceName[11]);
             break;        
           case 0xE:        
             printf_s("第一层:%s\n",ResourceName[12]);
             break;        
           case 0x10:        
             printf_s("第一层:%s\n",ResourceName[13]);
             break;        
           default:
             printf_s("第一层:%d\n",pResDE->Name);
             break;
           }
         }
         //找第二层 注意OFFEST 是相对于pResD也就是资源开始位置的偏移
         PIMAGE_RESOURCE_DIRECTORY pResD2=(PIMAGE_RESOURCE_DIRECTORY)((long)pResD+pResDE->OffsetToDirectory);
         DWORD ReSize2=pResD2->NumberOfIdEntries+pResD2->NumberOfNamedEntries;
         PIMAGE_RESOURCE_DIRECTORY_ENTRY pResDE2=(PIMAGE_RESOURCE_DIRECTORY_ENTRY)((long)pResD2+sizeof(IMAGE_RESOURCE_DIRECTORY));
         printf_s("第一层[名称条目]->:%04X   ",pResD2->NumberOfNamedEntries);  
         printf_s("第一层[ID条目]->:%04X   \n",pResD2->NumberOfIdEntries);
         for (DWORD SecondOrder=0;SecondOrder<ReSize2;SecondOrder++)
         {
           if (pResDE2->DataIsDirectory==1)
           {
             //输出第二层资源的标识看是数字还是字符串
             if (pResDE2->NameIsString==1)
             {
               PIMAGE_RESOURCE_DIR_STRING_U pREsDStrU2=(PIMAGE_RESOURCE_DIR_STRING_U)((long)pResD+pResDE2->NameOffset);
               //输出资源类型名字
               printf("第二层->资源类型名:%ls   ",pREsDStrU2->NameString);
             }
             else
             {
               printf_s("第二层->资源类型名ID:%d   ",pResDE2->Id);        
             }
             //解析第三层 
             PIMAGE_RESOURCE_DIRECTORY pResD3=(PIMAGE_RESOURCE_DIRECTORY)((long)pResD+pResDE2->OffsetToDirectory);
             PIMAGE_RESOURCE_DIRECTORY_ENTRY pResDE3=(PIMAGE_RESOURCE_DIRECTORY_ENTRY)((long)pResD3+sizeof(IMAGE_RESOURCE_DIRECTORY));
             PIMAGE_RESOURCE_DATA_ENTRY pResDataE=(PIMAGE_RESOURCE_DATA_ENTRY)((long)pResD+pResDE3->OffsetToData);
             
             printf_s("第三层->RVA:%08X   ",pResDataE->OffsetToData);
             printf_s("第三层->偏移:%08X   ",(CalcOffset(pResDataE->OffsetToData,pNtH)));
             printf_s("第三层->大小:%08X\n",pResDataE->Size);
    
           }
           else
           {
             break;
           }
           pResDE2++;
         }
         pResDE++;
       }
    


    重定位:
     pDatD=&(pOptH->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]);//也就是5
       PIMAGE_BASE_RELOCATION pBasR=(PIMAGE_BASE_RELOCATION)((long)buf+CalcOffset(pDatD->VirtualAddress,pNtH));
       RELOCAREAINFO Temp={0};
       int j=0;
       while (pBasR->VirtualAddress)
       {
         printf_s("索引:%d  ",j);
         //区域的虚拟地址输出或获取到其他地方
         Temp.dwAreaRVA=pBasR->VirtualAddress;
         
         RelCalcOffset(Temp.dwAreaRVA,pNtH,buf,Temp.szSectionName,NULL);
         printf_s("%s   ",Temp.szSectionName);
         printf_s("%08X   ",pBasR->VirtualAddress);
         Temp.NumberOfReloc=(pBasR->SizeOfBlock-sizeof(IMAGE_BASE_RELOCATION))/2;
         printf_s("%02X  %d\n", Temp.NumberOfReloc, Temp.NumberOfReloc);
         DWORD dwCount=Temp.NumberOfReloc;
         //得到第三个成员的TYPEOFFEST起始位置 之后开始循环获取重定位信息
         PTYPEOFFSET pOffset=(PTYPEOFFSET)((long)pBasR+sizeof(IMAGE_BASE_RELOCATION));
         for (DWORD i=0;i<dwCount;i++)
         {
           printf_s("索引:%d  ",i);
           RELOCINFO RelocInfoTemp={0};
           //需要重定位的虚拟地址(RVA)
           RelocInfoTemp.dwRelocRVA=Temp.dwAreaRVA+pOffset->Offset;
           printf_s("RVA:%08X  ", RelocInfoTemp.dwRelocRVA);
           //根据相对虚拟地址算出的文件偏移
           RelocInfoTemp.dwOffset=RelCalcOffset(RelocInfoTemp.dwRelocRVA,pNtH,NULL,NULL);
            printf_s("偏移:%08X  ", RelocInfoTemp.dwOffset);
           //重定位方式
           RelocInfoTemp.bType=pOffset->Type;
           printf_s("类型:HIGHLOW (%d)  ",RelocInfoTemp.bType);
           //从算出的文件偏移取出的数据 这个数据就是需要重定位的虚拟地址(VA)
           RelocInfoTemp.dwRelocValue=*(PDWORD)((long)buf+RelocInfoTemp.dwOffset);
           printf_s("FAR地址:%08X  ",RelocInfoTemp.dwRelocValue);
           //RelocInfoTemp.bData
           DWORD VA= RelCalcOffset(RelocInfoTemp.dwRelocValue,pNtH,buf,NULL,(PCHAR)RelocInfoTemp.bData,2);
           RelCalcOffset(VA,pNtH,buf,NULL,(PCHAR)RelocInfoTemp.bData,1);
           for (int i=0;i<10;i++)
           {
             //判断是否在有效字符32-126区间内
             if (32<=(RelocInfoTemp.bData)[0]&&(RelocInfoTemp.bData)[0]<=126)
             {
               printf_s("%c",(RelocInfoTemp.bData)[i]);
             }
             else
             {
              printf_s("%02X ",(RelocInfoTemp.bData)[i]);
             }
           }
            printf_s("\n");
           pOffset++;
         }
        
         //讲一个区域重定位信息添加
        VecRelocAreaInfo.push_back(Temp);
        pBasR=(PIMAGE_BASE_RELOCATION)((long)pBasR+pBasR->SizeOfBlock);
        j++;
       }
    


    这个虽然不实用 但让你进一步理解PE文件结构及运作原理还是能够的
    周末有空我再发MFC版吧
    ---------------------
    源码:
    PE.rar

    [培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

    上传的附件:
    收藏
    免费 5
    支持
    分享
    最新回复 (11)
    雪    币: 10865
    活跃值: (2838)
    能力值: ( LV2,RANK:10 )
    在线值:
    发帖
    回帖
    粉丝
    2
    Nice~~
    2015-11-25 19:52
    0
    雪    币: 6499
    活跃值: (3117)
    能力值: ( LV3,RANK:30 )
    在线值:
    发帖
    回帖
    粉丝
    3
    不错,其实输出到文本更方便
    2015-11-25 21:38
    0
    雪    币: 1
    活跃值: (10)
    能力值: ( LV2,RANK:10 )
    在线值:
    发帖
    回帖
    粉丝
    4
    不错,刚好在学习图形界面解析PE项目
    2015-11-28 07:33
    0
    雪    币: 201
    活跃值: (10)
    能力值: ( LV2,RANK:10 )
    在线值:
    发帖
    回帖
    粉丝
    5
    这个不错,正学习.
    2017-9-2 00:04
    0
    雪    币: 2
    活跃值: (10)
    能力值: ( LV2,RANK:10 )
    在线值:
    发帖
    回帖
    粉丝
    6
    好贴!!!!!!!
    2018-6-12 22:16
    0
    雪    币: 310
    活跃值: (2227)
    能力值: ( LV2,RANK:10 )
    在线值:
    发帖
    回帖
    粉丝
    7
    mark
    2018-6-13 08:12
    0
    雪    币: 1110
    活跃值: (1075)
    能力值: ( LV2,RANK:10 )
    在线值:
    发帖
    回帖
    粉丝
    8
    好东西,Mark
    2018-6-14 17:03
    0
    雪    币: 253
    能力值: ( LV1,RANK:0 )
    在线值:
    发帖
    回帖
    粉丝
    9
    您的PE文件用VS201几编译的?我VS2012打不开
    2019-5-27 15:51
    0
    雪    币: 253
    能力值: ( LV1,RANK:0 )
    在线值:
    发帖
    回帖
    粉丝
    10
    用VS2012打开后运行,提示语法错误
    2019-5-27 15:54
    0
    雪    币: 1176
    活跃值: (1234)
    能力值: ( LV12,RANK:380 )
    在线值:
    发帖
    回帖
    粉丝
    11
    feihuasimeng 用VS2012打开后运行,提示语法错误
    2019-5-29 01:37
    0
    雪    币: 1176
    活跃值: (1234)
    能力值: ( LV12,RANK:380 )
    在线值:
    发帖
    回帖
    粉丝
    12
    feihuasimeng 用VS2012打开后运行,提示语法错误
    我的没问题 你自己的环境有问题 再试试 不行重装
    2019-5-29 01:38
    0
    游客
    登录 | 注册 方可回帖
    返回
    //