写一个PE的壳_Part 5:PE格式修复+lief源码修改


系列汇总


用原教程中Part 4的py文件处理test.exe,生成名为packed_bug1.exe程序;运行时直接报错

在这里插入图片描述

下面给出了整个修复的思路

1.CFF查看

CFF看一下packed_bug1.exe,直观上会发现2处异常,导致PE格式解析出现问题

在这里插入图片描述

  • 异常1:Data Directory中的Import Directory没有识别

    构建程序会经历 unpacked.exe -> shifted_unpack.exe ->packed.exe的过程,packed.exe的header是shifted_unpack.exe的header的简单拷贝;CFF发现shifted_unpack.exe的header是正常的,说明问题应该不是出在这里

在这里插入图片描述

  • 异常2:Section Header中section table记录的信息错乱了

在这里插入图片描述

可以看到信息都被正确记录,但是解析时出现了错误,其他有用信息暂时没有,因为整体都是LIEF第三方库处理的

2.python再次加载

此时尝试用LIEF加载一下packed_bug1.exe试试(binary = lief.parse("C:\packed_bug1.exe")),发现报如下错误

在这里插入图片描述

SizeOfOptionalHeader的大小不对???

抓紧看一下packed_bug1.exe和shifted_unpack.exe的SizeOfOptionalHeader;果然不同,应该是0xE0才对,怎么少了8个bytes?

在这里插入图片描述

验证一下,给packed_bug1.exe的SizeOfOptionalHeader加上8个bytes试一下,在[step5].重新排列section中加入如下一行代码

在这里插入图片描述

再次构建一下,生成名为packed_bug2.exe的可执行文件(注意名字变了),发现异常1得到解决;异常2部分得到解决(Raw相关数据不对)

在这里插入图片描述


扩展:LIEF修改建议

  • 问题原因

[step5]中,使用output_PE = lief.PE.Binary("pe_from_scratch", lief.PE.PE_TYPE.PE32)生成一个空白的PE文件,里面有基本的header信息

LIEF产生的SizeOfOptionalHeader为什么会少8个bytes呢?

LIEF中Binary函数的源码截图如下,可以看到在计算sizeof_headers时,data directory的个数默认是15

如果你对PE文件格式熟悉,会知道这个data directory默认有16个(这个值可以修改,但是一般的带有PE查看器功能的软件都会默认使用16个);而一个data directory的元素大小就是8个bytes;因此找到了错误位置

下面是可执行文件的Optional Header中data directory个数的标识:

在这里插入图片描述

LIEF源码:

在这里插入图片描述

  • 修改建议

修改建议:直接将data directory个数改成16

可能隐患:因为我的环境LIEF不能构建,理论上这么改可以解决当前问题;既然LIEF是很多人使用的第三方库,这里写默认是15就一定有别的原因,暂时没有深究


3.异常2的Raw问题

下面是解决异常2中raw问题的主要处理思路

step 1:运行程序

假设没有看出异常2的Raw数据有问题,此时直接运行packed_bug2.exe,会报如下错误

在这里插入图片描述

step 2:调试器运行程序

x32dbg调试一下程序,直接运行程序,会报内存访问访问的错误(也就是俗称的“踩内存”),错误的位置是0x411001(记住这个位置,后面会用)

在这里插入图片描述

step 3:单步调试

单步调试,会发现在0x410079处有一个函数调用(调用的其实是mystrcmp),操作码是E8(后面地址是相对于当前地址的offset)

F7,进入函数发现反汇编解析出来不是一个函数正常起始汇编指令;继续一路F8,单步调试很快就会发现错在0x411001位置

在这里插入图片描述

0x410671处的机器码(50 72 6F 63 41 …)确实有问题,此时需要看一下二进制文件里,0x410671的位置的原始数据是什么?

step 4:CFF查看二进制

因为程序入口地址是0x410000(也是.text的起始地址),所以这个函数(packed_bug2.410671)的偏移地址应该是0x671,因此直接查看.text的起始地址中0x671的内容即可

在这里插入图片描述

.text的Raw Size的值是0x800(理论上0x671一定在里面),但是CFF查看时发现区段大小只有0x600为什么会没有显示全呢?

0x671 - 0x600 = 0x71,按理说数据应该在后面section中,下面验证一下猜想

.rdata大小只有0x40,小于0x71;最后,在.idata中的发现内容,但是.idata没有可执行权限,才会报内存访问访问的错误

在这里插入图片描述

CFF中查看的结果,验证了在这里插入图片描述
的产生的原因,根因还是Raw数据大小有问题导致.text区段大小显示异常导致的问题

step 5:查看LIEF源码

CFF中看到section的文件的起始地址有问题,python中操作section暂时只用了LIEF中的add_section函数,以这个函数作为突破口查看LIEF源码

add_section函数每次添加section,要做2件事

  • 1.检查setion前面的整个header中是否能放下一个section table?问题就出现在这里
  • 2.添加setion的具体操作,这里没有什么问题

分析源码前,先要对PE文件有一个基本的知识积累:PE中每个具体section在文件中的对齐默认是0x200

在这里插入图片描述

如果“DOS首部 + NT首部 + Section Table的大小”小于0x200,.text的起始地址是0x200;如果大于0x200 < 尺寸 <=0x400.text的起始地址是0x400

下面是源码中涉及到的关键部分:

在这里插入图片描述

源码中问题就出现在这里,当超过0x200时,能存放的个数available_sections_space_重新计算只是简单的加1;导致每次连续调用add_seciton时,会不断的平移整个已有的section,导致.alloc和后面的section一直被移动,最终section table整体错乱

step 6:解决办法

既然section table整体错乱,最终调用LIEF的build函数前,重新手动修改一下section table中相关raw数据,修改结果如下(这只是临时修改,可以用程序计算每个section大小进行动态指定大小会更好)

在这里插入图片描述

其中:名为.alloc的section的大小被设置为了0x200

step 7:结果验证

再次使用CFF查看raw相关数据,符合预期

在这里插入图片描述

运行程序也弹出了this is a test for compil with MinGW, no reloc,符合预期,说明不论是否支持ASLR的程序,我们现在都能处理了

step 8:源码修改建议

既然available_sections_space_计算有问题,直接在make_space_for_new_section函数修改如下:

available_sections_space_ = (0x200 - /* sizeof headers */ sizeof_headers) / sizeof(details::pe_section);

起始上面的公式是Binary函数的方法,部分截图:

在这里插入图片描述

4.参考

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值