macOS v10.15(Catalina)/x64上的自修改代码 [英] Self-modifying code on macOS v10.15 (Catalina) / x64

查看:159
本文介绍了macOS v10.15(Catalina)/x64上的自修改代码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

作为移植Forth编译器的一部分,我试图创建一个允许自我修改代码的二进制文件.详细信息位于 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. The gory details are 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                     // 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

但是,我得到了EACCES返回值.我怀疑这是因为苹果已经设置了一些安全策略,但是我找不到很好的文档.

However, I get an EACCES return value. I suspect that this is because of some security policy apple has set up, but I do not find good documentation.

mprotect的源代码在哪里,和/或将数据区域同时标记为可执行和可写的方法是什么?

Where is the source code for mprotect, and/or what are the methods to mark the data area executable and writable at the same time?

我发现可以使用

gcc -segprot __DATA rwx rwx

确实标记了整个数据段rwx,因此必须以某种方式可以做正确的事情.但是我更希望仅使包含Forth单词的区域可执行,而不是整个数据段.

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.

我发现了类似的讨论

I found a similar discussion here, but without any solution.

推荐答案

我要在其中取消保护"执行权限的段实际上有两个描述其权限的值:

The segment that I want to 'unprotect' exec permission in has really two values describing its permissions:

  1. 初始保护设置,我想为__DATA设置为rw-

  1. 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 first I need 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 v10.15(Catalina)/x64上的自修改代码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆