IMAGE_NT_HEADERS
结构及成员含义如下:
//默认大小为:
//32BIT: 0xF8 (248)字节
//64BIT: 0x108(264)字节
#define IMAGE_NT_SIGNATURE 0x00004550 // PE00
typedef struct _IMAGE_NT_HEADERS {
DWORD Signature;//PE标记 0x00004550
IMAGE_FILE_HEADER FileHeader;//标准PE头 大小固定为0x14(20)字节
IMAGE_OPTIONAL_HEADER32 OptionalHeader;//扩展PE头 32BIT默认大小为0xE0
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
typedef struct _IMAGE_NT_HEADERS64 {
DWORD Signature;//PE标记 0x00004550
IMAGE_FILE_HEADER FileHeader;//标准PE头 大小固定为0x14(20)字节
IMAGE_OPTIONAL_HEADER64 OptionalHeader;//扩展PE头 64BIT默认大小为0xF0
} IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64;
Signature: 成员为PE文件标识,该值必须为0x00004550('P''E''0''0')否则程序将无法正常启动.
FileHeader: 成员指向了标准PE头IMAGE_FILE_HEADER.由于PE扩展自通用COFF规范,所以该字段在官方文档中被称为标准COFF头.
OptionalHeader: 成员指向了扩展PE头IMAGE_OPTIONAL_HEADER.Windows操作系统可执行文件的大部分特性均在这个结构里呈现.因为在符合COFF规范的".obj"目标文件中该部分并不存在,所以该部分被称为OptionalHeader(可选 / 扩展的头部信息),它是操作系统映像文件所独有的头部信息.
通过十六进制编辑器查看对应数据:
代码定位IMAGE_NT_HEADERS如下:
读取文件代码
PVOID FileToMem(IN PCHAR szFilePath, OUT LPDWORD dwFileSize)
{
//打开文件
FILE* pFile = fopen(szFilePath, "rb");
if (!pFile)
{
printf("FileToMem fopen Fail \r\n");
return NULL;
}
//获取文件长度
fseek(pFile, 0, SEEK_END); //SEEK_END文件结尾
DWORD Size = ftell(pFile);
fseek(pFile, 0, SEEK_SET); //SEEK_SET文件开头
//申请存储文件数据缓冲区
PCHAR pFileBuffer = (PCHAR)malloc(Size);
if (!pFileBuffer)
{
printf("FileToMem malloc Fail \r\n");
fclose(pFile);
return NULL;
}
//读取文件数据
fread(pFileBuffer, Size, 1, pFile);
//判断是否为可执行文件
if (*(PSHORT)pFileBuffer != IMAGE_DOS_SIGNATURE)
{
printf("Error: MZ \r\n");
fclose(pFile);
free(pFileBuffer);
return NULL;
}
if (*(PDWORD)(pFileBuffer + *(PDWORD)(pFileBuffer + 0x3C)) != IMAGE_NT_SIGNATURE)
{
printf("Error: PE \r\n");
fclose(pFile);
free(pFileBuffer);
return NULL;
}
if (dwFileSize)
{
*dwFileSize = Size;
}
fclose(pFile);
return pFileBuffer;
}
输出文件代码
VOID MemToFile(IN PCHAR szFilePath, IN PVOID pFileBuffer, IN DWORD dwFileSize)
{
//打开文件
FILE* pFile = fopen(szFilePath, "wb");
if (!pFile)
{
printf("MemToFile fopen Fail \r\n");
return;
}
//输出文件
fwrite(pFileBuffer, dwFileSize, 1, pFile);
fclose(pFile);
}
定位NT头代码
int main()
{
//读取文件二进制数据
DWORD dwFileSize = 0;
PCHAR pFileBuffer = FileToMem(FILE_PATH_IN, &dwFileSize);
PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)pFileBuffer;
PIMAGE_NT_HEADERS pNth = (PIMAGE_NT_HEADERS)(pFileBuffer + pDos->e_lfanew);
printf("IMAGE_NT_HEADERS->Signature [0x%08x] \r\n", pNth->Signature);
return 0;
}
抹除Signature查看程序是否可以正常运行:
#include "Tools.h"
int main()
{
//读取文件二进制数据
DWORD dwFileSize = 0;
PCHAR pFileBuffer = FileToMem(FILE_PATH_IN, &dwFileSize);
PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)pFileBuffer;
PIMAGE_NT_HEADERS pNth = (PIMAGE_NT_HEADERS)(pFileBuffer + pDos->e_lfanew);
memset(&pNth->Signature, 0, 4);
//将二进制数据输出到文件
MemToFile(FILE_PATH_OUT, pFileBuffer, dwFileSize);
}
此标记在运行前不可更改.