延迟加载导入表

延迟加载导入表(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. 如何快速查询学术会议

    在告诉大家如何快速查询学术会议之前,先简单说下什么是学术会议,为什么要参加学术会议? 1.什么是学术会议 学术会议是一种以促进科学发展.学术交流.课题研究等学术性话题为主题的会议.一般参加学术会议的都 ...

  2. 【PE结构】由浅入深PE基础学习-菜鸟手动查询导出表、相对虚拟地址(RVA)与文件偏移地址转换(FOA)...

    0 前言 此篇文章想写如何通过工具手查导出表.PE文件代码编程过程中的原理.文笔不是很好,内容也是查阅了很多的资料后整合出来的.希望借此加深对PE文件格式的理解,也希望可以对看雪论坛有所贡献.因为了解 ...

  3. Windows Pe 第三章 PE头文件(上)

    第三章  PE头文件 本章是全书重点,所以要好好理解,概念比较多,但是非常重要. PE头文件记录了PE文件中所有的数据的组织方式,它类似于一本书的目录,通过目录我们可以快速定位到某个具体的章节:通过P ...

  4. Windows Pe 第三章 PE头文件(下)

    3.5  数据结构字段详解 3.5.1  PE头IMAGE_NT_HEADER的字段 1.IMAGE_NT_HEADER.Signature +0000h,双字.PE文件标识,被定义为00004550 ...

  5. Windows Pe 第三章 PE头文件(中)

    这一章的上半部分大体介绍了下PE文件头,下半部分是详细介绍里面的内容,这一章一定要多读几遍,好好记记基础概念和知识,方便之后的学习. 简单回忆一下: 3.4  PE文件头部解析 3.4.1 DOS M ...

  6. 如何判断一个文件是否为PE文件

    PE文件,Portable Executable file format简称. 那么如何判断一个文件是否为PE格式的文件? 1.首先检验文件头部第一个字的值是否等于 IMAGE_DOS_SIGNATU ...

  7. glob php,php使用glob函数快速查询指定目录文件的方法

    本文实例讲述了php使用glob函数快速查询指定目录文件的方法.分享给大家供大家参考.具体如下: php搜索当前目录所有文件,代码如下: $array = glob('*.*'); print_r($ ...

  8. 快速搜索服务器文件,最好用的文件快速搜索软件Everything官网最新版

    本帖最后由 zhangweiyi9 于 2019-12-3 12:16 编辑 今天看到一位朋友转了个Everything 1.4.1.958单文件测试版,官网测试版下载链接:https://www.v ...

  9. 九、将cs文件快速的转换成可执行文件和响应文件(配置编译开关的文件)

    1.将包含多个类型的源代码文件转换为可以部署的文件.有如下Program.cs的文件,代码如下: public sealed class Program{public static void Main ...

最新文章

  1. Http代理程序,基于hash缓存实现
  2. 谷歌大脑科学家亲解 LSTM:一个关于“遗忘”与“记忆”的故事
  3. 1.3 List集合:ArrayList和LinkedList类的用法及区别
  4. pycharm 黄色(黄字)高亮警告 Default argument value is mutable 原因及解决办法(mutable 可变对象与 immutable不可变对象)
  5. 在windows7上的通过composer安装yii2
  6. 演练 开心庄园 1002
  7. 如何在eclipse中,为整个工程生成javadoc文档
  8. SpringMvc-HandlerExceptionResolver
  9. 谷雨钜献 | 用深度学习理解遥感图像,识别效率提升90倍,PaddlePaddle中科院遥感地球所...
  10. 全球最大域名注册商 GoDaddy 的托管账户凭证遭泄露
  11. application.properties 中文乱码问题解决
  12. Dialog详解(包括进度条、PopupWindow、自定义view、自定义样式的对话框)
  13. ESX的VSWITCH坏了,如何转移到新建的虚拟交换机上?
  14. Linux0.11内核--进程调度分析之1.初始化
  15. laravel auth(api)-attempt 返回false_3分钟短文:Laravel把数据验证的手伸向“请求体”...
  16. 设置 Google Analytics(分析)全局网站统计代码
  17. 未转变者服务器bug,未转变者攻略 unturned无敌BUG说明
  18. 【愚公系列】2022年05月 vue3系列 axios请求的封装(TS版)
  19. 远程办公何时了,网络打洞帮你搞
  20. vulfocus——骑士cms任意代码执行(CVE-2020-35339)

热门文章

  1. 欢迎观看Toni_hou的#生活5
  2. vue3自定义全局指令(过滤前后空格,输入框自动聚焦,点击复制内容到粘贴板)
  3. Linux安装消息队列IBM MQ 7.5开发版安装配置详解
  4. 【转载】APP图标在手机上显示模糊的问题
  5. [工具] UltraEdit使用技巧汇总
  6. python数据挖掘领域工具包 - wentingtu - 博客园
  7. 天润融通牵手葵网新保险电销青睐云呼叫
  8. Armadillo C++ Library
  9. ios应用中添加广告
  10. 联阳(ITE)IT66021FN:HDMI转RGB芯片 3D 资料