当前位置: 首页 > news >正文

免杀笔记 ---> PE

本来是想先把Shellcode Loader给更新了的,但是涉及到一些PE相关的知识,所以就先把PE给更了,后面再把Shellcode Loader 给补上。

声明:本文章内容来自于B站小甲鱼

1.PE的结构

首先我们要讲一个PE文件,就得知道它的结构,可以参考下面的这张照片

2.DOS头部

首先一个PE文件,就是它的DOS结构。 其中,需要我们去了解的,就是一开始的那个DOS标记以及我们执行的PE文件头

那么我们随便打开一个EXE来看一下。我门可以看见标志性的MZ

然后我们直接定位到3C这个位置,这里指向PE文件的头(写死的)  

可以看见在这个PE文件中,它的PE开始是在80这个位置

于是我们就去到80这个位置

3.IMAGE_NT_HEADERS

1.Signature

这个字段,是用来标志着这是一个真正的PE文件,从上面,我们跳到了这里,就能看见我们的Signature标识字段。

2.IMAGE_FILE_HEADER

这个结构如下

其中重要的,就是SizeOfOptionalHeader这个值,这个就决定了后面的IMAGE_OPTIONAL_HEADER32的大小

3.IMAGE_OPTIONAL_HEADER32

其中一些比较重要的结构

  • AddressOfEntryPoint 程序执行入口RVA  在偏移值为28的地方 

我们去那个偏移位置找一找(相对于PE头的偏移)DWORD类型 ,指向的是我们的14C

  • ImageBase

  • SectionAlignment和FileAlignment字段

其中FileAlignment默认是200,我们自己去PE文件找找是不是这么回事(它的偏移地址是3C)

而且他是DWORD类型,四个字节,我们在对应的地方确实是能看到是200!! 

  • DataDirectory(数组)

其实可以这样子理解  他定义了一个长度为16的数组,然后数组的每一个元素都是一个结构,这个结构里面都存储了两个元素,一个就是数据的起始RVA,另外一个就是数据块的长度

数组中的有些元素十分的重要(导入表,导出表,资源,重定位表,IAT表

当我们需要寻找特定的资源的时候,我们就可以去找到这个数组的第三个元素,获取到对应的RVA以及长度,当我们要查看PE文件导入了哪些DLL的API的时候,我们就可以去导入表里面获取RVA(Relative Virtual Address)和长度!!!!  

4.区块

接下来就是块表,首先他是这么一个结构

然后,我们来看name,像这种以.开头的(当然这个.不是必须的)

接下来就是相应的一些结构,比较重要一点的就是PointerToRawData 和 SizeOfRawData ,通过这两个,我们就能找到下一个块表的位置

除此,还有一个比较重要,这个标定了该区块的属性!!!

最后的判断,是通过存在的属性进行OR的操作判断的,比如我们看到它的characteristic是6000000的话,我们就知道是通过20(Code) OR 20000000(Execute) OR 40000000(Read) == (60000020)  这样就能判断这个对应的属性

对于区块,一般都有以下的类型

然后就是区块的对对齐

RVA

相对虚拟地址

目标RVA和文件偏移的计算

在处理PE文件的时候,任何的RVA必须经过文件的偏移的换算,才能用来定位并访问文件中的数据。

  1. 首先,我们要循环扫描每个区块在内存中的起始RVA,并且根据区块的大小,算出区块的结束RVA,判断目标的RVA是否落在该区块内
  2. 然后通过获取到了目标区块之后,用目标RVA减去起始的RVA,这样就得到了目标RVA相对于起始地址的偏移量RVA2
  3. 最后,根据该区块表在文件中所处的偏移地址,将这个值加上RV2,就得到了文件的偏移地址!!!

假设我们有一个虚拟地址666666,那么我们就要去区块中查找

通过定位,我们可以发现他在.reloc这个区块中

那么RVA2 = 666666 - 66000 = 666,然后我们看到这个区块在文件中的偏移地址在60E00

所以我们这个虚拟地址在物理内存中的地址就是60E00 + 666 = 61466 

5.导入表

说到导入表,我们肯定不会陌生,我们在一开始的PE头中,就讲过一个IMAGE_OPTIONAL_HEADER里面有一个特别重要的DataDirectory这个地方,里面放着我们的导入表!!!!

其中的第二个成员就是导入表,如果我们跳转到它的RVA之后,我们就能看见一个以IMAGE_IMPORT_DESCRIPTOR(简称IID)的数组开始的,每一个被加载进来的DLL文件都分别对应一个IID数组结构,当我们看到一个IID全为0的时候,就代表结束!!!!


对于每一个IID,它的结构如下:

它的长度为5个DWORD,其中重要的两个就是我们的FirstTrunk 和 OriginalFirstTrunk

6.IAT &&  IMAGE_IMPORT_BY_NAME

终于,我们学免杀要学的IAT表终于要出现了!!!!  不过在此之前,我们先来看一张图片

其中能看见IID的第一个DWORD OriginalFirstTrunk指向了INT表的IMAGE_THUNK_DATA

然后DWORD FirstThunk 指向了IAT表中的IMAGE_THUNK_DATA ,并且这两个都指向了IMAGE_IMPORT_BY_NAME这个表

其中,对于我们的IMAGE_THUNK_DATA

然后就是IMAGE_IMPORT_BY_NAME

IAT(Import Address Table)导入地址表

那么下面,我们就来举个栗子演示一下:

首先我们来找一个程序,直接看他的DataDirectory中的导入表的地址

然后定位到块中的 .idata中

我们可以追踪到之后发现它存在两个IID,即调用了两个动态连接库

并且我们去查看第一个IID的Original_First_Thunk,指向的是INT表中的IMAGE_THUNK_DATA,并且这个值是2A15C,但是这是一个RVA,所以我们要找到它的实际偏移我们用这个RVA减去.idata块的RVA 得到的RVA2再加上Raw Data offs 就是我们的实际偏移地址,2815C

然后又找到一个02A2DC ,我们在上面说过,如果开头是0的话,它的值是RVA,指向一个IMAGE_IMPORT_BY_NAME,所以,我们就还要去找282DC这个地方

这样,我们就找到了我们的真正的函数的地址(在此期间指针指向了两次),来看这么一个图(第一个盒子里面是ORIGINAL_FIRST_THUNK一开始写错了)

那么刚才我们讲了通过OriginalFirstThunk找,那么现在我们通过FirstThunk查找

首先还是找到iid中的FirstThunk,然后转换为实际偏移地址就是282AC

然后我们就去282AC,找到指向的实际偏移地址是282DC

然后再去282DC处找,发现282dc处也能找到我们的这个函数的真实位置

过程如下

然后我们去让这个程序运行起来,并且将他的内存dump出来,然后再去跟踪它的导入表

这时候我们再去跟踪IAT表,282AC这个部分。终于,我们就找到了这个函数的真正的地址

这时候,我们的IAT表就是这样的了(在内存中,IAT表不在需要通过名字索引,而是通过地址了)

然后本次的PE文件就到这了,当然了PE文件远不止这些,导入表,重定位表,资源等等,当日后在免杀中用到的时候,我们再相应进行更新。

下一篇Blog,我们就会更新对应的Shellcode Loader了!!!!

相关文章:

  • 私域和社群的差别是什么?
  • FFT 简单基础(matlab
  • 扫描工具Metasploit的安装和使用
  • 设置Docker中时区不生效的问题
  • UDP协议深入解析
  • 系统级应用锁的实现方法
  • 评估指标rouge安装与测试
  • 恢复机制-数据库系统中的故障(事务故障、系统故障、介质故障)、一致性错误、窃取但不强制的缓冲区管理策略
  • 零知识学习之DPDK与RDMA(3)—— 认识DPDK(3)
  • 阿里云物联网应用层开发:第二部分,云产品流转
  • vue2由mapbox2升级为mapbox3遇到的矢量底图样式丢失问题解决办法
  • 马工程刑法期末复习笔记重点2
  • C++: 左值引用和右值引用
  • 初入Node.js必备知识
  • 安卓请求服务器[根据服务器的内容来更新spinner]
  • 78. Subsets
  • el-input获取焦点 input输入框为空时高亮 el-input值非法时
  • gcc介绍及安装
  • golang 发送GET和POST示例
  • JAVA 学习IO流
  • Java,console输出实时的转向GUI textbox
  • js 实现textarea输入字数提示
  • JS+CSS实现数字滚动
  • OpenStack安装流程(juno版)- 添加网络服务(neutron)- controller节点
  • Python 基础起步 (十) 什么叫函数?
  • Swift 中的尾递归和蹦床
  • tweak 支持第三方库
  • 初识 webpack
  • 你真的知道 == 和 equals 的区别吗?
  • 判断客户端类型,Android,iOS,PC
  • 前端之React实战:创建跨平台的项目架构
  • 设计模式走一遍---观察者模式
  • 收藏好这篇,别再只说“数据劫持”了
  • 手机app有了短信验证码还有没必要有图片验证码?
  • 腾讯大梁:DevOps最后一棒,有效构建海量运营的持续反馈能力
  • 体验javascript之美-第五课 匿名函数自执行和闭包是一回事儿吗?
  • 项目实战-Api的解决方案
  • 一起参Ember.js讨论、问答社区。
  • raise 与 raise ... from 的区别
  • 我们雇佣了一只大猴子...
  • ​软考-高级-系统架构设计师教程(清华第2版)【第1章-绪论-思维导图】​
  • (1)Jupyter Notebook 下载及安装
  • (12)Hive调优——count distinct去重优化
  • (20050108)又读《平凡的世界》
  • (2024,Flag-DiT,文本引导的多模态生成,SR,统一的标记化,RoPE、RMSNorm 和流匹配)Lumina-T2X
  • (delphi11最新学习资料) Object Pascal 学习笔记---第8章第2节(共同的基类)
  • (k8s中)docker netty OOM问题记录
  • (教学思路 C#之类三)方法参数类型(ref、out、parmas)
  • (每日持续更新)信息系统项目管理(第四版)(高级项目管理)考试重点整理第3章 信息系统治理(一)
  • (十七)devops持续集成开发——使用jenkins流水线pipeline方式发布一个微服务项目
  • (四)Linux Shell编程——输入输出重定向
  • (算法)N皇后问题
  • (一)硬件制作--从零开始自制linux掌上电脑(F1C200S) <嵌入式项目>
  • (转)Oracle 9i 数据库设计指引全集(1)
  • .NET CF命令行调试器MDbg入门(三) 进程控制