快速查询PE文件知识点和PE文件解析(下)
延迟加载导入表
延迟加载导入表(Delay Load Import Table)是PE中引入的专门用来描述与动态链接库延迟加载相关的数据,因为这些数据所起的作用和结构与导入表数据基本一致,所以称为延迟加载导入表。
延迟加载导入的概念:系统开始运行程序时被指定的延迟加载的 DLL是不被载入的,只有等到程序调用了该动态链接库的函数时,系统才将该链接库载入内存空间,并执行相关函数代码
typedef struct _IMAGE_DELAYLOAD_DESCRIPTOR {union {DWORD AllAttributes; // 属性,必须为0struct {DWORD RvaBased : 1; // Delay load version 2DWORD ReservedAttributes : 31;} DUMMYSTRUCTNAME;} Attributes;DWORD DllNameRVA; // 指向DLL名称的RVADWORD ModuleHandleRVA; // DLL模块句柄的RVADWORD ImportAddressTableRVA; // 延迟加载导入IAT的RVADWORD ImportNameTableRVA; // 延迟加载导入INT的RVADWORD BoundImportAddressTableRVA; // 绑定延迟加载导入表的RVADWORD UnloadInformationTableRVA; // 卸载延迟加载导入地址表的RVADWORD TimeDateStamp; // 此映像绑定到DLL的时间戳} IMAGE_DELAYLOAD_DESCRIPTOR, *PIMAGE_DELAYLOAD_DESCRIPTOR;typedef const IMAGE_DELAYLOAD_DESCRIPTOR *PCIMAGE_DELAYLOAD_DESCRIPTOR;
延迟导入表解析
#include<Windows.h>
#include<iostream>
using namespace std;DWORD RvaToFoa(_In_ DWORD rva, _In_ PIMAGE_SECTION_HEADER p, _In_ PIMAGE_FILE_HEADER f)
{for (int i = 0; i < f->NumberOfSections; i++){// FOA = 数据的RVA + 区段的RVA - 区段的FOAif (rva >= p->VirtualAddress && rva < (p->VirtualAddress + p->Misc.VirtualSize)){return rva - p->VirtualAddress + p->PointerToRawData;}f++;p++;}return 0;
}void ImageNtHeader(_In_z_ const char* path)
{// 获取文件对象HANDLE hfile = CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);// 获取文件大小DWORD fSize = GetFileSize(hfile, NULL);char* pBuff = new char[fSize];DWORD dwReadSize = 0;// 读文件BOOL bSuccess = ReadFile(hfile, pBuff, fSize, &dwReadSize, NULL);if (bSuccess){PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pBuff;PIMAGE_NT_HEADERS32 pNtHeader{ 0 };pNtHeader = (PIMAGE_NT_HEADERS32)(pDosHeader->e_lfanew + pBuff);PIMAGE_FILE_HEADER pFileHeader = (PIMAGE_FILE_HEADER)&pNtHeader->FileHeader;PIMAGE_OPTIONAL_HEADER32 pOptionalHeader = (PIMAGE_OPTIONAL_HEADER32)&pNtHeader->OptionalHeader;PIMAGE_SECTION_HEADER pSectionHeader = IMAGE_FIRST_SECTION(pNtHeader);PIMAGE_DATA_DIRECTORY dataDirectory = (PIMAGE_DATA_DIRECTORY)&pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT];//填充延迟导入表数据结构PIMAGE_DELAYLOAD_DESCRIPTOR pDelayLoad = (PIMAGE_DELAYLOAD_DESCRIPTOR)(RvaToFoa(dataDirectory->VirtualAddress, pSectionHeader, pFileHeader) + pBuff);while (pDelayLoad->DllNameRVA){char* szDllName = (char*)(RvaToFoa(pDelayLoad->DllNameRVA, pSectionHeader, pFileHeader) + pBuff);cout << "DllName:" << szDllName << endl;cout << "AllAttributes:" << pDelayLoad->Attributes.AllAttributes << endl;cout << "RvaBased:" << pDelayLoad->Attributes.RvaBased << endl;cout << "ModuleHandleRVA:" << pDelayLoad->ModuleHandleRVA << endl;cout << "ImportAddressTableRVA:" << pDelayLoad->ImportAddressTableRVA << endl;cout << "ImportNameTableRVA:" << pDelayLoad->ImportNameTableRVA << endl;cout << "BoundImportAddressTableRVA:" << pDelayLoad->BoundImportAddressTableRVA << endl;cout << "UnloadInformationTableRVA:" << pDelayLoad->UnloadInformationTableRVA << endl;cout << "TimeDateStamp:" << pDelayLoad->TimeDateStamp << endl;pDelayLoad++;}}else (cout.write("打开文件失败", 20));CloseHandle(hfile);delete[] pBuff;
}void main()
{ImageNtHeader(R"(C:\Users\11981\Desktop\Project1\2.exe)");
}
TLS表
使用线程本地存储器(TLS)可以将数据与执行的特定线程联系起来。当使用_declspec(thread)声明的TLS 变量时,编译器将它们放入一个.tls 区块。当应用程序加载到内存中时,系统要寻找可执行文件中的.tls 区块,并且动态地分配一个足够大的内存块,以便存放所有的 TLS变量。系统也将一个指向已分配的内存的指针放到TLS数组里,这个数组由 FS:[2Ch]指向(在x86架构上)
IMAGE_TLS_DIRECTORY结构中的地址是虚拟地址,而不是 RVA。这样,如果PE 文件不是从基地址载入的,那么这些地址就会通过基址重定位来修正。而且,IMAGE_TLS_DIRECTORY 本身不在.tls 区块中,而在 .rdata 区块中。
在一个可执行文件中,线程局部存储(TLS)数据是由数据目录表中的 IMAGE_DIRECTORY_ENTRY_TLS条目指出的。如果数据是非零的,这个字段指向一个IMAGE_TLS_DIRECTORY结构,其定义如下
typedef struct _IMAGE_TLS_DIRECTORY32 {DWORD StartAddressOfRawData; // TLS模板的起始地址DWORD EndAddressOfRawData; // TLS模板的结束地址DWORD AddressOfIndex; // TLS索引的位置,运行库使用这个索引来定位线程局部数据 DWORD AddressOfCallBacks; // PIMAGE_TLS_CALLBACK 函数指针数组的地址DWORD SizeOfZeroFill; // 后面跟0的个数union {DWORD Characteristics; // 保留,目前设为0struct {DWORD Reserved0 : 20;DWORD Alignment : 4;DWORD Reserved1 : 8;} DUMMYSTRUCTNAME;} DUMMYUNIONNAME;} IMAGE_TLS_DIRECTORY32;
typedef IMAGE_TLS_DIRECTORY32 * PIMAGE_TLS_DIRECTORY32;typedef struct _IMAGE_TLS_DIRECTORY64 {ULONGLONG StartAddressOfRawData;ULONGLONG EndAddressOfRawData;ULONGLONG AddressOfIndex; // PDWORDULONGLONG AddressOfCallBacks; // PIMAGE_TLS_CALLBACK *;DWORD SizeOfZeroFill;union {DWORD Characteristics;struct {DWORD Reserved0 : 20;DWORD Alignment : 4;DWORD Reserved1 : 8;} DUMMYSTRUCTNAME;} DUMMYUNIONNAME;} IMAGE_TLS_DIRECTORY64;typedef IMAGE_TLS_DIRECTORY64 * PIMAGE_TLS_DIRECTORY64;
TLS回调函数
(NTAPI *PIMAGE_TLS_CALLBACK) (PVOID DllHandle,DWORD Reason,PVOID Reserved);
AddressOfCallBacks是线程建立和退出时的回调函数,包括主线程和其他线程。当一个线程被创建或销毁时,列表中的回调函数会被调用。由于程序大都没有回调函数,这个列表是空的。有一点需要特别注意,程序运行时,TLS数据初始化和 TLS回调函数都在入口点(AddressOfEntryPoint)之前执行,也就是说,TLS 是程序开始运行的地方,许多病毒或外壳程序会利用这一点执行一些特殊操作。程序退出时,TLS回调函数会再执行一次。
TLS表解析
#include<Windows.h>
#include<iostream>
using namespace std;DWORD RvaToFoa(_In_ DWORD rva, _In_ PIMAGE_SECTION_HEADER p, _In_ PIMAGE_FILE_HEADER f)
{for (int i = 0; i < f->NumberOfSections; i++){// FOA = 数据的RVA + 区段的RVA - 区段的FOAif (rva >= p->VirtualAddress && rva < (p->VirtualAddress + p->Misc.VirtualSize)){return rva - p->VirtualAddress + p->PointerToRawData;}f++;p++;}return 0;
}void ImageNtHeader(_In_z_ const char* path)
{// 获取文件对象HANDLE hfile = CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);// 获取文件大小DWORD fSize = GetFileSize(hfile, NULL);char* pBuff = new char[fSize];DWORD dwReadSize = 0;// 读文件BOOL bSuccess = ReadFile(hfile, pBuff, fSize, &dwReadSize, NULL);if (bSuccess){PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pBuff;PIMAGE_NT_HEADERS32 pNtHeader{ 0 };pNtHeader = (PIMAGE_NT_HEADERS32)(pDosHeader->e_lfanew + pBuff);PIMAGE_FILE_HEADER pFileHeader = (PIMAGE_FILE_HEADER)&pNtHeader->FileHeader;PIMAGE_OPTIONAL_HEADER32 pOptionalHeader = (PIMAGE_OPTIONAL_HEADER32)&pNtHeader->OptionalHeader;PIMAGE_SECTION_HEADER pSectionHeader = IMAGE_FIRST_SECTION(pNtHeader);PIMAGE_DATA_DIRECTORY dataDirectory = (PIMAGE_DATA_DIRECTORY)&pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS];//填充结构PIMAGE_TLS_DIRECTORY pTLS = (PIMAGE_TLS_DIRECTORY)(RvaToFoa(dataDirectory->VirtualAddress, pSectionHeader, pFileHeader) + pBuff);cout << "数据块开始VA:" << pTLS->StartAddressOfRawData << endl;cout << "数据块结束VA:" << pTLS->EndAddressOfRawData << endl;cout << "索引变量VA:" << pTLS->AddressOfIndex << endl;cout << "回调表VA:" << pTLS->AddressOfCallBacks << endl;cout << "填充大小:" << pTLS->SizeOfZeroFill << endl;cout << "特征值:" << pTLS->Characteristics << endl;}else (cout.write("打开文件失败", 20));CloseHandle(hfile);delete[] pBuff;
}void main()
{ImageNtHeader(R"(C:\Users\11981\Desktop\Project1\2.exe)");
}
资源目录
数据目录表中的IMAGE_DIRECTORY_ENTRY_RESOURCE条目包含资源的BVA和大小。资源目录结构中的每一个节点都是由 IMAGE_RESOURCE_DIRECTORY 结构和紧随其后的数个IMAGE_RESOURCE_DIRECTORY_ENTRY结构组成的,这两种结构组成了一个目录块。
IMAGE_RESOURCE_DIRECTORY结构长度为16字节,共有6个字段,其定义如下。
typedef struct _IMAGE_RESOURCE_DIRECTORY {DWORD Characteristics; // 理论上是资源的属性标志,但是通常为0DWORD TimeDateStamp; // 资源建立的时间WORD MajorVersion; // 理论上是放置资源的版本,但是通常为0WORD MinorVersion;WORD NumberOfNamedEntries; // 使用名字的资源条目的个数WORD NumberOfIdEntries; // 使用ID数字资源条目的个数
// IMAGE_RESOURCE_DIRECTORY_ENTRY DirectoryEntries[];
} IMAGE_RESOURCE_DIRECTORY, *PIMAGE_RESOURCE_DIRECTORY;
资源目录入口
紧跟资源目录结构的就是资源目录入口(Resource Dir Entries)结构,此结构长度为8字节,包含2个字段。IMAGE_RESOURCE_DIRECTORY_ENTRY结构定义如下
typedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY {union {struct {DWORD NameOffset:31;DWORD NameIsString:1;} DUMMYSTRUCTNAME;DWORD Name;WORD Id;} DUMMYUNIONNAME; // 目录项的名称字符串指针或IDunion {DWORD OffsetToData;struct {DWORD OffsetToDirectory:31;DWORD DataIsDirectory:1;} DUMMYSTRUCTNAME2;} DUMMYUNIONNAME2; // 资源数据偏移地址或子目录偏移地址
} IMAGE_RESOURCE_DIRECTORY_ENTRY, *PIMAGE_RESOURCE_DIRECTORY_ENTRY;
根据不同的情况,这 2个字段的含义有所不同。
Name 字段:定义目录项的名称或 ID。当结构用于第1层目录时,定义的是资源类型;当结构用于第 2 层目录时,定义的是资源的名称;当结构用干第 3 层目录时,定义的是代码页编号。当最高位为 0时,表示字段的值作为ID使用;当最高位为1时。表示字段的低位作为指针使用,资源名称字符串使用Unicode 编码,这个指针不直接指向字符串,而指向一个IMAGE_RESOURCE_DIR_STRING_U结构。Name字段定义如下
typedef struct _IMAGE_RESOURCE_DIR_STRING_U {WORD Length; // 字符串的长度WCHAR NameString[ 1 ]; // Unicode字符串,按字对齐,长度可变// 由 Length 指明 Unicode 字符串的长度
} IMAGE_RESOURCE_DIR_STRING_U, *PIMAGE_RESOURCE_DIR_STRING_U;
OffsetToData字段∶是一个指针。当最高位(位31)为1时,低位数据指向下一层目录块的起始地址;当最高位为0时,指针指向IMAGE_RESOURCE_DATA_ENTRY结构。在将Name 和 OffsetToData 作为指针时需要注意,该指针从资源区块开始处计算偏移量,并非从 RVA (根目录的起始位置)开始处计算偏移量。
有一点要说明的是,当 IMAGE_RESOURCE_DIRECTORY_ENTRY 用在第 1层目录中时,它的Name 字段作为资源类型使用。当资源类型以ID定义且数值在1到16 之间时,表示是系统预定义的类型
#define RT_CURSOR MAKEINTRESOURCE(1) // 光标(Cursor)
#define RT_BITMAP MAKEINTRESOURCE(2) // 位图(Bitmap)
#define RT_ICON MAKEINTRESOURCE(3) // 图标(Icon)
#define RT_MENU MAKEINTRESOURCE(4) // 菜单(Menu)
#define RT_DIALOG MAKEINTRESOURCE(5) // 对话框(Dialog)
#define RT_STRING MAKEINTRESOURCE(6) // 字符串(String)
#define RT_FONTDIR MAKEINTRESOURCE(7) // 字体目录(Font Directory)
#define RT_FONT MAKEINTRESOURCE(8) // 字体(Font)
#define RT_ACCELERATOR MAKEINTRESOURCE(9) // 加速键(Acelerators)
#define RT_RCDATA MAKEINTRESOURCE(10) // 未格式化资源(Unformatted)
#define RT_MESSAGETABLE MAKEINTRESOURCE(11) // 消息表(MessageTable)#define DIFFERENCE 11
#define RT_GROUP_CURSOR MAKEINTRESOURCE((ULONG_PTR)(RT_CURSOR) + DIFFERENCE) // 光标组(Group Cursor)
#define RT_GROUP_ICON MAKEINTRESOURCE((ULONG_PTR)(RT_ICON) + DIFFERENCE) // 图标组(Group Ieon)
#define RT_VERSION MAKEINTRESOURCE(16) // 版本信息(Version Information)
资源头
资源表数据从第一级资源目录开始。资源的每一级目录都会有一个资源目录头,它标识了该类资源的属性、创建日期和版本等信息,其中也包含了随后的目录项的数量描述信息。
typedef struct _IMAGE_RESOURCE_DIRECTORY {DWORD Characteristics; // 资源属性DWORD TimeDateStamp; // 时间戳WORD MajorVersion; // 资源大版本号WORD MinorVersion; // 资源下版本号WORD NumberOfNamedEntries; // 以名称命名的入口数量WORD NumberOfIdEntries; // 以ID命名的入口数量
// IMAGE_RESOURCE_DIRECTORY_ENTRY DirectoryEntries[];
} IMAGE_RESOURCE_DIRECTORY, *PIMAGE_RESOURCE_DIRECTORY;
资源数据入口
经过3层IMAGE_RESOURCE_DIRECTORY_ENTRY(一般是3层,也有可能更少,第1层是资源类型,第2层是资源名,第3层是资源的Language),第 3层目录结构中的 OffsetToData 将指向IMAGE_RESOURCE_DATA_ENTRY结构。该结构描述了资源数据的位置和大小,其定义如下。
typedef struct _IMAGE_RESOURCE_DATA_ENTRY {DWORD OffsetToData; // 资源数据的RVADWORD Size; // 资源数据的长度DWORD CodePage; // 代码页,一般为0 DWORD Reserved; // 保留字段
} IMAGE_RESOURCE_DATA_ENTRY, *PIMAGE_RESOURCE_DATA_ENTRY;
经过多层结构,此处的 IMAGE_RESOURCE_DATA_ENTRY 结构就是真正的资源数据了。结构中的OffsetToData指向资源数据的指针(其为 RVA值)。
资源目录解析
#include<Windows.h>
#include<iostream>
using namespace std;DWORD RvaToFoa(_In_ DWORD rva, _In_ PIMAGE_SECTION_HEADER p, _In_ PIMAGE_FILE_HEADER f)
{for (int i = 0; i < f->NumberOfSections; i++){// FOA = 数据的RVA + 区段的RVA - 区段的FOAif (rva >= p->VirtualAddress && rva < (p->VirtualAddress + p->Misc.VirtualSize)){return rva - p->VirtualAddress + p->PointerToRawData;}f++;p++;}return 0;
}void ImageNtHeader(_In_z_ const char* path)
{// 获取文件对象HANDLE hfile = CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);// 获取文件大小DWORD fSize = GetFileSize(hfile, NULL);char* pBuff = new char[fSize];DWORD dwReadSize = 0;// 读文件BOOL bSuccess = ReadFile(hfile, pBuff, fSize, &dwReadSize, NULL);if (bSuccess){PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pBuff;PIMAGE_NT_HEADERS32 pNtHeader{ 0 };pNtHeader = (PIMAGE_NT_HEADERS32)(pDosHeader->e_lfanew + pBuff);PIMAGE_FILE_HEADER pFileHeader = (PIMAGE_FILE_HEADER)&pNtHeader->FileHeader;PIMAGE_OPTIONAL_HEADER32 pOptionalHeader = (PIMAGE_OPTIONAL_HEADER32)&pNtHeader->OptionalHeader;PIMAGE_SECTION_HEADER pSectionHeader = IMAGE_FIRST_SECTION(pNtHeader);PIMAGE_DATA_DIRECTORY dataDirectory = (PIMAGE_DATA_DIRECTORY)&pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE];//填充结构PIMAGE_RESOURCE_DIRECTORY pResource = (PIMAGE_RESOURCE_DIRECTORY)(RvaToFoa(dataDirectory->VirtualAddress, pSectionHeader, pFileHeader) + pBuff);cout << "数据块开始VA:" << pResource->NumberOfIdEntries << endl;cout << "数据块结束VA:" << pResource->TimeDateStamp << endl;}else (cout.write("打开文件失败", 20));CloseHandle(hfile);delete[] pBuff;
}void main()
{ImageNtHeader(R"(C:\Users\11981\Desktop\Project1\2.exe)");
}
调试目录
当使用调试信息构建个可执行文件时。按照惯例,应该句括这种信息的格式及位置细节。操作系统不需要通过它来运行可执行文件,但它对开发工具是有用的。
数据目录表的第 7 个条目(IMAGE_DIRECTORY_ENTRY_DEBUG)指向调试目录,它由一个IMAGE_DEBUG_DIRECTORY 结构数组组成。这些结构用于保存存储在文件中变量的类型、尺寸和位置的调试信息。debug目录中的元素数量可以通过 DataDirectory 中的 Size 字段来计算,其结构定义如下。
typedef struct _IMAGE_DEBUG_DIRECTORY {DWORD Characteristics; // 未使用,设为0DWORD TimeDateStamp; // debug信息的时间/日期戳WORD MajorVersion; // debug信息的主版本,未使用WORD MinorVersion; // debug信息的次版本,未使用DWORD Type; // debug信息的类型DWORD SizeOfData; // debug数据的大小DWORD AddressOfRawData; // 当被映射到内存时 debug 数据的 RVA,为0表示不被映射DWORD PointerToRawData; // debug数据的文件偏移(不是 RVA)PointerToRawData
} IMAGE_DEBUG_DIRECTORY, *PIMAGE_DEBUG_DIRECTORY;
到目前为止,存储 debug 信息的最普遍形式是PDB 文件。PDB 文件基本上是 CodeView样式的debug 信息的演变。PDB 信息是由一个 IMAGE_DEBUG_TYPE_CODEVIEW 类型的调试目录字段指出的。如果检查这个条目所指向的数据,将发现一个简短的 CodeView样式的头部。这个 debug数据多半指向外部 PDB 文件的路径。在 Visual Studio 6.0 中,debug 头部以 NB10标识开始。在 Visual Studio.NET中,debug头部以RSDS开始。
在Visual Studio 6.0中,COFF格式的 debug信息能用/DEBUGTYPE:COFF链接器开关生成。在Visual Studio.NET中没有这个选项。
Type:调试类型
#define IMAGE_DEBUG_TYPE_UNKNOWN 0
#define IMAGE_DEBUG_TYPE_COFF 1
#define IMAGE_DEBUG_TYPE_CODEVIEW 2
#define IMAGE_DEBUG_TYPE_FPO 3
#define IMAGE_DEBUG_TYPE_MISC 4
#define IMAGE_DEBUG_TYPE_EXCEPTION 5
#define IMAGE_DEBUG_TYPE_FIXUP 6
#define IMAGE_DEBUG_TYPE_OMAP_TO_SRC 7
#define IMAGE_DEBUG_TYPE_OMAP_FROM_SRC 8
#define IMAGE_DEBUG_TYPE_BORLAND 9
#define IMAGE_DEBUG_TYPE_RESERVED10 10
#define IMAGE_DEBUG_TYPE_CLSID 11
#define IMAGE_DEBUG_TYPE_VC_FEATURE 12
#define IMAGE_DEBUG_TYPE_POGO 13
#define IMAGE_DEBUG_TYPE_ILTCG 14
#define IMAGE_DEBUG_TYPE_MPX 15
#define IMAGE_DEBUG_TYPE_REPRO 16
#define IMAGE_DEBUG_TYPE_EX_DLLCHARACTERISTICS 20
调试目录解析
#include<Windows.h>
#include<iostream>
using namespace std;DWORD RvaToFoa(_In_ DWORD rva, _In_ PIMAGE_SECTION_HEADER p, _In_ PIMAGE_FILE_HEADER f)
{for (int i = 0; i < f->NumberOfSections; i++){// FOA = 数据的RVA + 区段的RVA - 区段的FOAif (rva >= p->VirtualAddress && rva < (p->VirtualAddress + p->Misc.VirtualSize)){return rva - p->VirtualAddress + p->PointerToRawData;}f++;p++;}return 0;
}void ImageNtHeader(_In_z_ const char* path)
{// 获取文件对象HANDLE hfile = CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);// 获取文件大小DWORD fSize = GetFileSize(hfile, NULL);char* pBuff = new char[fSize];DWORD dwReadSize = 0;// 读文件BOOL bSuccess = ReadFile(hfile, pBuff, fSize, &dwReadSize, NULL);if (bSuccess){PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pBuff;PIMAGE_NT_HEADERS32 pNtHeader{ 0 };pNtHeader = (PIMAGE_NT_HEADERS32)(pDosHeader->e_lfanew + pBuff);PIMAGE_FILE_HEADER pFileHeader = (PIMAGE_FILE_HEADER)&pNtHeader->FileHeader;PIMAGE_OPTIONAL_HEADER32 pOptionalHeader = (PIMAGE_OPTIONAL_HEADER32)&pNtHeader->OptionalHeader;PIMAGE_SECTION_HEADER pSectionHeader = IMAGE_FIRST_SECTION(pNtHeader);PIMAGE_DATA_DIRECTORY dataDirectory = (PIMAGE_DATA_DIRECTORY)&pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG];//填充结构PIMAGE_DEBUG_DIRECTORY pDebug = (PIMAGE_DEBUG_DIRECTORY)(RvaToFoa(dataDirectory->VirtualAddress, pSectionHeader, pFileHeader) + pBuff);cout << "debug数据的大小:" << pDebug->SizeOfData << endl;cout << "debug信息的类型:" << pDebug->Type << endl;}else (cout.write("打开文件失败", 20));CloseHandle(hfile);delete[] pBuff;
}void main()
{ImageNtHeader(R"(C:\Users\11981\Desktop\Project1\2.exe)");
}
加载配置目录
typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY32 {DWORD Size; // 加载配置属性DWORD TimeDateStamp; // 时间戳WORD MajorVersion; // 主版本号WORD MinorVersion; // 次版本号DWORD GlobalFlagsClear; // 标志1DWORD GlobalFlagsSet; // 标志2DWORD CriticalSectionDefaultTimeout; // 超时DWORD DeCommitFreeBlockThreshold; // 释放内存数量DWORD DeCommitTotalFreeThreshold; // 空闲内存总量DWORD LockPrefixTable;// 使用LOCK前缀的指令地址DWORD MaximumAllocationSize; // 最大的分配粒度DWORD VirtualMemoryThreshold; // 最大的虚拟内存大小DWORD ProcessHeapFlags; // 进程堆标识DWORD ProcessAffinityMask; // SetProcessAffinityMask 函数参数WORD CSDVersion; // Service Pack 版本标识WORD DependentLoadFlags; DWORD EditList; // VADWORD SecurityCookie; // VADWORD SEHandlerTable; // VADWORD SEHandlerCount;DWORD GuardCFCheckFunctionPointer; // VADWORD GuardCFDispatchFunctionPointer; // VADWORD GuardCFFunctionTable; // VADWORD GuardCFFunctionCount;DWORD GuardFlags;IMAGE_LOAD_CONFIG_CODE_INTEGRITY CodeIntegrity;DWORD GuardAddressTakenIatEntryTable; // VADWORD GuardAddressTakenIatEntryCount;DWORD GuardLongJumpTargetTable; // VADWORD GuardLongJumpTargetCount;DWORD DynamicValueRelocTable; // VADWORD CHPEMetadataPointer;DWORD GuardRFFailureRoutine; // VADWORD GuardRFFailureRoutineFunctionPointer; // VADWORD DynamicValueRelocTableOffset;WORD DynamicValueRelocTableSection;WORD Reserved2;DWORD GuardRFVerifyStackPointerFunctionPointer; // VADWORD HotPatchTableOffset;DWORD Reserved3;DWORD EnclaveConfigurationPointer; // VADWORD VolatileMetadataPointer; // VADWORD GuardEHContinuationTable; // VADWORD GuardEHContinuationCount;
} IMAGE_LOAD_CONFIG_DIRECTORY32, *PIMAGE_LOAD_CONFIG_DIRECTORY32;typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY64 {DWORD Size;DWORD TimeDateStamp;WORD MajorVersion;WORD MinorVersion;DWORD GlobalFlagsClear;DWORD GlobalFlagsSet;DWORD CriticalSectionDefaultTimeout;ULONGLONG DeCommitFreeBlockThreshold;ULONGLONG DeCommitTotalFreeThreshold;ULONGLONG LockPrefixTable; // VAULONGLONG MaximumAllocationSize;ULONGLONG VirtualMemoryThreshold;ULONGLONG ProcessAffinityMask;DWORD ProcessHeapFlags;WORD CSDVersion;WORD DependentLoadFlags;ULONGLONG EditList; // VAULONGLONG SecurityCookie; // VAULONGLONG SEHandlerTable; // VAULONGLONG SEHandlerCount;ULONGLONG GuardCFCheckFunctionPointer; // VAULONGLONG GuardCFDispatchFunctionPointer; // VAULONGLONG GuardCFFunctionTable; // VAULONGLONG GuardCFFunctionCount;DWORD GuardFlags;IMAGE_LOAD_CONFIG_CODE_INTEGRITY CodeIntegrity;ULONGLONG GuardAddressTakenIatEntryTable; // VAULONGLONG GuardAddressTakenIatEntryCount;ULONGLONG GuardLongJumpTargetTable; // VAULONGLONG GuardLongJumpTargetCount;ULONGLONG DynamicValueRelocTable; // VAULONGLONG CHPEMetadataPointer; // VAULONGLONG GuardRFFailureRoutine; // VAULONGLONG GuardRFFailureRoutineFunctionPointer; // VADWORD DynamicValueRelocTableOffset;WORD DynamicValueRelocTableSection;WORD Reserved2;ULONGLONG GuardRFVerifyStackPointerFunctionPointer; // VADWORD HotPatchTableOffset;DWORD Reserved3;ULONGLONG EnclaveConfigurationPointer; // VAULONGLONG VolatileMetadataPointer; // VAULONGLONG GuardEHContinuationTable; // VAULONGLONG GuardEHContinuationCount;
} IMAGE_LOAD_CONFIG_DIRECTORY64, *PIMAGE_LOAD_CONFIG_DIRECTORY64;
配置目录解析
#include<Windows.h>
#include<iostream>
using namespace std;DWORD RvaToFoa(_In_ DWORD rva, _In_ PIMAGE_SECTION_HEADER p, _In_ PIMAGE_FILE_HEADER f)
{for (int i = 0; i < f->NumberOfSections; i++){// FOA = 数据的RVA + 区段的RVA - 区段的FOAif (rva >= p->VirtualAddress && rva < (p->VirtualAddress + p->Misc.VirtualSize)){return rva - p->VirtualAddress + p->PointerToRawData;}f++;p++;}return 0;
}void ImageNtHeader(_In_z_ const char* path)
{// 获取文件对象HANDLE hfile = CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);// 获取文件大小DWORD fSize = GetFileSize(hfile, NULL);char* pBuff = new char[fSize];DWORD dwReadSize = 0;// 读文件BOOL bSuccess = ReadFile(hfile, pBuff, fSize, &dwReadSize, NULL);if (bSuccess){PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pBuff;PIMAGE_NT_HEADERS32 pNtHeader{ 0 };pNtHeader = (PIMAGE_NT_HEADERS32)(pDosHeader->e_lfanew + pBuff);PIMAGE_FILE_HEADER pFileHeader = (PIMAGE_FILE_HEADER)&pNtHeader->FileHeader;PIMAGE_OPTIONAL_HEADER32 pOptionalHeader = (PIMAGE_OPTIONAL_HEADER32)&pNtHeader->OptionalHeader;PIMAGE_SECTION_HEADER pSectionHeader = IMAGE_FIRST_SECTION(pNtHeader);PIMAGE_DATA_DIRECTORY dataDirectory = (PIMAGE_DATA_DIRECTORY)&pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG];//填充结构PIMAGE_LOAD_CONFIG_DIRECTORY32 pDebug = (PIMAGE_LOAD_CONFIG_DIRECTORY32)(RvaToFoa(dataDirectory->VirtualAddress, pSectionHeader, pFileHeader) + pBuff);cout << "加载配置属性:" << pDebug->Size << endl;cout << "最大的分配粒度:" << pDebug->MaximumAllocationSize << endl;cout << "最大的虚拟内存大小:" << pDebug->VirtualMemoryThreshold << endl;}else (cout.write("打开文件失败", 20));CloseHandle(hfile);delete[] pBuff;
}void main()
{ImageNtHeader(R"(C:\Users\11981\Desktop\Project1\2.exe)");
}
快速查询PE文件知识点和PE文件解析(下)相关推荐
- 如何快速查询学术会议
在告诉大家如何快速查询学术会议之前,先简单说下什么是学术会议,为什么要参加学术会议? 1.什么是学术会议 学术会议是一种以促进科学发展.学术交流.课题研究等学术性话题为主题的会议.一般参加学术会议的都 ...
- 【PE结构】由浅入深PE基础学习-菜鸟手动查询导出表、相对虚拟地址(RVA)与文件偏移地址转换(FOA)...
0 前言 此篇文章想写如何通过工具手查导出表.PE文件代码编程过程中的原理.文笔不是很好,内容也是查阅了很多的资料后整合出来的.希望借此加深对PE文件格式的理解,也希望可以对看雪论坛有所贡献.因为了解 ...
- Windows Pe 第三章 PE头文件(上)
第三章 PE头文件 本章是全书重点,所以要好好理解,概念比较多,但是非常重要. PE头文件记录了PE文件中所有的数据的组织方式,它类似于一本书的目录,通过目录我们可以快速定位到某个具体的章节:通过P ...
- Windows Pe 第三章 PE头文件(下)
3.5 数据结构字段详解 3.5.1 PE头IMAGE_NT_HEADER的字段 1.IMAGE_NT_HEADER.Signature +0000h,双字.PE文件标识,被定义为00004550 ...
- Windows Pe 第三章 PE头文件(中)
这一章的上半部分大体介绍了下PE文件头,下半部分是详细介绍里面的内容,这一章一定要多读几遍,好好记记基础概念和知识,方便之后的学习. 简单回忆一下: 3.4 PE文件头部解析 3.4.1 DOS M ...
- 如何判断一个文件是否为PE文件
PE文件,Portable Executable file format简称. 那么如何判断一个文件是否为PE格式的文件? 1.首先检验文件头部第一个字的值是否等于 IMAGE_DOS_SIGNATU ...
- glob php,php使用glob函数快速查询指定目录文件的方法
本文实例讲述了php使用glob函数快速查询指定目录文件的方法.分享给大家供大家参考.具体如下: php搜索当前目录所有文件,代码如下: $array = glob('*.*'); print_r($ ...
- 快速搜索服务器文件,最好用的文件快速搜索软件Everything官网最新版
本帖最后由 zhangweiyi9 于 2019-12-3 12:16 编辑 今天看到一位朋友转了个Everything 1.4.1.958单文件测试版,官网测试版下载链接:https://www.v ...
- 九、将cs文件快速的转换成可执行文件和响应文件(配置编译开关的文件)
1.将包含多个类型的源代码文件转换为可以部署的文件.有如下Program.cs的文件,代码如下: public sealed class Program{public static void Main ...
最新文章
- Http代理程序,基于hash缓存实现
- 谷歌大脑科学家亲解 LSTM:一个关于“遗忘”与“记忆”的故事
- 1.3 List集合:ArrayList和LinkedList类的用法及区别
- pycharm 黄色(黄字)高亮警告 Default argument value is mutable 原因及解决办法(mutable 可变对象与 immutable不可变对象)
- 在windows7上的通过composer安装yii2
- 演练 开心庄园 1002
- 如何在eclipse中,为整个工程生成javadoc文档
- SpringMvc-HandlerExceptionResolver
- 谷雨钜献 | 用深度学习理解遥感图像,识别效率提升90倍,PaddlePaddle中科院遥感地球所...
- 全球最大域名注册商 GoDaddy 的托管账户凭证遭泄露
- application.properties 中文乱码问题解决
- Dialog详解(包括进度条、PopupWindow、自定义view、自定义样式的对话框)
- ESX的VSWITCH坏了,如何转移到新建的虚拟交换机上?
- Linux0.11内核--进程调度分析之1.初始化
- laravel auth(api)-attempt 返回false_3分钟短文:Laravel把数据验证的手伸向“请求体”...
- 设置 Google Analytics(分析)全局网站统计代码
- 未转变者服务器bug,未转变者攻略 unturned无敌BUG说明
- 【愚公系列】2022年05月 vue3系列 axios请求的封装(TS版)
- 远程办公何时了,网络打洞帮你搞
- vulfocus——骑士cms任意代码执行(CVE-2020-35339)