C++ 獲取 PE 文件的各種信息


首先感謝 cyxvc 老哥,他的代碼可讀性超高,精簡有用以理解,我找這方面的資料好久了,這篇文章對我幫助很大。

參考代碼:

#include "stdafx.h"
#include <Windows.h>
 
extern void DirectoryString(DWORD dwIndex);
 
int _tmain(int argc, _TCHAR* argv[])
{
	//獲取文件句柄
	HANDLE hFile = CreateFile(
		_T("D:\\PE.exe"),
		GENERIC_READ,
		0,
		NULL,
		OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	//獲取文件大小
	DWORD dwFileSize = GetFileSize(hFile, NULL);
	CHAR *pFileBuf = new CHAR[dwFileSize];
	//將文件讀取到內存
	DWORD ReadSize = 0;
	ReadFile(hFile, pFileBuf, dwFileSize, &ReadSize, NULL);
 
	//判斷是否為PE文件
	PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pFileBuf;
	if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
	{
		//不是PE
		printf("不是PE文件\n");
		system("pause");
		return 0;
	}
 
	PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)(pFileBuf + pDosHeader->e_lfanew);
	if (pNtHeader->Signature != IMAGE_NT_SIGNATURE)
	{
		//不是PE文件
		printf("不是PE文件\n");
		system("pause");
		return 0;
	}
 
	//獲取基本PE頭信息
	//獲取信息所用到的兩個結構體指針	(這兩個結構體都屬於NT頭)
	PIMAGE_FILE_HEADER		pFileHeader		= &(pNtHeader->FileHeader);
	PIMAGE_OPTIONAL_HEADER	pOptionalHeader	= &(pNtHeader->OptionalHeader);
	//輸出PE頭信息
	printf("================== 基 本 P E 頭 信 息 ==================\n\n");
	printf("入 口 點:\t%08X\t", pOptionalHeader->AddressOfEntryPoint);
	printf("子 系 統:\t%04X\n", pOptionalHeader->Subsystem);
	printf("鏡像基址:\t%08X\t", pOptionalHeader->ImageBase);
	printf("區段數目:\t%04X\n", pFileHeader->NumberOfSections);
	printf("鏡像大小:\t%08X\t", pOptionalHeader->SizeOfImage);
	printf("日期時間標志:\t%08X\n", pFileHeader->TimeDateStamp);
	printf("代碼基址:\t%08X\t", pOptionalHeader->BaseOfCode);
	printf("部首大小:\t%08X\n", pOptionalHeader->SizeOfHeaders);
	printf("數據基址:\t%08X\t", pOptionalHeader->BaseOfData);
	printf("特 征 值:\t%04X\n", pFileHeader->Characteristics);
	printf("塊 對 齊:\t%08X\t", pOptionalHeader->SectionAlignment);
	printf("校 驗 和:\t%08X\n", pOptionalHeader->CheckSum);
	printf("文件塊對齊:\t%08X\t", pOptionalHeader->FileAlignment);
	printf("可選頭部大小:\t%04X\n", pFileHeader->SizeOfOptionalHeader);
	printf("標 志 字:\t%04X\t\t", pOptionalHeader->Magic);
	printf("RVA數及大小:\t%08X\n\n", pOptionalHeader->NumberOfRvaAndSizes);
 
	printf("======================= 目 錄 表 =======================\n");
	//獲取目錄表頭指針
	PIMAGE_DATA_DIRECTORY pDataDirectory = pOptionalHeader->DataDirectory;
	printf("\t\t  RAV\t\t  大小\n");
	for (DWORD i = 0; i < IMAGE_NUMBEROF_DIRECTORY_ENTRIES; i++)
	{
		DirectoryString(i);
		printf("%08X\t%08X\n",
			pDataDirectory[i].VirtualAddress, pDataDirectory[i].Size);
	}
 
	printf("======================= 區 段 表 =======================\n");
	//獲取區段表頭指針
	PIMAGE_SECTION_HEADER pSectionHeader = IMAGE_FIRST_SECTION(pNtHeader);
	printf("名稱      VOffset   VSize     ROffset   RSize     標志\n");
	//獲取區段個數
	DWORD dwSectionNum = pFileHeader->NumberOfSections;
	//根據區段個數遍歷區段信息
	for (DWORD i = 0; i < dwSectionNum; i++, pSectionHeader++)
	{
		for (DWORD j = 0; j < IMAGE_SIZEOF_SHORT_NAME; j++)
		{
			printf("%c", pSectionHeader->Name[j]);
		}
		printf("  %08X  %08X  %08X  %08X  %08X\n",
			pSectionHeader->VirtualAddress,
			pSectionHeader->Misc.VirtualSize,
			pSectionHeader->PointerToRawData,
			pSectionHeader->SizeOfRawData,
			pSectionHeader->Characteristics);
	}
	printf("\n");
 
	system("pause");
	return 0;
}
 
void DirectoryString(DWORD dwIndex)
{
	switch (dwIndex)
	{
	case 0:printf("輸出表:\t\t");
		break;
	case 1:printf("輸入表:\t\t");
		break;
	case 2:printf("資源:\t\t");
		break;
	case 3:printf("異常:\t\t");
		break;
	case 4:printf("安全:\t\t");
		break;
	case 5:printf("重定位:\t\t");
		break;
	case 6:printf("調試:\t\t");
		break;
	case 7:printf("版權:\t\t");
		break;
	case 8:printf("全局指針:\t");
		break;
	case 9:printf("TLS表:\t\t");
		break;
	case 10:printf("載入配置:\t");
		break;
	case 11:printf("輸入范圍:\t");
		break;
	case 12:printf("IAT:\t\t");
		break;
	case 13:printf("延遲輸入:\t");
		break;
	case 14:printf("COM:\t\t");
		break;
	case 15:printf("保留:\t\t");
		break;
	}
}

效果圖:

另外附上我的代碼。😕 獲取某指定區段的信息:

	HANDLE hFile = CreateFile(_T("C:\\Windows\\SysNative\\ntoskrnl.exe"), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if (hFile == INVALID_HANDLE_VALUE) {
		cout << "CreateFile failed:" << GetLastError() << endl;
		return false;
	}
	DWORD dwFileSize = GetFileSize(hFile, NULL);
	CHAR* pFileBuf = new CHAR[dwFileSize];
	DWORD ReadSize = 0;
	if (!ReadFile(hFile, pFileBuf, dwFileSize, &ReadSize, NULL)) {
		cout << "ReadFile failed:" << GetLastError() << endl;
		return false;
	}
	PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pFileBuf;
	PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)(pFileBuf + pDosHeader->e_lfanew);
	PIMAGE_FILE_HEADER		pFileHeader = &(pNtHeader->FileHeader);
	PIMAGE_OPTIONAL_HEADER	pOptionalHeader = &(pNtHeader->OptionalHeader);
	PIMAGE_SECTION_HEADER pSectionHeader = IMAGE_FIRST_SECTION(pNtHeader);
	DWORD dwSectionNum = pFileHeader->NumberOfSections;
	int page_vaddr = 0, page_roff = 0;
	for (DWORD i = 0; i < dwSectionNum; i++, pSectionHeader++) {
		string s_name;
		for (DWORD j = 0; j < IMAGE_SIZEOF_SHORT_NAME; j++) {
			if (pSectionHeader->Name[j]) {
				s_name += pSectionHeader->Name[j];
			}
		}
		if (s_name == "PAGE") {
			page_vaddr = pSectionHeader->VirtualAddress;
			page_roff = pSectionHeader->PointerToRawData;
			break;
		}
	}
	if (page_vaddr == 0 || page_roff == 0) { cout << "沒有找到 PAGE 區段" << endl; return false; }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM