xiaokaoy xiaokaoy - 4 months ago 13
Linux Question

How can I modify an instruction in a process? Linux & ARMv7

I tried to modify the first instruction of a function called g, but got a segment fault on the second statement in the following snippet

int a = *(int*)g;
*(int*)g=0; // segment fault!
*(int*)g=a;


Was this segment fault due to the no-write permission in the page table entry for the page where the instruction I wanted to modify was located ?

I did so because I wanted to see if I could patch a function with some bugs, while keeping the process running, like this:

1) A process with function g is running, and that g has been found to have some bugs. So write a new function called patch_g, which has no bugs.

2) Compile the new function into patch.so

3) dlopen & dlsym the .so file. Get the address of patch_g.

4) Suspend the running process

5) Use some code (somewhat similar to the second statement of the snippet above) to change the first instruction of g into
jump patch_g
.

Answer

Ok, let's do an experiment. Here is the code:

#include <stdio.h>

int (*functionPtr)(int,int);

int addInt(int n, int m) {
        return n+m;
}


int main()
{
    functionPtr = &addInt;
    printf("%p\n", functionPtr);
    while(1){};
    *(int *) functionPtr = 0x0;
    return 0;
}

Compile

$ gcc -o ./main.c main

Launch this app in first console.

$ ./main 
0x40052d

In second console

$ cat /proc/`pidof main`/maps
00400000-00401000 r-xp 00000000 08:01 6345711                            /tmp/main
00600000-00601000 r--p 00000000 08:01 6345711                            /tmp/main
00601000-00602000 rw-p 00001000 08:01 6345711                            /tmp/main

...

This r-xp means that when kernel loaded this binary, it has mapped text section into private virtual mapping with read and execute permissions, but without write permissions. I think this is done because of security reasons.

So appropriate vma_area in kernel marked as non writable, what leads to unhandled userspace page fault i.e. segfault is occured.

Now let'us add mprotect call to appropriate place

 17         if (mprotect((void *)0x00400000, 4096, PROT_READ | PROT_WRITE | PROT_EXEC)) {
 18                 printf("error\n");
 19                 return -1;
 20         }

You will notice that this will help your with your run-time patching idea.

00400000-00401000 rwxp 00000000 08:01 6345711                            /tmp/main
00600000-00601000 r--p 00000000 08:01 6345711                            /tmp/main
00601000-00602000 rw-p 00001000 08:01 6345711                            /tmp/main