| 本帖最后由 零五零八 于 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
 
   
   第一个结构中的VirtualAddress指向的是第二个结构体的开始第二个结构中的VirtualAddress指向的是重定位表的开始,SizeOfBlock表示块的大小
 
 3.重定位表的结构
 
 
 
   ①判断一共有几块数据最后一个结构的virtualAddress与SizeOfBlock都为0,则结束。②0011101010101010是第一项,先判断高四位0011值为3 代表的是需要修改的数据值为0 代表的是用于数据对齐的数据,可以不用修改当高4位是3则低12位101010101010是需要修改的地方的偏移地址真正的RVA = VIrtualAddress + 具体项的低地址
 ③具体项的数量 =(SizeOfBlock-8)/2
 ④下一个起始地址 = VirtualAddress + SizeOfBlock
 
 
 复制代码#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <windows.h>
 
DWORD ReadPEFile(char* filepath,PVOID* pFileBuffer)
{
    PVOID pTempFileBuffer = NULL;
    DWORD Filesize = 0;
 
 
    FILE* pFile = NULL;
    pFile = fopen(filepath,"rb");
    if(!pFile)
    {
        printf("文件打开失败");
        return 0;
    }
    fseek(pFile,0,SEEK_END);
    Filesize = ftell(pFile);
    fseek(pFile,0,SEEK_SET);
 
    pTempFileBuffer = malloc(Filesize);
 
    if(!pTempFileBuffer)
    {
        printf("申请动态内存失败");
        fclose(pFile);
        return 0;
 
    }
 
    size_t n = fread(pTempFileBuffer,Filesize,1,pFile);
    if(!n)
    {
        printf("文件写入文件缓冲区失败");
        free(pTempFileBuffer);
        fclose(pFile);
        return 0;
    }
    *pFileBuffer = pTempFileBuffer;
    pTempFileBuffer = NULL;
    free(pTempFileBuffer);
    fclose(pFile);
 
    return Filesize;
 
}
 
DWORD RvaToFoa(PIMAGE_NT_HEADERS pNTHeader, DWORD dwRVA)
{
    PIMAGE_SECTION_HEADER pSection = (PIMAGE_SECTION_HEADER)((DWORD)pNTHeader + sizeof(IMAGE_NT_HEADERS));
 
    for(int i = 0; i < pNTHeader->FileHeader.NumberOfSections; i++)
    {
        if(dwRVA >= pSection[i].VirtualAddress && dwRVA < (pSection[i].VirtualAddress + pSection[i].SizeOfRawData))
        {
            return pSection[i].PointerToRawData + (dwRVA - pSection[i].VirtualAddress);
        }
    }
 
    return 0;
}
 
 
 
void relocation(PVOID pFileBuffer)
{   
    BYTE secName[9] = {0};
    PIMAGE_DOS_HEADER pDosHeader;
    PIMAGE_NT_HEADERS pNtHeaders;
    PIMAGE_BASE_RELOCATION  pBaseRec;
    PIMAGE_SECTION_HEADER pSectionHeader;
 
    pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
    pNtHeaders = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer+pDosHeader->e_lfanew);
 
    printf("重定位表的相对虚拟地址:%x\n",pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
    printf("重定位表的大小:%x\n",pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size);
 
    DWORD pBaseRecOffset = RvaToFoa(pNtHeaders, pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress); //注意这个VirtualAddress是VA
    pBaseRec = (PIMAGE_BASE_RELOCATION)(pBaseRecOffset+(DWORD)pFileBuffer);
    pSectionHeader = (PIMAGE_SECTION_HEADER)(pNtHeaders+1);
 
    for(int i=0; pBaseRec->SizeOfBlock && pBaseRec->VirtualAddress; i++)
    {
        DWORD FOA = RvaToFoa(pNtHeaders, pBaseRec->VirtualAddress);
        DWORD size = (pBaseRec->SizeOfBlock - 8 )/2; // VirtualAddress SizeOfBlock共占8字节,每个项2字节
 
        //确定该结构所属的节
 
         for(DWORD j=0;j<pNtHeaders->FileHeader.NumberOfSections;j++)
         {
             DWORD lower =RvaToFoa(pNtHeaders, pSectionHeader[j].VirtualAddress);
             DWORD upper =RvaToFoa(pNtHeaders, pSectionHeader[j].VirtualAddress+pSectionHeader[j].Misc.VirtualSize);
 
            if(FOA>=lower && FOA<=upper )
            {
                memcpy(secName,pSectionHeader[j].Name,8);
                break;
            }
         }
         printf("第%d块.Relocation\n VirtualAddress %x(%s)\n SizeOfBlock %x\n", i+1, pBaseRec->VirtualAddress,secName, size); //打印本页的主要信息
         printf("RVA,TYPE\n");
 
         //打印一个页中,所有重定位地址与信息
         WORD * recAddr = (WORD *)((BYTE *)pBaseRec+8); //指向第一个目录项
        //如果高4位是3则取后12位地址加上VirtualAddress才是真正需要修复的数据的Rva
         for(j=0; j<size; j++)
         {
            DWORD offset = (recAddr[j] & 0x0FFF) + FOA ;
            WORD type = recAddr[j] >> 12;
 
            if(type!=0)
            {
                 printf("%08X,  %x\n",offset+pBaseRec->VirtualAddress,type);
            }
         }
        memset(secName, 0, 9);
        pBaseRec = (PIMAGE_BASE_RELOCATION )((BYTE *)pBaseRec + pBaseRec->SizeOfBlock);//移到下一页
    }
}
 
 
 
int main(int argc, char* argv[])
{
    char filepath[] = "F:\\pwn\\test\\TTTT.dll";
    PVOID pFileBuffer = NULL;
 
 
    ReadPEFile(filepath,&pFileBuffer);
    relocation(pFileBuffer);
 
    return 0;
}
 
 
 
 |