学习PE
PE结构和定义
pe大体结构,主要包含DOS Header和NT Header结构体.
DOS Header结构
DOS HEADER结构体定义
typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header
WORD e_magic; // Magic number "MZ"
WORD e_cblp; // Bytes on last page of file
WORD e_cp; // Pages in file
WORD e_crlc; // Relocations
WORD e_cparhdr; // Size of header in paragraphs
WORD e_minalloc; // Minimum extra paragraphs needed
WORD e_maxalloc; // Maximum extra paragraphs needed
WORD e_ss; // Initial (relative) SS value
WORD e_sp; // Initial SP value
WORD e_csum; // Checksum
WORD e_ip; // Initial IP value
WORD e_cs; // Initial (relative) CS value
WORD e_lfarlc; // File address of relocation table
WORD e_ovno; // Overlay number
WORD e_res[4]; // Reserved words
WORD e_oemid; // OEM identifier (for e_oeminfo)
WORD e_oeminfo; // OEM information; e_oemid specific
WORD e_res2[10]; // Reserved words
LONG e_lfanew; // File address of new exe header
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
NT Header下FileHeader结构
FileHeader结构体定义
typedef struct _IMAGE_FILE_HEADER {
WORD Machine;
WORD NumberOfSections;
DWORD TimeDateStamp;
DWORD PointerToSymbolTable;
DWORD NumberOfSymbols;
WORD SizeOfOptionalHeader;
WORD Characteristics;
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
NT Header下OPTIONAL HEADER结构
NT Head而下OPTIONAL HEADER结构体定义(分32位和64位,这里以32位为主)
typedef struct _IMAGE_OPTIONAL_HEADER {
//
// Standard fields.
//
WORD Magic;
BYTE MajorLinkerVersion;
BYTE MinorLinkerVersion;
DWORD SizeOfCode;
DWORD SizeOfInitializedData;
DWORD SizeOfUninitializedData;
DWORD AddressOfEntryPoint;
DWORD BaseOfCode;
DWORD BaseOfData;
//
// NT additional fields.
//
DWORD ImageBase;
DWORD SectionAlignment;
DWORD FileAlignment;
WORD MajorOperatingSystemVersion;
WORD MinorOperatingSystemVersion;
WORD MajorImageVersion;
WORD MinorImageVersion;
WORD MajorSubsystemVersion;
WORD MinorSubsystemVersion;
DWORD Win32VersionValue;
DWORD SizeOfImage;
DWORD SizeOfHeaders;
DWORD CheckSum;
WORD Subsystem;
WORD DllCharacteristics;
DWORD SizeOfStackReserve;
DWORD SizeOfStackCommit;
DWORD SizeOfHeapReserve;
DWORD SizeOfHeapCommit;
DWORD LoaderFlags;
DWORD NumberOfRvaAndSizes;
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
读取PE结构
1. 读取dos header的e_magic魔数
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
//读取pe头
int main(int argc, char* argv[])
{
if (argc < 2)
{
printf("argc <2!\n");
exit(EXIT_FAILURE);
}
FILE *pf = fopen(argv[1], "rb"); //以二进制方式读取pe程序
if (!pf)
{
printf("%s is open failed!\n");
exit(EXIT_FAILURE);
}
char magic[3] = { 0 }; //只读取前两位
fread(magic, 1, 2, pf); //读取前两个字节
fclose(pf);
printf("magic[0]=%02X\n", magic[0]);
printf("magic[1]=%02X\n", magic[1]);
printf("magic=%s\n", magic);
return 0;
}
输出结果:
读取File Header和Optional Header,并输出各个字段的值
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
int main(int argc, char* argv[])
{
if (argc < 2)
{
printf("argc <2!\n");
exit(EXIT_FAILURE);
}
//1.打开文件
HANDLE hFile = CreateFile(argv[1], GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);
DWORD file_size = GetFileSize(hFile, NULL);
printf("file size:%d\n", file_size);
printf("--------------dos_header---------------\n");
IMAGE_DOS_HEADER dos_header = { 0 };
//
SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
DWORD num = 0;
if (ReadFile(hFile, &dos_header, sizeof(IMAGE_DOS_HEADER), &num, NULL))
{
//dos header主要为了兼容pe文件在dos系统,能够运行并给出提示
//dos header结构中的e_lfanew字段,是nt_header的起止位置
long e_lfanew = dos_header.e_lfanew;
printf("dos_header.e_lfanew:%08X\n", e_lfanew);
}
IMAGE_NT_HEADERS nt_hreader = { 0 };
SetFilePointer(hFile, dos_header.e_lfanew, NULL, FILE_BEGIN); //从e_lfanew开始读取
if (ReadFile(hFile, &nt_hreader, sizeof(IMAGE_NT_HEADERS), &num, NULL))
{
printf("--------------nt_header---------------\n");
printf("nt_hreader.Signature:%08X\n", nt_hreader.Signature); //判断是不是pe文件
if (nt_hreader.Signature == IMAGE_NT_SIGNATURE)
{
printf("nt_hreader.Signature=%s\n", "PE00");
}
printf("--------------file_header---------------\n");
IMAGE_FILE_HEADER* file_header = &nt_hreader.FileHeader;
printf("file_header.Machine:%04X\n", file_header->Machine); //运行平台 i386->x86
printf("file_header.NumberOfSections:%04X\n", file_header->NumberOfSections); //节数(重要)
printf("file_header.TimeDateStamp:%08X\n", file_header->TimeDateStamp); //pe创建时间
printf("file_header.PointerToSymbolTable:%08X\n", file_header->PointerToSymbolTable); //符号表偏移
printf("file_header.NumberOfSymbols:%08X\n", file_header->NumberOfSymbols); //符号表数量
printf("file_header.SizeOfOptionalHeader:%04X\n", file_header->SizeOfOptionalHeader); //可选头大小
printf("file_header.Characteristics:%04X\n", file_header->Characteristics);
printf("---------------optional_header----------------\n");
IMAGE_OPTIONAL_HEADER32* optional_header = &nt_hreader.OptionalHeader;
printf("optional_header.Magic:%04X\n", optional_header->Magic); //0X010B(32位程序) 0X020B(64位程序)
printf("optional_header.MajorLinkerVersion:%02x\n", optional_header->MajorLinkerVersion);
printf("optional_header.MinorLinkerVersion:%04X\n", optional_header->MinorLinkerVersion);
printf("optional_header.SizeOfCode:%08X\n", optional_header->SizeOfCode);
printf("optional_header.SizeOfInitializedData:%08X\n", optional_header->SizeOfInitializedData);
printf("optional_header.SizeOfUninitializedData:%08X\n", optional_header->SizeOfUninitializedData);
printf("optional_header.AddressOfEntryPoint:%08X\n", optional_header->AddressOfEntryPoint);
printf("optional_header.BaseOfCode:%08X\n", optional_header->BaseOfCode);
printf("optional_header.BaseOfData:%08X\n", optional_header->BaseOfData);
printf("optional_header.ImageBase:%08X\n", optional_header->ImageBase); //基地址
printf("optional_header.SectionAlignment:%08X\n", optional_header->SectionAlignment); //段对齐大小
printf("optional_header.FileAlignment:%08X\n", optional_header->FileAlignment); //文件对齐
printf("optional_header.Subsystem:%04X",optional_header->Subsystem); //
}
//关闭文件
CloseHandle(hFile);
return 0;
}
解析PE文件算是完成一部分,后面主要是对节的学习,这篇拖了好长时间,代码早就写好了,只是不知道怎么写本篇博文.
秋风
2018-09-08