gpt4 book ai didi

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

转载 作者:太空宇宙 更新时间:2023-11-04 01:46:17 26 4
gpt4 key购买 nike

我想在不使用 dlfcn.h 中的函数的情况下动态加载一个库,我有一个充满 .so 文件的文件夹:

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

并且它们都有一个入口函数,名为:

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

(我知道,可能不是最好的名字)

然后我尝试通过 so 调用 open,然后读取 elf header 作为 Elf64_Ehdr 使用 mmap 将其加载到内存中(我知道我应该使用 mprotect 但我想让它先工作,然后添加安全性),最后将 elf header 条目添加到 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;
}

让我再解释一下:当我运行 objdump -d filename.so 时,我发现 _start 位于 0x6c0。 elf header 入口点返回 0x5c0(我补偿它在 dec 中添加 256)。

此外,pmap 显示了一个可执行区域正在创建,比方说 0x7fdf94d0c000
所以我得到并调用的函数指针方向位于 0x7fdf94d0c6c0 这应该是入口点并且可以通过函数指针调用。但我得到的是,你猜对了:段错误。

最后,我想指出的是,我有相同的示例运行 (dlopen, dlsym, dlclose) 但是它要求我使用 mmap 技巧。我已经看到我的教授成功实现了它,但我不知道如何实现。 (也许我缺少一种更简单的方法)。

我的代码基于 this jit example

提前致谢!

编辑:这是我编译成 .so 的 .c 代码:

#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.

为此,您的 __start必须完全独立,并且调用任何其他库(您通过调用 strcmpprintf 违反了该要求)。

当您调用未解析的符号时,您要求动态加载器解析该符号,加载器为此需要各种信息。该信息通常在 dlopen 期间设置称呼。因为你绕过了 dlopen ,您的程序崩溃一点也不令人惊讶。

您的第一步应该是更改您的代码,使 __start根本不做任何事情(为空),然后确认您可以调用 __start .这将确认您正在正确计算其地址。

其次,为该代码添加一个崩溃:

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

并确认您现在正在观察崩溃。这将确认您的代码已被调用。

第三,删除崩溃代码并使用直接系统调用(例如write(1, "Hello\n", 6)(但不要调用write——你必须直接在你的库中实现它))来实现无论你需要什么。

关于c - mmap 加载共享对象并获取函数指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53297596/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com