clinuxunixmemorymprotect

mprotect always returns invalid arguments


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)


Solution

  • 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.”

    #include <stdint.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #include <unistd.h>
    #include <sys/mman.h>
    
    
    extern int foo(void);
    
    
    int main(void)
    {
        //  New value to write into foo+5.
        int NewValue = 23;
    
        //  Find page size for this system.
        size_t pagesize = sysconf(_SC_PAGESIZE);
    
        //  Calculate start and end addresses for the write.
        uintptr_t start = (uintptr_t) &foo + 5;
        uintptr_t end = start + sizeof NewValue;
    
        //  Calculate start of page for mprotect.
        uintptr_t pagestart = start & -pagesize;
    
        //  Change memory protection.
        if (mprotect((void *) pagestart, end - pagestart,
                PROT_READ | PROT_WRITE | PROT_EXEC))
        {
            perror("mprotect");
            exit(EXIT_FAILURE);
        }
    
        //  Write new bytes to desired location.
        memcpy((void *) start, &NewValue, sizeof NewValue);
    
        //  Some systems could require an invalidate of instruction cache here.
    
        //  Try modified function.
        printf("foo returns %d.\n", foo());
    
        return 0;
    }
    

    For foo, I used this assembly code. Both sources were built with cc -arch i386.

        .globl  _foo
    _foo:
        nop
        nop
        nop
        nop
        mov $42, %eax
        ret
    

    You should modify code this way only as a learning exercise and not use it in any deployed application.