专业丰富的破解论坛技术交流,提供软件安全,病毒分析,脱壳破解,安卓破解,加密解密等,由无数热衷于软件爱好者共同维护
 
发新帖
楼主: 零五零八
查看: 1024|回复: 0

[技术文章] PE文件结构之打印重定位表

[复制链接]
零五零八 发表于 2020-10-9 17:16:58 | 显示全部楼层
本帖最后由 零五零八 于 2020-10-9 22:02 编辑

pe文件之重定位表

1.为什么出现重定位表?

一个软件一般由一个exe和多个dll组成,当一个exe运行的时候exe文件先根据ImageBase来载入内存,dll也是属于pe文件,首先是exe先载入内存,多个dll文件中的ImageBase也许会被其他dll占取,又因为编译以后地址是写死的,dll文件中的ImageBase被占住,只能占别的地方,因为地址写死,占的不是原来的地址,所以需要重定位表来标明需要修改的地址


2.在可选pe目录中,最后16个结构体的,第6个是是重定位表

注意:VirtualAddress是RVA,如在文件中使用(不是载入内存)则需要转换为FOA
1.jpg
2.jpg
第一个结构中的VirtualAddress指向的是第二个结构体的开始第二个结构中的VirtualAddress指向的是重定位表的开始,SizeOfBlock表示块的大小

3.重定位表的结构


3.jpg
①判断一共有几块数据最后一个结构的virtualAddress与SizeOfBlock都为0,则结束。②0011101010101010是第一项,先判断高四位0011值为3 代表的是需要修改的数据值为0 代表的是用于数据对齐的数据,可以不用修改当高4位是3则低12位101010101010是需要修改的地方的偏移地址真正的RVA = VIrtualAddress + 具体项的低地址
③具体项的数量 =(SizeOfBlock-8)/2
④下一个起始地址 = VirtualAddress + SizeOfBlock

  1. #include "stdafx.h"
  2. #include <stdlib.h>
  3. #include <stdio.h>
  4. #include <windows.h>

  5. DWORD ReadPEFile(char* filepath,PVOID* pFileBuffer)
  6. {
  7.     PVOID pTempFileBuffer = NULL;
  8.     DWORD Filesize = 0;


  9.     FILE* pFile = NULL;
  10.     pFile = fopen(filepath,"rb");
  11.     if(!pFile)
  12.     {
  13.         printf("文件打开失败");
  14.         return 0;
  15.     }
  16.     fseek(pFile,0,SEEK_END);
  17.     Filesize = ftell(pFile);
  18.     fseek(pFile,0,SEEK_SET);

  19.     pTempFileBuffer = malloc(Filesize);

  20.     if(!pTempFileBuffer)
  21.     {
  22.         printf("申请动态内存失败");
  23.         fclose(pFile);
  24.         return 0;

  25.     }

  26.     size_t n = fread(pTempFileBuffer,Filesize,1,pFile);
  27.     if(!n)
  28.     {
  29.         printf("文件写入文件缓冲区失败");
  30.         free(pTempFileBuffer);
  31.         fclose(pFile);
  32.         return 0;
  33.     }
  34.     *pFileBuffer = pTempFileBuffer;
  35.     pTempFileBuffer = NULL;
  36.     free(pTempFileBuffer);
  37.     fclose(pFile);

  38.     return Filesize;

  39. }

  40. DWORD RvaToFoa(PIMAGE_NT_HEADERS pNTHeader, DWORD dwRVA)
  41. {
  42.     PIMAGE_SECTION_HEADER pSection = (PIMAGE_SECTION_HEADER)((DWORD)pNTHeader + sizeof(IMAGE_NT_HEADERS));

  43.     for(int i = 0; i < pNTHeader->FileHeader.NumberOfSections; i++)
  44.     {
  45.         if(dwRVA >= pSection[i].VirtualAddress && dwRVA < (pSection[i].VirtualAddress + pSection[i].SizeOfRawData))
  46.         {
  47.             return pSection[i].PointerToRawData + (dwRVA - pSection[i].VirtualAddress);
  48.         }
  49.     }

  50.     return 0;
  51. }



  52. void relocation(PVOID pFileBuffer)
  53. {   
  54.     BYTE secName[9] = {0};
  55.     PIMAGE_DOS_HEADER pDosHeader;
  56.     PIMAGE_NT_HEADERS pNtHeaders;
  57.     PIMAGE_BASE_RELOCATION  pBaseRec;
  58.     PIMAGE_SECTION_HEADER pSectionHeader;

  59.     pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
  60.     pNtHeaders = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer+pDosHeader->e_lfanew);

  61.     printf("重定位表的相对虚拟地址:%x\n",pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
  62.     printf("重定位表的大小:%x\n",pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size);

  63.     DWORD pBaseRecOffset = RvaToFoa(pNtHeaders, pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress); //注意这个VirtualAddress是VA
  64.     pBaseRec = (PIMAGE_BASE_RELOCATION)(pBaseRecOffset+(DWORD)pFileBuffer);
  65.     pSectionHeader = (PIMAGE_SECTION_HEADER)(pNtHeaders+1);

  66.     for(int i=0; pBaseRec->SizeOfBlock && pBaseRec->VirtualAddress; i++)
  67.     {
  68.         DWORD FOA = RvaToFoa(pNtHeaders, pBaseRec->VirtualAddress);
  69.         DWORD size = (pBaseRec->SizeOfBlock - 8 )/2; // VirtualAddress SizeOfBlock共占8字节,每个项2字节

  70.         //确定该结构所属的节

  71.          for(DWORD j=0;j<pNtHeaders->FileHeader.NumberOfSections;j++)
  72.          {
  73.              DWORD lower =RvaToFoa(pNtHeaders, pSectionHeader[j].VirtualAddress);
  74.              DWORD upper =RvaToFoa(pNtHeaders, pSectionHeader[j].VirtualAddress+pSectionHeader[j].Misc.VirtualSize);

  75.             if(FOA>=lower && FOA<=upper )
  76.             {
  77.                 memcpy(secName,pSectionHeader[j].Name,8);
  78.                 break;
  79.             }
  80.          }
  81.          printf("第%d块.Relocation\n VirtualAddress %x(%s)\n SizeOfBlock %x\n", i+1, pBaseRec->VirtualAddress,secName, size); //打印本页的主要信息
  82.          printf("RVA,TYPE\n");

  83.          //打印一个页中,所有重定位地址与信息
  84.          WORD * recAddr = (WORD *)((BYTE *)pBaseRec+8); //指向第一个目录项
  85.         //如果高4位是3则取后12位地址加上VirtualAddress才是真正需要修复的数据的Rva
  86.          for(j=0; j<size; j++)
  87.          {
  88.             DWORD offset = (recAddr[j] & 0x0FFF) + FOA ;
  89.             WORD type = recAddr[j] >> 12;

  90.             if(type!=0)
  91.             {
  92.                  printf("%08X,  %x\n",offset+pBaseRec->VirtualAddress,type);
  93.             }
  94.          }
  95.         memset(secName, 0, 9);
  96.         pBaseRec = (PIMAGE_BASE_RELOCATION )((BYTE *)pBaseRec + pBaseRec->SizeOfBlock);//移到下一页
  97.     }
  98. }



  99. int main(int argc, char* argv[])
  100. {
  101.     char filepath[] = "F:\\pwn\\test\\TTTT.dll";
  102.     PVOID pFileBuffer = NULL;


  103.     ReadPEFile(filepath,&pFileBuffer);
  104.     relocation(pFileBuffer);

  105.     return 0;
  106. }
复制代码




快速回复 返回顶部 返回列表