使用 mprotect 使文本段在 macOS 上可写

som*_*ore 7 macos xcode text mprotect code-signing-entitlements

这基本上就是我想要做的,

#include <sys/mman.h>

int zero() {
    return 0;
}

int main(int argc, const char *argv[]) {
    return mprotect((void *) &zero, 4096, PROT_READ | PROT_WRITE);
}
Run Code Online (Sandbox Code Playgroud)

所以我试图使代码可写,本质上。这在当前的 macOS(Catalina 10.15.2)上不起作用,它只是返回-1并设置errnoEACCES,据我所知,这是因为缺乏权利/代码签名。我找到了我需要设置的权利,但我不知道如何去做,也不知道如何实际签署它..

如果我运行codesign -d --entitlements :- <path_to_app>,它会失败并显示code object is not signed at all,即使我已经尝试在 Xcode 中配置签名一段时间(我有证书等等)。那么我应该怎么做呢?实际上用 Xcode 签署它并不明显,所以我相当无能为力。

Ell*_*ink 6

这不是一个明确的答案,但它是一种解决方法。

您的问题是由 macOS Catalina 中链接器 (ld64) 的更改引起的。Mach-O 标头中段的max_prot属性的默认值__TEXT已更改。

以前的max_prot默认值为0x7( PROT_READ | PROT_WRITE | PROT_EXEC)。
默认值现已更改为0x5( PROT_READ | PROT_EXEC)。

这意味着mprotect不能使驻留在其中的任何区域__TEXT可写。

理论上,这应该通过提供链接器标志来解决-segprot __TEXT rwx rx,但事实并非如此。从 Catalina 开始,该max_prot字段被忽略。相反,max_prot设置为的值init_prot(请参阅此处)。

最重要的是,由于 macOS 拒绝执行具有可写属性的文件,init_prot因此无法设置为rwx两者之一__TEXT(init_prot)

一个粗暴的解决方法是在链接后手动修改并设置__TEXT(max_prot)0x7

printf '\x07' | dd of=<executable> bs=1 seek=160 count=1 conv=notrunc
Run Code Online (Sandbox Code Playgroud)

由于该代码段依赖于__TEXT(max_prot)被硬编码,以抵消0xA0,作为替代方案,我已经创建了一个简易替换/包装ld其中尊重max_prot的参数segprot