工具说明
参照书籍:《Windows PE权威指南》;
使用工具:WinHex、CFF、OD、IDA、MSDN;
所需文件干净的PE文件,在[原创] 小试牛刀·手动构建HelloWorld弹窗可执行文件中有说明和附件下载;
本帖文件在附件中(文件密码:apebro
);
环境:Windows7 x86,没有开DEP(数据执行保护);
摘要
在跟一个大兄弟请教问题的时候,他说了一句让我虎躯一震的话:”jmp过去不需要那个节有可执行权限。“
这倒是一个有意思的说法,以前还真没怎么注意;
在经过询问后,得到可以写贴的答复;
以下探索有问题之处,还请大佬们指正;
探索开始
1、先复习一下节表结构(_IMAGE_SECTION_HEADER
);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | typedef struct _IMAGE_SECTION_HEADER
{
BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; / / 0x00
union {
DWORD PhysicalAddress; / / 0x08
DWORD VirtualSize; / / 0x08
} Misc;
DWORD VirtualAddress; / / 0x0c
DWORD SizeOfRawData; / / 0x10
DWORD PointerToRawData; / / 0x14
DWORD PointerToRelocations; / / 0x18
DWORD PointerToLinenumbers; / / 0x1c
WORD NumberOfRelocations; / / 0x20
WORD NumberOfLinenumbers; / / 0x22
DWORD Characteristics; / / 0x24
};
|
我们使用一个干净的PE文件,来查看一下例子;
本期重点在于最后一个字段Characteristics
;
- 我们查看《Windows PE权威指南》
P88
,一下它的字段设置规则;
以及书中总结:
1 2 3 4 5 6 7 | 0x00000020 / / 代码段
0x00000040 / / 已初始化数据区
0x00000080 / / 未初始化数据区
0x20000000 / / 可执行
0x40000000 / / 可读
0x80000000 / / 可写
|
所以,我们一共要考虑9种可能
2、在此之前,我们先给test1.exe
文件进行添加节(使用WinHex
);
在标出的位置是节数量,我们先根据页面可否读写先增加三个节。所以填0004
;
- 再在紧贴着
.text
节下面增加三个两行半(一个节有两行半的数据);
这里我们还要修改节区VirtualAddress
、PointerToRawData
参数;
- 因为文件最后一个节的起始地点是
0x00000800
,文件是0x200
对齐,所以要填充到0x000009FF
;
都已经添加进去了,美滋滋,这时候还没完,还需要改SizeOfImage
字段;
一个节占用一个页,一个页是0x1000
,还要加上头节,所以共0x5000
;
3、现在开始填充代码;
- 因为一些字段没有正确设置,所以直接拖进没有插件的OD可能无法成功,可以先运行然后尝试
attach
附加上去;
这就是上一帖子很熟悉的代码,我们尝试每个节区都放上这个MessageBoxA
代码;
- 所以我们先用
WinHex
把代码编码填充到每个节区的开头位置;
这是程序入口地址的代码,复制,填充到每个节区的开头;
然后保存到可执行test2.exe
文件,如何保存在上一贴有描述;
可以执行!
- 将入口点
0x00401080
处添加代码jmp 00403020
,跳转到read section
;
然后保存到可执行test3.exe
文件,如何保存在上一贴有描述;
- 将入口点
0x00401080
处添加代码jmp 00404020
,跳转到write section
;
然后保存到可执行test4.exe
文件,如何保存在上一贴有描述;
准备工作做了那么多,我们要开始实验了;
4、准备工作做了那么多,我们要开始实验了(使用WinHex
);
(1)看0x00000020
+0x20000000
,代码段可执行,使用test2.exe
;
可执行!
(2)看0x00000020
+0x40000000
,代码段可读,使用test2.exe
;
可执行!
(3)看0x00000020
+0x80000000
,代码段可写,使用test2.exe
;
可执行!
(4)看0x00000040
+0x20000000
,已初始化数据区可执行,使用test3.exe
;
可执行!
(5)看0x00000040
+0x40000000
,已初始化数据区可读,使用test3.exe
;
可执行!
(6)看0x00000040
+0x80000000
,已初始化数据区可写,使用test3.exe
;
可执行!
(7)看0x00000080
+0x20000000
,未初始化数据区可执行,使用test4.exe
;
可执行!
(8)看0x00000080
+0x40000000
,未初始化数据区可读,使用test4.exe
;
可执行!
(9)看0x00000080
+0x80000000
,未初始化数据区可写,使用test4.exe
;
可执行!
总结
由此可见,的确如此呀。
由此可以看出,操作系统在加载PE文件的细节问题;
我想起在C/C++中,对于const *str="hello world"
定义声明后,对于原位置不能更改(通过debug修改段属性可以更改),现在看来并不影响执行指令;
大概这也就是为啥看别人写的shellcode放在数组里却依旧能执行的原因吧;
实验文件我放在附件了,欢迎下载论证;
有大佬指出有环境的特殊性,我准备在后续写到内核时,续写这个话题;
感谢各位大佬指正;
欢迎大佬讨论指点;
[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法
最后于 2021-4-8 15:41
被平头猿小哥编辑
,原因: 上传文件