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. HTTPS 简单学习

    1. HTTP缺点 使用明文通信,内容可能会被窃听: 通信加密:使用SSL和TLS: 内容加密: 不验证通信方的身份,因此可能会遭到伪装: SSL提供加密和证书: 无法证明报文的完整性,因此会遭到修改 ...

  2. php实现算法

    二分法查找(已排序) @params  $arr 查找的数组  $start 开始查找的下标  $end 结束查找的下标  $value 查找的值 function bin_search($arr,$ ...

  3. DevExpress WPF控件记录

    以下是博主用到DevExpress WPF控件时的一些记录笔记: 1.Canvas控件:Canvas控件的背景色一定要设置(background="Transparent"),不然 ...

  4. MySQL设置自增字段

    1.MySQL每张表只能有1个自增字段,这个自增字段即可作为主键,也可用作非主键使用,但是请注意将自增字段当做非主键使用时必须为其添加唯一索引,否则系统将会报错 )将自动增长字段设置为主键 CREAT ...

  5. DIP常用资源整理

    Deep Learning(深度学习): ufldl的2个教程(这个没得说,入门绝对的好教程,Ng的,逻辑清晰有练习):一 ufldl的2个教程(这个没得说,入门绝对的好教程,Ng的,逻辑清晰有练习) ...

  6. [转载]Linux缓存机制

    [转载]Linux缓存机制 来源:https://blog.csdn.net/weixin_38278334/article/details/96478405 linux下的缓存机制及清理buffer ...

  7. arcgis js之调用wms服务

    arcgis js之调用wms服务 定义: export const tdtlayer = async () => { let WMSLayer = await arcgisPackage.WM ...

  8. vue cli3.0 build 打包 的 js 文件添加时间戳 解决 js 缓存问题

    // vue.config.jsconst Timestamp = new Date().getTime();module.exports = { configureWebpack: { // web ...

  9. 基于SAML2.0的SAP云产品Identity Authentication过程介绍

    SAP官网的架构图 https://cloudplatform.sap.com/scenarios/usecases/authentication.html 上图介绍了用户访问SAP云平台时经历的Au ...

  10. 从0到1写rtos:事件的挂起

    任务的状态: 未创建:只定义了任务代码,未调用tTaskInit()初始化 就绪:任务已经创建完毕,且等待机会占用CPU运行 运行:任务正在占用CPU运行代码 延时:任务调用tTaskDelay()延 ...