PE导出表分析

1.导出表的定义

导出表大多存在于DLL中,目的就是用来导出其他exe运行的函数。不管exe或者DLL的本质都是PE文件。

2.准备工作

写一个DLL文件并简单调用一下。

1.主要代码

1.1 .C文件
DLLIMPORT int Add(int a,int b)
{
	return a+b;
}

DLLIMPORT int Sub(int a,int b)
{
	return a-b;
}
DLLIMPORT int Mul(int a,int b)
{
	return a*b;
}
DLLIMPORT int Div(int a,int b)
{
	return a/b;
}

DLLIMPORT关键字可以用来修饰某个函数或者时变量就会被导出。

1.2 .H文件
DLLIMPORT int Add(int a,int b);
DLLIMPORT int Sub(int a,int b);
DLLIMPORT int Mul(int a,int b);
DLLIMPORT int Div(int a,int b);
1.3 测试代码
#include<Windows.h>
#include<stdio.h>
#include<stdlib.h>
int main() 
{
	typedef int(* FUNT)(int,int);	//定义函数指针
	HINSTANCE Hint = LoadLibrary("test.dll");	调用先前写好的DLL
	
	if(Hint==NULL)
	{
	
	printf("DLL调用失败");	//测试
	return 0;
	}
	FUNT ADD =(FUNT)GetProcAddress(Hint,"Add");
	FUNT SUB =(FUNT)GetProcAddress(Hint,"Sub");
	FUNT MUL =(FUNT)GetProcAddress(Hint,"Mul");
	FUNT DIV =(FUNT)GetProcAddress(Hint,"Div");
	
	int a=20,b=10;
	
	printf("和为%d\n",ADD(a,b));
	printf("差为%d\n",SUB(a,b));
	printf("积为%d\n",MUL(a,b));
	printf("商为%d\n",DIV(a,b));
	
	FreeLibrary(Hint);	//释放
	return 0;
}
1.4 结果

测试结果

2.导出函数定义声明

> EXPORTS
    Add @1
    Div @2
    Mul @3
    Sub @4

3.导出表的位置

导出表位于扩展PE头的DIRECTORY DataDirectory[10]里,该数组有10个成员,第一个就是导出表,即DIRECTORY DataDirectory[0]。

typedef struct _IMAGE_DATA_DIRECTORY
{
DWORD VirtualAddress; //导出表开始的地址 注意是RVA的值
RVADWORD Size; //导出表大小
}
IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;

关于PE文件结构前面提到很多,这里不再赘述,直接用StudyPE+工具找出,如图:
在这里插入图片描述
选中区域就是数组里的内容,
前四个字节就是导出表的位置:0x00006000是RVA(内存偏移地址)的值,要转化成FOA(文件偏移地址)才能分析;

这里简单说一下,RVA转FOA的步骤:
1.判断RVA是否位于PE头中,如果在,那么RVA==FOA;
2.判断RVA的值在哪一个区段中,求出RVA与该区段开始地址的差值;
3.FOA=节.PointerToRawData(节区在文件中开始地址)+差值

我们来手动算一下,
在这里插入图片描述
1.节表开始的位置在0x00000178,则RVA不属于PE头
2.观察可知RVA介于.edata和.idata区段之间,
在这里插入图片描述

差值为:0x00006000-0x00006000=0x0
3.FOA=0x2000+0x0=0x2000

接着四个字节就是导出表的大小:0x00000069;

3.导出表的结构

现在我们找到了导出表的文件地址,贴上导出表的数据结构和对应的二进制代码:
在这里插入图片描述

typedef struct _IMAGE_EXPORT_DIRECTORY {
0x00
DWORD Characteristics; //用不到
0x04
DWORD TimeDateStamp; //时间戳. 编译的时间. 把秒转为时间.可以知道DLL的编译时间.此处和标准PE头的第二个成员一样
0x08
WORD MajorVersion;
0x0a
WORD MinorVersion;
0x0c
DWORD Name;           //指向该导出表文件名的字符串,也就是这个DLL的名称 存储的RVA 地址,需要转换
0x10
DWORD Base;           // 导出函数的起始序号
0x14
DWORD NumberOfFunctions; //所有的导出函数的个数
0x18
DWORD NumberOfNames; //以名字导出的函数的个数
0x1c
DWORD AddressOfFunctions; // 导出的函数地址的 地址表 RVA 即函数地址表
0x20
DWORD AddressOfNames; // 导出的函数名称表的 RVA 即函数名称表
0x24
DWORD AddressOfNameOrdinals; // 导出函数序号表的RVA 即函数序号表
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;

直接从名字开始分析:导出表文件名所在的地址是:0x6050
差值:0x00006050-0x00006000=0x00000050;
FOA=0x00002000+0x00000050=0x00002050;
在这里插入图片描述
字符串以00结尾,可知该DLL的名字是test.dll;
导出函数的起始序号(01)稍后分析;
导出函数的个数在0x14位,为4个;
以名字导出的函数的个数在0x18位,为4个(说明DLL没有隐藏函数名字,转用序号调用);
导出函数有4个,所以导出函数的地址有4个,是连续的;

                           **函数地址表**
起始序号——>下标函数地址(FOA)函数名 (此表中函数名为二进制代码推出)
01——>01450(A50)Add
02——>11474(A74)Div
03——>21468 (A68)Mul
04——>3145D (A5D)Add
                        **函数名称表**
下标函数名地址(FOA)函数名
06059 (2059)Add
1605D (205D)Div
26061 (2061)Mul
36065 (2065)Add
                   **导出函数序号(2字节)表**
下标序号
000
101
202
303

下面举一个函数调用过程的例子:

FUNT ADD =(FUNT)GetProcAddress(Hint,"Add");

此语句是名称调用,先查询函数名称表,Add函数名对应的下标为0,接下来查询导出函数序号表下标为0的序号,对应的序号为00,再查询函数地址表下标为0,对应的函数地址为1450(A50):
在这里插入图片描述

55 89 E5 8B 55 08 8B 45 0C 01 D0 5D C3

利用OD分析一下代码:

89E5          mov ebp,esp
8B55 08       mov edx,dword ptr ss:[ebp+0x8]           ;  ipmsg.<ModuleEntryPoint>
8B45 0C       mov eax,dword ptr ss:[ebp+0xC]
01D0          add eax,edx                              ;  ntdll.KiFastSystemCallRet
5D            pop ebp                                  ;  kernel32.7C817077
C3            retn                                 ;  

很容易分析出是加法操作即Add函数;
其他函数类似,至此,PE表分析结束。

总结:

PE导出表的分析难点主要在于后三个表,以及它们之间的关系,建议自己手动操作一遍,慢慢体会。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值