【转载】遍历pe导出表

optional头的最后一个域是一个数组列表,该数组大小为16,元素为IMAGE_DATA_DIRECTORY,至于以后平台是否会增加,说不清楚,但是FileHeader中明确给出了该数组的大小。

该数组表的第一个元素就是指向输出表的。而输出表的定义如下:

typedef struct _IMAGE_EXPORT_DIRECTORY {
    DWORD   Characteristics;
    DWORD   TimeDateStamp;
    WORD    MajorVersion;
    WORD    MinorVersion;
    DWORD   Name;
    DWORD   Base;
    DWORD   NumberOfFunctions;
    DWORD   NumberOfNames;
    DWORD   AddressOfFunctions;     // RVA from base of image
    DWORD   AddressOfNames;         // RVA from base of image
    DWORD   AddressOfNameOrdinals; // RVA from base of image
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;

前面就不管了,直接看重要的,该结构体说明了 总共输出项目总数[NumberOfFunctions],带名称的为NumberOfNames,由于某些个别变态函数会以序号的形式输出,所以这2个值可能不等。 接下来是指向函数入口的指针,指向名称的指针,指向序号的指针。

这里有3个对应关系,看雪书上讲得有点晕。 描述一个PE文件的输出函数需要3个变量

函数入口,函数名称,函数序号。

如果你想偷懒一次性把这个表取完,那你程序多半要崩溃,至少目前从网上找到的代码都崩溃了,手上几个现成的Delphi代码几乎读不懂,很久没碰Delphi,生疏了许多。。

numberoffunctions 告诉了我们总共有多少个函数,这时候我们可以一次性获取所有函数的入口RVA,接着numberofnames 告诉了我们有多少个被命名输出,

第一次获取的函数名,一定是第一个序号所指定的函数名称。

比如

proc_rva 表

80505450 805a5614 805f1adc 805f5312 805f1b0e

nam_etable

abcdef    hhhhhhh                 zxzzzzzzzz

ord_table

0100 0200 0400

这时候的对应关系如下:

        abcdef===>0001===>805a5614

        hhhhh===>0002===>805f1adc

        zxzzzzz===>0004===>805f1b0e

一句话,先读取函数入口,再读取名称,而名称的填充,则根据ordianl中的索引来查找。

红书这页讲的很晕人,尤其是winhex开10进制,举例时候的数据太特殊,过于简单。

这个问题确实比较气愤,记得大概在今年6月的时候,准备写一个PE explorer,兴致勃勃的完成了框架的

描述以及初步代码,当测试核心模块的时候,不得不因为对输出表的研究不够深入而彻底放弃,今通宵达旦,总算圆满解决掉输出表的问题。

PE文件中比较复杂的 一个是引入表,一个输出表,最复杂的则属资源描述表。

大概代码如下:

//前面有错直接返回

if(m_lasterr)return m_lasterr;

//枚举所有节,输出表的RawOffet = 输出表RVA - deltaK
//deltaK = sectionRVA - SectionRaw

IMAGE_DATA_DIRECTORY ExportDir = opheader.DataDirectory[0];
DWORD RawExportTableOffset;
BOOLEAN bExportTableFound = false;
DWORD DeltaK = 0;
DWORD i;
if(ExportDir.Size ==0 && ExportDir.VirtualAddress ==0)
{
   //no export table
   return 0;
}

for(i =0 ; i < fileheader.NumberOfSections; i++)
   if(ExportDir.VirtualAddress >=section[i].VirtualAddress && ExportDir.VirtualAddress < section[i].Misc.VirtualSize + section[i].VirtualAddress)
   {
    bExportTableFound = true;
    break;
   }
if(bExportTableFound)
{
   DeltaK = (section[i].VirtualAddress - section[i].PointerToRawData);
   RawExportTableOffset =ExportDir.VirtualAddress - DeltaK;
}//这里不存在else 的情况

IMAGE_EXPORT_DIRECTORY eat;
memcpy(&eat, rawbuffer + RawExportTableOffset, sizeof IMAGE_EXPORT_DIRECTORY);
//准备处理输出函数 
PE_EXPORT_TABLE export_proc = {0};
DWORD dw = 0;


for(i = 0 ; i < eat.NumberOfFunctions; i++)
{
   //文件偏移
    export_proc.proc_RAW = eat.AddressOfFunctions -DeltaK + i*4;
   //内存相对虚拟偏移
    memcpy(&export_proc.proc_RVA ,(rawbuffer + eat.AddressOfFunctions -DeltaK + i*4), 4);   
    export_proc.proc_ord = i;
    pe_export.push_back(export_proc);
   
}
DWORD nameBaseRaw = eat.AddressOfNames - DeltaK;
DWORD ordBaseRaw = eat.AddressOfNameOrdinals - DeltaK;
DWORD NameVA = 0;
DWORD Ord = 0;

for(i = 0 ; i < eat.NumberOfNames; i++)
{
  
//获取函数名称VA
   memcpy(&NameVA, rawbuffer + nameBaseRaw + i * 4, 4);
  
   memcpy(&Ord, rawbuffer + ordBaseRaw + i*2, 2);
//将函数名称取出并转化为unicode存放到vector对应的向量中.
   CHAR *str_proc_name = rawbuffer + NameVA - DeltaK
   MultiByteToWideChar(CP_ACP, 0,str_proc_name, strlen(str_proc_name), pe_export[Ord].proc_name, NAME_MAXLEN);

//这就是vc工具中 hint
   pe_export[Ord].proc_hint = i;
    
}

return 0;

转载自 

转载于:https://www.cnblogs.com/lilo_x/archive/2011/06/16/2082647.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值