【逆向】PE文件解析

news2024/10/5 18:33:34

文章目录

  • PE文件
  • DOS头部
  • PE/NT头解析
  • 区段头/区块表解析
  • 数据目录表(存放在某个区段)
    • 1. 导出表
    • 2. 导入表
    • 3. 重定位表

PE文件

  • PE文件:PE文件是在windows平台可执行的文件。
  • 包括:.exe(可执行程序),.dll(动态链接库),.sys(驱动程序)

在这里插入图片描述
在这里插入图片描述


DOS头部

  • 概念:

    • DOS头部共64个字节
    • DOS头部是一个结构体,包含如下字段:
      在这里插入图片描述
  • 重要字段:

    • e_magic(前两个字节):DOS头签名,可执行文件的标志.(固定的值:4D 5A
    • e_lfanew(后四个字节):PE头的偏移位置
  • DOS头解析:

    #include<Windows.h>
    #include<iostream>
    
    // 获取DOS头
    PIMAGE_DOS_HEADER get_pe_dos_header(char* pBuff)
    {
    	return (PIMAGE_DOS_HEADER)pBuff;
    }
    // 解析DOS头
    void parse_pedos_header(const char* path)
    {
    	DWORD fSize = 0;
    	char* pBuff = NULL;
    	DWORD dwReadSize = 0;
    	// 1.打开文件
    	HANDLE hfile = CreateFileA(
    		path, // 文件路径
    		GENERIC_READ, // 打开文件读方式
    		FILE_SHARE_READ,// 共享方式
    		NULL, // 安全属性
    		OPEN_EXISTING, // 创建标志
    		FILE_ATTRIBUTE_NORMAL, //默认创建
    		NULL
    	);
    
    	// 1.2 获取文件大小
    	fSize = GetFileSize(hfile, NULL); // 获取文件大小
    	pBuff = new char[fSize]; // 申请文件大小空间
    
    
    
    	// 2. 读取到内存中
    	ReadFile(hfile, pBuff, fSize, &dwReadSize, NULL);
    
    
    	// 3. 解析PE文件的DOS头部
    	PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)pBuff;
    	//PIMAGE_DOS_HEADER pDos = get_pe_dos_header(pBuff);
    	//pDos->e_magic; //DOS头签名,0x5A4D
    	//pDos->e_lfanew; // PE头的偏移
    
    
    	// 4. 判断是否是PE文件
    	if (pDos->e_magic != IMAGE_DOS_SIGNATURE)
    	{
    		printf("这不是一个PE文件\n");
    	}
    
    	printf("e_lfanew=%d\n", pDos->e_lfanew);
    
    
    	// 5. 关闭文件句柄
    	CloseHandle(hfile);
    }
    
    int main() {
    	parse_pedos_header("crackme1.exe");
    }
    
  • 其他:

    • 程序在硬盘中和在内存中存储状态不一样,在内存中的对齐值比在硬盘中大

PE/NT头解析

  • 概念

    • NT头是一个结构体,包含三个字段:
      在这里插入图片描述
  • 重要字段:

    • Signature(前4个字节):NT头签名,PE标志,固定值 50 45 00 00
    • FileHeader(20个字节):文件头
    • OptionalHeader(大小不固定):可选PE头
  • NT头解析:

    • FileHeader(文件头,共20字节):
      在这里插入图片描述

    重要字段:

    • Machine(2个字节):程序允许的CPU型号,如果为0表示可以在任何CPU上执行。若为0x014C,表示能在386及后续的CPU上运行
    • NumberOfSections(2个字节):文件中存在的区段的数量
    • TimeDateStamp(4个字节):时间戳
    • SizeOfOptionalHeader(2个字节):可选PE头的大小,32位PE文件默认E0,64位默认F0
    • Characteristics(2个字节):文件属性,每个位有不同的含义
    • OptionalHeader(可选PE头)
      在这里插入图片描述

    重要字段:

    • Magic(2个字节):表示是32位PE文件还是64位PE文件。0x010B表示32位,0x020B表示64位
    • SizeOfCode(4个字节):所有代码的总大小,按照FileAlignment对齐后的大小
    • SizeOfInitializedData(4个字节):已初始化的数据大小,按照FileAlignment对齐
    • SizeOfUninitializedData(4个字节):未初始化的数据大小 按照FileAlignment对齐
    • AddressOfEntryPoint(4个字节):程序入口 OEP(偏移地址)
    • BaseOfCode(4个字节):代码开始地址
    • BaseOfData(4个字节):数据开始地址
    • ImageBase(4个字节):内存镜像地址(程序被加载到内存后的起始地址(绝对地址))
    • SectionAlignment(4个字节):内存对齐大小
    • FileAlignment(4个字节):文件对齐大小
    • SizeOfImage(4个字节):文件在内存中的大小,按SectionAlignment对齐后的大小
    • SizeOfHeaders(4个字节):DOS头+NT头+标准PE头+可选PE头+区段头,按照FileAlignment对齐后的大小
    • NumberOfRvaAndSizes(4个字节):数据目录表的个数
    • DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]:存放数据目录表

区段头/区块表解析

  • 概念:

    • 区段头由多个结构体组成,有多少个区段就有多少个对应的的结构体:
      在这里插入图片描述
  • 重要字段:

    • Name[IMAGE_SIZEOF_SHORT_NAME(8)](8个字节):区段名称,注意此处跟字符串不一样,不会以0结尾
    • union {
      DWORD PhysicalAddress;
      DWORD VirtualSize;
      } Misc(8个字节)
      :该区段在内存中的真实大小(未对齐)
    • VirtualAddress(4个字节):区段在内存中的偏移位置,+ImageBase 为真正的地址。
    • SizeOfRawData(4个字节):区段在文件中对齐后大小
    • PointerToRawData(4个字节):区段在文件中的偏移位置
    • Characteristics(4个字节):区段属性 (是否可读 是否可写 是否可执行等等)

数据目录表(存放在某个区段)

  • 概念:

    可选PE头中包含两个字段:

    • NumberOfRvaAndSizes(4个字节):数据目录表的个数
    • DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]:存放数据目录表

    在这里插入图片描述
    在这里插入图片描述

1. 导出表

  • 概念:

    • 导出表存放该程序中定义的可供外部使用的函数
      在这里插入图片描述
  • 重要字段:

    • DWORD Name:指向导出表文件名 RVA -->FOA+FileBuff=char *name;
    • DWORD Base:导出函数起始序号
    • DWORD NumberOfFunctions:导出函数个数
    • DWORD NumberOfNames:以名称导出函数个数
    • DWORD AddressOfFunctions:导出函数地址表 RVA–>FOA +FileBuff
    • DWORD AddressOfNames:导出函数名称表 // RVA from base of image
    • DWORD AddressOfNameOrdinals:导出函数序号表 // RVA from base of image
      在这里插入图片描述

    FOA(文件偏移)与RVA(内存偏移)的转换:

    数据的RVA - 区段地址的RVA = 数据的FOA - 区段地址的FOA = 数据距离区段起始位置有多远,注意无论是RVA还是FOA都是偏移

    • 数据的FOA = 数据的RVA - 区段地址的RVA + 区段地址的FOA
    • 数据的RVA = 数据的FOA - 区段地址的FOA + 区段地址的RVA

2. 导入表

  • 知识点准备:

    • 调用dll文件函数原理
      程序在调用dll文件函数时,并不是把dll文件函数的代码编译到当前文件中,而是把dll文件对应的函数地址保存到了当前文件中
    • 一个进程空间中的exe、dll文件如何被加载到内存中
      exe文件先导入内存,然后再导入dll文件到内存中
    1. HMODULE hModule = LoadLibraryW(L"Dll1.dll"):将dll文件加载到内存中,并将ImageBase的值存放到hModule中
    2. GetProcAddress(hModule, “my_export2”):从dll文件中拿到对应的函数的地址
    3. 将得到的函数地址填到exe文件中的对应位置
    • exe文件调用的动态链接库在内存中与在硬盘中有什么不同
      内存中,exe文件中的 dll文件的对应的函数地址 在exe硬盘中 存放的是一个RVA,该RVA转为FOA后,发现存放的是对应的函数名称
    • 在硬盘中,exe文件存放使用的dll文件中的函数名称(准确的说是一个RVA值,该RVA转为FOA后,发现存放的是对应的函数名称)
    • 在内存中,exe文件存放使用的dll文件中的函数地址
  • 概念:

    • 导入表存放该程序使用的外部函数的信息:
      在这里插入图片描述
  • 重要字段:

    在这里插入图片描述

    • union {
      DWORD Characteristics; // 0 for terminating null import descriptor
      DWORD OriginalFirstThunk; // RVA,指向(IMAGE_THUNK_DATA,导入名称表)结构体数组,Import name table,简称INT
      } DUMMYUNIONNAME;(8个字节)

    在这里插入图片描述

    • TimeDateStamp:时间戳。为-1时,IAT在硬盘存储时会存放函数的地址而不是名称(由于存放地址可能会造成冲突,因此需要让所有dll文件导入内存的位置固定)
    • Name:RVA,存放dll的名称
    • FirstThunk:RVA,IAT 导入地址表 IMAGE_THUNK_DATA数组。在硬盘存储时,一般和INT一样(但不绝对);在内存存储时,会存函数的在内存中的地址。

3. 重定位表

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/514886.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

20230511干掉CV1826的buildroot系统的串口用户名和密码root

20230511干掉CV1826的buildroot系统的串口用户名和密码root 2023/5/11 11:56 https://blog.csdn.net/u011342132/article/details/126116391 buildroot跳过密码登录 1、全新原始编译&#xff1a; rootrootrootroot-X99-Turbo:~$ rootrootrootroot-X99-Turbo:~$ cd smartpen/ r…

【集群模式】执行MapReduce程序-wordcount

因为是在hadoop集群下通过jar包的方式运行我们自己写的wordcount案例&#xff0c;所以需要传递的是 HDFS中的文件路径&#xff0c;所以我们需要修改上一节【本地模式】中 WordCountRunner类 的代码&#xff1a; //5.设置统计文件输入的路径,将命令行的第一个参数作为输入文件的…

超细详解MyBatis操作数据库(1)

文章目录 1.MyBatis 是什么&#xff1f;2.回顾 JDBC 的操作流程3.MyBatis 在整个框架中的定位4.MyBatis的使用4.1创建数据库和表4.2 添加MyBatis框架支持4.2.1 老项目添加MyBatis4.2.2 新项目添加MyBatis 4.3 配置连接字符串和MyBatis4.3.1 配置连接字符串4.3.2 配置 MyBatis 中…

【一】设计模式~~~创建型模式~~~简单工厂模式(Java)

【学习难度&#xff1a;★★☆☆☆&#xff0c;使用频率&#xff1a;★★★☆☆】 1.1. 模式动机 考虑一个简单的软件应用场景&#xff0c;一个软件系统可以提供多个外观不同的按钮&#xff08;如圆形按钮、矩形按钮、菱形按钮等&#xff09;&#xff0c; 这些按钮都源自同一个…

学习之-spring cache缓存框架应用Redis

本文章用于个人学习记录 一、前言 1、SpringCache是Spring提供的一个缓存框架&#xff0c;在Spring3.1版本开始支持将缓存添加到现有的spring应用程序中&#xff0c;在4.1开始&#xff0c;缓存已支持JSR-107注释和更多自定义的选项。Spring 从 3.1 开始定义了 org.springframe…

设备树dtb文件的格式分析

设备树dtb文件的格式分析 文章目录 设备树dtb文件的格式分析DTB文件格式1.header头部1.magic2.totalsize3.off_dt_struct4.off_dt_strings字符串的偏移量5.off_mem_rsvmap 内存保留映射的偏移量6.version 格式版本7.last_comp_version最后兼容版本8.boot_cpuid_phys 我们正在启…

SpringBoot ( 五 ) 封装响应数据

2.6.业务处理 这是通过 Spring 在 Controller中注入Service模型层 而在 Service模型层 结合 Mybatis / Mybatis-Plus 进行数据加工, 数据持久化 2.7.封装响应值 将 业务处理得到数据封装到 Model作用域中, 伴随着转页将信息传递到页面 2.7.1.传值容器 2.7.1.1.Model 在Cont…

【Qt编程之Widgets模块】-001:QButtonGroup抽象容器

1.QButtonGroup简介 QButtonGroup提供了一个抽象容器&#xff0c;可以将按钮小部件放入其中。它不提供此容器的可视化表示&#xff0c;而是管理组中每个按钮的状态。 互斥按钮组&#xff0c;将关闭除已单击的按钮外的所有可选中&#xff08;可切换&#xff09;按钮。默认情况下…

七个合法学习黑客技术的网站,让你从萌新成为大佬

合法的学习网站&#xff0c;以下这些网站&#xff0c;虽说不上全方位的满足你的需求&#xff0c;但是大部分也都能。能带你了解到黑客有关的技术&#xff0c;视频&#xff0c;电子书&#xff0c;实践&#xff0c;工具&#xff0c;数据库等等相关学习内容。以上这些网站我都是用…

项目调研 | Loopring研究报告

一、项目简介及愿景 Loopring协议是一个专为应用程序开发的 zkRollup 协议、一个中继器、一个 L2 非托管交易所、一个智能钱包。用户可以在其中使用、交易和存储资产&#xff0c;同时让资产获得增长。 上述Loopring这些Title具体详情如下&#xff1a; 作为协议&#xff0c;Loop…

latex论文写作实用工具

从pdf定位到latex&#xff1a;ctrl 鼠标左键从latex定位到pdf&#xff1a;ctrl alt jVscode写latex时如何自动换行 最简单的方法就是使用快捷 Alt z 公式识别 SiimpleTex latex格式化 下载链接 在VSCode用户Json文件中添加如下&#xff1a; 表格转换工具 链接 Excel…

YOLOv5改进系列(3)——添加CA注意力机制

【YOLOv5改进系列】前期回顾&#xff1a; YOLOv5改进系列&#xff08;0&#xff09;——重要性能指标与训练结果评价及分析 YOLOv5改进系列&#xff08;1&#xff09;——添加SE注意力机制 YOLOv5改进系列&#xff08;2&#xff09;——添加CBAM注意力机制 目录 &#x1f68…

【Linux】Redis高可用概述1(RDB和AOF的备份恢复)

在web服务器中&#xff0c;高可用是指服务器可以正常访问的时间&#xff0c;衡量的标准是在多长时间内可以提供正常服务 &#xff08;99.9%、99.99%、99.999% 等等&#xff09;。 但是在Redis语境中&#xff0c;高可用的含义似乎要宽泛一些&#xff0c;除了保证提供正常服 务(如…

优惠卷秒杀——分布式锁

在集群的模式下&#xff0c;有多个jvm&#xff0c;每个jvm内部有他自己的锁&#xff0c;导致并行执行存在线程安全问题 分布式锁&#xff1a;满足分布式系统或集群模式下多线程可见并且互斥的锁 基于Redis实现分布式锁 基于redis锁的初级版本 public interface ILock {/*** …

第十四届蓝桥杯C++--A组题解(更新中)

本来考场上做完想着这回图一乐&#xff0c;打打暴力混个省奖得了&#xff0c;看完民间题解感觉跟自己估计的差不多&#xff0c;应该挺寄的&#xff0c;没想到出分捡了个省一&#xff0c;喜提弱省省一倒数 这篇博客把自己会的题先放上来&#xff0c;其他的题慢慢补&#xff0c;好…

干翻Mybatis源码系列之第八篇:Mybatis提供的缓存方案细节注意

前言 Mybatis缓存设计成了两层的体系&#xff0c;第一层叫做一级缓存&#xff0c;第二层叫做二级缓存&#xff08;全局缓存&#xff09;。我们从这里可以看到Mybatis的缓存方案是有两种处理方式的。 一级缓存&#xff08;默认开启&#xff09; 一级缓存默认开启的&#xff0c…

[天翼杯 2021]esay_eval

[天翼杯 2021]esay_eval <?php class A{ #定义一个名为A的类public $code ""; #定义一个公共属性code function __call($method,$args){ #call魔术方法 当调用一个不存在的成员方法的时候触发eval($this->code); #将code的值以php代码执行 }function __w…

c高级day3作业

#!/bin/bash # 脚本名称:myfirstshell echo hello hostname ls -a .. echo $PATH echo $HOME df -h id -g hostname echo goodbye #!/bin/bash a(ls -l /etc | grep "^-" ) #/etc文件中普通文件 b(ls -l /etc | grep "^d" ) #/etc文件中一级目录文件 …

一篇了解智慧网关

智慧网关是指基于互联网技术的智能网关&#xff0c;能够连接不同的物联网设备和传感器&#xff0c;实现数据采集、信息传递、远程控制、通信管理等功能。作为物联网架构中的核心设备之一&#xff0c;智慧网关在智能家居、智慧城市、智能制造、智能交通、智能农业等领域得到了广…

solidworks三维建模竞赛练习题

solidworks三维建模竞赛练习题&#xff1a;3D01‐ 01 solidworks三维建模竞赛练习题&#xff1a;3D01‐ 02 solidworks三维建模竞赛练习题&#xff1a;3D01‐ 03 solidworks三维建模竞赛练习题&#xff1a;3D01‐ 04 solidworks三维建模竞赛练习题&#xff1a;3D01‐ 05 solidw…