一、数据目录概述
数据目录的引入
-
我们当时解析可选PE头时,有一个字段为DWORD
NumberOfRvaAndSizes
,NumberOfRvaAndSizes
的值为多少,说明下面的_IMAGE_DATA_DIRECTORY DataDirectory[16]
;这种类型的结构体就有多少个 -
我们编写一个程序,这个程序的PE结构分节,有代码节,数据节等等节,但是不能理解成一个这些节中只有我们写的代码或者定义的变量等,编译器也会替我们往每一个节中加很多重要的内容:
-
比如我们写代码时会使用一写系统提供的函数,那么编译器就需要添加这个函数的相关信息,告诉系统需要去哪里找到这个函数;
-
一个程序不仅可以使用别的函数,也可以提供函数给别人程序或人使用,所以此时编译器会添加此程序中供别人使用的函数相关信息
-
数据目录结构
-
分别是:导出表的数据目录、导入表的数据目录、资源表的数据目录、异常信息表的数据目录、安全证书表的数据目录、重定位表的数据目录、调试信息表的数据目录、版权所有表的数据目录、全局指针表的数据目录、TLS表的数据目录、加载配置表的数据目录、绑定导入表的数据目录、IAT表的数据目录、延迟导入表的数据目录、COM信息表的数据目录、最后一个保留未使用
-
其中比较重要的就是导出表、导入表、重定位表、IAT表这四张表的数据目录,这四张表和程序的运行有直接关系,不管是加壳、脱壳、破解、病毒或反病毒,这些都是基础中的基础
可选PE头最后一个成员,就是数据目录.一共有16个:
typedef struct _IMAGE_DATA_DIRECTORY {
DWORD VirtualAddress; //内存偏移
DWORD Size; //大小
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
###
16个数据目录的大小一样,都是8字节,一行16字节,一共占8行,可以从节表往上倒着推8行,就是数据目录
#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
// Directory Entries
// 按顺序排列的数据目录表
#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 // Export Directory 导出表:动态链接库导出的函数会显示在这里
#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 // Import Directory 导入表:写程序时调用的动态链接库会显示在这里
#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 // Resource Directory 资源表:图片,图标,字符串,嵌入的程序都在这里
#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 // Exception Directory 异常目录表:保存文件中异常处理相关的数据
#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 // Security Directory 安全目录:存放数字签名和安全证书之类的东西
#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 // Base Relocation Table 基础重定位表:保存需要执行重定位的代码偏移
#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 // Debug Directory 调试表
// IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 // (X86 usage)
#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 7 // Architecture Specific Data 缓存信息表:有一些保留字段必须是0
#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 // RVA of GP 全局指针偏移目录
#define IMAGE_DIRECTORY_ENTRY_TLS 9 // TLS Directory 线程局部存储(暂时未知)
#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 // Load Configuration Directory 载入配置
#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 // Bound Import Directory in headers 存储一些API的绑定输入信息
#define IMAGE_DIRECTORY_ENTRY_IAT 12 // Import Address Table 导入地址表:导入函数的地址
#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 // Delay Load Import Descriptors
#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 // COM Runtime descriptor com运行时的目录
数据目录和16种表的关系
数据目录只是记录了对应的表的内存偏移地址和大小。我们通过找到表的数据目录,得到表的内存偏移地址,接着这个内存偏移地址处才是表本身真正的所在位置!
比如我们找到了导出表的数据目录,通过数据目录中的VirtualAddress + ImageBase得到导出表所在的地址
二、编程输出全部目录项
VOID OutputDataDirectory()
{
PVOID pFileBuffer;
PVOID pImageBuffer;
PVOID pNewBuffer;
PIMAGE_DOS_HEADER pDosHeader = NULL;
PIMAGE_FILE_HEADER pPEHeader = NULL;
PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
PIMAGE_SECTION_HEADER pSectionHeader = NULL;
BOOL isOk = FALSE;
DWORD size = 0;
ReadPEFile(file_path, &pFileBuffer);
if (!pFileBuffer)
{
printf("文件-缓冲区失败");
return;
}
/*FileBuffer->ImageBuffer*/
pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)((DWORD)pFileBuffer + pDosHeader->e_lfanew) + 4);
pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)(((DWORD)pFileBuffer + pDosHeader->e_lfanew) + 4 + IMAGE_SIZEOF_FILE_HEADER);
pSectionHeader = (PIMAGE_SECTION_HEADER)(((DWORD)pFileBuffer + pDosHeader->e_lfanew) + 4 + IMAGE_SIZEOF_FILE_HEADER + pPEHeader->SizeOfOptionalHeader);
printf("%X %X\n", pOptionHeader->DataDirectory[0].Size, pOptionHeader->DataDirectory[0].VirtualAddress);
printf("%X %X\n", pOptionHeader->DataDirectory[1].Size, pOptionHeader->DataDirectory[1].VirtualAddress);
}