写一个PE的壳_Part 2:ASLR+修复输入表(IAT)+重定位表支持(.reloc)


系列汇总



重要的事情说3遍:

笔记更新换位置了!
笔记更新换位置了!
笔记更新换位置了!

新位置:我写的新系列,刚开始写没几天,后续文章主要在新地址更新,欢迎支持;写作不易,且看且珍惜(点击跳转,欢迎收藏

Part 2:ASLR+修复输入表(IAT)+重定位表支持(.reloc)

本文主要处理Part 1中遗留的2张表:输入表和重定位表(执行一个ASLR使能的文件不会出错)

当前现状:Part 1中执行loader.exe C:\Windows\SysWOW64\calc.exe没有出现计算器,loader.exe没有处理C:\Windows\SysWOW64\calc.exe的输入表是一个主要原因

处理2个表前,最好先复习一下ASLR的相关知识

1.ASLR预备知识

ASLR(Address Space Layout Randomization,地址空间布局随机化)是一种针对缓冲区溢出的安全保护技术,从Vista开始支持;主要是使exe文件运行时加载到内存中的地址是随机的

  • 产生原因

没有ASLR前,一般情况下,exe文件都会加载在OS给分配的虚拟内存0x400000上,微软自己的DLL总会加载在固定的地址上,这给程序安全带来的很大的隐患;因此需要将PE文件每次加载到内存的地址进行随机化

  • 编译器支持

支持ASLR的前提是OS的内核版本必须是6以上,且编译工具必须支持/DYNMAICBASE;下面的界面中还可以设置PE文件的ImageBase(exe文件默认是0x400000,dll文件默认是0x10000000,默认值都是可以修改的)

在这里插入图片描述

  • .reloc节区

支持ASLR的PE文件多了一个名为.reloc的节区,一般情况下普通的exe文件不存在这个节区,开了ASLR技术的二进制才出现这个节区,是由编译器在编译时指定并保存在可执行文件中的

在这里插入图片描述

PE文件加载进入内存时,.reloc节区主要是做重定位参考的

  • PE header变化

File HeaderCharacteristics属性里,IMGE_FILE_RELOCS_STRIPPED不在支持ASLR时默认是勾选的,支持ASLR时不会勾选;增加ASLR的支持后,同一套源码产生的PE文件区段个数也会多一个

在这里插入图片描述

Optional HeaderDllCharacteristics属性里,IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE不在支持ASLR时默认是不勾选的,支持ASLR时会勾选(是否勾选不要与上面弄混了

在这里插入图片描述

题外话:逆向时,如果一个文件支持ASLR会给逆向增加难度,可以直接将Optional HeaderDllCharacteristics属性里的IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE删掉,这样就不支持ASLR了;这样程序每次运行都会加载到同一地址,方便分析

2.输入表支持

结论:输入表支持就是我们要自己遍历INT,给IAT填写真实内存地址的过程

detail 1:什么是输入表?

简单归纳:就是将程序使用的第三方库的函数放在一个表格里进行统一管理的表

一般情况下,当一个PE二进制用额外的库时,它通常将输入表存储在.idata区段;下面以一个ShellExecuteW(被calc.exe导入)函数为例,说明一下输入表

calc.exe要调用ShellExecuteW,是需要知道ShellExecuteW函数在内存中的位置的;dll文件只有在运行时才会加载进内存,因此在编译阶段,编译器是不知道ShellExecuteW在内存中的确切位置

输入表中的IAT就是为了解决上面的编译时运行时的矛盾的

  • 编译时:在调用ShellExecuteW的地方,ShellExecuteW使用的是中转地址,或者可以理解成指向输入表中的IAT
  • 运行时:当运行程序时,相应的dll文件被加载时,PE装载器会先将ShellExecuteW的真实地址在IAT保留;都处理完后,才会执行用户写的代码,此时执行ShellExecuteW就会通过IAT找到真正的加载地址

结论:PE被装载进入内存后,输入表中真正有用的只有IAT了

下面是x32dbg加载calc.exe的截图,可以看到输入表中IAT的身影

在这里插入图片描述

  • 位置1:外部call指令,调用的是外部模块(shell32.dll),call指令(用FF15操作码)的参数(38306700)来自于IAT,被ShellExecuteW标识;具体是用函数名还是用序号(ordinal)取决取IAT加载的方式
  • 位置2:内部call指令,编译器知道被调用函数的目的地址,因此用E8操作码(“realtive call”

输入表的基本知识介绍完了,下面使用CFF查看一下输入表在PE中的相关部分

detail 2:PE Header描述

输入表信息这么重要,PE头文件哪里描述呢?可以从Data Directories(是Optional Header的一部分)开始学习

在这里插入图片描述

目录的顺序是事先确定的,默认个数是16;与导入相关的有2个directories(都位于名为.idata的section里):

  • Import Directory:编号是01,指向“Import Directory Table” (IDT),告诉我们什么函数要被程序导入,即what
  • Import Address Table Directory:编号是12,指向“Import Address Table” (IAT),将要导入的函数的地址放在IAT里,即where

题外话:Part 4中会看到LIEF建立一个空白PE时,Data Directories数组的个数指定的是15,导致输入表不能识别

detail 3:真实的输入表

CFF查看IDT的内容如下:

在这里插入图片描述

每一个dll都有一个条目记录需要导入的函数,下面通过编程处理输入表

detail 4:编程处理

现在直接说编程处理输入表,估计还是会不知所云,因为还有最后一项没有介绍,即输入表需要的数据结构

数据结构

Data Directories中的Import Directory指向一个数组,数组里每个元素都是IMAGE_IMPORT_DESCRIPTOR的结构体,数组终止条件是一个全为0的IMAGE_IMPORT_DESCRIPTOR的结构

每一个DLL都用一个IMAGE_IMPORT_DESCRIPTOR的结构体进行描述,定义如下:

//每一个DLL都用一个 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值