PE檔案結構複習
突然想到好久沒有複習PE檔案結構了,正好又到了寫部落格的日子,話不多說,開淦!
#include "Entry.h"
int main()
{
//檔案讀取
FILE * pFile = NULL;
char * buffer;
int nFileLength = 0;
pFile = fopen("C:\\Users\\86188\\Desktop\\DragonNest.exe", "rb");
//pFile = fopen("C:\\Users\\86188\\Desktop\\user32.dll", "rb");
fseek(pFile, 0, SEEK_END);
nFileLength = ftell(pFile);
rewind(pFile);
int imageLength = nFileLength * sizeof(char) + 1;
buffer = (char *)malloc(imageLength);
memset(buffer, 0, nFileLength * sizeof(char) + 1);
fread(buffer, 1, imageLength, pFile);
//MS-DOS頭解析
PIMAGE_DOS_HEADER ReadDosHeader;
ReadDosHeader = (PIMAGE_DOS_HEADER)buffer;
printf("MS-DOS Info:\n");
printf("MZ標誌位:%x\n", ReadDosHeader->e_magic);
printf("PE頭偏移:%x\n", ReadDosHeader->e_lfanew);
printf("==================================================================\n");
printf("PE Header Info:\n");
PIMAGE_NT_HEADERS32 ReadNTHeaders;
//PE頭解析
ReadNTHeaders = (PIMAGE_NT_HEADERS32)(buffer + ReadDosHeader->e_lfanew);
//PE頭標誌
printf("PE標誌位:%x\n", ReadNTHeaders->Signature);
//標準PE頭欄位
printf("執行平臺:%x\n", ReadNTHeaders->FileHeader.Machine);
//擴充套件PE頭欄位
printf("ImageBase:%x\n", ReadNTHeaders->OptionalHeader.ImageBase);
printf("==================================================================\n");
printf("Section Header Info:\n");
//區段解析遍歷
PIMAGE_SECTION_HEADER ReadSectionHeader = IMAGE_FIRST_SECTION(ReadNTHeaders);
PIMAGE_FILE_HEADER pFileHeader = &ReadNTHeaders->FileHeader;
for (int i = 0; i < pFileHeader->NumberOfSections; i++)
{
printf("Name(區段名稱):%s\n", ReadSectionHeader[i].Name);
printf("VOffset(起始的相對虛擬地址):%08X\n", ReadSectionHeader[i].VirtualAddress);
printf("VSize(區段大小):%08X\n", ReadSectionHeader[i].SizeOfRawData);
printf("ROffset(檔案偏移):%08X\n", ReadSectionHeader[i].PointerToRawData);
printf("RSize(檔案中區段大小):%08X\n", ReadSectionHeader[i].Misc.VirtualSize);
printf("標記(區段的屬性):%08X\n\n", ReadSectionHeader[i].Characteristics);
}
printf("==================================================================\n");
//ImportTable(buffer);
//ExportTable(buffer);
//TLSTable(buffer);
//DelayImportTable(buffer);
//RelocTable(buffer);
ResourceTable(buffer);
free(buffer);
return 0;
}
//dwRva是某個資料目錄表的VirtualAddress
//buffer是讀取到的PE檔案緩衝區
DWORD RvaToOffset(DWORD dwRva, char * buffer)
{
//Dos頭
PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)buffer;
//PE頭
PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(pDos->e_lfanew + buffer);
//區段表
PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(pNt);
//判斷是否落在了頭部當中
if (dwRva < pSection[0].VirtualAddress)
{
return dwRva;
}
for (int i = 0; i < pNt->FileHeader.NumberOfSections; i++)
{
//VirtualAddress 起始地址
//Size 長度
//VirtualAddress + Size 結束地址
//判斷是否落在某個區段內
if (dwRva >= pSection[i].VirtualAddress && dwRva <= pSection[i].VirtualAddress + pSection[i].Misc.VirtualSize)
{
//dwRva - pSection[i].VirtualAddress是資料目錄表起始地址到區段起始地址的偏移(OFFSET)
//pSection[i].PointerToRawData區段到檔案頭的偏移(OFFSET)
//返回的是資料目錄表起始地址到檔案頭的偏移(OFFSET)
return dwRva - pSection[i].VirtualAddress + pSection[i].PointerToRawData;
}
}
}
void ImportTable(char * buffer)
{
//Dos
PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)buffer;
//PE
PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(pDos->e_lfanew + buffer);
//定位匯入表
PIMAGE_DATA_DIRECTORY pImportDir = (PIMAGE_DATA_DIRECTORY)(pNt->OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_IMPORT);
//填充結構
PIMAGE_IMPORT_DESCRIPTOR pImport = (PIMAGE_IMPORT_DESCRIPTOR)(RvaToOffset(pImportDir->VirtualAddress, buffer) + buffer);
while (pImport->Name != NULL)
{
char *szDllName = (char *)(RvaToOffset(pImport->Name, buffer) + buffer);
printf("DLL名稱:%s\n", szDllName);
printf("日期時間標誌:%08X\n", pImport->TimeDateStamp);
printf("ForwarderChain:%08X\n", pImport->ForwarderChain);
printf("名稱OFFSET:%08X\n", pImport->Name);
printf("FirstThunk:%08X\n", pImport->FirstThunk);
printf("OriginalFirstThunk:%08X\n\n", pImport->OriginalFirstThunk);
//指向匯入地址表的RVA
PIMAGE_THUNK_DATA pIat = (PIMAGE_THUNK_DATA)(RvaToOffset(pImport->OriginalFirstThunk, buffer) + buffer);
DWORD index = 0;
DWORD ImprotOffset = 0;
//被匯入函式的序號
while (pIat->u1.Ordinal != 0)
{
printf("ThunkRva:%08X\n", pImport->OriginalFirstThunk + index);
ImprotOffset = RvaToOffset(pImport->OriginalFirstThunk, buffer);
printf("ThunkOffset:%08X\n", ImprotOffset + index);
index += 4;
if ((pIat->u1.Ordinal & 0x80000000) != 1)
{
PIMAGE_IMPORT_BY_NAME pName = (PIMAGE_IMPORT_BY_NAME)(RvaToOffset(pIat->u1.AddressOfData, buffer) + buffer);
//名稱
printf("API名稱:%s\n", pName->Name);
//序號
printf("Hint:%04X\n", pName->Hint);
//被匯入函式的地址
printf("ThunkValue:%08X\n\n", pIat->u1.Function);
}
pIat++;
}
pImport++;
}
}
void ExportTable(char * buffer)
{
//Dos
PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)buffer;
//PE
PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(pDos->e_lfanew + buffer);
//定位資料目錄表中的匯出表
PIMAGE_DATA_DIRECTORY pExportDir = pNt->OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_EXPORT;
//填充匯出表結構
PIMAGE_EXPORT_DIRECTORY pExport = (PIMAGE_EXPORT_DIRECTORY)(RvaToOffset(pExportDir->VirtualAddress, buffer) + buffer);
char * szName = (char *)(RvaToOffset(pExport->Name, buffer) + buffer);
if (pExport->AddressOfFunctions == 0)
{
printf("當前沒有匯出表!\n");
return;
}
printf("匯出表OFFSET:%08X\n", RvaToOffset(pExportDir->VirtualAddress, buffer));
printf("特徵值:%08X\n", pExport->Characteristics);
printf("基:%08X\n", pExport->Base);
printf("名稱OFFSET:%08X\n", pExport->Name);
printf("名稱:%s\n", szName);
printf("函式數量:%08X\n", pExport->NumberOfFunctions);
printf("函式名數量:%08X\n", pExport->NumberOfNames);
printf("函式地址:%08X\n", pExport->AddressOfFunctions);
printf("函式名稱地址:%08X\n", pExport->AddressOfNames);
printf("函式名稱序號地址:%08X\n", pExport->AddressOfNameOrdinals);
//函式數量
DWORD dwNumOfFun = pExport->NumberOfFunctions;
//函式名數量
DWORD dwNumOfNames = pExport->NumberOfNames;
//基
DWORD dwBase = pExport->Base;
//匯出地址表
PDWORD pEat32 = (PDWORD)(RvaToOffset(pExport->AddressOfFunctions, buffer) + buffer);
//匯出名稱表
PDWORD pEnt32 = (PDWORD)(RvaToOffset(pExport->AddressOfNames, buffer) + buffer);
//匯出序號表
PWORD pId = (PWORD)(RvaToOffset(pExport->AddressOfNameOrdinals, buffer) + buffer);
for (DWORD i = 0; i < dwNumOfFun; i++)
{
if (pEat32[i] == 0)
{
continue;
}
DWORD Id = 0;
for (; Id < dwNumOfNames; Id++)
{
if (pId[Id] == i)
{
break;
}
}
if (Id == dwNumOfNames)
{
printf("Id:%x Address:0x%08X Name[NULL]\n", i + dwBase, pEat32[i]);
}
else
{
char * szFunName = (char *)(RvaToOffset(pEnt32[Id], buffer) + buffer);
printf("Id:%x Address:0x%08X Name[%s]\n", i + dwBase, pEat32[i], szFunName);
}
}
}
void TLSTable(char * buffer)
{
PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)buffer;
PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(pDos->e_lfanew + buffer);
PIMAGE_DATA_DIRECTORY pTLSDir = (pNt->OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_TLS);
PIMAGE_TLS_DIRECTORY pTLS32 = (PIMAGE_TLS_DIRECTORY)(RvaToOffset(pTLSDir->VirtualAddress, buffer) + buffer);
printf("資料塊開始VA:%08X\n", pTLS32->StartAddressOfRawData);
printf("資料塊結束VA:%08X\n", pTLS32->EndAddressOfRawData);
printf("索引變數VA:%08X\n", pTLS32->AddressOfIndex);
printf("回撥錶VA:%08X\n", pTLS32->AddressOfCallBacks);
printf("填零大小:%08X\n", pTLS32->SizeOfZeroFill);
printf("特徵值:%08X\n", pTLS32->Characteristics);
}
void DelayImportTable(char * buffer)
{
PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)buffer;
PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(pDos->e_lfanew + buffer);
PIMAGE_DATA_DIRECTORY pImportDir = (pNt->OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT);
PIMAGE_DELAYLOAD_DESCRIPTOR pDelayLoad = (PIMAGE_DELAYLOAD_DESCRIPTOR)(RvaToOffset(pImportDir->VirtualAddress, buffer) + buffer);
while (pDelayLoad->DllNameRVA != NULL)
{
char* szDllName = (char*)(RvaToOffset(pDelayLoad->DllNameRVA, buffer) + buffer);
printf("DllName:%s\n", szDllName);
printf("Attributes:%08X\n", pDelayLoad->Attributes);
printf("ModuleHandleRVA:%08X\n", pDelayLoad->ModuleHandleRVA);
printf("ImportAddressTableRVA:%08X\n", pDelayLoad->ImportAddressTableRVA);
printf("ImportNameTableRVA:%08X\n", pDelayLoad->ImportNameTableRVA);
printf("BoundImportAddressTableRVA:%08X\n", pDelayLoad->BoundImportAddressTableRVA);
printf("UnloadInformationTableRVA:%08X\n", pDelayLoad->UnloadInformationTableRVA);
printf("TimeDateStamp:%08X\n\n", pDelayLoad->TimeDateStamp);
pDelayLoad++;
}
}
void RelocTable(char * buffer)
{
typedef struct _TYPE {
WORD Offset : 12; // (1) 大小為12Bit的重定位偏移
WORD Type : 4; // (2) 大小為4Bit的重定位資訊型別值
}TYPE, *PTYPE;
PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)buffer;
PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(pDos->e_lfanew + buffer);
PIMAGE_DATA_DIRECTORY pRelocDir =
(pNt->OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_BASERELOC);
//2 找到基址重定位表
PIMAGE_BASE_RELOCATION pReloc =
(PIMAGE_BASE_RELOCATION)
(RvaToOffset(pRelocDir->VirtualAddress, buffer) + buffer);
PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(pNt);//區段
PIMAGE_FILE_HEADER pFileHeader = &pNt->FileHeader;
while (pReloc->SizeOfBlock != 0)
{
//找到本1000位元組的起始位置
DWORD dwCount = (pReloc->SizeOfBlock - 8) / 2; //本塊內需要重定位的個數。
DWORD dwRva = pReloc->VirtualAddress;
PTYPE pRelocArr = (PTYPE)(pReloc + 1); // 陣列:儲存需要重定位的每一個點的偏移;
printf("RVA:%08X\n", dwRva);
printf("專案:%X H/%d D\n", pReloc->SizeOfBlock, pReloc->SizeOfBlock);
printf("區段:%s\n\n", pSection->Name);
//找到下一個1000位元組的結構體
pReloc = (PIMAGE_BASE_RELOCATION)
((char*)pReloc + pReloc->SizeOfBlock);
for (int i = 0; i < dwCount; i++)
{
PDWORD pData =
(PDWORD)(RvaToOffset(pRelocArr[i].Offset + dwRva, buffer) + buffer);
DWORD DAD = RvaToOffset(dwRva + pRelocArr[i].Offset,buffer);
printf("RVA:%08X\n", dwRva + pRelocArr[i].Offset);
printf("區段:%08X\n", *pData);
printf("偏移:%08X\n\n", DAD);
}
}
}
void ResourceTable(char * buffer)
{
char * g_ResType[0x11] = {
"NULL",
"滑鼠指標",
"點陣圖",
"圖示",
"選單",
"對話方塊",
"字串列表",
"字型目錄",
"字型",
"快捷鍵",
"非格式化資源",
"訊息列表",
"滑鼠指標組",
"NULL",
"圖示組",
"NULL",
"版本資訊",
};
PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)buffer;
PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(pDos->e_lfanew + buffer);
PIMAGE_OPTIONAL_HEADER pOPtionHeader = (PIMAGE_OPTIONAL_HEADER)&pNt->OptionalHeader;
PIMAGE_DATA_DIRECTORY pResDir = pOPtionHeader->DataDirectory + IMAGE_DIRECTORY_ENTRY_RESOURCE;
PIMAGE_RESOURCE_DIRECTORY pFirst = (PIMAGE_RESOURCE_DIRECTORY)(RvaToOffset(pResDir->VirtualAddress, buffer) + buffer);
DWORD dwResNum = pFirst->NumberOfIdEntries + pFirst->NumberOfNamedEntries;
PIMAGE_RESOURCE_DIRECTORY_ENTRY pFirstEntry =
(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pFirst + 1);
printf("根目錄名稱入口:%04X\n", pFirst->NumberOfNamedEntries);
printf("根目錄ID入口:%04X\n\n", pFirst->NumberOfIdEntries);
for (int i = 0; i < dwResNum; i++)
{
//ID不是字串,代表該資源是系統內建資源
if (pFirstEntry->NameIsString != 1)
{
//
if (pFirstEntry->Id < 0x10)
{
printf("ResType:%s\n", g_ResType[pFirstEntry->Id]);
}
else
{
printf("ResType:%d\n", g_ResType[pFirstEntry->Id]);
}
}
// ID是字串,代表該資源是開發者的資源
else
{
PIMAGE_RESOURCE_DIR_STRING_U pResName =
(PIMAGE_RESOURCE_DIR_STRING_U)
(pFirstEntry->NameOffset + (DWORD)pFirst);
wchar_t * EpName = new wchar_t[pResName->Length + 1];
memset(EpName, 0, sizeof(wchar_t)*(pResName->Length + 1));
wcsncpy_s(EpName, pResName->Length + 1, pResName->NameString, pResName->Length);
}
if (pFirstEntry->DataIsDirectory == 1)
{
PIMAGE_RESOURCE_DIRECTORY pSecond = (PIMAGE_RESOURCE_DIRECTORY)(pFirstEntry->OffsetToDirectory + (DWORD)pFirst);
DWORD dwSecondCount = pSecond->NumberOfIdEntries + pSecond->NumberOfNamedEntries;
PIMAGE_RESOURCE_DIRECTORY_ENTRY pSecondEntry =
(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pSecond + 1);
//解析資源型別下的每個資源
printf("名稱入口:%04X\n",pSecond->NumberOfNamedEntries);
printf("ID入口:%04X\n", pSecond->NumberOfIdEntries);
for (int i = 0; i < dwSecondCount; i++)
{
//解析資源ID
if (pSecondEntry->NameIsString != 1)
{
printf("Id:%d\n", pSecondEntry->Id);
}
else
{
PIMAGE_RESOURCE_DIR_STRING_U pResName =
(PIMAGE_RESOURCE_DIR_STRING_U)
(pSecondEntry->NameOffset + (DWORD)pFirst);
wchar_t * pName = new wchar_t[pResName->Length + 1];
memset(pName, 0, sizeof(wchar_t)*(pResName->Length + 1));
wcsncpy_s(pName, pResName->Length + 1, pResName->NameString, pResName->Length);
printf("Name:%s\n\n", pName);
delete[]pName;
}
if (pSecondEntry->DataIsDirectory == 1)
{
PIMAGE_RESOURCE_DIRECTORY pThird =
(PIMAGE_RESOURCE_DIRECTORY)
(pSecondEntry->OffsetToDirectory + (DWORD)pFirst);
PIMAGE_RESOURCE_DIRECTORY_ENTRY pThirdEnty =
(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pThird + 1);
pThirdEnty->Name;
//解析每個資源的資訊
if (pThirdEnty->DataIsDirectory != 1)
{
PIMAGE_RESOURCE_DATA_ENTRY pStcData =
(PIMAGE_RESOURCE_DATA_ENTRY)
(pThirdEnty->OffsetToData + (DWORD)pFirst);
char* pResbuf = (char *)
(RvaToOffset(pStcData->OffsetToData, buffer) + buffer);
DWORD StcDataOffset = RvaToOffset(pStcData->OffsetToData,buffer);
printf("RVA:%08X\n", pStcData->OffsetToData);
printf("Offset:%08X\n", StcDataOffset);
printf("Size:%08X\n\n", pStcData->Size);
}
}
pSecondEntry++;
}
printf("============================================\n");
}
pFirstEntry++;
}
}
標頭檔案
#pragma once
#include <stdio.h>
#include <Windows.h>
//計算資料目錄表起始位置到檔案頭的偏移
DWORD RvaToOffset(DWORD dwRva, char *buffer);
//解析匯入表的函式
void ImportTable(char * buffer);
//解析匯出表的函式
void ExportTable(char * buffer);
//解析TLS表的函式
void TLSTable(char* buffer);
//解析延遲匯入表的函式
void DelayImportTable(char *buffer);
//解析重定位表的函式
void RelocTable(char *buffer);
//解析資源表的函式
void ResourceTable(char *buffer);
爽,不過我到底是在複習還是在改bug啊哈哈哈哈哈
相關文章
- PE 檔案結構圖
- PE檔案結構解析3
- PE檔案結構解析1
- PE檔案結構解析2
- PE檔案結構(五)基址重定位
- PE檔案結構(四) 輸出表
- 再探.NET的PE檔案結構(安全篇)
- PE檔案結構(二) 區塊,檔案偏移與RVA轉換
- PE檔案格式
- PE結構分析(二)
- 深入剖析PE檔案
- 手工構造一個超微型的 PE 檔案 (轉)
- JVM學習--Class類檔案結構JVM
- PE教程2: 檢驗PE檔案的有效性
- 類檔案結構_class類檔案的的結構
- PE檔案格式的RVA概念
- 羽夏殼世界—— PE 結構(上)
- BMP檔案結構
- office檔案格式複合文件二進位制結構解析
- PE檔案格式詳細解析(一)
- 初步瞭解PE檔案格式(上)
- win32 PE 檔案格式 (轉)Win32
- windows載入PE檔案的流程Windows
- 資料結構複習專貼資料結構
- PE結構各欄位偏移參考
- Class類檔案結構
- wsdl檔案結構分析
- Linux檔案結構Linux
- 控制檔案的結構
- BMP檔案結構 (轉)
- oracle結構梳理---歸檔檔案Oracle
- PE檔案格式詳細解析(二)--IAT
- 惡意軟體PE檔案重建指南
- 21.1 Python 使用PEfile分析PE檔案Python
- PE檔案檢測DOS頭\NT頭
- PE教程3: File Header (檔案頭)Header
- 2013資料結構課程設計之通訊錄(複習連結串列與檔案知識)資料結構
- 羽夏筆記——PE結構(不包含.Net)筆記