我正在研究这个c程序。我在64位x64 linux上用gcc编译它:
#include <stdio.h>
char buffer[]={0x90,0x90,0xC3};
int main(int argc, char *argv[])
{
void (*fct)();
fct=buffer;
fct();
return 0;
}
0x90操作码是NOP
0xC3操作码是RET
我想知道我应该怎么做才能运行这个程序。运行时我遇到了段错误...
谢谢
TL; DR与-z execstack
编译
该程序是错误的,因为buffer
符号进入.data
部分,然后与其他部分一起进入映射读写但不可执行的ELF段。
要使buffer
可执行文件最好的做法是使用标志RWE创建一个新的ELF段并为其分配一个新的部分,然后告诉GCC将buffer
放入这个新的部分。
原则上可以使用以下链接器脚本完成此操作:
PHDRS
{
MYSEG PT_LOAD FLAGS (7);
}
SECTIONS
{
MYSECT : { *(MYSECT) } : MYSEG
}
,改变来源:
#include <stdio.h>
char buffer[] __attribute__ ((section ("MYSECT"))) ={0x90,0x90,0xC3};
int main(int argc, char *argv[])
{
void (*fct)();
fct=buffer;
fct();
return 0;
}
并编译通过-T
切换到GCC。
但这不起作用。
GCC使用基于命令行的默认链接描述文件,-T
开关完全替换它。
可以使用-Wl,-verbose
获取GCC使用的脚本并更新它。
如果我们通过首先使用-c
然后LD调用GCC来拆分编译和链接,我们只得到一个段,因为这是我们在链接器脚本中放置的 - 从而使我们所有努力只使buffer
成为唯一的可执行数据。
使用-z execstack
,我们实际上只告诉GCC使用设置GNU_STACK
ELF段RWE的链接描述文件。
这是加载程序用于设置堆栈页面的正确权限的标记段(大小和lma为零)。
But in truth it is used as a compatibility switch - 当堆栈设置为可执行文件时,加载程序会将所有可写页面设置为可执行文件。
如果你正在使用shellcodes -z execstack
会让它变得简单,但它会让你的应用程序受到大量攻击,但我想这首先是你需要的。