1 year ago

#342583

test-img

Software-security-is-not-free

How to execute aarch64 generated machine code in c

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.

arm64

machine-code

generated

0 Answers

Your Answer

Accepted video resources