前言:

昨天写了一题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\n", pDosHeader->e_magic);
printf("Dos->e_cblp :%02X\n", pDosHeader->e_cblp);
printf("Dos->e_cp :%02X\n", pDosHeader->e_cp);
printf("Dos->crlc :%02X\n", pDosHeader->e_crlc);
printf("Dos->e_cparhdr :%02X\n", pDosHeader->e_cparhdr);
printf("Dos->e_minalloc:%02X\n", pDosHeader->e_minalloc);
printf("Dos->e_maxalloc:%02X\n", pDosHeader->e_maxalloc);
printf("Dos->e_ss :%02X\n", pDosHeader->e_ss);
printf("Dos->e_sp :%02X\n", pDosHeader->e_sp);
printf("Dos->e_csum :%02X\n", pDosHeader->e_csum);
printf("Dos->e_ip :%02X\n", pDosHeader->e_ip);
printf("Dos->e_cs :%02X\n", pDosHeader->e_cs);
printf("Dos->e_lfarlc :%02X\n", pDosHeader->e_lfarlc);
printf("Dos->e_ovno :%02X\n", pDosHeader->e_ovno);
for (int i = 0; i < 4; i++)
{
printf("Dos->e_res[%d] :%02X\n", i, pDosHeader->e_res[i]);
}
printf("Dos->e_oemid :%02X\n", pDosHeader->e_oemid);
printf("Dos->e_oeminfo :%02X\n", pDosHeader->e_oeminfo);
for (int i = 0; i < 10; i++)
{
printf("Dos->e_res2[%d] :%02X\n", 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\n", pFileHeader->Machine);
printf("FileHeader->NumberOfSections :%02X\n", pFileHeader->NumberOfSections);
printf("FileHeader->TimeDataStamp: :%04X\n", pFileHeader->TimeDateStamp);
printf("FileHeader->PointerToSymbolTable: %04X\n", pFileHeader->PointerToSymbolTable);
printf("FileHeader->NumberOfSymbols :%04X\n", pFileHeader->NumberOfSymbols);
printf("FileHeader->SizeOfOptionalHeader :%02X\n", pFileHeader->SizeOfOptionalHeader);
printf("FileHeader->Characteristics :%02X\n", 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*************************\n");
printf("OptionalHeader->Magic : %02X\n", pOptionalHeader->Magic);
printf("OptionalHeader->MajorLinkerVersion : %01X\n", pOptionalHeader->MajorLinkerVersion);
printf("OptionalHeader->MinorLinkerVersion : %01X\n", pOptionalHeader->MinorLinkerVersion);
printf("OptionalHeader->SizeOfCode : %04X\n", pOptionalHeader->SizeOfCode);
printf("OptionalHeader->SizeOfInitializedData : %04X\n", pOptionalHeader->SizeOfInitializedData);
printf("OptionalHeader->SizeOfUninitializedData : %04X\n", pOptionalHeader->SizeOfUninitializedData);
printf("OptionalHeader->AddressOfEntryPoint : %04X\n", pOptionalHeader->AddressOfEntryPoint);
printf("OptionalHeader->BaseOfCode : %04X\n", pOptionalHeader->BaseOfCode);
printf("OptionalHeader->BaseOfData : %04X\n", pOptionalHeader->BaseOfData);
printf("OptionalHeader->ImageBase : %04X\n", pOptionalHeader->ImageBase);
printf("OptionalHeader->SectionAlignment : %04X\n", pOptionalHeader->SectionAlignment);
printf("OptionalHeader->FileAlignment : %04X\n", pOptionalHeader->FileAlignment);
printf("OptionalHeader->MajorOperatingSystemVersion : %02X\n", pOptionalHeader->MajorOperatingSystemVersion);
printf("OptionalHeader->MinorOperatingSystemVersion : %02X\n", pOptionalHeader->MinorOperatingSystemVersion);
printf("OptionalHeader->MajorImageVersion : %02X\n", pOptionalHeader->MajorImageVersion);
printf("OptionalHeader->MinorImageVersion : %02X\n", pOptionalHeader->MinorImageVersion);
printf("OptionalHeader->MajorSubsystemVersion : %02X\n", pOptionalHeader->MajorSubsystemVersion);
printf("OptionalHeader->MinorSubsystemVersion : %02X\n", pOptionalHeader->MinorSubsystemVersion);
printf("OptionalHeader->Win32VersionValue : %04X\n", pOptionalHeader->Win32VersionValue);
printf("OptionalHeader->SizeOfImage : %04X\n", pOptionalHeader->SizeOfImage);
printf("OptionalHeader->SizeOfHeaders : %04X\n", pOptionalHeader->SizeOfHeaders);
printf("OptionalHeader->CheckSum : %04X\n", pOptionalHeader->CheckSum);
printf("OptionalHeader->Subsystem : %02X\n", pOptionalHeader->Subsystem);
printf("OptionalHeader->DllCharacteristics : %02X\n", pOptionalHeader->DllCharacteristics);
printf("OptionalHeader->SizeOfStackReserv : %04X\n", pOptionalHeader->SizeOfStackReserve);
printf("OptionalHeader->SizeOfStackCommit : %04X\n", pOptionalHeader->SizeOfStackCommit);
printf("OptionalHeader->SizeOfHeapReserve : %04X\n", pOptionalHeader->SizeOfHeapReserve);
printf("OptionalHeader->SizeOfHeapCommit : %04X\n", pOptionalHeader->SizeOfHeapCommit);
printf("OptionalHeader->LoaderFlags : %04X\n", pOptionalHeader->LoaderFlags);
printf("OptionalHeader->NumberOfRvaAndSizes : %04X\n", pOptionalHeader->NumberOfRvaAndSizes); printf("*****************OPTIONAL_HEADER32 END************************\n"); 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*************************\n");
for (int i = 0; i < pFileHeader->NumberOfSections; i++)
{
printf("pSectionGroup[%d].Name : %s\n", i, pSectionGroup[i].Name);
printf("pSectionGroup[%d].Misc.VirtualSize : %04X\n", i, pSectionGroup[i].Misc.VirtualSize);
printf("pSectionGroup[%d].VirtualAddress : %04X\n", i, pSectionGroup[i].VirtualAddress);
printf("pSectionGroup[%d].SizeOfRawData : %04X\n", i, pSectionGroup[i].SizeOfRawData);
printf("pSectionGroup[%d].PointerToRawData : %04X\n", i, pSectionGroup[i].PointerToRawData);
printf("pSectionGroup[%d].PointerToRelocations : %04X\n", i, pSectionGroup[i].PointerToRelocations);
printf("pSectionGroup[%d].PointerToLinenumbers : %04X\n", i, pSectionGroup[i].PointerToLinenumbers);
printf("pSectionGroup[%d].NumberOfRelocations : %02X\n", i, pSectionGroup[i].NumberOfRelocations);
printf("pSectionGroup[%d].NumberOfLinenumbers : %02X\n", i, pSectionGroup[i].NumberOfLinenumbers);
printf("pSectionGroup[%d].Characteristics : %04X\n\n\n", i, pSectionGroup[i].Characteristics);
} printf("*****************SECTION_HEADER END************************\n"); 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上

PE文件头格式解析的更多相关文章

  1. PE文件解析器的编写(二)——PE文件头的解析

    之前在学习PE文件格式的时候,是通过自己查看各个结构,自己一步步计算各个成员在结构中的偏移,然后在计算出其在文件中的偏移,从而找到各个结构的值,但是在使用C语言编写这个工具的时候,就比这个方便的多,只 ...

  2. PE文件格式详解,第二讲,NT头文件格式,以及文件头格式

    PE文件格式详解,第二讲,NT头文件格式,以及文件头格式 作者:IBinary出处:http://www.cnblogs.com/iBinary/版权所有,欢迎保留原文链接进行转载:) PS:本篇博客 ...

  3. 第二讲,NT头文件格式,以及文件头格式

    今天详解NT 头格式,以及文件头格式,以及作用, 关于DOS头文件格式,以及DOSStub昨天的博客已经写过了.主要是分散讲解.便于理解. 一丶最小PE的生成,以及标准PE的生成 ps: (如果直接学 ...

  4. PE文件头

    pe文件头查看器下载与原文地址: http://www.pc6.com/softview/SoftView_109840.html PE文件入门: PE文件总的来说是由DOS文件头.DOS加载模块.P ...

  5. WindowsPE权威指南-PE文件头中的重定位表

    PE加载的过程 任何一个EXE程序会被分配4GB的内存空间,用户层处理低2G的内存,驱动处理高2G的内存. 1.双击EXE程序,操作系统开辟一个4GB的空间. 2.从ImageBase决定了加载后的基 ...

  6. MP3文件头格式

    MP3文件结构及编解码流程 http://blog.sina.com.cn/s/blog_67b7cb7b01018i2l.html http://blog.csdn.net/liuyan4794/a ...

  7. PE笔记之NT头PE文件头

    typedef struct _IMAGE_FILE_HEADER {       WORD    Machine;                         //014C-IMAGE_FILE ...

  8. pe文件头详解

  9. DEX文件解析---1、dex文件头解析

    DEX文件解析---1.dex文件头解析 一.dex文件     dex文件是Android平台上可执行文件的一种文件类型.它的文件格式可以下面这张图概括:     dex文件头一般固定为0x70个字 ...

随机推荐

  1. git使用简单教程-(转自linux人)

    什么是Git Git是目前世界上最先进的分布式版本控制系统.最初由Linus Torvalds编写,用作Linux内核代码的管理.如果你是windows用户,看到这里你可能会担心"是不是只能 ...

  2. STM32进阶日志1

    一 工程习惯 ①必须模块化编程-一个功能一个CH分开,一个对象一个结构体; ②习惯使用bsp.c/bsp.h,BSP板级支持包源文件; ③多使用#define 来定义IO口与硬件相关特性,方便修改; ...

  3. Linux系统添加永久静态路由的方法(包含Centos7)

    一.使用route命令添加 使用route 命令添加的路由,机器重启或者网卡重启后路由就失效了,方法:A.添加到主机的路由# route add –host 192.168.1.10 dev eth0 ...

  4. 90%的人都不知道的Node.js 依赖关系管理(上)

    转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. 原文参考:https://dzone.com/articles/nodejs-dependency-mana ...

  5. 图解CSS布局(一)- Grid布局

    图解CSS布局(一)- Grid布局 先上图 简介 Grid 布局是将容器划分成"行"和"列",产生单元格,然后指定"项目所在"的单元格,可 ...

  6. 西门子 S7200 以太网模块连接组态王方法

    北京华科远创科技有限研发的远创智控ETH-YC模块,以太网通讯模块型号有MPI-ETH-YC01和PPI-ETH-YC01,适用于西门子S7-200/S7-300/S7-400.SMART S7-20 ...

  7. Resource和Autowired区别

    1.使用场景 @Resource和@Autowired都是做bean注入时使用 @Resource是jdk的注解,不是spring的注解:由包javax.annotation.Resource提供,需 ...

  8. Jittor实现Conditional GAN

    Jittor实现Conditional GAN Generative Adversarial Nets(GAN)提出了一种新的方法来训练生成模型.然而,GAN对于要生成的图片缺少控制.Conditio ...

  9. Pytorch和CNN图像分类

    Pytorch和CNN图像分类 PyTorch是一个基于Torch的Python开源机器学习库,用于自然语言处理等应用程序.它主要由Facebookd的人工智能小组开发,不仅能够 实现强大的GPU加速 ...

  10. 开放式神经网络交换-ONNX(下)

    开放式神经网络交换-ONNX(下) 计算节点由名称.它调用的算子operator的名称.命名输入的列表.命名输出的列表和属性列表组成. 输入和输出在位置上与算子operator输入和输出相关联.属性通 ...