快速查询PE文件知识点和PE文件解析(下)

延迟加载导入表

延迟加载导入表(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[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; // 保留,目前设为0
        struct {
            DWORD Reserved0 : 20;
         
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值