MacOS Catalina/x64上的自修改代码 [英] self-modifying code on MacOS Catalina / x64
问题描述
作为移植第四代编译器的一部分,我试图创建一个允许自我修改代码的二进制文件.有关详细信息,请参见 https://github.com/klapauciusisgreat/jonesforth-MacOS-x64
As part as porting a forth compiler, I'm trying to create a binary that allows for self modifying code. Gory details at https://github.com/klapauciusisgreat/jonesforth-MacOS-x64
理想情况下,我为用户定义创建了一堆页面,然后像这样调用mprotect:
Ideally, I create a bunch of pages for user definitions and call mprotect like so:
#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 // 1st param: stderr
lea errENOTSUP(%rip),%rsi // 2nd param: error message
mov $8,%rdx // 3rd param: length of string
mov $__NR_write,%rax // write syscall
syscall
jmp 3f
1:
mov $2,%rdi // 1st param: stderr
lea errEINVAL(%rip),%rsi // 2nd param: error message
mov $7,%rdx // 3rd param: length of string
mov $__NR_write,%rax // write syscall
syscall
jmp 3f
2:
mov $2,%rdi // 1st param: stderr
lea errEACCES(%rip),%rsi // 2nd param: error message
mov $7,%rdx // 3rd param: 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 //128kiB ought to be enough for everybody
.bss
.balign 8
user_defs_start:
.space USER_DEFS_SIZE
但是,我得到了EACCES返回值.我怀疑这是因为苹果已经制定了一些安全策略,但是找不到好的文档.
However, I get an EACCES return value. I suspect that this is because of some security policy apple has set up but do not find good documentation.
有人可以指出mprotect的源代码和/或标记数据区域可同时执行和写入的方法吗?
Can someone point out the source code for mprotect, and/or methods to mark the data area executable and writable at the same time ?
我发现使用
gcc -segprot __DATA rwx rwx
确实标记了整个数据段rwx,因此必须以某种方式可以做正确的事情.但是我更希望仅使包含单词的区域可执行,而不是整个数据段.
does mark the entire data segment rwx, so it must somehow be possible to do the right thing. But I would prefer to only make the area hosting forth words executable, not the entire data segment.
Any advice greatly appreciated. I found a similar discussion here but no solution.
推荐答案
我要取消保护"执行权限的段实际上有两个值来描述其权限:
The segment that I want to 'unprotect' exec permission in has really two values describing it's permissions:
-
初始保护设置,对于__DATA我想要rw-
the initial protection settings, which for __DATA I want rw-
最大保护(最松散)设置,我想成为rwx.
the maximum protection (loosest) settings, which I want to be rwx.
所以我要做的第一件事是将maxprot字段设置为rwx.根据ld联机帮助页,这应该通过使用标志-segprot __DATA rwx rw
调用gcc或ld来实现.但是,Apple最近对链接器进行的更改实际上忽略了maxprot值,并设置了maxprot = initprot.
So the first thing I need to do is to set the maxprot field to rwx. According to the ld manpage, this should be achieved by invoking gcc or ld with the flags -segprot __DATA rwx rw
. However, a recent change made by Apple to the linker essentially ignores the maxprot value, and sets maxprot=initprot.
由于 Darfink ,您可以使用
Thanks to Darfink, you can use this script to tweak the maxprot bits after the fact. I thought additional code signing with special entitlements was required, but it's not, at least for the __DATA segment. The __TEXT segment may need code signing with the com.apple.security.cs.disable-executable-page-protection
entitlement.
另请参见此处.
从更大的角度来看,我还应该指出,与其取消保护原本受保护的__DATA段的片段,不如为具有rwx权限的自修改代码创建一个完整的新数据/代码段可能更好.开始.这样,仍可以由操作系统保护其余数据,并且不需要非标准工具.
Looking at the larger picture, I should also point out that rather to unprotect pieces of an otherwise protected __DATA segment, it may be better to create a complete new data/code segment just for the self-modifying code with rwx permissions from the start. This allows still protecting the rest of data by the operating system, and requires no non-standard tools.
这篇关于MacOS Catalina/x64上的自修改代码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!