在mmap中执行代码以生成可执行代码段错误

Lam*_*eta 1 c linux assembly function-pointers currying

我正在尝试编写一个复制函数的函数(并最终修改其程序集)并返回它.这适用于一个级别的间接,但在两个我得到段错误.

这是一个最小(非)工作示例:

#include <stdio.h>
#include <string.h>
#include <sys/mman.h>

#define BODY_SIZE 100

int f(void) { return 42; }
int (*G(void))(void) { return f; }
int (*(*H(void))(void))(void) { return G; }

int (*g(void))(void) {
    void *r = mmap(0, BODY_SIZE, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
    memcpy(r, f, BODY_SIZE);
    return r;
}

int (*(*h(void))(void))(void) {
    void *r = mmap(0, BODY_SIZE, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
    memcpy(r, g, BODY_SIZE);
    return r;
}

int main() {
    printf("%d\n", f());
    printf("%d\n", G()());
    printf("%d\n", g()());
    printf("%d\n", H()()());
    printf("%d\n", h()()()); // This one fails - why?

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我可以记忆到一个mmap的区域,创建一个可以被调用的有效函数(g()()).但是,如果我再次尝试应用它(h()()())它会发生段错误.我已经确认它正确创建了复制版本g,但是当我执行该版本时,我得到了一个段错误.

我有什么理由不能在另一个mmap的区域中的一个mmap的区域中执行代码吗?从带有x/i检查的探索性gdb-ing 看起来我可以成功调用,但是当我返回我来自的函数时已被删除并替换为0.

我怎样才能使这种行为起作用?它甚至可能吗?

大编辑:

许多人问我的理由,因为我在这里显然是在做XY问题.这是真实而有意的.你看,一个月之前这个问题发布在代码高尔夫堆栈交换上.它也为C/Assembly解决方案带来了不错的赏金.我对这个问题做了一些空洞的思考,并意识到通过复制一个函数体同时删除一个具有一些唯一值的地址,我可以在其内存中搜索该值并将其替换为有效地址,从而允许我有效地创建lambda函数将单个指针作为参数.使用这个我可以得到单一的currying工作,但我需要更一般的currying.因此,我目前的部分解决方案与此相关.这是展示我试图避免的段错误的完整代码.虽然这几乎是一个坏主意的定义,但我觉得它很有趣,并且想知道我的方法是否可行.我唯一缺少的是运行从函数创建的函数的能力,但我无法让它工作.

Jes*_*ter 5

代码使用相对调用来调用mmap,memcpy因此复制的代码最终会调用无效的位置.

您可以通过指针调用它们,例如:

#include <stdio.h>
#include <string.h>
#include <sys/mman.h>

#define BODY_SIZE 100

void* (*mmap_ptr)(void *addr, size_t length, int prot, int flags,
                  int fd, off_t offset) = mmap;
void* (*memcpy_ptr)(void *dest, const void *src, size_t n) = memcpy;

int f(void) { return 42; }
int (*G(void))(void) { return f; }
int (*(*H(void))(void))(void) { return G; }

int (*g(void))(void) {
    void *r = mmap_ptr(0, BODY_SIZE, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
    memcpy_ptr(r, f, BODY_SIZE);
    return r;
}

int (*(*h(void))(void))(void) {
    void *r = mmap_ptr(0, BODY_SIZE, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
    memcpy_ptr(r, g, BODY_SIZE);
    return r;
}

int main() {
    printf("%d\n", f());
    printf("%d\n", G()());
    printf("%d\n", g()());
    printf("%d\n", H()()());
    printf("%d\n", h()()()); // This one fails - why?

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

  • 64位可能正在使用rip-relative寻址数据,因此相同的问题仍然存在于相对调用. (2认同)