x86_64 Linux汇编shellcode写入.text段报错及mprotect使用求助
问题解答
1. 段错误原因确认
你的判断基本正确。现代Linux系统默认启用W^X(写入异或执行)内存保护机制:可执行内存页默认不可写,可写页默认不可执行。如果你的shellcode所在内存页被标记为可执行但不可写,执行mov [rdx+7], al这类写入操作时,必然会触发段错误——这是系统对违反内存权限的直接响应。
2. 能否通过mprotect设置内存页为可写且可执行
完全可以。mprotect系统调用支持修改指定内存区域的权限,只要你能定位到目标内存页的起始地址,且该页属于当前进程空间,就能将其权限设置为PROT_READ | PROT_WRITE | PROT_EXEC,从而同时支持写入和执行操作。
3. 汇编中获取内存页起始地址的方法
x86_64 Linux下内存页默认大小为4KB(可通过getpagesize系统调用确认),要获取shellcode所在页的起始地址,只需将当前指令的地址对齐到页边界即可,具体步骤如下:
- 用
call指令获取当前指令地址:执行call get_current_addr后,返回地址会被压入栈中,在get_current_addr标签处通过pop rbx就能将当前指令的地址存入rbx寄存器。 - 用页掩码对齐地址:执行
and rbx, 0xfffffffffffff000(4KB页的掩码为~0xfff,64位下对应值为0xfffffffffffff000),即可将rbx中的地址对齐到当前页的起始位置。
示例汇编片段
; 获取当前shellcode所在页的起始地址 call get_current_addr get_current_addr: pop rbx ; rbx = 当前指令的内存地址 and rbx, 0xfffffffffffff000 ; 对齐到4KB页边界 ; 调用mprotect修改内存权限 mov rdi, rbx ; 参数1:页起始地址 mov rsi, 4096 ; 参数2:修改的内存大小(整页) mov rdx, 7 ; 参数3:PROT_READ|PROT_WRITE|PROT_EXEC(7=1|2|4) mov rax, 10 ; x86_64 Linux下mprotect的系统调用号为10 syscall
调用mprotect完成权限修改后,你就可以安全地向该内存区域写入数据了。需要注意的是,部分系统可能开启了SMAP/SMEP等额外保护机制,但在常规漏洞研究环境中,上述方法足以解决问题。
内容的提问来源于stack exchange,提问作者Tom BARAT
相关产品推荐
相关产品推荐

