1.dos头
结构:
struct _IMAGE_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];
    DWORD e_lfanew;
}
重要的属性:
 
2.标准pe头
根据dos头的e_lfanew可以找到nt头;
nt头的结构:
struct _IMAGE_NT_HEADERS {
    DWORD Signature;
    _IMAGE_FILE_HEADER FileHeader;
    _IMAGE_OPTIONAL_HEADER OptionalHeader;
};
nt头的第一个属性是pe标记,占4个字节,值是50 45 00 00,其中50 45对应英文字母pe;
 
标志pe头结构:
struct _IMAGE_FILE_HEADER {
    WORD Machine;
    WORD NumberOfSections;
    DWORD TimeDateStamp;
    DWORD PointerToSymbolTable;
    DWORD NumberOfSymbols;
    WORD SizeOfOptionalHeader;
    WORD Characteristics;
};
重要的属性:
3.可选pe头
结构:
struct _IMAGE_OPTIONAL_HEADER {
    WORD Magic;
    BYTE MajorLinkerVersion;
    BYTE MinorLinkerVersion;
    DWORD SizeOfCode;
    DWORD SizeOfInitializedData;
    DWORD SizeOfUninitializedData;
    DWORD AddressOfEntryPoint;
    DWORD BaseOfCode;
    DWORD BaseOfData;
    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[16];
};
 
属性说明及重要属性:
 
4.内存镜像基址
如果用程序将一个exe文件读到自己申请的内存即缓冲区时;
缓冲区内容和exe文件的内容完全一样;
缓冲区中的内容无法运行,因为缺少一个拉伸的过程和其它操作;
如果想让程序运行,需要从ImageBase开始向后装载程序;
例如:
    一个exe文件,从硬盘直接读到内存是从地址0开始的,此时无法运行;
    如果想让它运行,必须从内存镜像基址ImageBase开始加载,例如如果内存是400000就从地址400000处开始放dos头,后面以此类推;
    而0到400000则是系统保留区,请求这里的内存时会报错;例如经常将malloc申请的内存释放后,指针指向NULL,也就是0,别再使用该指针就会报错;
 
计算程序入口点时需要加上ImageBase的值,即ImageBase+AddressOfEntryPoint;
 
pe程序为什么要设计成ImageBase+偏移地址的形式:
    因为imagebase不靠谱,可能被其它pe文件抢占,为了保证即使地址被抢占了程序也能正常运行;
 
加ImageBase的目的:
    空出一块内存保护指针;
    为了模块对齐;    ->例如一个exe可能有多个pe文件dll,对齐可以提高查询速度,相当于书的分页方便查找;
 
5.解析pe头
LPVOID ReadPEFile(LPSTR lpszFile)        
{        
    FILE *pFile = NULL;    
    DWORD fileSize = 0;    
    LPVOID pFileBuffer = NULL;    
        
    //打开文件    
    pFile = fopen(lpszFile, "rb");        
    if(!pFile)    
    {    
        printf(" 无法打开 EXE 文件! ");
        return NULL;
    }    
    //读取文件大小        
    fseek(pFile, 0, SEEK_END);    
    fileSize = ftell(pFile);        
    fseek(pFile, 0, SEEK_SET);        
    //分配缓冲区    
    pFileBuffer = malloc(fileSize);    
        
    if(!pFileBuffer)    
    {    
        printf(" 分配空间失败! ");
        fclose(pFile);
        return NULL;
    }    
    //将文件数据读取到缓冲区    
    size_t n = fread(pFileBuffer, fileSize, 1, pFile);    
    if(!n)    
    {    
        printf(" 读取数据失败! ");
        free(pFileBuffer);
        fclose(pFile);
        return NULL;
    }    
    //关闭文件    
    fclose(pFile);    
    return pFileBuffer;        
}        
        
VOID PrintNTHeaders()        
{        
    LPVOID pFileBuffer = NULL;    
    PIMAGE_DOS_HEADER pDosHeader = NULL;    
    PIMAGE_NT_HEADERS pNTHeader = NULL;    
    PIMAGE_FILE_HEADER pPEHeader = NULL;    
    PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;    
    PIMAGE_SECTION_HEADER pSectionHeader = NULL;    
        
    pFileBuffer = ReadPEFile(FILEPATH);    
    if(!pFileBuffer)    
    {    
        printf("文件读取失败\n");
        return ;
    }    
        
    //判断是否是有效的MZ标志    
    if(*((PWORD)pFileBuffer) != IMAGE_DOS_SIGNATURE)    
    {    
        printf("不是有效的MZ标志\n");
        free(pFileBuffer);
        return ;
    }    
    pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;    
    //打印DOC头    
    printf("********************DOC头********************\n");    
    printf("MZ标志:%x\n",pDosHeader->e_magic);    
    printf("PE偏移:%x\n",pDosHeader->e_lfanew);    
    //判断是否是有效的PE标志    
    if(*((PDWORD)((DWORD)pFileBuffer+pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE)    
    {    
        printf("不是有效的PE标志\n");
        free(pFileBuffer);
        return ;
    }    
    pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer+pDosHeader->e_lfanew);    
    //打印NT头    
    printf("********************NT头********************\n");    
    printf("NT:%x\n",pNTHeader->Signature);    
    pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 4);    
    printf("********************PE头********************\n");    
    printf("PE:%x\n",pPEHeader->Machine);    
    printf("节的数量:%x\n",pPEHeader->NumberOfSections);    
    printf("SizeOfOptionalHeader:%x\n",pPEHeader->SizeOfOptionalHeader);    
    //可选PE头    
    pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader+IMAGE_SIZEOF_FILE_HEADER);    
    printf("********************OPTIOIN_PE头********************\n");    
    printf("OPTION_PE:%x\n",pOptionHeader->Magic);    
    //释放内存    
    free(pFileBuffer);    
}        
 
 
 

pe头的更多相关文章

  1. PE文件学习系列三-PE头详解

    合肥程序员群:49313181.    合肥实名程序员群:128131462 (不愿透露姓名和信息者勿加入) Q  Q:408365330     E-Mail:egojit@qq.com 最近比较忙 ...

  2. PE头的应用---插入代码到EXE或DLL文件中

    三.代码实现(DELPHI版本),采用第三种方式实现代码插入. 1. 定义两个类,一个用来实现在内存中建立输入表:一个用来实现对PE头的代码插入. DelphiCode: const MAX_SECT ...

  3. PE文件格式学习之PE头移位

    以前刚开始学网络安全,是从免杀开始的.记得那时候杀毒软件还很弱.金山江民瑞星还存在. 那会什么原理也不懂,就一直瞎鼓捣.(后来转入渗透行列了) 这段时间一直在学PE格式,突然想起来以前很古老的PE文件 ...

  4. 逆向-PE头解析

    目录 PE头解析 数据结构 IMAGE_DOS_HEADER IMAGE_NT_HEADERS 区块 PE头解析 PE 格式是Windows系统下组织可执行文件的格式.PE文件由文件头和对应的数据组成 ...

  5. Windows Pe 第三章 PE头文件-EX-相关编程-2(RVA_FOA转换)

    RVA-FOA之间转换 1.首先PE头加载到内存之后是和文件头内容一样的,就算是偏移不同,一个是磁盘扇区大小(400H)另一个是内存页大小(1000H),但是因为两个都是开头位置,所以相同. 2.看下 ...

  6. Windows Pe 第三章 PE头文件-EX-相关编程-1(PE头内容获取)

    获取pE头相关的内容,就是类似如下内容 原理:比较简单,直接读取PE到内存,然后直接强转就行了. #include <windows.h> #include <stdio.h> ...

  7. Windows Pe 第三章 PE头文件(下)

    3.5  数据结构字段详解 3.5.1  PE头IMAGE_NT_HEADER的字段 1.IMAGE_NT_HEADER.Signature +0000h,双字.PE文件标识,被定义为00004550 ...

  8. Windows Pe 第三章 PE头文件(中)

    这一章的上半部分大体介绍了下PE文件头,下半部分是详细介绍里面的内容,这一章一定要多读几遍,好好记记基础概念和知识,方便之后的学习. 简单回忆一下: 3.4  PE文件头部解析 3.4.1 DOS M ...

  9. Windows Pe 第三章 PE头文件(上)

    第三章  PE头文件 本章是全书重点,所以要好好理解,概念比较多,但是非常重要. PE头文件记录了PE文件中所有的数据的组织方式,它类似于一本书的目录,通过目录我们可以快速定位到某个具体的章节:通过P ...

随机推荐

  1. 【AtCoder】AGC034

    AGC034 刷了那么久AtCoder我发现自己还是只会ABCE(手动再见 A - Kenken Race 大意是一个横列,每个点可以跳一步或者跳两步,每个格子是空地或者石头,要求每一步不能走到石头或 ...

  2. 代理模式与动态代理之JDK实现和CGlib实现

    静态代理 静态代理中的代理类和委托类会实现同一接口或是派生自相同的父类. 由业务实现类.业务代理类 两部分组成.业务实现类 负责实现主要的业务方法,业务代理类负责对调用的业务方法作拦截.过滤.预处理, ...

  3. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by de

    MySQL在高版本需要指明是否进行SSL连接 spring.datasource.url=jdbc:mysql://127.0.0.1:3306/framework?characterEncoding ...

  4. 微信小程序实现折叠面板

    wxml: <view class='help'> <view class='help_item'> <view class='title' data-index='1' ...

  5. wrbstrom使用

    使用webstrom时遇到Firefox浏览器打不开问题,是webstrom未找到你Firefox的安装路径下面为大家提供解决方法: 文件--->设置--->工具--->web浏览器 ...

  6. Shiro——入门Demo

    Shiro——入门Demo 环境-  引入相关maven依赖, shiro-core,commons-logging 配置shiro配置文件:ini后缀 主方法测试: import org.apach ...

  7. 启动tomcat提示某个端口被占用

    原文参见:https://www.cnblogs.com/liuyanxia/p/6755520.html 解决办法 找出占用1099端口的进程,进入windows命令,查看什么进程占用了1099端口 ...

  8. JS笛卡尔积算法与多重数组笛卡尔积实现方法示例

    js 笛卡尔积算法的实现代码,据对象或者数组生成笛卡尔积,并介绍了一个javascript多重数组笛卡尔积的例子,以及java实现笛卡尔积的算法与实例代码. 一.javascript笛卡尔积算法代码 ...

  9. 轮播图--使用原生js的轮播图

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  10. python实现蓝牙通信

    安装和示例 linux下安装 -dev sudo pip install bluepy 官方示例 import btle class MyDelegate(btle.DefaultDelegate): ...