+18h WORD Magic;// 标志字, ROM 映像(0107h),普通可执行文件(010Bh)
+1Ah BYTE MajorLinkerVersion;// 链接程序的主版本号
+1Bh BYTE MinorLinkerVersion;// 链接程序的次版本号
+1Ch DWORD SizeOfCode;// 所有含代码的节的总大小
+20h DWORD SizeOfInitializedData;// 所有含已初始化数据的节的总大小
+24h DWORD SizeOfUninitializedData;// 所有含未初始化数据的节的大小
+28h DWORD AddressOfEntryPoint;// 程序执行入口RVA
+2Ch DWORD BaseOfCode;// 代码的区块的起始RVA
+30h DWORD BaseOfData;// 数据的区块的起始RVA
// NT additional fields. 以下是属于NT结构增加的领域。
+34h DWORD ImageBase;// 程序的首选装载地址
+38h DWORD SectionAlignment;// 内存中的区块的对齐大小
+3Ch DWORD FileAlignment;// 文件中的区块的对齐大小
+40h WORD MajorOperatingSystemVersion;// 要求操作系统最低版本号的主版本号
+42h WORD MinorOperatingSystemVersion;// 要求操作系统最低版本号的副版本号
+44h WORD MajorImageVersion;// 可运行于操作系统的主版本号
+46h WORD MinorImageVersion;// 可运行于操作系统的次版本号
+48h WORD MajorSubsystemVersion;// 要求最低子系统版本的主版本号
+4Ah WORD MinorSubsystemVersion;// 要求最低子系统版本的次版本号
+4Ch DWORD Win32VersionValue;// 莫须有字段,不被病毒利用的话一般为0
+50h DWORD SizeOfImage;// 映像装入内存后的总尺寸
+54h DWORD SizeOfHeaders;// 所有头 + 区块表的尺寸大小
+58h DWORD CheckSum;// 映像的校检和
+5Ch WORD Subsystem;// 可执行文件期望的子系统
+5Eh WORD DllCharacteristics;// DllMain()函数何时被调用,默认为 0
+60h DWORD SizeOfStackReserve;// 初始化时的栈大小
+64h DWORD SizeOfStackCommit;// 初始化时实际提交的栈大小
+68h DWORD SizeOfHeapReserve;// 初始化时保留的堆大小
+6Ch DWORD SizeOfHeapCommit;// 初始化时实际提交的堆大小
+70h DWORD LoaderFlags;// 与调试有关,默认为 0
+74h DWORD NumberOfRvaAndSizes;// 下边数据目录的项数,这个字段自Windows NT 发布以来一直是16
+78h IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
// 数据目录表
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
重要的有:
AddressOfEntryPoint: 也就是上文提到的OEP,程序源入口点。
ImageBase: 默认加载基址。
SectionAlignment: 内存当中的块对齐数,一般为0x1000。
FileAlignment:磁盘当中块对齐数,一般为0x200。
SizeOfHeaders:所有头部大小 也就是DOS头 文件头 以及区块头的总大小,文件主体相对文件其实的偏移。
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]:数据目录表,保存了各种表的RVA及大小。
来看一下数据目录的定义:
IMAGE_DATA_DIRECTORY STRUCT
VirtualAddress DWORD ? ; 数据的起始RVA
Size DWORD ? ; 数据块的长度
IMAGE_DATA_DIRECTORY ENDS
在010 Editor上查看一下:
m_hFile = CreateFile(
m_DeleFileName,GENERIC_READ,NULL,NULL,OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,NULL);
DWORD dwSize = GetFileSize(m_hFile,NULL);
PBYTE pBuf =newBYTE[dwSize]{};
ReadFile(m_hFile,pBuf,dwSize,&dwSize,NULL);
//判断是否为PE文件
m_pDos = PIMAGE_DOS_HEADER(pBuf);
if(m_pDos->e_magic!=IMAGE_DOS_SIGNATURE)
MessageBox(L"不是有效的PE文件 \n");
CloseHandle(m_hFile);
m_hFile =NULL;
return;
m_pNTHeader = PIMAGE_NT_HEADERS(pBuf+m_pDos->e_lfanew);
if(m_pNTHeader->Signature!= IMAGE_NT_SIGNATURE)
MessageBox(L"不是有效的PE文件 \n");
CloseHandle(m_hFile);
m_hFile =NULL;
return;
//读取文件头信息
m_pFileHeader = &(m_pNTHeader->FileHeader);
m_NumberOfSections.Format(L"%X",m_pFileHeader->NumberOfSections);
m_TimeDateStamp.Format(L"%p", m_pFileHeader->TimeDateStamp);
m_SizeOfOptionalHeader.Format(L"%X", m_pFileHeader->SizeOfOptionalHeader);
//拓展头信息
m_pOptionalHeader = &(m_pNTHeader->OptionalHeader);
m_AddressOfEntryPoint.Format(L"%X",m_pOptionalHeader->AddressOfEntryPoint);
m_SizeOfHeaders.Format(L"%X", m_pOptionalHeader->SizeOfHeaders);
m_ImageBase.Format(L"%X", m_pOptionalHeader->ImageBase);
m_SizeOfImage.Format(L"%X", m_pOptionalHeader->ImageBase);
m_BaseOfCode.Format(L"%X", m_pOptionalHeader->BaseOfCode);
m_DllCharacteristics.Format(L"%X", m_pOptionalHeader->DllCharacteristics);
m_BaseOfData.Format(L"%X", m_pOptionalHeader->BaseOfData);
m_NumberOfRvaAndSizes.Format(L"%X", m_pOptionalHeader->NumberOfRvaAndSizes);
m_SectionAlignment.Format(L"%X", m_pOptionalHeader->SectionAlignment);
m_FileAlignment.Format(L"%X", m_pOptionalHeader->FileAlignment);
m_CheckSum.Format(L"%X", m_pOptionalHeader->CheckSum);
m_Magic.Format(L"%X", m_pOptionalHeader->CheckSum);
m_Subsystem.Format(L"%X", m_pOptionalHeader->Subsystem);
实现的效果如下: