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. eclipse scala Could not reserve enough space for object heap

    [学习笔记] 防盗版实名手机尾号:73203 Could not reserve enough space for object heap 解决方法:下面的缩写中:一个是memory max(Xmx) ...

  2. 基于docker的mongodb安装以及PHP使用

    说明:用docker基于单服务器,虚拟多个服务器的方案, 以下是两个config服务器,两个分片,以及每个分片有一个副本的方案 这里关于给mongodb设置远程密码的问题,我采取了用两个compser ...

  3. 超级简单的requests模块教程

    在web后台开发过程中,会遇到需要向第三方发送http请求的场景,python中的requests库可以很好的满足这一要求,这里简要记录一下requests模块的使用! 说明: 这里主要记录一下req ...

  4. 适合新手的160个creakme(三)

    先跑一下,这个程序应该是有定时器,多久之后自动开启,测试一下输入,序列号以字母方式输入会出现类型不匹配,之后程序自动退出 但是如果以数字方式输入序列号,则会出现,Try Again,所以这里序列号应该 ...

  5. SMTP实现发送邮箱2(封装版)

    SMTP.h #ifndef __SMTP_H__ //避免重复包含 #define __SMTP_H__ #include <iostream> #include <list> ...

  6. SQL连接(join)

    INNER JOIN:如果表中有至少一个匹配,则返回行 LEFT JOIN:即使右表中没有匹配,也从左表返回所有的行 RIGHT JOIN:即使左表中没有匹配,也从右表返回所有的行 FULL JOIN ...

  7. 统一用户认证系统CUAS实现要点

    背景: 基于目前存在多套员工使用的日常工作子系统,现状为各系统各自有一套用户体系,员工需要记住各系统的用户名.密码等信息,还需要登录多个系统,重复工作量颇多.统一用户认证组件将用户名.密码等信息统一存 ...

  8. 使用nodejs创建Marketing Cloud的contact数据

    源代码如下: var config = require("./mcConfig"); var request = require('request'); var url = con ...

  9. @ComponentScan注解及其XML配置

    开发中会经常使用包扫描,只要标注了@Controller.@Service.@Repository,@Component 注解的类会自动加入到容器中,ComponentScan有注解和xml配置两种方 ...

  10. Python学习记录3-函数参数详解

    参数详解 参数分类 普通参数 默认参数 关键字参数 收集参数 普通参数 定义时直接定义变量名 调用的时候直接把变量或者值放入指定位置 def 函数名 (参数1, 参数2, ....): 函数体 # 调 ...