I'm trying to modify a value in the .text segment using protect to give me writing access:
int pageSize = sysconf(_SC_PAGE_SIZE);
int *toModify = (int *)(foo+5);
if (mprotect(toModify, pageSize, PROT_WRITE) < 0 ) {
perror("mprotect failed with error:");
return -1;
}
*toModify = 5;
printf("Modify :%i",foo());
mprotect does never work. It always returns an mprotect failed with error:: Invalid argument
error.
foo is a method that returns an int that is stored 5bytes after the function(thats the reason for foo+5)
The address argument to
mprotect
needs to be page-aligned, as well as the size argument being a whole number of pages. Also, setting the page toPROT_WRITE
alone means you're not allowed to read it anymore -- and this particular page will be in the text segment, so it needs to bePROT_EXEC
as well, or the program will crash the moment it returns frommprotect
(because the code on that page is no longer considered executable).This modification of your program does what you want:
WARNING: Writing to a
const
datum triggers undefined behavior, no matter that you have used operating system primitives to disable write protection for the page containing it. When I first tested this code, I didn't haveconst int foo = 23;
in its own file, and GCC rewrote bothprintf
calls asprintf("...", 23, &foo)
. This is a valid optimization. If I turned link-time optimization on I would expect this to happen even though the definition of the constant was moved to its own file. Moreover, GCC would also be within its rights to replace*(int *)&foo = 42;
with an unconditionalabort()
or a trap instruction.I have executed the following code on OS X 10.9, and it appears to have the desired behavior. The output is “foo returns 23.”
For
foo
, I used this assembly code. Both sources were built withcc -arch i386
.You should modify code this way only as a learning exercise and not use it in any deployed application.
From
man mprotect
:You are not paying attention to the part where
addr
needs to be a multiple ofPAGESIZE
, apparently... Although in at least one version of the man page, that requirement is not made particularly clear, stating simply "specifies the desired protection for the memory page(s) containing part or all of the interval [addr,addr+len-1]".Finding the address of the page containing a particular address is not particularly hard, since you've already done the
pageSize = sysconf(_SC_PAGE_SIZE);
bit:Then modify your
mprotect
call to saymprotect(pageof(toModify), pageSize, ...)
. Although, see the answer by @Zack for a warning regarding the permissions you are specifying. And do go back and read the man page formprotect()
and make sure you really understand what you are doing...