手工解析PE(导出表)_GNAIXGNAHZ的博客-CSDN博客上一节讲了如何解析导出表的结构,最终结果就是要解析出导出表的三个地址:名称表地址、序号表地址、函数表地址,有了这三张表 我们才可以进一步使用导出表,找到我们想要的函数地址
名称表中存放的是名称的地址,所以我们找到名称表时,不能直接用里面的值,需要解引用得到的才是函数名称
序号表中存放的是导出函数的序号,但是并不是真正的序号,表值+base 才是真正导出序号,所以我们在使用时,找到序号表的值后还需要加base才可以
函数表中存放的是导出函数的地址,这个地址是内存中的地址,只要我们清楚函数表中第几个是我们要的函数,就可以取到对应的地址
名称表、序号表、函数表 都可以通过解析导出表结构得到:
步骤
有了这三张表,我们
首先要遍历名称表,找到我们需要的函数和其所在名称表的名称下标,
然后根据名称下标 = 序号表的下标 找到序号表下标所对应的序号
最后根据序号表中的序号 = 函数表下标 找到函数表中的函数地址
注意以上提到的地址全是内存地址,在使用时转化为文件地址更方便我们操作
代码如下
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include "mycode.h"
int main()
{
char* sourcefile="D:\\CODE\\DLL\\TestDll.dll";
//char* sourcefile="D:\\CODE\\DEMO\\004\\Debug\\004.dll";
char* ptr=read_file_to_file_buffer(sourcefile);
PE filePE;
set_pe(ptr,&filePE);
printf("导出表地址:%x \n",*filePE.pdirectory_entry_export_virtualaddress);
int FOA=0x99999999;
int i=0;
for( i;i<16;i++ )
{
FOA=trans_RVA_to_FOA(*filePE.DIR[i].pvirtualaddress,sourcefile);
printf("第%d个表:\n",i+1);
printf("RVA地址:%x\t\t",*filePE.DIR[i].pvirtualaddress);
printf("FOA地址:%x\t\t",FOA);
printf("大小:%x\n",*filePE.DIR[i].psize);
}
//地址表 地址
char* addressoffunctions = ptr + *filePE.addressoffunctions; //每次移动4字节
char* addressofordianls = ptr + *filePE.addressofnameordinals; //每次移动2字节
char* addressofnames = ptr + *filePE.addressofnames; //每次移动4字节
//[地址][名称数组下标][名称地址]
int funs_index; //[函数数组下标]
int ordi_index; //[序号数组下标]
int name_index; //[名称数组下标]
int funs_value_rva; //[函数地址]
int ordi_value_rva; //[序号值]
int name_value_rva; //[名称地址]
int funs_value_foa; //rva对应的foa
int ordi_value_foa; //rva对应的foa
int name_value_foa; //rva对应的foa
//遍历名称地址表
//遍历序号地址表
//遍历函数地址表
//遍历名称地址表
printf("\n名称列表:\n");
int name_length=0;
for( name_index=0;name_index < *filePE.numberofnames;name_index++)
{
name_value_rva = *((int*)addressofnames+name_index); //名称表里 存的是名字的地址 想得到名字 需要加* [地址][名称数组下标][名称地址]
name_value_foa = trans_RVA_to_FOA(name_value_rva,sourcefile);
printf("\n 名称地址name_value_rva : %p\t 名称地址name_value_foa : %p\ ",name_value_rva,name_value_foa );
//计算名称长度 直到0x00结尾 名称结束
name_length=0;
for(i=0;*(ptr + name_value_foa + i +1) != 0x00;i++)
{
name_length++;
}
//打印名称
printf("函数名称:[%d]",name_index);
for(i=0;i<=name_length+1;i++)
{
printf("%c",*(ptr + name_value_foa + i -1));
}
}
//遍历序号地址表
printf("\n\n序号列表:\n\n");
for( ordi_index=0;ordi_index < *filePE.numberofnames;ordi_index++)
{
ordi_value_rva = *((short*)addressofordianls + ordi_index);
printf("[%d]:%d \n",ordi_index,ordi_value_rva);
}
//遍历函数地址表
printf("\n函数列表:\n");
for( funs_index=0;funs_index < *filePE.numberoffunctions;funs_index++)
{
funs_value_rva = *((int*)addressoffunctions + funs_index);
funs_value_foa = trans_RVA_to_FOA(funs_value_rva,sourcefile);
printf("\n [%d] 函数地址funs_value_rva : %p\t 函数地址funs_value_foa : %p ",funs_index,funs_value_rva,funs_value_foa );
}
//根据名称查找函数地址
char* findname="Mul";
//根据序号查找函数地址
int findno=1;
//printf("\n\n当前查找函数: %s 长度 %d \n",findname,strlen(findname));
//strcmp(char *a, char *b);
//1.根据名称 在名称表 找到序号表的下标
int findnameresultno=0;
for( name_index=0;name_index < *filePE.numberofnames;name_index++)
{
name_value_rva = *((int*)addressofnames+name_index); //名称表里 存的是名字的地址 想得到名字 需要加* [地址][名称数组下标][名称地址]
name_value_foa = trans_RVA_to_FOA(name_value_rva,sourcefile);
printf("\n 名称地址name_value_rva : %p\t 名称地址name_value_foa : %p\ ",name_value_rva,name_value_foa );
//计算名称长度 直到0x00结尾 名称结束
name_length=0;
for(i=0;*(ptr + name_value_foa + i +1) != 0x00;i++)
{
name_length++;
}
//打印名称
printf("函数名称:[%d]",name_index);
for(i=0;i<=name_length+1;i++)
{
printf("%c",*(ptr + name_value_foa + i -1));
}
//判断是否相对
if( memcmp(findname,ptr + name_value_foa,name_length + 2) == 0 ) //加2 是为了到达 0x00的长度
{
findnameresultno=name_index;
//printf("\n\t find result oridinal下标: %d \n",findnameresultno);
}
}
//2.根据序号表的下标 在序号表 找到函数表的下标
int findordiresultno;
for( ordi_index=0;ordi_index < *filePE.numberofnames;ordi_index++)
{
if( ordi_index == findnameresultno)
{
ordi_value_rva = *((short*)addressofordianls + ordi_index);
findordiresultno=ordi_value_rva;
//printf("\t \nfind result 序号: %d \n",findordiresultno + *filePE.base); //序号 = base + 表值
//printf("\t \nfind result 函数下标: %d \n",findordiresultno);
}
}
//3.根据函数表的下标 在函数表 找到函数的地址
int findfunresultaddr;
for( funs_index=0;funs_index < *filePE.numberoffunctions;funs_index++)
{
if( funs_index == findordiresultno )
{
funs_value_rva = *((int*)addressoffunctions + funs_index);
funs_value_foa = trans_RVA_to_FOA(funs_value_rva,sourcefile);
findfunresultaddr = funs_value_foa;
//printf("\t find result 函数地址RVA: %x \n",funs_value_rva);
//printf("\t find result 函数地址FOA: %x \n",funs_value_foa);
}
}
printf("\n\n当前查找函数: %s 长度 %d \n",findname,strlen(findname));
printf("\t find result oridinal下标: %d \n",findnameresultno);
printf("\t find result 序号: %d \n",findordiresultno + *filePE.base); //序号 = base + 表值
printf("\t find result 函数下标: %d \n",findordiresultno);
printf("\t find result 函数地址RVA: %x \n",funs_value_rva);
printf("\t find result 函数地址FOA: %x \n",funs_value_foa);
return 0;
}