每个DLL都有自己的imagebase,如果有多个DLL的imagebase相同,那么地址就会冲突,为了防止两个函数共用同一个地址,引入了重定位表,修改函数地址,重定位表中分为几块,每一块中又分为几项
根据PE标志找出16个数据目录中的第六个就是重定位表,根据重定位表的地址可以找到重定位表,在重定位表中继续细分,就是每一块,每一块中再细分 就是每一项,不想解释了,我都快绕晕了,反正代码就是这样 能运行 结果也没有问题,就这样吧
代码如下
<mycode.cpp>
void set_pe(char* ptr,PE* p_PE )
{
//DOS头
p_PE->p_e_magic=(short*)ptr; //MZ标记 用于判断是否为可执行文件
p_PE->p_e_cblp=(short*)ptr+1;
p_PE->p_e_cp=(short*)ptr+2;
p_PE->p_e_crlc=(short*)ptr+3;
p_PE->p_e_cparhdr=(short*)ptr+4;
p_PE->p_e_minalloc=(short*)ptr+5;
p_PE->p_e_maxalloc=(short*)ptr+6;
p_PE->p_e_ss=(short*)ptr+7;
p_PE->p_e_sp=(short*)ptr+8;
p_PE->p_e_csum=(short*)ptr+9;
p_PE->p_e_ip=(short*)ptr+10;
p_PE->p_e_cs=(short*)ptr+11;
p_PE->p_e_lfarlc=(short*)ptr+12;
p_PE->p_e_ovno=(short*)ptr+13;
p_PE->p_e_res=(short*)ptr+17;
p_PE->p_e_oemid=(short*)ptr+18;
p_PE->p_e_oeminfo=(short*)ptr+19;
p_PE->p_e_res2=(short*)ptr+20;
p_PE->p_e_lfanew=(int*)ptr+15; //第60个字节 一行16个字节 第四行的最后四个字节就是 e_lfanew,从文件开始偏移 *p_e_lfanew 就是PE
//PE标记
p_PE->p_signature = ptr+(*(p_PE->p_e_lfanew));
//标准PE头
p_PE->p_machine=(short*)(p_PE->p_signature+4); //程序运行的CPU型号 0x0任何处理器 0x14C 386及后续处理器
p_PE->p_numberofsections=(short*)(p_PE->p_signature+6); //节的总数
p_PE->p_timedatestamp=(int*)(p_PE->p_signature+8);
p_PE->p_pointertosymboltable=(int*)(p_PE->p_signature+12);
p_PE->p_numberofsymbols=(int*)(p_PE->p_signature+16);
p_PE->p_sizeofoptionalheader=(short*)(p_PE->p_signature+20); //可选PE头的大小 32位默认E0 64位默认F0 可以自定义
p_PE->p_characteristics=(short*)(p_PE->p_signature+22);
//可选PE头
p_PE->p_magic=(short*)(p_PE->p_signature+24); //程序运行的CPU型号 0x0任何处理器 0x14C 386及后续处理器
p_PE->p_majorlinkerversion=(char*)(p_PE->p_signature+26);
p_PE->p_minorlinkerversion=(char*)(p_PE->p_signature+27);
p_PE->p_sizeofcode=(int*)(p_PE->p_signature+28); //所有代码节的和 内存对齐字节数的整数倍
p_PE->p_sizeofinitializeddata=(int*)(p_PE->p_signature+32); //初始化的数据大小
p_PE->p_sizeofuninitializeddata=(int*)(p_PE->p_signature+36); //未初始化的数据的大小
p_PE->p_addressofentrypoint=(int*)(p_PE->p_signature+40); //程序入口
p_PE->p_baseofcode=(int*)(p_PE->p_signature+44);
p_PE->p_baseofdata=(int*)(p_PE->p_signature+48);
p_PE->p_imagebase=(int*)(p_PE->p_signature+52); //内存镜像基址
p_PE->p_sectionalignment=(int*)(p_PE->p_signature+56); //内存对齐字节数
p_PE->p_filealignment=(int*)(p_PE->p_signature+60); //文件对齐字节数
p_PE->p_majoroperatingsystemversion=(short*)(p_PE->p_signature+64);
p_PE->p_minoroperatingsystemversion=(short*)(p_PE->p_signature+66);
p_PE->p_majorimageversion=(short*)(p_PE->p_signature+68);
p_PE->p_minorimageversion=(short*)(p_PE->p_signature+70);
p_PE->p_majorsubsystemversion=(short*)(p_PE->p_signature+72);
p_PE->p_minorsubsystemversion=(short*)(p_PE->p_signature+74);
p_PE->p_win32versionvalue=(int*)(p_PE->p_signature+76);
p_PE->p_sizeofimage=(int*)(p_PE->p_signature+80);
p_PE->p_sizeofheaders=(int*)(p_PE->p_signature+84);
p_PE->p_checksum=(int*)(p_PE->p_signature+88);
p_PE->p_subsystem=(short*)(p_PE->p_signature+92);
p_PE->p_dllcharacteristics=(short*)(p_PE->p_signature+94);
p_PE->p_sizeofstackreserve=(int*)(p_PE->p_signature+96);
p_PE->p_sizeofstackcommit=(int*)(p_PE->p_signature+100);
p_PE->p_sizeofheapreserve=(int*)(p_PE->p_signature+104);
p_PE->p_sizeofheapcommit=(int*)(p_PE->p_signature+108);
p_PE->p_loaderflags=(int*)(p_PE->p_signature+112);
p_PE->p_numberofrvaandsizes=(int*)(p_PE->p_signature+116);
p_PE->p_datadirectory_base=(char*)(p_PE->p_signature+120);
//节表
p_PE->image_section_header_base=(p_PE->p_signature)+4+20+ *(p_PE->p_sizeofoptionalheader);
memcpy(p_PE->name,p_PE->image_section_header_base,8);
p_PE->name[8]='\0';
p_PE->pmisc=(int*)(p_PE->image_section_header_base+8);
p_PE->pvirtualaddress=(int*)(p_PE->image_section_header_base+12);
p_PE->psizeofrawdata=(int*)(p_PE->image_section_header_base+16);
p_PE->ppointertorawdata=(int*)(p_PE->image_section_header_base+20);
p_PE->ppointertorelocations=(int*)(p_PE->image_section_header_base+24);
p_PE->ppointertolinenumbers=(int*)(p_PE->image_section_header_base+28);
p_PE->pnumberofrelocations=(short*)(p_PE->image_section_header_base+32);
p_PE->pnumberoflinenumbers=(short*)(p_PE->image_section_header_base+34);
p_PE->pcharacteristics=(int*)(p_PE->image_section_header_base+36);
p_PE->DIR[0].pvirtualaddress=(int*)(p_PE->p_signature+120); //导出表地址
p_PE->DIR[1].pvirtualaddress=(int*)(p_PE->p_signature+128);
p_PE->DIR[2].pvirtualaddress=(int*)(p_PE->p_signature+136);
p_PE->DIR[3].pvirtualaddress=(int*)(p_PE->p_signature+144);
p_PE->DIR[4].pvirtualaddress=(int*)(p_PE->p_signature+152);
p_PE->DIR[5].pvirtualaddress=(int*)(p_PE->p_signature+160); //重定位表地址
p_PE->DIR[6].pvirtualaddress=(int*)(p_PE->p_signature+168);
p_PE->DIR[7].pvirtualaddress=(int*)(p_PE->p_signature+176);
p_PE->DIR[8].pvirtualaddress=(int*)(p_PE->p_signature+184);
p_PE->DIR[9].pvirtualaddress=(int*)(p_PE->p_signature+192);
p_PE->DIR[10].pvirtualaddress=(int*)(p_PE->p_signature+200);
p_PE->DIR[11].pvirtualaddress=(int*)(p_PE->p_signature+208);
p_PE->DIR[12].pvirtualaddress=(int*)(p_PE->p_signature+216);
p_PE->DIR[13].pvirtualaddress=(int*)(p_PE->p_signature+224);
p_PE->DIR[14].pvirtualaddress=(int*)(p_PE->p_signature+232);
p_PE->DIR[15].pvirtualaddress=(int*)(p_PE->p_signature+240);
p_PE->DIR[0].psize=(int*)(p_PE->p_signature+120+4); //导出表地址
p_PE->DIR[1].psize=(int*)(p_PE->p_signature+128+4);
p_PE->DIR[2].psize=(int*)(p_PE->p_signature+136+4);
p_PE->DIR[3].psize=(int*)(p_PE->p_signature+144+4);
p_PE->DIR[4].psize=(int*)(p_PE->p_signature+152+4);
p_PE->DIR[5].psize=(int*)(p_PE->p_signature+160+4);
p_PE->DIR[6].psize=(int*)(p_PE->p_signature+168+4);
p_PE->DIR[7].psize=(int*)(p_PE->p_signature+176+4);
p_PE->DIR[8].psize=(int*)(p_PE->p_signature+184+4);
p_PE->DIR[9].psize=(int*)(p_PE->p_signature+192+4);
p_PE->DIR[10].psize=(int*)(p_PE->p_signature+200+4);
p_PE->DIR[11].psize=(int*)(p_PE->p_signature+208+4);
p_PE->DIR[12].psize=(int*)(p_PE->p_signature+216+4);
p_PE->DIR[13].psize=(int*)(p_PE->p_signature+224+4);
p_PE->DIR[14].psize=(int*)(p_PE->p_signature+232+4);
p_PE->DIR[15].psize=(int*)(p_PE->p_signature+240+4);
//导出表
p_PE->p_datadirectory_base=(char*)(p_PE->p_signature+120);
p_PE->pdirectory_entry_export_virtualaddress=(int*)(p_PE->p_signature+120); //导出表地址 RVA内存地址
p_PE->pdirectory_entry_export_size=(int*)(p_PE->p_signature+124);
//重定位表
p_PE->pdirectory_relocation_virtualaddress=(int*)(p_PE->p_signature+160);
p_PE->sizeofblock=(int*)(p_PE->p_signature+164);
//导出表属性
p_PE->pexportdirectory_base= ptr + *p_PE->pdirectory_entry_export_virtualaddress;
p_PE->characteristics=(int*)(p_PE->pexportdirectory_base);
p_PE->timedatestamp=(int*)(p_PE->pexportdirectory_base+4);
p_PE->majorversion=(short*)(p_PE->pexportdirectory_base+8);
p_PE->minorversion=(short*)(p_PE->pexportdirectory_base+10);
p_PE->exportname=(int*)(p_PE->pexportdirectory_base+12); //导出表文件名
p_PE->base=(int*)(p_PE->pexportdirectory_base+16); //导出函数基址
p_PE->numberoffunctions=(int*)(p_PE->pexportdirectory_base+20); //导出函数个数
p_PE->numberofnames=(int*)(p_PE->pexportdirectory_base+24); //以函数名导出的函数个数
p_PE->addressoffunctions=(int*)(p_PE->pexportdirectory_base+28); //导出函数表地址
p_PE->addressofnames=(int*)(p_PE->pexportdirectory_base+32); //导出函数名称地址表
p_PE->addressofnameordinals=(int*)(p_PE->pexportdirectory_base+36); //导出函数序号地址表
}
//RVA转化为FOA
int trans_RVA_to_FOA(int pRVA,char* pfilename)
{
//用于存放硬盘中 和 内存中的PE结构
PE PE_file;
PE PE_memory;
//找出文件中的PE结构
char* ptr=read_file_to_file_buffer(pfilename);
set_pe(ptr,&PE_file);
//为ImageBuffer申请空间
char* p_imagebuffer;
p_imagebuffer = (char*) malloc(*PE_file.p_sizeofimage);
//找出内存中的PE结构
if( p_imagebuffer == NULL)
{
printf("空间不足\n");
return 0;
}
else
{
memset(p_imagebuffer,0,*PE_file.p_sizeofimage);
//这里一定要注意 p_imagebuffer里面有数据之后 才能set_pe
//FileBuffer内容 复制到 ImageBuffer
trans_file_buffer_to_image_buffer(ptr,p_imagebuffer);
set_pe(p_imagebuffer,&PE_memory);
//printf("ImageBuffer范围:%x --> %x \n",p_imagebuffer,p_imagebuffer+(*PE_file.p_sizeofimage));
}
//节表大小
int sectablesize = *PE_file.p_numberofsections*40;
//节表结束位置
int sectableend = (int)(PE_memory.image_section_header_base + sectablesize);
//printf("节表范围:%x --> %x \n",PE_memory.image_section_header_base,sectableend);
int RVA = pRVA + (int)p_imagebuffer;
int FOA = 0x99999999;
int section_no; //RVA属于第几节
int section_offset; //RVA节偏移
//printf("请输入RVA值\n");
//scanf("%p",&RVA);
//printf("RVA = %x \n",RVA);
//如果RVA在节表结束之前 那么不用转换 直接减去基址就是FOA
if( RVA < sectableend )
{
FOA = RVA - (int)p_imagebuffer;
//printf("节表之前 无需转化 FOA = %x \n",FOA);
}
else
{
//找出 RVA在内存中节数 和 节偏移量
int rva_offset = (char*)RVA - p_imagebuffer;
//判断是第几个节
int i=1;
for(i;i<=*PE_memory.p_numberofsections;i++)
{
// RVA的偏移量 在 两点之间 此时的节数才是我们要的
if( rva_offset >= *PE_memory.pvirtualaddress
&& rva_offset < ( *PE_memory.pvirtualaddress + (*PE_memory.pmisc) ) )
{
section_no=i;
section_offset = rva_offset - *PE_memory.pvirtualaddress ;
//printf("RVA是第%d个节 节偏移量为%d \n",section_no,section_offset);
break;
}
//image_section_header_base=image_section_header_base+40;
//这里注意 pvirtualaddress 要往下走40个字节(一个节表的大小),
//因为pvirtualaddress 是int 所以指针需要加10 即可
PE_memory.pvirtualaddress=PE_memory.pvirtualaddress+10;
PE_memory.pmisc=PE_memory.pmisc+10;
}
//根据 节数 找出文件中节的位置 第n节 需要遍历n-1次
for(i=1;i<section_no;i++)
{
PE_file.ppointertorawdata=PE_file.ppointertorawdata+10;
}
//加上 节偏移量 得出最终在文件中的位置
FOA=*PE_file.ppointertorawdata+section_offset;
//printf("FOA = %x \n",*PE_file.ppointertorawdata+section_offset);
}
//释放内存
free(p_imagebuffer);
p_imagebuffer=NULL;
read_file_to_file_buffer_free(ptr);
return FOA;
}
//内存地址对齐
char* trans_memory_order(char* paddr,int poffset,int block)
{
int zhengshu=((int)(paddr+poffset))/block;
int yushu= (int)(paddr+poffset) - zhengshu*block;
int addsize=block-yushu;
return (char*)(paddr + poffset + addsize);
}
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include "mycode.h"
int main()
{
char* sourcefile="D:\\CODE\\DLL\\TestDll.dll";
char* ptr=read_file_to_file_buffer(sourcefile);
PE filePE;
set_pe(ptr,&filePE);
//重定位表
int relocation_virtualaddress_foa = trans_RVA_to_FOA(*filePE.pdirectory_relocation_virtualaddress,sourcefile);
printf("重定位表地址RVA:%x \t FOA:%x \n",*filePE.pdirectory_relocation_virtualaddress,relocation_virtualaddress_foa);
printf("重定位表大小:%x \n",*filePE.sizeofblock);
//重定位表的每一块
int block_base= (int)(ptr+relocation_virtualaddress_foa); //所有块的起始地址
int no_block_addr = *(int*)block_base; //第n块的起始地址
int no_block_size = *(int*)((char*)block_base+4); //第n块的大小
int next_block_addr=0; //下一块的地址
int next_block_size=0x9999; //下一块的大小
int all_block=0; //块数
int all_item=0; //每一块的项数
int items=0; //第几项
int i,j;
short block_item; //每一项的地址
int block_item_addr; //地址的低12位
int attribute; //地址的高4位
for( i=1; next_block_size != 0; i++ ) //下一块大小为0时 结束
{
items=(no_block_size-8)/2;
printf("第%d块:RVA %x 大小%x 项数%x \n",i,no_block_addr,no_block_size,items);
all_item=0;
//重定位表每一块的每一项
for(j=1;j<=items;j++)
{
block_item=*(short*)((char*)block_base+all_block+8+all_item*2 );
attribute=block_item & 0xF000; //高4位是属性
block_item_addr=block_item & 0xFFF; //低12位是rva地址
printf("第%d项 RVA: %x 高4位:%x \n",j,no_block_addr+block_item_addr,attribute);
all_item=all_item+1;
}
all_block=all_block+no_block_size; //总块数增加
next_block_addr = *(int*)((char*)block_base+all_block); //下一块地址
next_block_size = *(int*)((char*)block_base+all_block+4); //下一块大小
no_block_size=next_block_size; //下一块改为当前块
no_block_addr=next_block_addr; //
}
return 0;
}
运行结果如下