简体   繁体   中英

mmap load shared object and get function pointer

I want to dynamically load a library without using functions from dlfcn.h i have a folder full of .so files compiled with:

gcc -Wall -shared -fPIC -o filename.so filename.c

And all of them have an entry function named:

void __start(int size, char** cmd);

(I know, probably not the best name)

then i try to call open over the so, then read the elf header as an Elf64_Ehdr load it into memory with mmap (i know i should use mprotect but i want to make it work first and then add the security) and finally adding the the elf header entry to the pointer returned by mmap (plus an offset of 0x100).

The test code is the following:

#include <elf.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/mman.h>

typedef void (*ptr_t) (int, char**);

void* alloc_ex_memory(int fd) {
    struct stat s;
    fstat(fd, &s);
    void * ptr = mmap(0, s.st_size, PROT_READ | PROT_WRITE | PROT_EXEC,
    MAP_PRIVATE | MAP_ANONYMOUS, fd, 0);
    if (ptr == (void *)-1) {
        perror("mmap");
        return NULL;
    }
    return ptr;
}

void* load_ex_file(const char* elfFile) {
    Elf64_Ehdr header;
    void * ptr;
    FILE* file = fopen(elfFile, "rb");
    if(file) {
        fread(&header, 1, sizeof(header), file);

        if (memcmp(header.e_ident, ELFMAG, SELFMAG) == 0) {
            ptr = alloc_ex_memory(fileno(file));
            printf("PTR AT -> %p\n", ptr);
            printf("Entry at -> %lx\n", header.e_entry+256);
            ptr = (header.e_entry + 256);
        } else {
            ptr = NULL;
            }

        fclose(file);
            return ptr;
    }
    return NULL;
}

int main(int argc, char** argv) {
    ptr_t func = load_ex_file(argv[1]);
    printf("POINTER AT: %p\n", func);
    getchar();
    func(argc, argv);
    return 0;
}

Let me explain a bit further: When i run objdump -d filename.so i get that the _start is at 0x6c0 . The elf header entry point returns 0x5c0 (i compensate it adding 256 in dec).

Also pmap shows an executable area being created at lets say 0x7fdf94d0c000 so the function pointer direction that i get and which i call is at 0x7fdf94d0c6c0 this should be the entry point and callable via function pointer. But what i get is, you guessed it: segfault.

Las thing that i would like to point out is that i have the same example running with ( dlopen , dlsym , dlclose ) but its required that i use the mmap trick. I have seen my professor implement it successfully but i cannot figure out how. (perhaps there is a simpler way that im missing).

I based the code on this jit example

Thank you in advance!

Edit: This is the code of the .c that i compile into .so:

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

void __start(int size, char** cmd) {
    if (size==2) {
        if (!strcmp(cmd[1], "-l")) {
            printf("******.********.*****@udc.es\n");
            return;
        } else if (!strcmp(cmd[1], "-n")) {
            printf("****** ******** *****\n");
            return;
        }
    } else if (size==1) {
            printf("****** ******** ***** (******.********.*****@udc.es)\n");
            return;
    }
    printf("Wrong command syntax: autores [-l | -n]\n");
}

its required that i use the mmap trick. I have seen my professor implement it successfully but i cannot figure out how.

For this to work, your __start must be completely stand-alone, and not call any other library (you violated that requirement by calling strcmp and printf ).

The moment you call an unresolved symbol, you ask the dynamic loader to resolve that symbol, and the loader needs all kinds of info for that. That info is normally set up during dlopen call. Since you bypassed dlopen , it is not at all surprising that your program crashes.

Your first step should be to change your code such that __start doesn't do anything at all (is empty), and verify that you can then call __start . That would confirm that you are computing its address correctly.

Second, add a crash to that code:

void __start(...)
{
  int *p = NULL;
  *p = 42;  // should crash here
}

and verify that you are observing the crash now. That will confirm that your code is getting called.

Third, remove the crashing code and use only direct system calls (eg write(1, "Hello\\n", 6) (but don't call write -- you must implement it directly in your library)) to implement whatever you need.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM