This is not a definitive answer, but it's a workaround.
Your problem is caused by changes of the linker (ld64) in macOS Catalina. The default value of the max_prot
attribute of the __TEXT
segment in the Mach-O header has been changed.
Previously max_prot
default value was 0x7
(PROT_READ | PROT_WRITE | PROT_EXEC
).
The default value has now been changed to 0x5
(PROT_READ | PROT_EXEC
).
This means that mprotect
cannot make any region that resides within __TEXT
writable.
In theory, this should be resolved by providing the linker flag -segprot __TEXT rwx rx
, but this is not the case. Since Catalina, the max_prot
field is ignored. Instead, max_prot
is set to the value of init_prot
(see here).
To top it all off, init_prot
cannot be set to rwx
either due to macOS refusing to execute a file which has a writable __TEXT(init_prot)
attribute.
A brute workaround is to manually modify and set __TEXT(max_prot)
to 0x7
after linking.
printf 'x07' | dd of=<executable> bs=1 seek=160 count=1 conv=notrunc
Since that code snippet relies on the __TEXT(max_prot)
offset being hardcoded to 0xA0
, as an alternative, I've created a drop-in replacement/wrapper for ld
which respects the max_prot
parameter of segprot
.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…