Kla*_*ius 5 macos assembly x86-64 forth macos-catalina
作为移植 Forth 编译器的一部分,我正在尝试创建一个允许自修改代码的二进制文件。血淋淋的细节位于https://github.com/klapauciusisgreat/jonesforth-MacOS-x64
理想情况下,我为用户定义创建一堆页面并调用 mprotect,如下所示:
#define __NR_exit 0x2000001
#define __NR_open 0x2000005
#define __NR_close 0x2000006
#define __NR_read 0x2000003
#define __NR_write 0x2000004
#define __NR_mprotect 0x200004a
#define PROT_READ 0x01
#define PROT_WRITE 0x02
#define PROT_EXEC 0x04
#define PROT_ALL (PROT_READ | PROT_WRITE | PROT_EXEC)
#define PAGE_SIZE 4096
// https://opensource.apple.com/source/xnu/xnu-201/bsd/sys/errno.h
#define EACCES 13 /* Permission denied */
#define EINVAL 22 /* Invalid argument */
#define ENOTSUP 45 /* Operation not supported */
/* Assembler entry point. */
.text
.globl start
start:
// Use mprotect to allow read/write/execute of the .bss section
mov $__NR_mprotect, %rax // mprotect
lea user_defs_start(%rip), %rdi // Start address
and $-PAGE_SIZE,%rdi // Align at page boundary
mov $USER_DEFS_SIZE, %rsi // Length
mov $PROT_ALL,%rdx
syscall
cmp $EINVAL, %rax
je 1f
cmp $EACCES,%rax
je 2f
test %rax,%rax
je 4f // All good, proceed:
// must be ENOTSUP
mov $2,%rdi // First parameter: stderr
lea errENOTSUP(%rip),%rsi // Second parameter: error message
mov $8,%rdx // Third parameter: length of string
mov $__NR_write,%rax // Write syscall
syscall
jmp 3f
1:
mov $2,%rdi // First parameter: stderr
lea errEINVAL(%rip),%rsi // Second parameter: error message
mov $7,%rdx // Third parameter: length of string
mov $__NR_write,%rax // Write syscall
syscall
jmp 3f
2:
mov $2,%rdi // First parameter: stderr
lea errEACCES(%rip),%rsi // Second parameter: error message
mov $7,%rdx // Third parameter: length of string
mov $__NR_write,%rax // Write syscall
syscall
3:
// did't work -- then exit
xor %rdi,%rdi
mov $__NR_exit,%rax // syscall: exit
syscall
4:
// All good, let's get started for real:
.
.
.
.set RETURN_STACK_SIZE,8192
.set BUFFER_SIZE,4096
.set USER_DEFS_SIZE,65536*2 // 128 kiB ought to be enough for everybody
.bss
.balign 8
user_defs_start:
.space USER_DEFS_SIZE
Run Code Online (Sandbox Code Playgroud)
但是,我得到了 EACCES 返回值。我怀疑这是因为苹果设置了一些安全策略,但我没有找到好的文档。
mprotect 的源代码在哪里,和/或同时标记数据区域可执行和可写的方法是什么?
我发现编译
#define __NR_exit 0x2000001
#define __NR_open 0x2000005
#define __NR_close 0x2000006
#define __NR_read 0x2000003
#define __NR_write 0x2000004
#define __NR_mprotect 0x200004a
#define PROT_READ 0x01
#define PROT_WRITE 0x02
#define PROT_EXEC 0x04
#define PROT_ALL (PROT_READ | PROT_WRITE | PROT_EXEC)
#define PAGE_SIZE 4096
// https://opensource.apple.com/source/xnu/xnu-201/bsd/sys/errno.h
#define EACCES 13 /* Permission denied */
#define EINVAL 22 /* Invalid argument */
#define ENOTSUP 45 /* Operation not supported */
/* Assembler entry point. */
.text
.globl start
start:
// Use mprotect to allow read/write/execute of the .bss section
mov $__NR_mprotect, %rax // mprotect
lea user_defs_start(%rip), %rdi // Start address
and $-PAGE_SIZE,%rdi // Align at page boundary
mov $USER_DEFS_SIZE, %rsi // Length
mov $PROT_ALL,%rdx
syscall
cmp $EINVAL, %rax
je 1f
cmp $EACCES,%rax
je 2f
test %rax,%rax
je 4f // All good, proceed:
// must be ENOTSUP
mov $2,%rdi // First parameter: stderr
lea errENOTSUP(%rip),%rsi // Second parameter: error message
mov $8,%rdx // Third parameter: length of string
mov $__NR_write,%rax // Write syscall
syscall
jmp 3f
1:
mov $2,%rdi // First parameter: stderr
lea errEINVAL(%rip),%rsi // Second parameter: error message
mov $7,%rdx // Third parameter: length of string
mov $__NR_write,%rax // Write syscall
syscall
jmp 3f
2:
mov $2,%rdi // First parameter: stderr
lea errEACCES(%rip),%rsi // Second parameter: error message
mov $7,%rdx // Third parameter: length of string
mov $__NR_write,%rax // Write syscall
syscall
3:
// did't work -- then exit
xor %rdi,%rdi
mov $__NR_exit,%rax // syscall: exit
syscall
4:
// All good, let's get started for real:
.
.
.
.set RETURN_STACK_SIZE,8192
.set BUFFER_SIZE,4096
.set USER_DEFS_SIZE,65536*2 // 128 kiB ought to be enough for everybody
.bss
.balign 8
user_defs_start:
.space USER_DEFS_SIZE
Run Code Online (Sandbox Code Playgroud)
确实标记了整个数据段 rwx,因此必须以某种方式可以做正确的事情。但我宁愿只使托管 Forth 字的区域可执行,而不是整个数据段。
我在这里找到了类似的讨论,但没有任何解决方案。
我想要“取消保护”执行权限的段实际上有两个值来描述其权限:
初始保护设置,对于 __DATA 我想要 rw-
最大保护(最宽松)设置,我希望将其设置为 rwx。
所以首先我需要将 maxprot 字段设置为 rwx。根据 ld 手册页,这应该通过使用flags调用gcc或ld-segprot __DATA rwx rw来实现。然而,Apple 最近对链接器所做的更改基本上忽略了 maxprot 值,并设置 maxprot=initprot。
感谢Darfink,您可以使用此脚本在事后调整maxprot 位。我认为需要具有特殊权利的额外代码签名,但事实并非如此,至少对于 __DATA 段而言。__TEXT 段可能需要使用com.apple.security.cs.disable-executable-page-protection权利进行代码签名。
另请参阅此处了解更多详细信息。
从更大的角度来看,我还应该指出,与其取消对受保护的 __DATA 段的保护,不如从一开始就为具有 rwx 权限的自修改代码创建一个完整的新数据/代码段。这允许操作系统仍然保护其余数据,并且不需要非标准工具。
| 归档时间: |
|
| 查看次数: |
758 次 |
| 最近记录: |