在理解二进制文件(虚拟内存布局,执行等)的过程中,我编写了一个C
代码,声明了一个包含可执行代码字节的全局字符串,然后我覆盖了返回通过在main()
中声明指针(PTR
)使用简单技巧从main()
函数到该可执行代码的地址,该指针是在堆栈2上保留的本地内存区域。来自main()
的返回地址,所以我所做的就是将返回地址的地址分配给该指针(PTR=(int*)&PTR+2)
,然后用可执行代码的地址(静态字符串)覆盖该地址的内容)。
现在的困境是,每当我编译并执行时,我都会收到分段错误。
可执行代码没有内存input/output
(它只是一堆NOPs
)。
使用GDB我确保过程完美地工作:返回地址被更改为字符串的地址但返回从未发生。
我所知道的是可执行文件代码映射到虚拟内存中的页面thar标记为RW
(.data
& .bss
段)所以除非代码注入{{{}},否则可能无法执行此类代码执行1}}内存区域(标记为executable
的页面)。这是我关于这个主题的理论,我邀请你提供更多细节。
RE
答案 0 :(得分:2)
我收到分段错误。
它是数据执行预防的硬件控制(https://en.wikipedia.org/wiki/Executable_space_protection#Linux) - 如果没有' x'那么你就不能跳转到数据页面。 (执行)在页表中设置的位。所有位的内存映射在/proc/$pid/maps
/ /proc/$pid/smaps
文件中列为' rwx'对于可写代码,' rw - '对于没有执行的数据,' r - '对于只读数据,' r-x'对于普通代码。
如果要执行数据,则应在要成为代码的数据部分调用带有mprotect
标记的PROT_EXEC
系统调用。
在x86世界中,这完全实现为奔腾4(Prescott)中的"NX bit" / "XD bit" feature和更新(Core,Core2,Core i *,核心m)/ Athlon 64 / Opteron及更新版本。如果OS在32位模式下工作,则必须打开PAE才能在页表中使用该位。在x86_64模式(64位)中,始终支持NX / XD位。
2004年左右,Linux的第一个支持变种被添加到http://linuxgazette.net/107/pramode.html
2007年,您可能已经过时了没有PAE的硬件,旧内核或32位模式内核。
有关NX / XD位的信息:https://en.wikipedia.org/wiki/NX_bit
有时' rwx'模式可能被禁止,请检查https://en.wikipedia.org/wiki/W^X。
对于pre-NX系统,存在基于x86的段寄存器的解决方案,以部分禁用部分内存空间执行。
我可以执行上面的程序而不会出现分段错误吗?
你可以:
mprotect
PROT_READ|PROT_EXEC
,使数据页可执行
ld
个脚本 - 默认位于ld --verbose
)execstack