系列汇总

  • 写一个PE的壳_Part 1:加载PE文件到内存
  • 写一个PE的壳_Part 2:ASLR+修复输入表(IAT)+重定位表支持(.reloc)
  • 写一个PE的壳_Part 3:Section里实现PE装载器
  • 写一个PE的壳_Part 4:修复对ASLR支持+lief构建新PE
  • 写一个PE的壳_Part 5:PE格式修复+lief源码修改
  • 写一个PE的壳_Part 6:简单的混淆

文章目录

  • 1.CFF查看
  • 2.python再次加载
  • 3.异常2的Raw问题
    • step 1:运行程序
    • step 2:调试器运行程序
    • step 3:单步调试
    • step 4:CFF查看二进制
    • step 5:查看LIEF源码
    • step 6:解决办法
    • step 7:结果验证
    • step 8:源码修改建议
  • 4.参考

用原教程中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.参考

  • 1.Writing a PE packer – Part 4 : packing with no relocation

  • 2.02 - Create a PE from scratch — LIEF Documentation (lief-project.github.io)

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

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

    系列汇总 写一个PE的壳_Part 1:加载PE文件到内存 写一个PE的壳_Part 2:ASLR+修复输入表(IAT)+重定位表支持(.reloc) 写一个PE的壳_Part 3:Section里实 ...

  2. 15行Python代码能干嘛?能写一个抖音网页版的简易爬虫(附源码)

    前言 随着互联网时代的到来,人们更加倾向于互联网购物,某宝又是电商行业的巨头,在某宝平台中有很多商家数据,今天带大家使用python+selenium工具获取这些公开的商家数据 环境介绍: pytho ...

  3. 写一个PE的壳_Part 3:Section里实现PE装载器

    系列汇总 写一个PE的壳_Part 1:加载PE文件到内存 写一个PE的壳_Part 2:ASLR+修复输入表(IAT)+重定位表支持(.reloc) 写一个PE的壳_Part 3:Section里实 ...

  4. 写一个PE的壳_Part 4:修复对ASLR支持+lief构建新PE

    系列汇总 写一个PE的壳_Part 1:加载PE文件到内存 写一个PE的壳_Part 2:ASLR+修复输入表(IAT)+重定位表支持(.reloc) 写一个PE的壳_Part 3:Section里实 ...

  5. 字符串右移n位,例如 “hello world“ 右移两位 后ldhello wor 要求写一个方法实现此功能,方法的格式是 String moveToRight(String str,int po

    字符串右移n位,例如 "hello world" 右移两位 后ldhello wor 要求写一个方法实现此功能,方法的格式是 String moveToRight(String s ...

  6. 适合新手:从零开发一个IM服务端(基于Netty,有完整源码)

    本文由"yuanrw"分享,博客:juejin.im/user/5cefab8451882510eb758606,收录时内容有改动和修订. 0.引言 站长提示:本文适合IM新手阅读 ...

  7. C++判断一个数字是否是某个数字的阶乘(附完整源码)

    C++判断一个数字是否是某个数字的阶乘算法 C++判断一个数字是否是某个数字的阶乘算法完整源码(定义,实现,main函数测试) C++判断一个数字是否是某个数字的阶乘算法完整源码(定义,实现,main ...

  8. 高斯正算C语言程序,一个老师给的高斯投影正、反算c++源码(最新整理)

    <一个老师给的高斯投影正.反算c++源码(最新整理)>由会员分享,可在线阅读,更多相关<一个老师给的高斯投影正.反算c++源码(最新整理)(4页珍藏版)>请在人人文库网上搜索. ...

  9. 一个可以在线解密qmc和ncm等音乐加密格式的网站源码

    介绍 这是一个可以在线解密QQ音乐.网易云音乐付费音乐加密格式的网站源码. 由于程序编写使用了ES6语法,Blob,Web Worker特性,过旧的浏览器可能无法使用. 截图 特性 支持的格式 QQ ...

最新文章

  1. python 线程类 threading.Thread.run() 方法
  2. flask执行python脚本_如何在Flask中运行python脚本
  3. 修改centos默认启动级别为字符模式
  4. spring boot log4j2与三方依赖库log4j冲突无法初始化问题解决方法
  5. 我眼中的“SSD” ..update
  6. 文本属性之文本颜色(CSS、HTML)
  7. 27岁后月薪低于8K,会被淘汰吗?
  8. 表白代码(纯干货),送给你爱的人
  9. 2022-08-19 mysql/stonedb-索引优化专利交底书-改进点
  10. Java实现 LeetCode 69 x的平方根
  11. python爬虫获取html_python3爬虫获取html内容及各属性值的方法
  12. 这几个棘手的面试常见问题,如何高情商的回答?
  13. 上海康桥先进制造技术创业园项目-安科瑞苏月婷
  14. 【原创】超级详细的iPhone铃声制作、导入、设置全过程教程
  15. 来了,k8s!-----------------k8s集群部署
  16. Superl-url:一款开源关键词URL采集工具
  17. 车道线检测---色彩空间变换
  18. 微信小程序《沈航二手书》
  19. vue-cropper笔记
  20. LINUX下完全免费的P2P网络电视SopCast

热门文章

  1. 内网ssl证书颁发_使用SSL和开放源证书颁发机构消除垃圾邮件
  2. 植物识别库java_基于百度api的植物图片识别,人脸检测,人脸对比。
  3. 9.NBA球员数据分析
  4. html5怎么引入苹方简,css 引入苹方字体
  5. 十句话,不黄不色,但很经典~~~~~~~~~~
  6. 我的csdn博客所有的留言和评论我都不太想回复了
  7. 独立开发的基于springboot + websocket IM网站聊天系统总结
  8. vue关于时间顺序排序
  9. 从零开始的ESP8266探索(11)-定时任务调度器Ticker使用演示
  10. 按位寻址与按字节寻址的区别