JATothrim
JATothrim

Reputation: 852

Linux AMD64 call C library functions from copied assembly

How do I call from an memcpy'ed assembly function a C library functions?

I'm making an example test code how one can allocate and change memory protection on Linux, AMD64 to run arbitrarily generated code from C. What I done is that I compile an small GAS assembly function along side my main program (written in C) and then copy the assembly binary blob onto piece executable memory in run-time and jump into it. This part works OK.

But I if call C library puts() from the copied assembly blob it results in segfault due to bad function address?! How do I fix it?

The assembly code blob:

       .text
       .global      _print_hello_size
       .global      _print_hello
       .type        _print_hello,@function
_print_hello:
       push %rbp
       mov %rsp, %rbp
       # puts("Hello World\n")
       mov $_message, %rdi
       call puts    # <-- SEGFAULT
       pop %rbp
       ret
procend: # mark end address of the _print_hello code
       .section .rodata
_message:
       .asciz  "Hello, world\n"
_print_hello_size:
       .long procend - _print_hello

Then in C main() I do (pseudo code):

// Import assembler function and its size
extern "C" void _print_hello(void);
extern "C" const long _print_hello_size;
int main() {
    // Use special function that allocates Read-Write-Executable memory
    void * memexec = MallocExecutableMemory(1024);
    // Copy the binary asm blob, memexec is aligned to at least 16-bytes
    memcpy(memexec, (void*)_print_hello, _print_hello_size);

    void (*jmpfunc)(void) = (void (*)(void))memexec; 
    jmpfunc(); // Works, jumps into copied assembly func
    return 0;
}

Later if this is even possible would not even compile the asm blob, but just encode the example program in in unsigned char execblob[] = { 0xCC,0xCC,0xC3,..} and copy that into the executable region. This bit code exploration how to start generating asm from C.

Upvotes: 2

Views: 449

Answers (2)

user35443
user35443

Reputation: 6403

Maybe you could do

push %rbp
mov %rsp, %rbp
# puts("Hello World\n")
mov $_message, %rdi
mov $puts, %eax
call %eax
pop %rbp
ret

and thus forcing the call to become an absolute one. The question is whether the assembler won't optimize this out for its own purposes.

Upvotes: 2

JATothrim
JATothrim

Reputation: 852

It it impossible call any C standard library function (or any linked) from memcpy-ed block of code, as if linker decides the puts function entry point is any where else than it originally was the copied code block is simply malformed. The first answer stops working the second binary blob is out-of-sync with the rest of the program.

Only way around is to modify the binary blob at run-time and assign the current real function addresses (from the C program) to the blob like C linker does.

Upvotes: 0

Related Questions