问题描述:

I have a simple hello world program written in assembly. It prints "Hello, world!" and exits. When compiling with nasm and executing the code directly, everything works fine.

I also wrote some C code to load a flat binary and execute its code using mmap. When loading the flat binary, the text is not printed out. I'm pretty sure the call is happening, because adding an extra call to exit causes the program to exit prematurely. Here's the code for the assembly program:

 global start

section .text

start:

; write is not run

mov rax, 0x2000004

mov rdi, 1

mov rsi, msg

mov rdx, msg.len

syscall

; but exit is...

mov rax, 0x2000001

mov rdi, 0

syscall

section .data

msg: db "Hello, world!", 10

.len: equ $ - msg

Compile it with nasm -f macho64 hello.s && ld -macosx_version_min 10.7.0 hello.o -o hello and generate a flat binary with objcopy -O binary hello.o hello.bin.

The code to load and execute the binary looks like this:

#include <sys/mman.h>

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

/* allocate executable memory size-bytes long */

void* memexec_alloc(size_t size)

{

void* ptr = mmap(0, size,

PROT_READ | PROT_WRITE | PROT_EXEC,

MAP_PRIVATE | MAP_ANON,

-1, 0);

if (ptr == (void *)-1) {

printf("mmap error\n");

return NULL;

}

return ptr;

}

/* Load contents of file f into mem */

void memload(const char *f, unsigned char *mem)

{

FILE *file;

size_t size;

unsigned char *data;

file = fopen(f, "r");

fseek(file, 0, SEEK_END);

size = ftell(file);

rewind(file);

data = (unsigned char*) malloc(sizeof(char) * size);

fread(data, sizeof(char), size, file);

fclose(file);

memcpy(mem, data, sizeof(char) * size);

free(data);

}

static const size_t SIZE = 1024;

typedef void (*voidfunc)(void);

int main(int argc, char **argv)

{

if (argc != 2) {

puts("no file specified!");

return 1;

}

void *mem = memexec_alloc(SIZE);

memload(argv[1], mem);

voidfunc func = mem;

func();

return 1;

}

Inspecting the code in a debugger shows that the first syscall is indeed executed, but nothing is printed out, the program then exits with a value of 0 instead of 1. How do I get it to print?

(The OS is OS X Mavericks, 64 bit.)

网友答案:

After a few hours of debugging and research, it seems I've got it. The loading of the value of msg is done with mov rsi, msg. This uses an absolute address, which has no meaning when inside the C program (the loader). The loader's addresses are completely different, and the location of msg is also different. Thus, we need to load the address with lea rsi, [rel msg]. This will give us the relative address of msg. We're still missing something though. Compiling hello.bin using the command from before won't work, because relative addressing is decided at link time, thus, we need to link hello.o first:

   global start

   section .text
start:
   mov   rax, 0x2000004
   mov   rdi, 1
   lea   rsi, [rel msg]
   mov   rdx, msg.len
   syscall
; added a `ret' so we return to the loader
   ret

   section .data
msg:    db      "Hello, world!", 10
.len:   equ     $ - msg

Compile with:

$ nasm -f macho64 hello.s
$ ld -macosx_version_min 10.7.0 hello.o -o hello
$ objcopy -O binary hello hello.bin

And it should result in a hello.bin that runs properly.

相关阅读:
Top