写一个PE的壳_Part 5:PE格式修复+lief源码修改
系列汇总
- 写一个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源码修改相关推荐
- 写一个PE的壳_Part 2:ASLR+修复输入表(IAT)+重定位表支持(.reloc)
系列汇总 写一个PE的壳_Part 1:加载PE文件到内存 写一个PE的壳_Part 2:ASLR+修复输入表(IAT)+重定位表支持(.reloc) 写一个PE的壳_Part 3:Section里实 ...
- 15行Python代码能干嘛?能写一个抖音网页版的简易爬虫(附源码)
前言 随着互联网时代的到来,人们更加倾向于互联网购物,某宝又是电商行业的巨头,在某宝平台中有很多商家数据,今天带大家使用python+selenium工具获取这些公开的商家数据 环境介绍: pytho ...
- 写一个PE的壳_Part 3:Section里实现PE装载器
系列汇总 写一个PE的壳_Part 1:加载PE文件到内存 写一个PE的壳_Part 2:ASLR+修复输入表(IAT)+重定位表支持(.reloc) 写一个PE的壳_Part 3:Section里实 ...
- 写一个PE的壳_Part 4:修复对ASLR支持+lief构建新PE
系列汇总 写一个PE的壳_Part 1:加载PE文件到内存 写一个PE的壳_Part 2:ASLR+修复输入表(IAT)+重定位表支持(.reloc) 写一个PE的壳_Part 3:Section里实 ...
- 字符串右移n位,例如 “hello world“ 右移两位 后ldhello wor 要求写一个方法实现此功能,方法的格式是 String moveToRight(String str,int po
字符串右移n位,例如 "hello world" 右移两位 后ldhello wor 要求写一个方法实现此功能,方法的格式是 String moveToRight(String s ...
- 适合新手:从零开发一个IM服务端(基于Netty,有完整源码)
本文由"yuanrw"分享,博客:juejin.im/user/5cefab8451882510eb758606,收录时内容有改动和修订. 0.引言 站长提示:本文适合IM新手阅读 ...
- C++判断一个数字是否是某个数字的阶乘(附完整源码)
C++判断一个数字是否是某个数字的阶乘算法 C++判断一个数字是否是某个数字的阶乘算法完整源码(定义,实现,main函数测试) C++判断一个数字是否是某个数字的阶乘算法完整源码(定义,实现,main ...
- 高斯正算C语言程序,一个老师给的高斯投影正、反算c++源码(最新整理)
<一个老师给的高斯投影正.反算c++源码(最新整理)>由会员分享,可在线阅读,更多相关<一个老师给的高斯投影正.反算c++源码(最新整理)(4页珍藏版)>请在人人文库网上搜索. ...
- 一个可以在线解密qmc和ncm等音乐加密格式的网站源码
介绍 这是一个可以在线解密QQ音乐.网易云音乐付费音乐加密格式的网站源码. 由于程序编写使用了ES6语法,Blob,Web Worker特性,过旧的浏览器可能无法使用. 截图 特性 支持的格式 QQ ...
最新文章
- python 线程类 threading.Thread.run() 方法
- flask执行python脚本_如何在Flask中运行python脚本
- 修改centos默认启动级别为字符模式
- spring boot log4j2与三方依赖库log4j冲突无法初始化问题解决方法
- 我眼中的“SSD” ..update
- 文本属性之文本颜色(CSS、HTML)
- 27岁后月薪低于8K,会被淘汰吗?
- 表白代码(纯干货),送给你爱的人
- 2022-08-19 mysql/stonedb-索引优化专利交底书-改进点
- Java实现 LeetCode 69 x的平方根
- python爬虫获取html_python3爬虫获取html内容及各属性值的方法
- 这几个棘手的面试常见问题,如何高情商的回答?
- 上海康桥先进制造技术创业园项目-安科瑞苏月婷
- 【原创】超级详细的iPhone铃声制作、导入、设置全过程教程
- 来了,k8s!-----------------k8s集群部署
- Superl-url:一款开源关键词URL采集工具
- 车道线检测---色彩空间变换
- 微信小程序《沈航二手书》
- vue-cropper笔记
- LINUX下完全免费的P2P网络电视SopCast