appsion 发表于 2020-10-31 10:43

PE 文件解析2-获取PE头、区段、数据目录

本帖最后由 appsion 于 2020-10-31 12:33 编辑

PE 文件解析2 - 获取PE头、区段、数据目录新手学习PE文件解析记录,持续更新. 部分参考来源于网络, 无法逐一标注, 如果侵权,请及时联系. 如有错误请指正,误喷.


上文链接: https://www.52pojie.cn/thread-1294150-1-1.html




概念:
      TLS:
            Thread Local Storage,   线程本地存储,用来保存变量或回调函数.

      IAT:
             Import Address Table, 导入地址表, 由于导入函数就是被程序调用但其执行代码又不在程序中的函数,这些函数的代码位于一个或者多个DLL 中.当PE 文件被装入内存的时候,Windows 装载器才将DLL 装入,并将调用导入函数的指令和函数实际所处的地址联系起来(动态连接),这操作就需要导入表完成.其中导入地址表就指示函数实际地址.



结构体: IMAGE_DATA_DIRECTORY
说明: 数据目录
头文件: winnt.h
参考文档: https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-image_data_directory

typedef struct _IMAGE_DATA_DIRECTORY
{
      DWORD VirtualAddress;
      DWORD Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;

参数说明: 仅供参考, 详细说明请参考原文.
      VirtualAddress:
                数据目录相对虚拟地址(RVA)
      Size:
                表的大小

VirtualAddress成员如下:

Offset (PE/PE32+)Description
96/112Export table address and size
104/120Import table address and size
112/128Resource table address and size
120/136Exception table address and size
128/144Certificate table address and size
136/152Base relocation table address and size
144/160Debugging information starting address and size
152/168Architecture-specific data address and size
160/176Global pointer register relative virtual address
168/184Thread local storage (TLS) table address and size
176/192Load configuration table address and size
184/200Bound import table address and size
192/208Import address table address and size
200/216Delay import descriptor address and size
208/224The CLR header address and size
216/232Reserved




2.1 获取PE头信息


IMAGE_FILE_HEADER.Machine                                                               // 处理器类型

IMAGE_OPTIONAL_HEADER.MajorLinkerVersion                                     // 链接器版本号
IMAGE_OPTIONAL_HEADER.MinorLinkerVersion

IMAGE_OPTIONAL_HEADER.MajorOperatingSystemVersion                  // 系统版本号
IMAGE_OPTIONAL_HEADER.MinorOperatingSystemVersion

IMAGE_OPTIONAL_HEADER.Subsystem                                                 // 子系统名称

IMAGE_OPTIONAL_HEADER.MajorSubsystemVersion                           // 子系统版本号
IMAGE_OPTIONAL_HEADER.MinorSubsystemVersion

IMAGE_FILE_HEADER.TimeDateStamp                                                // 映像时间

IMAGE_FILE_HEADER.Characteristics                                                    // 映像特征

IMAGE_OPTIONAL_HEADER.Magic                                                      // 映像类型

IMAGE_OPTIONAL_HEADER.MajorImageVersion                              // 映像版本号
IMAGE_OPTIONAL_HEADERMinorImageVersion

IMAGE_OPTIONAL_HEADER.ImageBase                                              // 映像基址

IMAGE_OPTIONAL_HEADER.BaseOfCode                                           // 代码基址

IMAGE_OPTIONAL_HEADER.BaseOfData                                          // 数据基址

IMAGE_OPTIONAL_HEADER.AddressOfEntryPoint                           // 入口点相对地址

ImageBase + AddressOfEntryPoint                                                    // 入口点实际地址

IMAGE_OPTIONAL_HEADER.SizeOfImage                                       // 映像内存大小

IMAGE_OPTIONAL_HEADER.CheckSum                                          // 映像校验合

IMAGE_OPTIONAL_HEADER.DllCharacteristics                                 // 映像的DLL特性

IMAGE_OPTIONAL_HEADER.SizeOfHeaders                                    // 文件头大小

IMAGE_FILE_HEADER.NumberOfSections                                       // 节表数量

IMAGE_OPTIONAL_HEADER.SectionAlignment                              // 节表内存对齐

IMAGE_OPTIONAL_HEADER.FileAlignment                                    // 文件对齐

IMAGE_FILE_HEADER.PointerToSymbolTable                              // 符号表偏移地址

IMAGE_FILE_HEADER.NumberOfSymbols                                     // 符号表数量

IMAGE_OPTIONAL_HEADER.SectionAlignment                            // 节表(区段)对齐

IMAGE_OPTIONAL_HEADER.FileAlignment                                  // 文件对齐

IMAGE_OPTIONAL_HEADER.DataDirectory                                 // 数据目录

IMAGE_NT_HEADERS.OptionalHeader.NumberOfRvaAndSizes             // 数据目录数量

IMAGE_OPTIONAL_HEADER.DataDirectory                              // 数据目录表


2.2 获取区段信息

// 节表数量
IMAGE_FILE_HEADER.NumberOfSections
// 节表头
IMAGE_SECTION_HEADER *SectionHead = (IMAGE_SECTION_HEADER *)(DataBuff + DosHead->e_lfanew + sizeof(IMAGE_NT_HEADERS));

for (size_t i = 0; i < IMAGE_FILE_HEADER.NumberOfSections; i++)
{
      IMAGE_SECTION_HEADER Section = SectionHead;

      // 节表名称
      // Section.Name

      // 节表的RVA
      // Section.VirtualAddress

      // 节表的虚拟大小
      // Section.Misc.VirtualSize

      // 节表的Raw
      // Section.PointerToRawData

      // 节表的Raw的数据大小
      // Section.SizeOfRawData

      // 特征
      // Section.Characteristics

}


2.3 获取数据目录

// NT头
IMAGE_NT_HEADERS * NTHead = GetNTHead(DataBuff);

// 数据目录数量
DataDirectoryCount = NTHead->OptionalHeader.NumberOfRvaAndSizes;

// 数据目录头
IMAGE_DATA_DIRECTORY *DirectoryHead = NTHead->OptionalHeader.DataDirectory;

// 数据目录说明

IMAGE_DIRECTORY_ENTRY_EXPORT0导出表
IMAGE_DIRECTORY_ENTRY_IMPORT1导入表
IMAGE_DIRECTORY_ENTRY_RESOURCE2资源表
IMAGE_DIRECTORY_ENTRY_EXCEPTION3异常表
IMAGE_DIRECTORY_ENTRY_SECURITY4安全证书表
IMAGE_DIRECTORY_ENTRY_BASERELOC5基址重定位表
IMAGE_DIRECTORY_ENTRY_DEBUG6调试表
IMAGE_DIRECTORY_ENTRY_ARCHITECTURE7版权信息
IMAGE_DIRECTORY_ENTRY_GLOBALPTR8全局指针
IMAGE_DIRECTORY_ENTRY_TLS9TLS表
IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG10加载配置表
IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT11绑定导入表
IMAGE_DIRECTORY_ENTRY_IAT12IAT表
IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT13延迟导入表
IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR14COM描述符表
15保留


获取数据目录
for (size_t i = 0; i < DataDirectoryCount; i++)
{
      // 获取数据目录标题
      switch (i)
      {
                case 0: Caption = "导出表"; break;
                case 1: Caption = "导入表"; break;
                case 2: Caption = "资源表"; break;
                case 3: Caption = "异常表"; break;
                case 4: Caption = "安全证书表"; break;
                case 5: Caption = "基址重定位表"; break;
                case 6: Caption = "调试表"; break;
                case 7: Caption = "版权信息"; break;
                case 8: Caption = "全局指针"; break;
                case 9: Caption = "TLS表"; break;
                case 10: Caption = "加载配置表"; break;
                case 11: Caption = "绑定导入表"; break;
                case 12: Caption = "IAT表"; break;
                case 13: Caption = "延迟导入表"; break;
                case 14: Caption = "COM描述符表"; break;
                case 15: Caption = "保留"; break;
                default:      break;
      }

      // 表的RVA
      // DataDirectoryHead.VirtualAddress

      // 表的大小
      // DataDirectoryHead.Size

      // 节表数量
      int SECTIONCount = IMAGE_FILE_HEADER.NumberOfSections;
      
      // 节表头
      IMAGE_SECTION_HEADER *SectionHead = (IMAGE_SECTION_HEADER *)(DataBuff + DosHead->e_lfanew + sizeof(IMAGE_NT_HEADERS));


      // 表的FOA
      // 注: 获取表的FOA需要以下几步
                //1. 判断表的RVA所在节表中的哪一个.
                //2. 表的FOA = 表的RVA - 节表的RVA + 节表FOA
      DWORD DataDirectoryFOA = RVAToRaw(SectionHead, SectionCount, DataDirectoryHead.VirtualAddress);
}


RVA 转 FOA

DWORD RVAToRaw(IMAGE_SECTION_HEADER *SectionHead, int SECTIONCount, DWORD m_RVA)
{
      // 遍历节表
      for (size_t i = 0; i < SECTIONCount; i++)
      {
                IMAGE_SECTION_HEADER section = ((IMAGE_SECTION_HEADER*)SectionHead);

                // 判断 RVA 所在的节表
                if (m_RVA >= section.VirtualAddress && m_RVA <= (section.VirtualAddress + section.SizeOfRawData))
                {
                        // 获取偏移差
                        m_RVA = m_RVA - section.VirtualAddress;
                        m_RVA = m_RVA + section.PointerToRawData;
                        return m_RVA;
                }
      }
      return 0;
}

appsion 发表于 2020-11-1 09:03

lthink 发表于 2020-10-31 16:48
学PE看看这套就行
https://www.52pojie.cn/forum.php?mod=viewthread&tid=1174321
节表定位方式严谨的写 ...

好的谢谢, 先做记录以后更新

lthink 发表于 2020-10-31 16:48

学PE看看这套就行
https://www.52pojie.cn/forum.php?mod=viewthread&tid=1174321
节表定位方式严谨的写法是选项头地址+选项头的大小,视频中都有详细说明

0xdada 发表于 2020-10-31 17:14

感谢大佬,水滴逆向的课的作业一直做不出来,一来就是好东西

KatharsisKing 发表于 2020-11-1 08:23

cptw 发表于 2020-11-1 09:08

谢谢分享,

winooxx 发表于 2020-11-1 14:08

感谢楼主的分享!

平凡的无序 发表于 2020-11-1 15:26

看看,学习一下

归来仍是英雄 发表于 2020-11-1 19:31

感谢大佬分享,

iijjjyonu 发表于 2020-11-2 10:29

谢了,有空慢慢看下
页: [1] 2
查看完整版本: PE 文件解析2-获取PE头、区段、数据目录