Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mapping existing memory (data segment) to another memory segment

As the title suggests, I would like to ask if there is any way for me to map the data segment of my executable to another memory so that any changes to the second are updated instantly on the first. One initial thought I had was to use mmap, but unfortunately mmap requires a file descriptor and I do not know of a way to somehow open a file descriptor on my running processes memory. I tried to use shmget/shmat in order to create a shared memory object on the process data segment (&__data_start) but again I failed ( even though that might have been a mistake on my end as I am unfamiliar with the shm API). A similar question I found is this: Linux mapping virtual memory range to existing virtual memory range? , but the replies are not helpful.. Any thoughts are welcome.

Thank you in advance.

Some pseudocode would look like this:

extern char __data_start, _end;

char test = 'A';

int main(int argc, char *argv[]){
  size_t size = &_end - &__data_start;
  char *mirror = malloc(size);
  magic_map(&__data_start, mirror, size); //this is the part I need.
  printf("%c\n", test) // prints A

  int offset = &test - &__data_start;
  *(mirror + offset) = 'B';
  printf("%c\n", test) // prints B
  free(mirror);
  return 0;
}


like image 977
Gecal Avatar asked Jun 18 '26 13:06

Gecal


1 Answers

it appears I managed to solve this. To be honest I don't know if it will cause problems in the future and what side effects this might have, but this is it (If any issues arise I will try to log them here for future references).

Solution:

Basically what I did was use the mmap flags MAP_ANONYMOUS and MAP_FIXED.

  • MAP_ANONYMOUS: With this flag a file descriptor is no longer required (hence the -1 in the call)
  • MAP_FIXED: With this flag the addr argument is no longer a hint, but it will put the mapping on the address you specify.
  • MAP_SHARED: With this you have the shared mapping so that any changes are visible to the original mapping.

I have left in a comment the munmap function. This is because if unmap executes we free the data_segment (pointed to by &__data_start) and as a result the global and static variables are corrupted. When at_exit function is called after main returns the program will crash with a segmentation fault. (Because it tries to double free the data segment)

Code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>

#define _GNU_SOURCE 1
#include <unistd.h>
#include <sys/mman.h>

extern char __data_start;
extern char _end;

int test = 10;

int main(int argc, char *argv[])
{

    size_t size = 4096;
        char *shared = mmap(&__data_start, 4096, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_ANONYMOUS | MAP_SHARED, -1, 0);
        if(shared == (void *)-1){
                printf("Cant mmap\n");
                exit(-1);
        }
    printf("original: %p, shared: %p\n",&__data_start, shared);
    size_t offset = (void *)&test - (void *)&__data_start;
        *(shared+offset) = 50;
        msync(shared, 4096, MS_SYNC);
        printf("test: %d :: %d\n", test, *(shared+offset));
        test = 25;
        printf("test: %d :: %d\n", test, *(shared+offset));
        //munmap(shared, 4096);
}

Output:

original: 0x55c4066eb000, shared: 0x55c4066eb000
test: 50 :: 50
test: 25 :: 25
like image 144
Gecal Avatar answered Jun 21 '26 01:06

Gecal



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!