PE文件结构—导入表解析

#include<iostream>
#include<Windows.h>

DWORD RvaToFoa(DWORD dwRva, const char* buffer)
{
	PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)buffer;
	PIMAGE_NT_HEADERS pNt = PIMAGE_NT_HEADERS(buffer + pDos->e_lfanew);
	PIMAGE_SECTION_HEADER pSh = IMAGE_FIRST_SECTION(pNt);
	if (dwRva < pSh[0].VirtualAddress)
	{
		return dwRva;//因为Dos头+PE头+节表,在文件和在内存中展开都是一样的
	}
	for (size_t i = 0; i < pNt->FileHeader.NumberOfSections; i++)
	{
		if (dwRva >= pSh[i].VirtualAddress && dwRva <= pSh[i].VirtualAddress + pSh[i].Misc.VirtualSize)//判断是否落在了某一个区段内
		{
			return dwRva - pSh[i].VirtualAddress + pSh[i].PointerToRawData; //返回文件中的偏移
		}
	}
    return NULL;
}

char* Loadfile(const char* szbuffer)
{
	HANDLE fRet = CreateFileA(szbuffer, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if (fRet == INVALID_HANDLE_VALUE)
	{
		std::cout << "打开文件失败:" << std::endl;
		return NULL;
	}
	DWORD H_size = 0;
	DWORD L_size = GetFileSize(fRet, &H_size);
	if (L_size == INVALID_FILE_SIZE)
	{
		std::cout << "获取文件大小失败:" << GetLastError() << std::endl;
		return NULL;
	}
	char* tempbuff = new char[L_size];
	memset(tempbuff, 0, L_size);
	DWORD readszie = 0;
	if (ReadFile(fRet, tempbuff, L_size, &readszie, NULL))
	{
		return tempbuff;
	}
	std::cout << "读取文件失败!" << std::endl;
	return NULL;
}

BOOL ImportTable(const char* szbuffer, DWORD index)
{
	PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)szbuffer;
	PIMAGE_NT_HEADERS pNt = PIMAGE_NT_HEADERS(szbuffer + pDos->e_lfanew);
	//通过数据目录表获取了Import的结构体
	PIMAGE_DATA_DIRECTORY pData = &(pNt->OptionalHeader).DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
	//获取了导入表数组的首地址
	PIMAGE_IMPORT_DESCRIPTOR pImport = (PIMAGE_IMPORT_DESCRIPTOR)(RvaToFoa(pData->VirtualAddress, szbuffer) + szbuffer);
	pImport += index;
	//获取了Thunk数组的首地址
	PIMAGE_THUNK_DATA pTd = (PIMAGE_THUNK_DATA)(RvaToFoa(pImport->OriginalFirstThunk, szbuffer) + szbuffer);
	DWORD dwIndex = 0;
	while (pTd->u1.Ordinal != NULL)
	{
		PIMAGE_IMPORT_BY_NAME pIbn = (PIMAGE_IMPORT_BY_NAME)(RvaToFoa(pTd->u1.AddressOfData, szbuffer) + szbuffer);
		//因为PIMAGE_THUNK_DATA每一个都是4字节,pImport->OriginalFirstThunk指向PIMAGE_THUNK_DATA类型的数组
		printf("ThunkRVA:%08X\n", pImport->OriginalFirstThunk + dwIndex);
		printf("ThunkOffset:%08X\n", (RvaToFoa(pImport->OriginalFirstThunk, szbuffer) + dwIndex));
		printf("Thunk值:%08X\n", pTd->u1.Ordinal);
		try
		{
			printf("提示:%04X\n", pIbn->Hint);
			printf("函数名:%s\n\n", pIbn->Name);
		}
		catch (...)
		{
			DWORD temp = pTd->u1.Ordinal - 0x80000000;
			char tempbuff[MAX_PATH] = { 0 };
			sprintf_s(tempbuff, "序号:%Xh %dd", temp, temp);
			printf("——\n");
			printf("函数名:%s\n\n", tempbuff);
		}
		pTd++;
		dwIndex += 4;
	}
	return TRUE;
}

int main()
{
	char* szbuffer = Loadfile("E:\\VS_2019\\ConsoleApplication2\\Debug/ConsoleApplication2.exe");
	PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)szbuffer;
	PIMAGE_NT_HEADERS pNt = PIMAGE_NT_HEADERS(szbuffer + pDos->e_lfanew);
	PIMAGE_DATA_DIRECTORY pData = &(pNt->OptionalHeader).DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
	PIMAGE_IMPORT_DESCRIPTOR pImport = (PIMAGE_IMPORT_DESCRIPTOR)(RvaToFoa(pData->VirtualAddress, szbuffer) + szbuffer);
	DWORD nDll = 0;//导入表的数量
	DWORD index = 0;//导入表的次数标志
	while (pImport->Name != 0)
	{
		nDll++;
		pImport++;
	}
	pImport -= nDll;
	for (size_t i = 0; i < nDll; i++)
	{
		char* MoudleName = (char*)(RvaToFoa(pImport->Name, szbuffer) + szbuffer);
		printf("%s\n", MoudleName);
		printf("名称Rva:0x%x\n", pImport->Name);
		printf("时间戳:0x%x\n", pImport->TimeDateStamp);
		printf("导入名称表的RVA:0x%x\n", pImport->OriginalFirstThunk);
		printf("ForwarderChain:0x%x\n", pImport->ForwarderChain);
		printf("导入地址表的RVA:0x%x\n", pImport->FirstThunk);
		printf("Characteristics:0x%x\n\n", pImport->Characteristics);
		ImportTable(szbuffer, index);
		index++;
		pImport++;
	}
	system("pause");
	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值