您的位置:首页 > 科技 > 能源 > python建立简易网站_抖音小程序开通_百度seo网站在线诊断_今天合肥刚刚发生的重大新闻

python建立简易网站_抖音小程序开通_百度seo网站在线诊断_今天合肥刚刚发生的重大新闻

2025/4/18 16:01:01 来源:https://blog.csdn.net/linshantang/article/details/146703674  浏览:    关键词:python建立简易网站_抖音小程序开通_百度seo网站在线诊断_今天合肥刚刚发生的重大新闻
python建立简易网站_抖音小程序开通_百度seo网站在线诊断_今天合肥刚刚发生的重大新闻

目录

一、导出表

1.1 导出表概述

1.2 说明与使用

二、导入表

2.1 导入表概述

2.2 说明与使用


一、导出表

1.1 导出表概述

(1)导出行为和导出表用途:PE文件能把自身的函数、变量或者类,提供给其他PE文件使用,这种行为就叫导出。导出表专门用来存放这些导出项目的信息。当一个PE文件要调用其他PE文件里的导出函数(变量、类)时,依靠导出表就能迅速找到它们在文件里的位置。一般来说,这些被导出的函数、变量、类,也叫做符号(Symbol)。
(2)导出项序号的特点:每一个被导出的函数(变量、类),都有一个独一无二的序号。在有些情况下,可能找不到对应的函数名(变量、类名),但函数(变量、类)的地址和序号是存在的,听说可以通过序号来调用这类函数。
(3)导出表的内容组成:导出表里面记录的内容,包含了函数(变量、类)的地址、序号,还有函数(变量、类)名。
(4)导出表的查找方法:数据目录表的第一个元素里有相对虚拟地址,利用前面讲过的相对虚拟地址转文件偏移的办法,就能找到导出表的位置(后面会给出具体代码) 。

导出表的数据结构如下:

typedef struct _IMAGE_EXPORT_DIRECTORY  {DWORD   Characteristics;      //1( 没用)保留值,恒为0DWORD  TimeDateStamp;    //2( 没用)和文件头中的时间一样的。WORD   MajorVersion;  //3(没 用)主版本号WORD   MinorVersion;    //4 ( 没用 )次版本号DWORD  Name;             //5(有用)本PE文件的名字,也就是谁导出的这些函数(变量,类)DWORD  Base;             //6(有用)序号基数DWORD  NumberOfFunctions;//7 (重要) 函数数量DWORD  NumberOfNames;    //8   (重要)  函数名称数量DWORD  AddressOfFunctions;//9(重要)函数地址表的相对虚拟地址//RVA from base of imageDWORD AddressOfNames;    //10(重要)函数名称表的相对虚拟地址//RVA from base of imageDWORD AddressOfNameOrdinals;//11(重要)序号表的相对虚拟地址//RVA from base of image
}IMAGE_EXPORT_DIRECTORY,*PIMAGE_EXPORT_DIRECTORY;

1.2 说明与使用

说明
(1)导出表存储位置:导出表一般在.edata段,不过.edata段通常会合并到.rdata段。
(2)序号基数:有个序号基数,从序号表得到的序号得加上它,才是真实函数序号,这方便在函数地址、序号和函数名之间互相查找。
(3)表项地址定位:导出表最后三个成员是相对虚拟地址,转换成文件偏移后,能找到函数地址表、函数名称表和序号表。
(4)函数名称表:函数名称表存的是函数名的相对虚拟地址,得再转换成文件偏移才能用,解析时要注意。
(5)导出表各表关系:
    - 序号顺序:序号不是按顺序排列的。
    - 对应关系:序号和函数名一一对应,两个表相同位置元素对应,所以结构体没设序号数量,因为它和函数名数量一样。
    - 序号中断:序号可能中断,比如缺1、5,但不代表没对应的函数地址。
    - 数量关系:函数个数比函数名个数多,多出来的可能是序号导出函数,也可能是地址填0的无效函数。
    - 表间关联:序号表元素值对应函数地址表位置,该位置的函数地址就是对应函数名的地址,靠这个把三个表联系起来。
    - 序号导出函数:函数地址表有地址值,但序号表没对应序号,说明是序号导出函数,序号就是它在函数地址表中的位置,没函数名。
    - 无效函数:函数地址表元素填0,就是无效函数,没序号和函数名对应。

看下面这张导出表图示,能更好理解导出表。

        函数表5、7位置是无效函数,2、3、4、6、8位置是函数名导出,注意函数名位置和地址表地址位置不同,1、9是序号导出函数,序号就是本身位置。

使用
(1)导出表信息提取:想提取导出表所有信息并过滤无效地址,得用循环,循环次数是函数地址个数。根据函数地址位置,在序号表找对应值,这个值的位置就是函数名位置。

        代码思路如下,假设目标文件已读入内存,首地址为pFile(void类型指针),且用到之前计算偏移的函数:

for(Ordinal=0;Ordinal<函数个数;dwOrdinal++){if(!导出函数数组[Ordinal])continue ;for(Index=0;Index<函数个数;dwIndex++){if(导出序号数组[Index]== Ordinal ){输出带函数名的导出函数信息}elseif(已经遍历完导出表){输出不带函数名的导出函数信息}}
}

在LoadPE中,点击导出表的“...”即可弹出导出表界面,序号代表结构体中成员的序号。

导出表偏移:这个偏移是用数据目录中的相对虚拟地址算出来的

特征:特征值恒0

函数地址:函数地址的相对虚拟地址

函数名地址:函数名称的相对虚拟地址

函数名顺序地址:序号表的相对虚拟地址

名称:名称的相对虚拟地址

字符串名称:根据名称的地址算出编移存储的名称

(2)根据函数名查找函数地址:导出表还有其他用途,比如给定一个函数名,查找其函数地址,这类似于GetProcAddress()函数。在编写壳程序等特殊场景中会用到此功能。该方法比上述代码更简单,直接根据函数名找到其位置,该位置序号的值即为所要查找函数的地址索引。若要查找已加载到内存后的dll中的函数地址,就不应再使用文件偏移,而应直接使用虚拟地址(VA)。

二、导入表

2.1 导入表概述

(1)导入行为和导入表用途:PE文件运行过程中,如果用到其他PE文件里的函数、变量或者类,这种行为就叫做导入。导入表专门记录这部分信息。
(2)导入表的查找方法:数据目录表的第二个元素能帮我们定位导入表,查找的办法和找导出表一样。
(3)导入表的存储内容:导入表会记录从其他PE文件导入的函数名和序号。当PE文件加载到内存后,导入表还会保存这些函数的实际内存地址。
(4)导入表的结构特点:一个PE文件往往需要多个其他PE文件提供支持,所以导入表通常有多个。从结构上来说,导入表是一个结构体数组,数组以一个全零元素作为结束标志,数组里每个元素,都对应着一个PE文件的导入信息 。

2.2 说明与使用

导入表相关数据结构如下:

typedef struct _IMAGE_IMPORT_DESCRIPTOR
union {DWORD   Characteristics;   DWORD  OriginalFirstThunk;//1(重要)指向一个结构体数组的相对虚拟地址(RVA), 结构体数组叫输入名称表
}  DUMMYUNIONNAME;     
DWORD TimeDateStamp;          //2(有用)没用
DWORD ForwarderChain;    //3(有用)转发机制用到,这里不探讨
DWORD Name;         //4(有用)导入的PE文件的名字的相对虚拟地址RVA
DWORD FirstThunk;    //5(重要)指向一个结构体数组的相对虚拟地址(RVA),结构体数组叫做输入地址表(IAT:Import Address Table)
}IMAGE_IMPORT_DESCRIPTOR,*PIMAGE_IMPORT_DESCRIPTOR;

说明
(1)指针指向特性:OriginalFirstThunk和FirstThunk这两个指针,都指向IMAGE_THUNK_DATA类型的结构体。
(2)磁盘与内存数据变化:在磁盘上的文件里,OriginalFirstThunk和FirstThunk所指向的数据是一样的。基于此,我们可以把输入名称表(INT)当作输入地址表(IAT)的备份。等到文件加载到内存后,加载器会把对应PE文件里函数的真实地址,填充到输入地址表中。这时,输入地址表才成了真正可用的输入地址表。
(3)输入名称表情况:有些文件的输入名称表内容全为零,处于空白状态。这意味着输入地址表有时没有备份。所以在解析输入表时,优先使用输入地址表;当然,也可以同时解析输入名称表和输入地址表,对比查看。
(4)解析终止条件:这两个指针指向的结构体数组,是以全零元素作为结尾的。我们可以利用这一特性,作为解析过程的结束标志。
(5)相关结构体介绍:

typedef struct _IMAGE_THUNK_DATA32 {union {DWORD ForwarderString;   //转发用到DWORD Function;          //导入函数的地址,在加载到内存后,这里才起作用DWORD Ordinal;            //假如是序号导入的,用到这里DWORD AddressOfData;     //假如是函数名导入的,用到这里,它指向一个PIMAGE_IMPORT_BY_NAME结构体}ul;
}IMAGE_THUNK_DATA32;

        在磁盘文件中,起作用的只有后两个成员。该结构占4个字节,若最高位为1,则序号导入起作用,只需输出一个序号;若最高位为0,则最后一个成员起作用,指向一个PIMAGE_IMPORT_BY_NAME。可使用系统提供的宏IMAGE_SNAP_BY_ORDINAL32()判断最高位是否为1,参数为该结构体。

typedef struct _IMAGE_IMPORT_BY_NAME {WORD   Hint;CHAR Name[1];
}IMAGE_IMPORT_BY_NAME,*PIMAGE_IMPORT_BY_NAME;

该结构包含序号和函数名。

使用:

//循环打印INT的内容
while(pINT->u1.Ordinal)
{//判断最高位是否不为1,是的话则打印其AddressOfData的内容if(!IMAGE_SNAP_BY_ORDINAL32(pINT->u1.Ordinal)){PIMAGE_IMPORT_BY_NAME pBN =获取ByName;printf("%04X %s\r\n",pBN->Hint,pBN->Name);}pINT++;continue;
}
//如果最高位为1,则直接打印Ordinal部分
printf("%04X %s\r\n",pINT->u1.Ordinal&0xFFFF,"(Null)");
pINT++;

原始 FirstThunk:导入名称表的RVA

FirstThunk:导入地址表的RVA

正向链:转发用

ThunkEVA:每-个Thunk统构的RVA(算的)

Thunk 偏移:Thunk结构的编移(算的)

Hint:函数的序号

API名称:函数的名称

        计算每个Thunk结构的相对虚拟地址(RVA)时,只要知道第一个结构的RVA,后续结构的RVA依次加4就能得出。偏移计算方法也是一样,算出第一个偏移后,后续偏移每次加4。

        LoadPE软件会对输入名称表(INT)和输入地址表(IAT)这两个数据域进行解析。软件默认展示INT的解析结果,如果点击软件下方“总是查看FirstThunk”复选框,软件就会显示IAT的解析结果。

        到这里,关于导出表和导入表的解析说明就结束了。

 

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com