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. nginx浏览器开启密码验证

    如果我们在 nginx 下搭建了一些站点,但是由于站点内容或者流量的关系,我们并不想让所有人都能正常访问,那么我们可以设置访问认证.只有让用户输入正确的用户名和密码才能正常访问.效果如下: 在 ngi ...

  2. 关于BIOS系统的认识和学习(源自摘录)

    BIOS系统的介绍与学习 BIOS (basic input output system 即基本输入输出系统)在计算机系统中起着非常重要的作用,其是计算机系统最底层的设置, BIOS设置程序是被固化到 ...

  3. Fiddler 抓包工具详解

    Fiddler是一个蛮好用的抓包工具,可以将网络传输发送与接受的数据包进行截获.重发.编辑.转存等操作.也可以用来检测网络安全.反正好处多多,举之不尽呀!当年学习的时候也蛮费劲,一些蛮实用隐藏的小功能 ...

  4. Centos7 部署.net core2.1 详细步骤

    安装dotnet sdk(添加产品秘钥与yum源) 添加yum源:sudo rpm -Uvh https://packages.microsoft.com/config/rhel/7/packages ...

  5. 【ES6 】ES6 字符串扩展及新增方法

    模板字符串 传统写法 var str = 'There are <b>' + basket.count + '</b> ' + 'items in your basket, ' ...

  6. Objective-C 之Extension

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

  7. Java基础加强-内部类及代理

    /*内部类是一个编译时的概念,*/ 常规内部类.静态内部类.局部内部类.匿名内部类 1.常规内部类(常规内部类没有static修饰且定义在外部类类体中) 1.常规内部类中的方法可以直接使用外部类的实例 ...

  8. Spring Cloud(九)高可用的分布式配置中心 Spring Cloud Config 集成 Eureka 服务

    上一篇文章,讲了SpringCloudConfig 集成Git仓库,这一篇我们讲一下SpringCloudConfig 配和 Eureka 注册中心一起使用 在分布式系统中,由于服务数量巨多,为了方便 ...

  9. echo打印换行

    shell环境中,echo是常用的数据命令,但有的时候,想通过“\n”使输出换行却换不了,这个时候需要增加-e选项: $ echo "Hellow.\nHey man~" Hell ...

  10. 【url ---lib___】笔趣阁(抓取斗罗大陆完整)和(三寸天堂)

    # coding=gbk #因为在黑屏下执行,所以代码会使用GBK url='http://www.biquge.info/10_10218/' UA={"User-Agent": ...