This is essentially what I'm trying to do,
#include <sys/mman.h>
int zero() {
return 0;
}
int main(int argc, const char *argv[]) {
return mprotect((void *) &zero, 4096, PROT_READ | PROT_WRITE);
}
so I'm trying to make code writable, essentially. This doesn't work on the current macOS (Catalina 10.15.2), it just returns -1 and sets errno to EACCES, which as far as I know is because of lack of entitlement/code signing. I've found the entitlement I need to set, but I have no idea how to go about that, nor how to actually sign it..
If I run codesign -d --entitlements :- <path_to_app>, it fails with code object is not signed at all, even though I've tried configuring signing in Xcode for a while (I have a certificate and so on). So how should I go about this? Actually signing it isn't obvious with Xcode, so I'm fairly clueless.
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_protattribute of the__TEXTsegment in the Mach-O header has been changed.Previously
max_protdefault value was0x7(PROT_READ | PROT_WRITE | PROT_EXEC).The default value has now been changed to
0x5(PROT_READ | PROT_EXEC).This means that
mprotectcannot make any region that resides within__TEXTwritable.In theory, this should be resolved by providing the linker flag
-segprot __TEXT rwx rx, but this is not the case. Since Catalina, themax_protfield is ignored. Instead,max_protis set to the value ofinit_prot(see here).To top it all off,
init_protcannot be set torwxeither 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)to0x7after linking.Since that code snippet relies on the
__TEXT(max_prot)offset being hardcoded to0xA0, as an alternative, I've created a drop-in replacement/wrapper forldwhich respects themax_protparameter ofsegprot.