PE文件和COFF文件格式分析——签名、COFF文件头和可选文件头2
之前的博文中介绍了IMAGE_FILE_HEADER结构,现在来讨论比较复杂的“可选文件头”结构体。(转载请指明来自breaksoftware的csdn博客)先看下其声明
[cpp]
typedef struct _IMAGE_OPTIONAL_HEADER {
//
// Standard fields.
//
WORD Magic;
.
.
.
DWORD BaseOfData; // not exist in PE32+
//
// NT additional fields.
//
DWORD ImageBase;
.
.
.
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
看一下64位版本该结构体www.zzzyk.com
[cpp]
typedef struct _IMAGE_OPTIONAL_HEADER64 {
WORD Magic;
.
.
.
DWORD BaseOfCode;
ULONGLONG ImageBase;
.
.
.
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64;
我们观察这个32位版本结构体,可以看到该结构体包含两块数据:Standard fields和NT additional fields。我们可以猜想到,该结构体应该在第一个NT操作系统之前就存在了,只是当时其内容只有Standard fields(以后称为标准域)下的内容,后来NT系统增加了NT additional fields(以后称为扩展域)下元素。
此处需要特别注意一点,我们看两个在WinNT.h中定义的结构体
[cpp]
typedef struct _IMAGE_NT_HEADERS64 {
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER64 OptionalHeader;
} IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64;
typedef struct _IMAGE_NT_HEADERS {
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
该结构给出了PE文件头的结构体布局,但是切记,这仅仅是布局。我们千万不要想当然的认为直接从PE头部开始将IMAGE_NT_HEADERS32(64)结构体大小的数据拷贝到该结构体对象中。
[cpp]
memcpy( &ImageNTHeader32,lpPEStart,sizeof(IMAGE_NT_HEADERS32 );// 这是错误的!!
为什么?因为一个文件中不一定有完整的IMAGE_OPTIONAL_HEADER32(64)结构体对象信息。原因在《可选文件头1》做了介绍,IMAGE_FILE_HEADER中字段SizeOfOptionalHeader指定了该文件中保存的“可选文件头”真实长度,我们应该根据该元素来给IMAGE_OPTIONAL_HEADER32(64)对象赋值。
我们的文件是使用IMAGE_OPTIONAL_HEADER32还是IMAGE_OPTIONAL_HEADER64结构体呢?可能有人会记起,我们在《可选文件头1》中介绍了判断文件是32位还是64位的方法,我们是否可以通过该判断的结果来判断是哪种结构体呢?最开始我也是这么想的,后来我发现我电脑上Microsoft Visual Studio 10.0\VC\lib\amd64\Microsoft.VisualC.STLCLR.dll文件是个64位文件但是使用了IMAGE_OPTIONAL_HEADER32结构体!!!是不是很惊讶!我不知道微软这么设计的原因,但是我知道了通过之前判断是否为64位文件来决定可选文件头结构体类型是错误的。那如何判断呢?
其实是有标记的。紧跟着IMAGE_FILE_HEADER结构体的肯定是IMAGE_OPTIONAL_HEADER32(64)的Magic字段。如果该字段是0x010B,则是使用了IMAGE_OPTIONAL_HEADER32(称为PE32);如果是0x020B,则使用了IMAGE_OPTIONAL_HEADER32(称为PE32+)。切记PE32和PE32+和这个文件是32为文件还是64位文件是没有关系的!它们是两种不同的概念!切记要分清。
[cpp]
BOOL CGetPEInfo::GetOptionalHeader(){
CHECKOPHEADER();
GETFILETYPE();
size_t unDwordSize = sizeof(DWORD);
size_t unImgFileHeaderSize = sizeof(IMAGE_FILE_HEADER);
size_t unImgOpHeaderSize = 0;
LPBYTE lpImgOpHeaderAddr = m_lpPEStart + unDwordSize + unImgFileHeaderSize;
LPVOID lpOpHeaderStart= NULL;
WORD dwOptionHeader = 0;
if ( FALSE == SafeCopy( &dwOptionHeader, lpImgOpHeaderAddr, sizeof(WORD) ) ) {
return FALSE;
}
if ( E64Bit == m_eFileType && PE32MAGICNUM == dwOptionHeader ) {
// D:\Microsoft Visual Studio 10.0\VC\lib\amd64\Microsoft.VisualC.STLCLR.dll
//_ASSERT(FALSE);
}
if ( IMAGE_NT_OPTIONAL_HDR32_MAGIC == dwOptionHeader ) {
// 64位系统文件也存在该格式可选头
m_eFileOpType = EOp32;
unImgOpHeaderSize = sizeof(IMAGE_OPTIONAL_HEADER32);
lpOpHeaderStart = &m_OptionalHeader32;
}
else if ( IMAGE_NT_OPTIONAL_HDR64_MAGIC== dwOptionHeader ) {
m_eFileOpType = EOp32Plus;
unImgOpHeaderSize = sizeof(IMAGE_OPTIONAL_HEADER64);
lpOpHeaderStart = &m_OptionalHeader64;
}
else {
_ASSERT(FALSE);
return FALSE;
}
memset( lpOpHeaderStart, 0 , unImgOpHeaderSize);
// 根据镜像文件头中可选文件头大小拷贝数据
BOOL bSuc = SafeCopy( lpOpHeaderStart, lpImgOpHeaderAddr, m_FileHeader.SizeOfOptionalHeader );
if ( bSuc ) {
m_dwInfoMask |= OPHEADER;
}
else {
_ASSERT(FALSE);
}
if ( EOp32 == m_eFileOpType ) {
m_dwFileAlignment = m_OptionalHeader32.FileAlignment;
}
else {
m_dwFileAlignment = m_OptionalHeader64.FileAlignment;
}
return bSuc;
}
&nbs
补充:软件开发 , C++ ,