The example consists of two sources that each need to be compiled into an executable.
proc-1.c
This is the first source. It prints its PID and the address and length of a variable (foo
).
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main() {
char foo[] = "This is some text from proc-1";
printf("Now execute\n");
printf(" sudo ./proc-2 %d %lx %lu\n", getpid(), (long unsigned int) foo, strlen(foo)+1);
printf("Press any key\n");
getchar();
printf("foo has changed to: %s\n", foo);
}
proc-2.c
This program takes the information that the first program printed to open a »file« and read the memory of the variable of the first program.
After printing the value of the variable, it overwrites it with another string. The first program will then see the new value.
#include <stdio.h>
#include <stdlib.h>
// #include <sys/mman.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char* argv[]) {
if (argc != 4) {
printf("proc-2 pid addr length\n");
exit(1);
}
int pid = strtol (argv[1], NULL, 10);
unsigned long addr = strtoul(argv[2], NULL, 16);
int len = strtol (argv[3], NULL, 10);
char* proc_mem = malloc(50);
sprintf(proc_mem, "/proc/%d/mem", pid);
printf("opening %s, address is %ld\n", proc_mem, addr);
int fd_proc_mem = open(proc_mem, O_RDWR);
if (fd_proc_mem == -1) {
printf("Could not open %s\n", proc_mem);
exit(1);
}
char* buf = malloc(len);
lseek(fd_proc_mem, addr, SEEK_SET);
read (fd_proc_mem, buf , len );
printf("String at %ld in process %d is:\n", addr, pid);
printf(" %s\n", buf);
printf("\nNow, this string is modified\n");
strncpy(buf, "Hello from proc-2", len);
lseek(fd_proc_mem, addr, SEEK_SET);
if (write (fd_proc_mem, buf , len ) == -1) {
printf("Error while writing\n");
exit(1);
}
free(buf);
free(proc_mem);
}