快速查询PE文件知识点和PE文件解析(下)
本帖最后由 fz12 于 2022-5-5 11:21 编辑延迟加载导入表
延迟加载导入表(Delay Load Import Table)是PE中引入的专门用来描述与动态链接库延迟加载相关的数据,因为这些数据所起的作用和结构与导入表数据基本一致,所以称为延迟加载导入表。延迟加载导入的概念:系统开始运行程序时被指定的延迟加载的 DLL是不被载入的,只有等到程序调用了该动态链接库的函数时,系统才将该链接库载入内存空间,并执行相关函数代码
typedef struct _IMAGE_DELAYLOAD_DESCRIPTOR {
union {
DWORD AllAttributes; // 属性,必须为0
struct {
DWORD RvaBased : 1; // Delay load version 2
DWORD ReservedAttributes : 31;
} DUMMYSTRUCTNAME;
} Attributes;
DWORD DllNameRVA; // 指向DLL名称的RVA
DWORD ModuleHandleRVA; // DLL模块句柄的RVA
DWORD ImportAddressTableRVA; // 延迟加载导入IAT的RVA
DWORD ImportNameTableRVA; // 延迟加载导入INT的RVA
DWORD BoundImportAddressTableRVA; // 绑定延迟加载导入表的RVA
DWORD UnloadInformationTableRVA; // 卸载延迟加载导入地址表的RVA
DWORD 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 - 区段的FOA
if (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;
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;
//填充延迟导入表数据结构
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:指向(在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; // 保留,目前设为0
struct {
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; // PDWORD
ULONGLONG 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 - 区段的FOA
if (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;
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;
//填充结构
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; // 理论上是资源的属性标志,但是通常为0
DWORD TimeDateStamp; // 资源建立的时间
WORD MajorVersion; // 理论上是放置资源的版本,但是通常为0
WORD 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; // 目录项的名称字符串指针或ID
union {
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; // 资源数据的RVA
DWORD 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 - 区段的FOA
if (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;
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;
//填充结构
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; // 未使用,设为0
DWORD 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_DLLCHARACTERISTICS20
调试目录解析
#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 - 区段的FOA
if (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;
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;
//填充结构
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; // 标志1
DWORD GlobalFlagsSet; // 标志2
DWORD 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; // VA
DWORD SecurityCookie; // VA
DWORD SEHandlerTable; // VA
DWORD SEHandlerCount;
DWORD GuardCFCheckFunctionPointer; // VA
DWORD GuardCFDispatchFunctionPointer; // VA
DWORD GuardCFFunctionTable; // VA
DWORD GuardCFFunctionCount;
DWORD GuardFlags;
IMAGE_LOAD_CONFIG_CODE_INTEGRITY CodeIntegrity;
DWORD GuardAddressTakenIatEntryTable; // VA
DWORD GuardAddressTakenIatEntryCount;
DWORD GuardLongJumpTargetTable; // VA
DWORD GuardLongJumpTargetCount;
DWORD DynamicValueRelocTable; // VA
DWORD CHPEMetadataPointer;
DWORD GuardRFFailureRoutine; // VA
DWORD GuardRFFailureRoutineFunctionPointer; // VA
DWORD DynamicValueRelocTableOffset;
WORD DynamicValueRelocTableSection;
WORD Reserved2;
DWORD GuardRFVerifyStackPointerFunctionPointer; // VA
DWORD HotPatchTableOffset;
DWORD Reserved3;
DWORD EnclaveConfigurationPointer; // VA
DWORD VolatileMetadataPointer; // VA
DWORD GuardEHContinuationTable; // VA
DWORD 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;
ULONGLONGDeCommitFreeBlockThreshold;
ULONGLONGDeCommitTotalFreeThreshold;
ULONGLONGLockPrefixTable; // VA
ULONGLONGMaximumAllocationSize;
ULONGLONGVirtualMemoryThreshold;
ULONGLONGProcessAffinityMask;
DWORD ProcessHeapFlags;
WORD CSDVersion;
WORD DependentLoadFlags;
ULONGLONGEditList; // VA
ULONGLONGSecurityCookie; // VA
ULONGLONGSEHandlerTable; // VA
ULONGLONGSEHandlerCount;
ULONGLONGGuardCFCheckFunctionPointer; // VA
ULONGLONGGuardCFDispatchFunctionPointer; // VA
ULONGLONGGuardCFFunctionTable; // VA
ULONGLONGGuardCFFunctionCount;
DWORD GuardFlags;
IMAGE_LOAD_CONFIG_CODE_INTEGRITY CodeIntegrity;
ULONGLONGGuardAddressTakenIatEntryTable; // VA
ULONGLONGGuardAddressTakenIatEntryCount;
ULONGLONGGuardLongJumpTargetTable; // VA
ULONGLONGGuardLongJumpTargetCount;
ULONGLONGDynamicValueRelocTable; // VA
ULONGLONGCHPEMetadataPointer; // VA
ULONGLONGGuardRFFailureRoutine; // VA
ULONGLONGGuardRFFailureRoutineFunctionPointer; // VA
DWORD DynamicValueRelocTableOffset;
WORD DynamicValueRelocTableSection;
WORD Reserved2;
ULONGLONGGuardRFVerifyStackPointerFunctionPointer; // VA
DWORD HotPatchTableOffset;
DWORD Reserved3;
ULONGLONGEnclaveConfigurationPointer; // VA
ULONGLONGVolatileMetadataPointer; // VA
ULONGLONGGuardEHContinuationTable; // VA
ULONGLONGGuardEHContinuationCount;
} 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 - 区段的FOA
if (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;
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;
//填充结构
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)");
}
参考文章
https://blog.csdn.net/Gamma_lab/article/details/123869956
https://blog.csdn.net/adam001521/article/details/84658708
查考书
加密与解密
Windows PE权威指南
PE文件其他资料
metoo2 发表于 2022-5-7 22:16
最新360解压也有问题,里面pe文件.pdf打开出错,另外一个文件打开正常。楼主你检查下呢?
你把后面的zip去掉,用360解压 fz12 发表于 2022-5-7 17:59
我用的是360压缩
最新360解压也有问题,里面pe文件.pdf打开出错,另外一个文件打开正常。楼主你检查下呢? 谢谢楼主无私分享。 pe资料,学习。谢谢楼主无私分享。
pe资料,学习。谢谢楼主无私分享 pe资料,学习 好东西啊~~~~~~~ 点赞支持,感谢楼主 附件用什么软件压缩的?7z打不开,提示文件错误 metoo2 发表于 2022-5-7 13:39
附件用什么软件压缩的?7z打不开,提示文件错误
我用的是360压缩
页:
[1]
2