当项目中包含汇编文件时,mmap 出现意外的执行权限
- 2024-10-14 08:40:00
- admin 原创
- 93
问题描述:
我正为此而撞墙。
在我的项目中,当我使用mmap
映射分配内存时(/proc/self/maps
)显示它是一个可读和可执行的区域,尽管我只请求可读内存。
在研究了 strace(看起来不错)和其他调试之后,我能够确定似乎可以避免这个奇怪问题的唯一方法:从项目中删除汇编文件并只留下纯 C。(什么?!)
这是我奇怪的例子,我正在使用 Ubunbtu 19.04 和默认 gcc。
如果您使用 ASM 文件(为空)编译目标可执行文件,则mmap
返回可读和可执行区域,如果您不使用 ASM 文件进行构建,则其行为正确。请参阅/proc/self/maps
我在示例中嵌入的输出。
例子.c
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
int main()
{
void* p;
p = mmap(NULL, 8192,PROT_READ,MAP_ANONYMOUS|MAP_PRIVATE,-1,0);
{
FILE *f;
char line[512], s_search[17];
snprintf(s_search,16,"%lx",(long)p);
f = fopen("/proc/self/maps","r");
while (fgets(line,512,f))
{
if (strstr(line,s_search)) fputs(line,stderr);
}
fclose(f);
}
return 0;
}
example.s:是一个空文件!
输出
包含 ASM 的版本
VirtualBox:~/mechanics/build$ gcc example.c example.s -o example && ./example
7f78d6e08000-7f78d6e0a000 r-xp 00000000 00:00 0
不包含 ASM 的版本
VirtualBox:~/mechanics/build$ gcc example.c -o example && ./example
7f1569296000-7f1569298000 r--p 00000000 00:00 0
解决方案 1:
Linux 有一个执行域,称为READ_IMPLIES_EXEC
,这会导致所有分配了 的页面PROT_READ
也被赋予PROT_EXEC
。较旧的 Linux 内核曾经将其用于使用 等效项的可执行文件gcc -z execstack
。此程序将显示它是否已为其自身启用:
#include <stdio.h>
#include <sys/personality.h>
int main(void) {
printf("Read-implies-exec is %s
", personality(0xffffffff) & READ_IMPLIES_EXEC ? "true" : "false");
return 0;
}
如果您将其与空.s
文件一起编译,您将看到它已启用,但如果没有,它将被禁用。它的初始值来自二进制文件中的 ELF 元信息。执行readelf -Wl example
。当您在没有空文件的情况下进行编译时,您将看到此行.s
:
GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0x10
但是当你用它编译时:
GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RWE 0x10
注意,RWE
不要只使用RW
。这样做的原因是,除非明确告知链接器不需要,否则链接器会假定您的汇编文件需要 read-implies-exec,并且如果程序的任何部分需要 read-implies-exec,则将为整个程序启用它。GCC 编译的汇编文件会用以下行(如果您使用 进行编译,则会看到此行)告诉它不需要此功能-S
:
.section .note.GNU-stack,"",@progbits
默认部分权限不包括 e ec。请参阅文档x
的 ELF 部分以了解“标志”和 @attributes 的含义。.section
(如果您依赖于文件顶部的默认部分,请不要忘记在该指令之后切换到另一个部分,如.text
或。).data
`.section.s
.text`
把该行放入(以及项目中的example.s
每个其他文件)。该部分的存在将告诉链接器此目标文件不依赖于可执行堆栈,因此链接器将使用元数据,而不是元数据,然后您的程序将按预期工作。.s
`.note.GNU-stackRW
RWE`GNU_STACK
类似地,对于 NASM,section
具有正确标志的指令指定不可执行堆栈。
5.4 和 5.8 之间的现代 Linux 内核改变了ELF 程序加载器的行为READ_IMPLIES_EXEC
。对于 x86-64,什么都不再起作用。最多(通过GNU_STACK
添加RWE ld
),您将获得可执行的堆栈本身,而不是每个可读页面。(此答案.data
涵盖了 5.8 中的最后一个更改,但在此之前肯定还有其他更改,因为该问题显示在x86-64 Linux 5.4上成功执行了代码)
exec-all
( READ_IMPLIES_EXEC
) 仅发生在旧版 32 位可执行文件中,其中链接器根本没有添加GNU_STACK
标头条目。但如此处所示,现代ld
总是通过一种设置或另一种设置添加该条目,即使输入.o
文件缺少注释。
您仍应使用此.note
部分来在正常程序中发出不可执行堆栈的信号。但是,如果您希望在测试 shellcode.data
的旧教程中或按照旧教程测试自修改代码,那么在现代内核上,这不是一个选项。
解决方案 2:
作为使用 GNU 特定的节指令变体修改汇编文件的替代方法,您可以将其添加-Wa,--noexecstack
到命令行以构建汇编文件。例如,看看我在 musl 中是如何做的configure
:
https://git.musl-libc.org/cgit/musl/commit/configure?id=adefe830dd376be386df5650a09c313c483adf1a
我相信至少某些带有集成汇编器的 clang 版本可能要求将其作为--noexecstack
(不带-Wa
)传递,因此您的配置脚本应该检查两者并查看哪个被接受。
您还可以-Wl,-z,noexecstack
在链接时(在 中LDFLAGS
)使用以获得相同的结果。 这样做的缺点是,如果您的项目生成供其他软件使用的静态( )库文件,则它无济于事.a
,因为当其他程序使用它时,您无法控制链接时选项。
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 项目管理必备:盘点2024年13款好用的项目管理软件