PE文件笔记九 实战之HOOK程序添加弹窗续
继续PE系列笔记的更新PE其它笔记索引可前往:
(https://www.52pojie.cn/thread-1391994-1-1.html)
------
在前面的(https://www.52pojie.cn/thread-1408866-1-1.html)中能够使用OD达到在运行态时添加弹窗的功能,接下来则要对先前的反汇编的硬编码稍作修改然后插入到PE文件中,最后再修改入口点即可;具体流程在上个笔记已经说明了,这里不再赘述
# PE实战之给程序添加弹窗续
## 最终效果图
先看一下最终的效果图
![弹窗](https://610-pic-bed.oss-cn-shenzhen.aliyuncs.com/弹窗.gif)
------
## 反汇编和硬编码的对应关系
因为后面要将反汇编代码转换为硬编码,于是这里就要研究一下两者的对应关系
先贴上先前得到的反汇编代码
```c
00401130 > 6A 00 push 0x0
00401132 68 52114000 push MessageB.00401152
00401137 68 48114000 push MessageB.00401148
0040113C 6A 00 push 0x0
0040113E E8 A7F69477 call user32.MessageBoxA
00401143 - E9 8801C4FF jmp 000412D0
00401148 6c db 6c
........
```
------
### push对应硬编码
压入的第一个和第四个参数是一个**立即数**0,于是它对应的硬编码固定为6A 00
```assembly
00401130 > 6A 00 push 0x0
0040113C 6A 00 push 0x0
```
前面的6A是固定的,表示压入一个立即数,
后面的字节码表示压入的立即数,该立即数 的范围是0~0x7F即0~127
当立即数大于0x7F后硬编码和其含义就都改变了
```assembly
6A 7F push 0x7F
68 80000000 push 0x80
```
于是得到了**push 立即数 对应的硬编码为6A 立即数**
------
压入的第二个和第三个参数是**内存地址**0x00401152中存储的数据和0x00401148中存储的数据
```assembly
00401132 68 52114000 push MessageB.00401152
00401137 68 48114000 push MessageB.00401148
```
观察硬编码和压入的地址的关系
前面的68是固定的,表示push 一个内存地址
后面的则是要push的内存地址的小端存储,倒过来看就是压入的内存地址了
举个例子,如果push 的内存地址为0x12345678
则其对应的硬编码为 68 78 56 34 12
```assembly
68 78563412 push 0x12345678
```
于是得到了**push 内存地址 对应的硬编码为 68 内存地址的小端存储**
------
### call对应硬编码
接下来就是调用MessageBoxA了,其形式为:call MessageBoxA对应的**内存地址**
```assembly
0040113E E8 A7F69477 call user32.MessageBoxA
上面为OD的反汇编引擎为方便我们观看,而显示的内容,下面才是实际的反汇编代码
0040113E E8 A7F69477 call 77D507EA
```
分析call 内存地址 和 硬编码的关系
前面的E8是固定的,表示**直接**调用一个内存地址
后面的则是偏移,该偏移为小端存储,此时值为:0x7794F6A7
不难发现这个**偏移 = call的内存地址 - 当前的内存地址 - 当前指令的总长度**
即 0x7794F6A7 = 0x77D507EA - 0x0040113E - 5
再举个例子,如果当前要跳转的内存地址为0x12345678
则其对应的 偏移 = 0x12345678 - 0040113E - 5 = 11F44535
```assembly
0040113E E8 3545F411 call 12345678
```
于是得到了**call 内存地址 对应的硬编码为 E8 偏移的小端存储,其中偏移 = 要调用的内存地址 - 当前的内存地址 - 当前指令的总长度**
------
### jmp对应硬编码
```assembly
00401143 - E9 8801C4FF jmp 000412D0
```
前面的E9是固定的,表示跳转到一个内存地址
后面的也是偏移,该偏移为小端存储,此时值为:0xFFC40188
偏移 = jmp的内存地址 - 当前的内存地址 - 当前指令总长度
即 0xFFC40188 = 0x000412D0 - 0x00401143 - 5
于是得到了**jmp 内存地址 对应的硬编码为 E9 偏移的小端存储,其中偏移 = 要跳转的内存地址 - 当前的内存地址 - 当前指令总长度**
## 寻找空白区
知道了硬编码如何构造以后,就要在PE文件中找一块空白区,向里面写入要执行的硬编码
有了先前(https://www.52pojie.cn/thread-1393291-1-1.html)的知识,可以知道由于文件对齐,在块表和块之间是存在空隙(空白区)的,于是可以向这块区域写入硬编码
这次用来演示的软件是前面经常出场的EverEdit.exe,直接找到其对应的空白区:
!(https://610-pic-bed.oss-cn-shenzhen.aliyuncs.com/image-20210403135440893.png)
------
## 构造硬编码
找到空白区的地址为0x2B0,注意此时的地址为文件中的状态
在内存中其对应的地址为ImageBase+0x2B0 = 0x00400000+0x2B0 = 0x004002B0
PS:如果选取的空白区为块中的空白区,则需要进行FOA到VA的转换,相关内容在(https://www.52pojie.cn/thread-1408576-1-1.html)已说明,这里不再赘述
!(https://610-pic-bed.oss-cn-shenzhen.aliyuncs.com/image-20210403141604370.png)
------
于是从这里开始构造硬编码
根据前面反汇编一行一行来构造硬编码
```assembly
00401130 > 6A 00 push 0x0
00401132 68 52114000 push MessageB.00401152
00401137 68 48114000 push MessageB.00401148
0040113C 6A 00 push 0x0
0040113E E8 A7F69477 call user32.MessageBoxA
00401143 - E9 8801C4FF jmp 000412D0
00401148 6c db 6c
```
------
### push 参数
1.push 0 直接用6A 00填充,无需修改
2.push 内存地址,该内存地址存储第二个参数"tips",因为内存地址尚未填充,先用00代替,为 68 00 00 00 00
3.push 内存地址,该内存地址存储第三个参数"lyl610abc",同样先用00代替,为 68 00 00 00 00
4.push 0 直接用6A 00填充,无需修改
于是得到的硬编码为:6A 00 68 00 00 00 00 68 00 00 00 00 6A 00,将其写入文件中:
```
6A00680000000068000000006A00
```
!(https://610-pic-bed.oss-cn-shenzhen.aliyuncs.com/image-20210403142658934.png)
------
### call MessageBoxA
call 内存地址,要call的内存地址为MessageBoxA对应的地址,在本机中为0x77D507EA
此时的内存地址为ImageBase+0x2BE= 0x004002BE
于是可以算出 偏移 = 要跳转的地址 - 内存地址 - 当前指令总长度 = 0x77D507EA - 0x004002BE -5 = 0x77950527
于是得到的硬编码为 E8 27 05 95 77,将其写入文件中:
```
E827059577
```
!(https://610-pic-bed.oss-cn-shenzhen.aliyuncs.com/image-20210403143107638.png)
------
### jmp 程序入口点
所谓的程序入口点就是 扩展PE头中的AddressOfEntryPoint + ImageBase得到的内存地址
在先前的(https://www.52pojie.cn/thread-1405930-1-1.html#37759493_addressofentrypoint)中其实已经看过了,这里再用PE工具:Detect It Easy查看一下:
!(https://610-pic-bed.oss-cn-shenzhen.aliyuncs.com/image-20210403143747806.png)
------
可以得到AddressOfEntryPoint 为0x16AF12,加上ImageBase得到0x56AF12
于是要跳转的地址就是0x56AF12,对应汇编为 jmp 0x56AF12
此时的内存地址为ImageBase+0x2C3 = 0x004002C3
偏移 = 要跳转的地址 - 此时的内存地址 - 当前指令的总长度 = 0x56AF12 - 0x004002C3 - 5 = 0x0016AC4A
于是得到对应的硬编码为 E9 4A AC 16 00,将其写入文件中:
```
E94AAC1600
```
!(https://610-pic-bed.oss-cn-shenzhen.aliyuncs.com/image-20210403144457310.png)
------
填充字符串ASCII码
| 参数 | 含义 | 字符串 | ASCII | 文件中起始地址 | 内存中起始地址 |
| ---------- | -------- | --------- | -------------------- | -------------- | -------------- |
| 第三个参数 | 窗口内容 | lyl610abc | 6C796C36313061626300 | 2C8 | 004002C8 |
| 第二个参数 | 窗口标题 | tips | 7469707300 | 2D2 | 004002D2 |
填充完如下:
!(https://610-pic-bed.oss-cn-shenzhen.aliyuncs.com/image-20210403150527290.png)
------
### 修正参数
填充完字符串就可以修正参数了
第二个参数 为 push0x004002D2,对应"tips",对应硬编码为68 D2 02 40 00
```
68D2024000
```
第三个参数为push0x004002C8,对应"lyl610abc",对应硬编码为68 C8 02 40 00
```
68C8024000
```
修正完的结果为:
!(https://610-pic-bed.oss-cn-shenzhen.aliyuncs.com/image-20210403150921982.png)
------
### 所有的硬编码
```
6A0068D202400068C80240006A00E827059577E94AAC16006C796C363130616263007469707300
```
------
## 修改程序入口点
构造完硬编码后,只要将程序入口点改为硬编码的首地址:0x2B0即可
### 找到原本的程序入口点
!(https://610-pic-bed.oss-cn-shenzhen.aliyuncs.com/image-20210403151245859.png)
------
### 修改程序入口点
!(https://610-pic-bed.oss-cn-shenzhen.aliyuncs.com/image-20210403151407916.png)
------
## 保存程序并测试运行
最后便是将程序保存,然后打开
### 保存
我这里另存为了EverEdit2.exe
!(https://610-pic-bed.oss-cn-shenzhen.aliyuncs.com/image-20210403151545013.png)
------
### 测试运行
![弹窗](https://610-pic-bed.oss-cn-shenzhen.aliyuncs.com/%E5%BC%B9%E7%AA%97.gif)
可以看到能够成功地为程序添加弹窗,完毕(~ ̄▽ ̄)~
# 说明
测试的系统**务必为32位的XP系统**,在高版本的系统有**DEP和ASLR**等**保护机制**,使用以上方法修改后**无法运行**
上面的MessageBoxA的地址是**用OD获取的**,具体方法见上一篇笔记,如果想要复现为程序添加弹窗,则**要修改对应的MessageBoxA的地址**
# 附件
附上本笔记中要修改的EverEdit文件:[点我下载](https://610-pic-bed.oss-cn-shenzhen.aliyuncs.com/EverEdit.zip?versionId=CAEQHhiBgID6g6vXxBciIDMxMjY5Y2Q0NGE5NTRkNmNiNTUwOGM0YjdmZTQxMTI3) aswcy815174418 发表于 2021-4-3 20:18
测试的系统务必为32位的XP系统?
我修改程序入口后程序直接c0000007b报错,我程序入口改到其他空白区就能 ...
因为我这里的空白区取的是节表和节之间的空白区,可能是不具备对应的可执行权限
一般来说是要取的空白区是具备权限的、在节和节之间的那片空白区 aswcy815174418 发表于 2021-4-3 20:37
经验+1,坐等扩大节
我特地修改为节和节之间具备权限的空白区后去测试了,在WIN10 x64上没有c0000007b报错了
但由于ASLR(地址随机化)的原因 无法push直接的内存地址了,只能改为全部改为push 0,然后修正一下MessageBoxA的地址即可正常运行了:
运行结果:
taotianc 发表于 2021-4-6 18:13
只有XP才能运行吗
因为高版本系统有 ASLR(地址随机化)和DEP(数据执行保护) 两种系统保护机制
由于地址的随机化,和插入代码权限不匹配的原因是无法执行的
并且不同系统的MessageBoxA是不同的,这次添加的弹窗的代码是一种伪ShellCode
很多内容要到后面才好说明,这次的例子主要是为了巩固PE知识,也就不再继续深入了 测试的系统务必为32位的XP系统?
我修改程序入口后程序直接c0000007b报错,我程序入口改到其他空白区就能打开 lyl610abc 发表于 2021-4-3 20:29
因为我这里的空白区取的是节表和节之间的空白区,可能是不具备对应的可执行权限
一般来说是要取的空白区 ...
经验+1:lol:lol,坐等扩大节 aswcy815174418 发表于 2021-4-3 20:37
经验+1,坐等扩大节
先前我所写的RVA和FOA的转换有些错误,正在改正,也在补充FOA转RVA的内容{:301_977:} 类似的文章读过一次。用到的时候找不到。我总是不肯下功夫。 哎,汇编真是好东西啊 好东西收藏~~~~ 大佬是用吾爱的那个xp虚拟机来写代码的、?我记得爱盘里面有一个吾爱的xp的虚拟机镜像。里面很多工具和环境。