Linux AMD64从复制的程序集中调用C库函数

时间:2015-05-30 17:44:15

标签: c linux assembly x86-64

如何从memcpy的汇编函数调用C库函数?

我正在制作一个示例测试代码,如何在Linux上分配和更改内存保护,AMD64从C运行任意生成的代码。 我所做的是我在主程序(用C编写)的旁边编译一个小的GAS汇编函数,然后在运行时将汇编二进制blob复制到一块可执行内存中并跳转到它。 这部分工作正常。

但是如果从复制的程序集blob调用C库puts(),它会因为函数地址错误而导致段错误?!我该如何解决?

汇编代码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

然后在C main()中我做(伪代码):

// 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;
}

稍后如果这甚至可能甚至不能编译asm blob,而只是编码 unsigned char execblob [] = {0xCC,0xCC,0xC3,..} 中的示例程序并复制进入可执行区域。这个位代码探索如何从C开始生成asm。

2 个答案:

答案 0 :(得分:2)

也许你可以做到

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

因而迫使call成为绝对的。问题是汇编程序是否不会出于自身目的对其进行优化。

答案 1 :(得分:0)

不可能从 memcpy-ed代码块中调用任何C标准库函数(或任何链接的),就好像链接器决定puts函数入口点是否是最初的其他地方复制的代码块只是格式错误。第一个答案停止工作,第二个二进制blob与程序的其余部分不同步。

唯一的方法是在运行时修改二进制blob,并将当前的实际函数地址(从C程序)分配给blob,就像C链接器一样。