【发布时间】:2019-04-07 23:42:24
【问题描述】:
感谢this 问题中的帮助,加载程序现在可以将静态编译的 hello world 映射到内存并跳转到该内存区域的某个位置。我现在面临的问题是我似乎没有跳转到正确的地址或者我以错误的方式调用函数(或错误的函数?)。
下面是要尝试的代码;我在 glibc 中找不到加载程序调用程序入口点的位置来验证我在做正确的事情。我试过了:
- 调用 _start(void)
- 调用 _start(int, char**, char**)
- 在最后一个参数设置为 NULL 的情况下调用 __libc_start_main(找到 here)
- 直接调用main
- 调用一些地址(使用 gdb 在 rdi: 400B4D, r8: 4018E0, rcx: 401840)
入口点是0x400a30,__libc_start_main下面的一些指令。其中一些是 SIGSEGV、SIGABRT 或打印:
hello, world! haswell xeon_phi ../csu/libc-start.c FATAL: kernel too old
__ehdr_start.e_phentsize == sizeof *GL(dl_phdr) unexpected reloc type in static binary FATAL: cannot determine kernel version
__libc_start_main /dev/full /dev/null cannot set %fs base address for thread-local storage : %s%s%s:%u: %s%sAssertion `%s' failed.
%n Unexpected error.
还有几百条垃圾线。
int main(int argc, char* argv[argc+1]) {
FILE *fp = fopen(argv[1], "r");
if (!fp) {
fprintf(stderr, "cannot open file %s", argv[1]);
return 1;
}
fseek(fp, 0L, SEEK_END);
size_t sz = ftell(fp) + 1;
rewind(fp);
char *region = mmap(NULL, sz, PROT_READ, MAP_PRIVATE, fileno(fp), 0);
if (region == MAP_FAILED) {
fprintf(stderr, "could not mmap");
return 1;
}
Elf64_Ehdr elf64Ehdr;
memmove(&elf64Ehdr, region, sizeof(elf64Ehdr));
size_t offset;
Elf64_Phdr elf64Phdr;
for (uint16_t i = 0; i != elf64Ehdr.e_phnum; ++i) {
offset = elf64Ehdr.e_phoff + i * elf64Ehdr.e_phentsize;
memmove(&elf64Phdr, region + offset, sizeof(elf64Phdr));
switch (elf64Phdr.p_type) {
case PT_NULL:
break;
case PT_LOAD:
if (load(&elf64Phdr, region + elf64Phdr.p_offset)) {
exit(EXIT_FAILURE);
}
break;
default:
break;
}
}
printf("jumping to: 0x%x\n", elf64Ehdr.e_entry);
char *argv1[] = {"", NULL};
int ret = ((int (*)(int, char **, char **)) elf64Ehdr.e_entry)(1, argv1, argv1);
return ret;
}
int load(const Elf64_Phdr *phdr, const void *elf_bytes_for_phdr) {
const size_t pagesize = getpagesize();
const size_t unaligned_bytes = phdr->p_vaddr % pagesize;
void *base_addr = phdr->p_vaddr - unaligned_bytes;
size_t total_bytes = phdr->p_memsz + unaligned_bytes;
void *region = mmap(base_addr, total_bytes,
phdr->p_flags | PROT_WRITE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
if (region != MAP_FAILED) {
memset(region, 0, unaligned_bytes);
return memcpy(region + unaligned_bytes, elf_bytes_for_phdr, phdr->p_filesz) != region + unaligned_bytes &&
! mprotect(region, total_bytes, phdr->p_flags);
}
return 1;
}
【问题讨论】:
-
我错过了什么吗?看起来您是直接调用 elf64Ehdr.e_entry ,即没有偏移基址(区域)...?