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. 回炉重铸系列之javaEE基础

    这篇文章主要介绍 servlet filter listener interceptor 之 知识点.博文主要从 概念,生命周期,使命介绍其区别.详情如下:   概念 生命周期 使命 servlet ...

  2. LC 349. Intersection of Two Arrays

    题目描述 Given two arrays, write a function to compute their intersection. Example 1: Input: nums1 = [1, ...

  3. phpstudy的设置目录列表显示403找不到

    小白视角具体步骤如下 在phpstudy的->其它选项菜单->phpstudy设置->允许目录列表 phpstudy->其他选项菜单->站点域名管理(新增并保存) 然后会 ...

  4. k8s-PV和PVC使用

    上节课我们学习了 PV 的使用,但是在我们真正使用的时候是使用的 PVC,就类似于我们的服务是通过 Pod 来运行的,而不是 Node,只是 Pod 跑在 Node 上而已,所以这节课我们就来给大家讲 ...

  5. 初识机器学习——概念介绍(imooc笔记)

    前言 imooc的机器学习一个最基本的介绍类课程,http://www.imooc.com/learn/717 ,不怎么涉及具体的算法或实现,只是讲了讲一些理论概念. 概述 机器学习: 利用计算机从历 ...

  6. 贝叶斯优化 Bayesian Optimization

    贝叶斯优化 Bayesian Optimization 2018年07月02日 22:28:06 余生最年轻 阅读数 4821更多 分类专栏: 机器学习   版权声明:本文为博主原创文章,遵循CC 4 ...

  7. js 超浓缩 双向绑定

    绑定确实是个有趣的话题. 现在我的绑定器有了不少的功能 1. 附着在Object对象上,一切以对象为中心 2. 与页面元素进行双向绑定 3. 与任意对象绑定,主要是应用在绑定到页面元素的一些属性上,比 ...

  8. iOS 定义多个参数函数的写法

    多个参数的写法 (方法的数据类型)函数名:(参数1数据类型)参数1的数值的名字 参数2的名字: (参数2数据类型) 参数2值的名字 …. ; 如  :  有三个参数 -(void)getdetailI ...

  9. vue-cli3 本地数据模拟后台接口

    vue-cli3 本地数据模拟后台接口 原理: 将本地的json数据在前端模拟为后台接口,然后调用接口,完成前端操作.在后台接通后可以直接在api配置文件中修改路径,完成前后台对接. 配置: 1.文件 ...

  10. Objective-C 之Extension

    Objective-C 之Extension class extension:类扩展 类扩展与 category 有相似性,但在编译时它只能被添加到已有源代码的一类中(该类扩展和该类同时被编译). 在 ...