• PE文件头格式解析


    前言:

    昨天写了一题de1ctf的题,发现要脱壳,手脱之后发现要iat修复,我就发现自己在这块知识缺失了,win逆向,好像一直都是打ctf,然后用逆向方法论去肝的

    其他方面倒是没有很深入学习,但实际上win的一些思想沿用到移动端也是很不错的,所以接下来会把pe格式这块搞清楚,接下来再搞别的,不过估计没那么多精力玩了

    pe文件格式

    图解


    发现从上往下,大体结构为dos头,dos体,nt头(魔数,文件头,可选头),节区表,各种节(如code section,data section等),接下来我会从上往下说明

    DOS头

    typedef struct _IMAE_DOS_HEADER {       
        WORD e_magic;        
        WORD e_cblp;
        WORD e_cp;
        WORD e_crlc;
        WORD e_cparhdr;
        WORD e_minalloc;
        WORD e_maxalloc;
        WORD e_ss;
        WORD e_sp;
        WORD e_csum;
        WORD e_ip;
        WORD e_cs;
        WORD e_lfarlc;
        WORD e_ovno;
        WORD e_res[4];
        WORD e_oemid;
        WORD e_oeminfo;
        WORD e_res2[10];
        LONG e_lfanew;       
    } IMAGE_DOS-HEADER, *PIMAGE_DOS_HEADER;
    

    重点关注,e_magic和e_lfanew两个字段,第一个是dos头的魔数MZ ,4D5A,第二个e_lfanew则为nt头的文件偏移

    dos体

    略,里面的内容即使都为空,都是不影响exe的功能的

    nt头

    typedef struct _IMAGE_NT_HEADERS {
      DWORD                   Signature;       
      IMAGE_FILE_HEADER       FileHeader;        
      IMAGE_OPTIONAL_HEADER32 OptionalHeader;    
    } IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
    

    Signature

    这个其实就是"PE",占了4个字节

    FileHeader(文件头)

    typedef struct _IMAGE_FILE_HEADER {
      WORD  Machine;                    **        机器号     相对该结构的偏移0x00**
      WORD  NumberOfSections;           **重要成员 节区数量   相对该结构的偏移0x02**
      DWORD TimeDateStamp;              **        时间戳     相对该结构的偏移0x04**
      DWORD PointerToSymbolTable;       **        符号表偏移  相对该结构的偏移0x08**
      DWORD NumberOfSymbols;            **        符号表数量  相对该结构的偏移0x0C**
      WORD  SizeOfOptionalHeader;       **重要成员 可选头大小  相对该结构的偏移0x10**
      WORD  Characteristics;            **重要成员 PE文件属性  相对该结构的偏移0x12**
    } IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
    

    重点介绍几个字段

    1. Machine
      主要是exe可以运行在哪种架构的机器上
    2. NumberOfSections
      节区的数量
    3. SizeOfOptionalHeader
      可选头的大小,32位和64位的exe,可选头大小是不同的,32位为0xe0,64位则为0xf0
    4. Characteristics

    可选头

    typedef struct _IMAGE_OPTIONAL_HEADER {
      WORD                 Magic;                        **魔术字                     偏移0x00
      BYTE                 MajorLinkerVersion;           **链接器主版本                偏移0x02
      BYTE                 MinorLinkerVersion;           **链接器副版本                偏移0x03
      DWORD                SizeOfCode;                   **所有含代码的节的总大小       偏移0x04
      DWORD                SizeOfInitializedData;        **所有含初始数据的节的总大小    偏移0x08
      DWORD                SizeOfUninitializedData;      **所有含未初始数据的节的总大小  偏移0x0C    
      DWORD                AddressOfEntryPoint;          **程序执行入口地址             偏移0x10   重要
      DWORD                BaseOfCode;                   **代码节的起始地址             偏移0x14
      DWORD                BaseOfData;                   **数据节的起始地址             偏移0x18
      DWORD                ImageBase;                    **程序首选装载地址             偏移0x1C   重要
      DWORD                SectionAlignment;             **内存中节区对齐大小           偏移0x20   重要
      DWORD                FileAlignment;                **文件中节区对齐大小           偏移0x24   重要
      WORD                 MajorOperatingSystemVersion;  **操作系统的主版本号           偏移0x28
      WORD                 MinorOperatingSystemVersion;  **操作系统的副版本号           偏移0x2A
      WORD                 MajorImageVersion;            **镜像的主版本号               偏移0x2C
      WORD                 MinorImageVersion;            **镜像的副版本号               偏移0x2E
      WORD                 MajorSubsystemVersion;        **子系统的主版本号             偏移0x30
      WORD                 MinorSubsystemVersion;        **子系统的副版本号             偏移0x32
      DWORD                Win32VersionValue;            **保留,必须为0               偏移0x34
      DWORD                SizeOfImage;                  **镜像大小                    偏移0x38   重要
      DWORD                SizeOfHeaders;                **PE头大小                    偏移0x3C   重要
      DWORD                CheckSum;                     **校验和                      偏移0x40
      WORD                 Subsystem;                    **子系统类型                   偏移0x44
      WORD                 DllCharacteristics;           **DLL文件特征                  偏移0x46
      DWORD                SizeOfStackReserve;           **栈的保留大小                 偏移0x48
      DWORD                SizeOfStackCommit;            **栈的提交大小                 偏移0x4C
      DWORD                SizeOfHeapReserve;            **堆的保留大小                 偏移0x50
      DWORD                SizeOfHeapCommit;             **堆的提交大小                 偏移0x54
      DWORD                LoaderFlags;                  **保留,必须为0                偏移0x58
      DWORD                NumberOfRvaAndSizes;          **数据目录的项数               偏移0x5C
      IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
    } IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
    
    1. AddressOfEntryPoint
      程序入口点,也是之后写shellcode需要修改的地方,是rva,需要加上imagebase才是虚拟地址
    2. ImageBase
      程序加载到内存的基地址
      3.SectionAlignment和FileAlignment
      都是用来对齐的,不过站在的角度是不同的,第一个是以加载在内存中,节区地址是sectionalignment的整数倍,第二个是文件的偏移,是需要是filealignment整数倍,是站在磁盘角度考虑的
      4.SizeOfImage
      加载到内存中所占的大小
      5.SizeOfHeaders;
      整个头部的大小,包括dos头dos体nt头,节区表

    节区表

    typedef struct _IMAGE_SECTION_HEADER {
      BYTE  Name[IMAGE_SIZEOF_SHORT_NAME];         **节区名                 偏移0x00
      union {
        DWORD PhysicalAddress;
        DWORD VirtualSize;                         **节区的虚拟大小          偏移0x08      重要
      } Misc;                                     
      DWORD VirtualAddress;                        **节区的虚拟地址          偏移0x0C      重要  
      DWORD SizeOfRawData;                         **节区在硬盘上的大小       偏移0x10      重要
      DWORD PointerToRawData;                      **节区在硬盘上的地址       偏移0x14      重要
      DWORD PointerToRelocations;                  **指向重定位项开头的地址   偏移0x18
      DWORD PointerToLinenumbers;                  **指向行号项开头的地址     偏移0x1C
      WORD  NumberOfRelocations;                   **节区的重定位项数         偏移0x20
      WORD  NumberOfLinenumbers;                   **节区的行号数            偏移0x22
      DWORD Characteristics;                       **节区的属性              偏移0x24       重要
    } IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
    

    1.VirtualSize
    实际上加载到内存的节区大小
    2.VirtualAddress
    节区的虚拟地址,但是并不是va,而是rva
    3.SizeOfRawData
    节区在硬盘上的大小
    3. PointerToRawData
    节区在磁盘上相对于文件的偏移
    4.Characteristics
    节区的属性

    编写解析器,解析pe文件头

    #define _CRT_SECURE_NO_WARNINGS
    #include "stdio.h"
    #include"stdlib.h"
    #include "windows.h"
    #include "pe.h"
    //typedef struct _IMAE_DOS_HEADER {        
    //WORD e_magic;        **重要成员 相对该结构的偏移0x00**
    //WORD e_cblp;
    //WORD e_cp;
    //WORD e_crlc;
    //WORD e_cparhdr;
    //WORD e_minalloc;
    //WORD e_maxalloc;
    //WORD e_ss;
    //WORD e_sp;
    //WORD e_csum;
    //WORD e_ip;
    //WORD e_cs;
    //WORD e_lfarlc;
    //WORD e_ovno;
    //WORD e_res[4];
    //WORD e_oemid;
    //WORD e_oeminfo;
    //WORD e_res2[10];
    //LONG e_lfanew;        **重要成员 相对该结构的偏移0x3C**
    //} IMAGE_DOS - HEADER, *PIMAGE_DOS_HEADER;
    
    int  PrintPEDosHeader(PVOID pFileAddress)
    {
    	int ret = 0;
    	PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pFileAddress;
    
    	printf("*********************DOS_Header STAR*********************");
    	printf("Dos->e_magic   :%02X
    ", pDosHeader->e_magic);
    	printf("Dos->e_cblp    :%02X
    ", pDosHeader->e_cblp); 
    	printf("Dos->e_cp      :%02X
    ", pDosHeader->e_cp);
    	printf("Dos->crlc      :%02X
    ", pDosHeader->e_crlc);
    	printf("Dos->e_cparhdr :%02X
    ", pDosHeader->e_cparhdr);
    	printf("Dos->e_minalloc:%02X
    ", pDosHeader->e_minalloc);
    	printf("Dos->e_maxalloc:%02X
    ", pDosHeader->e_maxalloc);
    	printf("Dos->e_ss      :%02X
    ", pDosHeader->e_ss);
    	printf("Dos->e_sp      :%02X
    ", pDosHeader->e_sp);
    	printf("Dos->e_csum    :%02X
    ", pDosHeader->e_csum);
    	printf("Dos->e_ip      :%02X
    ", pDosHeader->e_ip);
    	printf("Dos->e_cs      :%02X
    ", pDosHeader->e_cs);
    	printf("Dos->e_lfarlc   :%02X
    ", pDosHeader->e_lfarlc);
    	printf("Dos->e_ovno     :%02X
    ", pDosHeader->e_ovno);
    	for (int i = 0; i < 4; i++)
    	{
    		printf("Dos->e_res[%d]   :%02X
    ", i, pDosHeader->e_res[i]);
    	}
    	printf("Dos->e_oemid     :%02X
    ", pDosHeader->e_oemid);
    	printf("Dos->e_oeminfo     :%02X
    ", pDosHeader->e_oeminfo);
    	for (int i = 0; i < 10; i++)
    	{
    		printf("Dos->e_res2[%d]    :%02X
    ", i, pDosHeader-> e_res2[i]);
    	}
    	printf("Dos->e_lfanew   :%04X", pDosHeader->e_lfanew); //NT头的文件偏移
    	return ret;
    
    	
    }
    int PrintPEFileHeader(PVOID pFileAddress)
    {
    	int ret = 0;
    	PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pFileAddress;
    	PIMAGE_FILE_HEADER pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pFileAddress + (DWORD)(pDosHeader->e_lfanew + 4));
    	
    	printf("*********FILE_HEADER START*********");
    	printf("FileHeader->Machine     :%02X
    ", pFileHeader->Machine);
    	printf("FileHeader->NumberOfSections  :%02X
    ", pFileHeader->NumberOfSections);
    	printf("FileHeader->TimeDataStamp:    :%04X
    ", pFileHeader->TimeDateStamp);
    	printf("FileHeader->PointerToSymbolTable: %04X
    ", pFileHeader->PointerToSymbolTable);
    	printf("FileHeader->NumberOfSymbols   :%04X
    ", pFileHeader->NumberOfSymbols);
    	printf("FileHeader->SizeOfOptionalHeader :%02X
    ", pFileHeader->SizeOfOptionalHeader);
    	printf("FileHeader->Characteristics      :%02X
    ", pFileHeader->Characteristics);
    
    	printf("**********************FILE_HEADER END*************************");
    	return ret;
    	
    }
    int PrintPEOptionalHeader(PVOID pFileAddress)
    {
    	int ret = 0;
    	PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pFileAddress;
    	PIMAGE_FILE_HEADER pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pDosHeader + (DWORD)(pDosHeader->e_lfanew + 4));
    	PIMAGE_OPTIONAL_HEADER32 pOptionalHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pFileHeader + sizeof(PIMAGE_FILE_HEADER));
    
    	printf("****************OPTIONAL_HEADER32 STAR*************************
    ");
    	printf("OptionalHeader->Magic                        : %02X
    ", pOptionalHeader->Magic);
    	printf("OptionalHeader->MajorLinkerVersion           : %01X
    ", pOptionalHeader->MajorLinkerVersion);
    	printf("OptionalHeader->MinorLinkerVersion           : %01X
    ", pOptionalHeader->MinorLinkerVersion);
    	printf("OptionalHeader->SizeOfCode                   : %04X
    ", pOptionalHeader->SizeOfCode);
    	printf("OptionalHeader->SizeOfInitializedData        : %04X
    ", pOptionalHeader->SizeOfInitializedData);
    	printf("OptionalHeader->SizeOfUninitializedData      : %04X
    ", pOptionalHeader->SizeOfUninitializedData);
    	printf("OptionalHeader->AddressOfEntryPoint          : %04X
    ", pOptionalHeader->AddressOfEntryPoint);
    	printf("OptionalHeader->BaseOfCode                   : %04X
    ", pOptionalHeader->BaseOfCode);
    	printf("OptionalHeader->BaseOfData                   : %04X
    ", pOptionalHeader->BaseOfData);
    	printf("OptionalHeader->ImageBase                    : %04X
    ", pOptionalHeader->ImageBase);
    	printf("OptionalHeader->SectionAlignment             : %04X
    ", pOptionalHeader->SectionAlignment);
    	printf("OptionalHeader->FileAlignment                : %04X
    ", pOptionalHeader->FileAlignment);
    	printf("OptionalHeader->MajorOperatingSystemVersion  : %02X
    ", pOptionalHeader->MajorOperatingSystemVersion);
    	printf("OptionalHeader->MinorOperatingSystemVersion  : %02X
    ", pOptionalHeader->MinorOperatingSystemVersion);
    	printf("OptionalHeader->MajorImageVersion            : %02X
    ", pOptionalHeader->MajorImageVersion);
    	printf("OptionalHeader->MinorImageVersion            : %02X
    ", pOptionalHeader->MinorImageVersion);
    	printf("OptionalHeader->MajorSubsystemVersion        : %02X
    ", pOptionalHeader->MajorSubsystemVersion);
    	printf("OptionalHeader->MinorSubsystemVersion        : %02X
    ", pOptionalHeader->MinorSubsystemVersion);
    	printf("OptionalHeader->Win32VersionValue            : %04X
    ", pOptionalHeader->Win32VersionValue);
    	printf("OptionalHeader->SizeOfImage                  : %04X
    ", pOptionalHeader->SizeOfImage);
    	printf("OptionalHeader->SizeOfHeaders                : %04X
    ", pOptionalHeader->SizeOfHeaders);
    	printf("OptionalHeader->CheckSum                     : %04X
    ", pOptionalHeader->CheckSum);
    	printf("OptionalHeader->Subsystem                    : %02X
    ", pOptionalHeader->Subsystem);
    	printf("OptionalHeader->DllCharacteristics           : %02X
    ", pOptionalHeader->DllCharacteristics);
    	printf("OptionalHeader->SizeOfStackReserv            : %04X
    ", pOptionalHeader->SizeOfStackReserve);
    	printf("OptionalHeader->SizeOfStackCommit            : %04X
    ", pOptionalHeader->SizeOfStackCommit);
    	printf("OptionalHeader->SizeOfHeapReserve            : %04X
    ", pOptionalHeader->SizeOfHeapReserve);
    	printf("OptionalHeader->SizeOfHeapCommit             : %04X
    ", pOptionalHeader->SizeOfHeapCommit);
    	printf("OptionalHeader->LoaderFlags                  : %04X
    ", pOptionalHeader->LoaderFlags);
    	printf("OptionalHeader->NumberOfRvaAndSizes          : %04X
    ", pOptionalHeader->NumberOfRvaAndSizes);
    
    	printf("*****************OPTIONAL_HEADER32 END************************
    ");
    
    	return ret;
    }
    int PrintPESectionHeader(PVOID pFileAddress)
    {
    	int ret = 0;
    	PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pFileAddress;
    	PIMAGE_FILE_HEADER pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pDosHeader + (DWORD)pDosHeader->e_lfanew + 4);
    	PIMAGE_OPTIONAL_HEADER32 pOptionalHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pFileHeader + sizeof(IMAGE_FILE_HEADER));
    	PIMAGE_SECTION_HEADER pSectionGroup = (PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader + pFileHeader->SizeOfOptionalHeader);
    
    	printf("****************SECTION_HEADER STAR*************************
    ");
    	for (int i = 0; i < pFileHeader->NumberOfSections; i++)
    	{
    		printf("pSectionGroup[%d].Name                   : %s
    ", i, pSectionGroup[i].Name);
    		printf("pSectionGroup[%d].Misc.VirtualSize       : %04X
    ", i, pSectionGroup[i].Misc.VirtualSize);
    		printf("pSectionGroup[%d].VirtualAddress         : %04X
    ", i, pSectionGroup[i].VirtualAddress);
    		printf("pSectionGroup[%d].SizeOfRawData          : %04X
    ", i, pSectionGroup[i].SizeOfRawData);
    		printf("pSectionGroup[%d].PointerToRawData       : %04X
    ", i, pSectionGroup[i].PointerToRawData);
    		printf("pSectionGroup[%d].PointerToRelocations   : %04X
    ", i, pSectionGroup[i].PointerToRelocations);
    		printf("pSectionGroup[%d].PointerToLinenumbers   : %04X
    ", i, pSectionGroup[i].PointerToLinenumbers);
    		printf("pSectionGroup[%d].NumberOfRelocations    : %02X
    ", i, pSectionGroup[i].NumberOfRelocations);
    		printf("pSectionGroup[%d].NumberOfLinenumbers    : %02X
    ", i, pSectionGroup[i].NumberOfLinenumbers);
    		printf("pSectionGroup[%d].Characteristics        : %04X
    
    
    ", i, pSectionGroup[i].Characteristics);
    	}
    
    	printf("*****************SECTION_HEADER END************************
    ");
    
    	return ret;
    }
    int main(int argc,char const* argv[])
    {
    
    		int ret = 0;
    		PVOID pFileAddress=NULL;
    		ret=MyReadFile(&pFileAddress);
    		if (ret != 0)
    		{
    			return ret;
    		}
    		printf("将文件载入内存成功!");
    		ret=PrintPEDosHeader(pFileAddress); //DOS头
    		if (ret != 0)
    		{
    			if (pFileAddress != NULL)
    			{
    				free(pFileAddress);
    			}
    			return ret;
    		}
    		ret = PrintPEFileHeader(pFileAddress);
    		if (ret != 0)
    		{
    			if (pFileAddress != NULL)
    			{
    				free(pFileAddress);
    			}
    			return ret;
    		}
    		ret = PrintPEOptionalHeader(pFileAddress);
    		if (ret != 0)
    		{
    			if (pFileAddress != NULL)
    			{
    				free(pFileAddress);
    			}
    			return ret;
    		}
    		ret = PrintPESectionHeader(pFileAddress);
    		if (ret != 0)
    		{
    			if (pFileAddress != NULL)
    			{
    				free(pFileAddress);
    			}
    			return ret;
    		}	
    }
    

    之后还有一篇关于目录表的解析,之后代码都传github上

  • 相关阅读:
    Excel导出
    上传进度基础
    git基本使用
    git学习记录
    Composer 扩展包安装方法
    selected多次点击不生效
    ajaxFileUpload的data数据带pre标签
    php-resque 简单的php消息队列
    git checkout 报错 refname 'origin/branch-name' is ambiguous
    MySQL单独存放表空间Innodb_file_per_table
  • 原文地址:https://www.cnblogs.com/YenKoc/p/14532409.html
Copyright © 2020-2023  润新知