Get the address and size of a loaded shared object on memory from C

84 views Asked by At

I am making a 64-bit memory-scanning library in C, and I need to "scan" the memory region where a shared object resides. For this, I need to get the address and size of the module, similar to the output of /proc/self/maps.

Obviously I would need to ignore non-readable sections, and just scan the module I want (e.g. only /usr/lib/libXau.so or /usr/lib/libdbus-1.so):

7a9d2f92e000-7a9d2f930000 r--p 00000000 103:03 15505103                  /usr/lib/libXdmcp.so.6.0.0
7a9d2f930000-7a9d2f932000 r-xp 00002000 103:03 15505103                  /usr/lib/libXdmcp.so.6.0.0
7a9d2f932000-7a9d2f934000 r--p 00004000 103:03 15505103                  /usr/lib/libXdmcp.so.6.0.0
7a9d2f934000-7a9d2f935000 r--p 00005000 103:03 15505103                  /usr/lib/libXdmcp.so.6.0.0
7a9d2f935000-7a9d2f936000 rw-p 00006000 103:03 15505103                  /usr/lib/libXdmcp.so.6.0.0
7a9d2f936000-7a9d2f937000 r--p 00000000 103:03 15505107                  /usr/lib/libXau.so.6.0.0
7a9d2f937000-7a9d2f938000 r-xp 00001000 103:03 15505107                  /usr/lib/libXau.so.6.0.0
7a9d2f938000-7a9d2f939000 r--p 00002000 103:03 15505107                  /usr/lib/libXau.so.6.0.0
7a9d2f939000-7a9d2f93a000 r--p 00002000 103:03 15505107                  /usr/lib/libXau.so.6.0.0
7a9d2f93a000-7a9d2f93b000 rw-p 00003000 103:03 15505107                  /usr/lib/libXau.so.6.0.0
7a9d2f93b000-7a9d2f949000 r--p 00000000 103:03 15490157                  /usr/lib/libdbus-1.so.3.32.4
7a9d2f949000-7a9d2f977000 r-xp 0000e000 103:03 15490157                  /usr/lib/libdbus-1.so.3.32.4
7a9d2f977000-7a9d2f989000 r--p 0003c000 103:03 15490157                  /usr/lib/libdbus-1.so.3.32.4
7a9d2f989000-7a9d2f98b000 r--p 0004e000 103:03 15490157                  /usr/lib/libdbus-1.so.3.32.4
7a9d2f98b000-7a9d2f98c000 rw-p 00050000 103:03 15490157                  /usr/lib/libdbus-1.so.3.32.4

Until now, I have been using an extended version of the link_map struct (See dlopen(3)), and I have been getting the start and end addresses from link->l_addr and link->phdr[0].p_memsz respectively.

#include <dlfcn.h>    /* dlopen() */
#include <link.h>     /* link_map */

struct my_link_map {
    /* Base from link.h */
    ElfW(Addr) l_addr;
    const char* l_name;
    ElfW(Dyn) * l_ld;
    struct my_link_map* l_next;
    struct my_link_map* l_prev;

    /* Added */
    struct my_link_map* real;
    long int ns;
    struct libname_list* moduleName;
    ElfW(Dyn) * info[DT_NUM + DT_VERSIONTAGNUM + DT_EXTRANUM + DT_VALNUM + DT_ADDRNUM];
    const ElfW(Phdr) * phdr;
};

struct my_link_map* link = dlopen(module, RTLD_NOLOAD | RTLD_NOW);
if (!link)
    return;

uint8_t* start = (uint8_t*)link->l_addr;
uint8_t* end   = start + link->phdr[0].p_memsz;

/* ... */

Today I tried using this code for getting the start and end addresses of the main 64-bit executable (i.e. passing NULL to dlopen() instead of the module name), and it's crashing when trying to assign end.

I thought about parsing /proc/self/maps, and although I made a function that filters everything except the module name, I still think this is not the best way.

TDLR:

I know how to get the address of a loaded module using link_map->l_addr after calling dlopen(), but what's the best way of getting the module size/end address?

0

There are 0 answers