Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/xamarin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C mmap加载共享对象并获取函数指针_C_Elf_Mmap - Fatal编程技术网

C mmap加载共享对象并获取函数指针

C mmap加载共享对象并获取函数指针,c,elf,mmap,C,Elf,Mmap,我想动态加载一个库,而不使用dlfcn.h中的函数。我有一个文件夹,里面装满了编译时使用的.so文件: gcc -Wall -shared -fPIC -o filename.so filename.c 它们都有一个输入函数,名为: void __start(int size, char** cmd); (我知道,可能不是最好的名字) 然后,我尝试通过so调用open,然后将elf头作为Elf64_Ehdr读取,并使用mmap将其加载到内存中(我知道我应该使用mprotect,但我想先让它工

我想动态加载一个库,而不使用
dlfcn.h
中的函数。我有一个文件夹,里面装满了编译时使用的.so文件:

gcc -Wall -shared -fPIC -o filename.so filename.c
它们都有一个输入函数,名为:

void __start(int size, char** cmd);
(我知道,可能不是最好的名字)

然后,我尝试通过so调用
open
,然后将elf头作为
Elf64_Ehdr
读取,并使用
mmap
将其加载到内存中(我知道我应该使用
mprotect
,但我想先让它工作,然后添加安全性),最后将elf头条目添加到mmap返回的指针中(加上偏移量0x100)

测试代码如下所示:

#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;
}
这要求我使用mmap技巧。我已经看到我的教授成功地实现了它,但我不知道如何实现

要使其工作,您的
\u start
必须是完全独立的,并且不能调用任何其他库(您通过调用
strcmp
printf
违反了该要求)

在调用未解析的符号时,您要求动态加载程序解析该符号,加载程序需要各种信息。这些信息通常在
dlopen
调用期间设置。由于您绕过了
dlopen
,因此程序崩溃一点也不奇怪

您的第一步应该是更改代码,使
\uuuu start
完全不起任何作用(为空),然后验证您是否可以调用
\uu start
。这将确认您正确计算了它的地址

其次,将崩溃添加到该代码中:

void __start(...)
{
  int *p = NULL;
  *p = 42;  // should crash here
}
并验证您现在正在观察崩溃。这将确认您的代码正在被调用


第三,删除崩溃代码,只使用直接系统调用(例如
write(1,“Hello\n”,6)
(但不要调用
write
——您必须在库中直接实现它))来实现您需要的任何功能。

printf(“PTR AT->%lx\n”,PTR);
是指针的错误格式。
%p
用于打印指针。@AndrewHenle编辑了代码。感谢您的回答,很抱歉直到今天才回复:如果我需要加载复杂的代码怎么办?。实际上我作为示例上传的代码是其中最简单的。我无法自己实现每个系统调用。有什么想法吗?@tretraft“什么是我需要复杂的代码”--然后您需要重新实现动态加载程序的一部分。但是为什么您不能简单地
dlopen
这个库呢?
void __start(...)
{
  int *p = NULL;
  *p = 42;  // should crash here
}