如何在C中执行AARCH64生成的计算机代码

发布于 2025-01-17 15:08:17 字数 3482 浏览 3 评论 0原文

我看到并尝试了一些在 Linux 上用 C 执行机器代码的示例。效果很好。 当我尝试使用 aarch64 时,它总是失败。这是我尝试过的。 C 文件:

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

#include <limits.h>    /* for PAGESIZE */
#ifndef PAGESIZE
#define PAGESIZE 4096
#endif

const static unsigned char code[] = {
    0x40, 0x05, 0x80, 0x52, // mov     w0, #0x2a
    //0xd6, 0x5f, 0x03, 0xc0 // ret instruction
    0x40, 0x97, 0x3b, 0xd4  //  brk     #0xdcba
};

int main(int argc, char **argv) { 
    int codelen = (int) sizeof(code);
    // in order to manipulate memory protection, we must work with
    // whole pages allocated directly from the operating system.
    static size_t pagesize=0;
    if (!pagesize) {
        pagesize = sysconf(_SC_PAGESIZE);
        if (pagesize == (size_t)-1) {
            printf("getpagesize fail\n");
            return 1;
        } else {
            printf("--success getting the pagesize=%ld\n", pagesize);
        }
    }

    // allocate at least enough space for the code + 1 byte
    // (so that there will be at least one INT3 - see below),
    // rounded up to a multiple of the system page size.
    size_t rounded_codesize = ((codelen + 1 + pagesize - 1)/ pagesize) * pagesize;

    void *executable_area = mmap(0, rounded_codesize,
                                 PROT_READ|PROT_WRITE,
                                 MAP_PRIVATE|MAP_ANONYMOUS,
                                 -1, 0);
    if (!executable_area) {
        printf("mmap fail\n");
        return 1;
    } else {
        printf("--success mapping the rounded_codesize=%ld of %p\n", rounded_codesize, executable_area);
    }

    // at this point, executable_area points to memory that is writable but
    // *not* executable.  load the code into it.
    memcpy(executable_area, code, codelen);

    // fill the space at the end with INT3 instructions, to guarantee
    // a prompt crash if the generated code runs off the end.
    // must change this if generating code for non-x86.
    memset(executable_area + codelen, 0xCC, rounded_codesize - codelen);

    // make executable_area actually executable (and unwritable)
    if (mprotect(executable_area, rounded_codesize, PROT_READ|PROT_EXEC))
    {
        printf("mprotect fail\n");
        return 1;
    } else {
        printf("--success in calling mprotect with read|exec\n");
    }
    // now we can call it. passing arguments / receiving return values
    // is left as an exercise (consult libffi source code for clues).
    int ret = ((int (*)(void)) executable_area)();
    printf("get this done. returned: %d", ret);
    munmap(executable_area, rounded_codesize);
    return 0;
}

这是我尝试编译/运行上述代码的文件。

aarch64-linux-gnu-gcc test.c -g -O0 -o test.out -DGNU_SOURCE
file test.out
test.out: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, BuildID[sha1]=209123aff57cef69be8037e5616a3b71ceb6ad38, for GNU/Linux 3.7.0, with debug_info, not stripped
qemu-aarch64-static -L /usr/aarch64-linux-gnu/ ./test.out
--success getting the pagesize=4096
--success mapping the rounded_codesize=4096 of 0x40019ca000
--success in calling mprotect with read|exec
qemu: uncaught target signal 5 (Trace/breakpoint trap) - core dumped
make: *** [Makefile:21: aarch64_test1] Trace/breakpoint trap

调用上面的机器码“int ret = ((int (*)(void))executable_area)();”失败。我只是想知道我尝试使用 aarch 编译工具链是否有什么问题。

I saw and tried some samples of executing machine code in C for Linux. It works well.
When I tried for aarch64, it always fails. Here is what I tried.
C file:

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

#include <limits.h>    /* for PAGESIZE */
#ifndef PAGESIZE
#define PAGESIZE 4096
#endif

const static unsigned char code[] = {
    0x40, 0x05, 0x80, 0x52, // mov     w0, #0x2a
    //0xd6, 0x5f, 0x03, 0xc0 // ret instruction
    0x40, 0x97, 0x3b, 0xd4  //  brk     #0xdcba
};

int main(int argc, char **argv) { 
    int codelen = (int) sizeof(code);
    // in order to manipulate memory protection, we must work with
    // whole pages allocated directly from the operating system.
    static size_t pagesize=0;
    if (!pagesize) {
        pagesize = sysconf(_SC_PAGESIZE);
        if (pagesize == (size_t)-1) {
            printf("getpagesize fail\n");
            return 1;
        } else {
            printf("--success getting the pagesize=%ld\n", pagesize);
        }
    }

    // allocate at least enough space for the code + 1 byte
    // (so that there will be at least one INT3 - see below),
    // rounded up to a multiple of the system page size.
    size_t rounded_codesize = ((codelen + 1 + pagesize - 1)/ pagesize) * pagesize;

    void *executable_area = mmap(0, rounded_codesize,
                                 PROT_READ|PROT_WRITE,
                                 MAP_PRIVATE|MAP_ANONYMOUS,
                                 -1, 0);
    if (!executable_area) {
        printf("mmap fail\n");
        return 1;
    } else {
        printf("--success mapping the rounded_codesize=%ld of %p\n", rounded_codesize, executable_area);
    }

    // at this point, executable_area points to memory that is writable but
    // *not* executable.  load the code into it.
    memcpy(executable_area, code, codelen);

    // fill the space at the end with INT3 instructions, to guarantee
    // a prompt crash if the generated code runs off the end.
    // must change this if generating code for non-x86.
    memset(executable_area + codelen, 0xCC, rounded_codesize - codelen);

    // make executable_area actually executable (and unwritable)
    if (mprotect(executable_area, rounded_codesize, PROT_READ|PROT_EXEC))
    {
        printf("mprotect fail\n");
        return 1;
    } else {
        printf("--success in calling mprotect with read|exec\n");
    }
    // now we can call it. passing arguments / receiving return values
    // is left as an exercise (consult libffi source code for clues).
    int ret = ((int (*)(void)) executable_area)();
    printf("get this done. returned: %d", ret);
    munmap(executable_area, rounded_codesize);
    return 0;
}

Here is what I tried to compile/run the above code.

aarch64-linux-gnu-gcc test.c -g -O0 -o test.out -DGNU_SOURCE
file test.out
test.out: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, BuildID[sha1]=209123aff57cef69be8037e5616a3b71ceb6ad38, for GNU/Linux 3.7.0, with debug_info, not stripped
qemu-aarch64-static -L /usr/aarch64-linux-gnu/ ./test.out
--success getting the pagesize=4096
--success mapping the rounded_codesize=4096 of 0x40019ca000
--success in calling mprotect with read|exec
qemu: uncaught target signal 5 (Trace/breakpoint trap) - core dumped
make: *** [Makefile:21: aarch64_test1] Trace/breakpoint trap

It fails in calling the above machine code "int ret = ((int (*)(void)) executable_area)();". I am just wondering if there is anything wrong in my trying with aarch compiling toolchain.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文