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;
} lthink 发表于 2020-10-31 16:48
学PE看看这套就行
https://www.52pojie.cn/forum.php?mod=viewthread&tid=1174321
节表定位方式严谨的写 ...
好的谢谢, 先做记录以后更新 学PE看看这套就行
https://www.52pojie.cn/forum.php?mod=viewthread&tid=1174321
节表定位方式严谨的写法是选项头地址+选项头的大小,视频中都有详细说明 感谢大佬,水滴逆向的课的作业一直做不出来,一来就是好东西 谢谢分享, 感谢楼主的分享!
看看,学习一下 感谢大佬分享, 谢了,有空慢慢看下
页:
[1]
2