Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/macos/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
macOS v10.15(Catalina)/x64上的自修改代码_Macos_Assembly_X86 64_Macos Catalina_Forth - Fatal编程技术网

macOS v10.15(Catalina)/x64上的自修改代码

macOS v10.15(Catalina)/x64上的自修改代码,macos,assembly,x86-64,macos-catalina,forth,Macos,Assembly,X86 64,Macos Catalina,Forth,作为移植Forth编译器的一部分,我正在尝试创建一个允许自修改代码的二进制文件。血淋淋的细节在 理想情况下,我会为用户定义创建一组页面,并调用mprotect,如下所示: #define __NR_exit 0x2000001 #define __NR_open 0x2000005 #define __NR_close 0x2000006 #define __NR_read 0x2000003 #define __NR_write 0x2000004 #define __NR_mprotect

作为移植Forth编译器的一部分,我正在尝试创建一个允许自修改代码的二进制文件。血淋淋的细节在

理想情况下,我会为用户定义创建一组页面,并调用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

但是,我得到一个EACCES返回值。我怀疑这是因为苹果公司制定了一些安全政策,但我没有找到好的文档

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

我发现是用

gcc-segport\uuuu数据rwx rwx
确实标记了整个数据段rwx,因此必须能够以某种方式执行正确的操作。但我更愿意只让承载Forth单词的区域可执行,而不是整个数据段


我发现了一个类似的讨论,但没有任何解决方案。

我想要“取消保护”exec权限的段实际上有两个值描述其权限:

  • 初始保护设置,我想要rw-

  • 最大保护(最宽松)设置,我希望是rwx

  • 所以首先我需要将maxprot字段设置为rwx。根据ld手册页,这应该通过调用带有标志
    -segport\uuu DATA rwx rw
    的gcc或ld来实现。然而,苹果最近对链接器所做的一项更改实际上忽略了maxprot值,并设置maxprot=initprot

    多亏了,您可以在事后使用调整maxprot位。我认为需要额外的带有特殊权限的代码签名,但事实并非如此,至少对于_数据段是如此。__文本段可能需要使用
    com.apple.security.cs.disable executable page protection
    权限进行代码签名

    有关更多详细信息,请参见


    综观全局,我还应该指出,与其取消对受保护数据段的保护,不如从一开始就为具有rwx权限的自修改代码创建一个完整的新数据/代码段。这仍然允许操作系统保护其余数据,并且不需要非标准工具。

    通常的方法是在执行更改时将其标记为可写但不可执行,然后在完成更改时将其标记为只读可执行。第四,这样做似乎不切实际,因为第四个汇编程序可以在同一段中执行单词,所以它正在编译一个新词。但是玩这个是个好主意,谢谢!我试着用PROT|u READ | PROT|u WRITE调用mprotect,得到同样的结果。也许我的系统调用约定错了?好吧,我是个白痴。1.我需要
    和$-PAGE\u SIZE,%rdi
    而不是
    和$-PAGE\u SIZE,%rdi
    2。我用gdb跟踪,在%rax中实际返回的是14(默认值)。我假设每个手册页只返回EACCES、EINVAL或ENOTSUP。这有点帮助,但还不够。我可能需要查看mprotect的代码来了解发生了什么。是否有理由需要静态分配可写/可执行区域?为什么不
    mmap()
    一些具有所需权限的内存?