2013-08-29 2 views
1

Я пытаюсь кодирование программы, чтобы вставить пустой (как первый шаг) PHDR структуру к любому эльф двоичного, так что я кодирование, как показано ниже:Вставьте новый раздел в двоичный файл?

кошка add_phdr.c

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <fcntl.h> 
#include <unistd.h> 
#include <elf.h> 
#include <sys/mman.h> 
#include <stddef.h> 

static void calc_dyntables(void **ehdr_ptr, size_t bound_size) 
{ 
    void *ptr = *ehdr_ptr; 
    Elf32_Ehdr *Elf32_ptr = NULL; 

    Elf32_ptr = (Elf32_Ehdr *)ptr; 
    Elf32_Phdr *elf32_phdr = NULL; 
    int n, found = 0; 

    n = Elf32_ptr->e_phnum; 
    elf32_phdr = ptr + Elf32_ptr->e_phoff; 
    while (n--) { 
     if (elf32_phdr->p_type == PT_DYNAMIC) { 
      found = 1; 
      break; 
     } 
     elf32_phdr++; 
    } 

    if (found) { 
     /* printf("=== PT_DYNAMIC: offset: 0x%x, size: 0x%x\n", */ 
       /* elf32_phdr->p_offset, elf32_phdr->p_filesz); */ 
     /* printf("sizeof(Elf32_Dyn): %d\n", sizeof(Elf32_Dyn)); */ 
    } 
    else 
     return; 

    /* list all of dynamic sections */ 
    found = 0; 
    Elf32_Dyn *dyn_entry = ptr + elf32_phdr->p_offset; 
    while (dyn_entry->d_tag != DT_NULL) { 
     switch (dyn_entry->d_tag) { 
      case 0x6ffffef5: 
       dyn_entry->d_un.d_ptr += bound_size; 
       break; 
      case 0x6ffffff0: 
       dyn_entry->d_un.d_ptr += bound_size; 
       break; 
      case 0x6ffffffe: 
       dyn_entry->d_un.d_ptr += bound_size; 
       break; 
      case 0x0000000c: 
       dyn_entry->d_un.d_ptr += bound_size; 
       break; 
      case 0x0000000d: 
       dyn_entry->d_un.d_ptr += bound_size; 
       break; 
      case 0x00000019: 
       dyn_entry->d_un.d_ptr += bound_size; 
       break; 
      case 0x0000001a: 
       dyn_entry->d_un.d_ptr += bound_size; 
       break; 
      case 0x00000005: 
       dyn_entry->d_un.d_ptr += bound_size; 
       break; 
      case 0x00000006: 
       dyn_entry->d_un.d_ptr += bound_size; 
       break; 
      case 0x00000003: 
       dyn_entry->d_un.d_ptr += bound_size; 
       break; 
      case 0x00000017: 
       dyn_entry->d_un.d_ptr += bound_size; 
       break; 
      case 0x00000011: 
       dyn_entry->d_un.d_ptr += bound_size; 
       break; 
      default: 
       break; 
     } 
     /* printf("== tag: 0x%x, value: 0x%x\n", dyn_entry->d_tag, */ 
       /* dyn_entry->d_un.d_val); */ 
     dyn_entry++; 
    } 

} 

static int write_phdr(int fd_dst, void *ptr, size_t filesize) 
{ 
    /* ptr for Ehdr */ 
    Elf32_Ehdr *Elf32_ptr = NULL; 
    Elf32_ptr = (Elf32_Ehdr *)ptr; 

    /* ptr for Phdr */ 
    Elf32_Phdr *elf32_phdr = NULL; 
    /* ptr for Shdr */ 
    Elf32_Shdr *elf32_shdr = NULL; 

    int n; 

    /* 
    * We must find the phdr array's border, then recalcuate 
    * the offset of phdrs & shdrs which's offset beyond the 
    * offset of border. 
    */ 
    off_t old_phdr_border = Elf32_ptr->e_phoff + Elf32_ptr->e_phentsize * Elf32_ptr->e_phnum; 
    printf("=== border 0x%x\n", (unsigned int) (0x8048000 + old_phdr_border)); 
    off_t phdr_size = Elf32_ptr->e_phentsize; 

    /* recalcuate the hash table address */ 
    calc_dyntables(&ptr, phdr_size); 
    /* pdhr */ 
    n = Elf32_ptr->e_phnum; 
    elf32_phdr = ptr + Elf32_ptr->e_phoff; 

    /* recalculate phdr offset */ 
    while (n-- > 0) { 
     if (elf32_phdr->p_offset >= old_phdr_border) { 
      elf32_phdr->p_offset += phdr_size; 
      elf32_phdr->p_vaddr += phdr_size; 
      elf32_phdr->p_paddr += phdr_size; 
     } 
     else { 
      if ((elf32_phdr->p_offset + elf32_phdr->p_filesz) >= old_phdr_border) { 
       elf32_phdr->p_filesz += phdr_size; 
       elf32_phdr->p_memsz += phdr_size; 
      } 
     } 
     elf32_phdr++; 
    } 

    /* recalculate shdr offset */ 
    n = Elf32_ptr->e_shnum; 
    elf32_shdr = ptr + Elf32_ptr->e_shoff; 
    while (n-- > 0) { 
     if (elf32_shdr->sh_offset >= old_phdr_border) { 
      elf32_shdr->sh_offset += phdr_size; 
      elf32_shdr->sh_addr += phdr_size; 
     } 
     else { 
      if ((elf32_shdr->sh_offset + elf32_shdr->sh_size) >= old_phdr_border) { 
       elf32_shdr->sh_size += phdr_size; 
      } 
     } 
     elf32_shdr++; 
    } 

    Elf32_ptr->e_shoff += phdr_size; 

    Elf32_Phdr *new_ptr = malloc(sizeof(Elf32_Phdr)); 
    if (new_ptr == NULL) 
     return -1; 

    Elf32_ptr->e_phnum += 1; 

    /* recalculate the entry */ 
    if (Elf32_ptr->e_entry > old_phdr_border) 
     Elf32_ptr->e_entry += phdr_size; 


    write(fd_dst, ptr, old_phdr_border); 
    memset(new_ptr, 0, sizeof(Elf32_Phdr)); 
    new_ptr->p_type = PT_NULL; 
    new_ptr->p_offset = 0xffff; 
    new_ptr->p_vaddr = 0xffff; 
    new_ptr->p_paddr = 0xffff; 
    new_ptr->p_filesz = 0x1111; 
    new_ptr->p_memsz = 0; 
    new_ptr->p_flags = PF_R; 
    new_ptr->p_align = 0x4; 
    write(fd_dst, new_ptr, phdr_size); 
    write(fd_dst, ptr + old_phdr_border, filesize - old_phdr_border); 

    free(new_ptr); 

    return 0; 
} 

/* 
* this version of write_phdr will apend phdr to 
* the tail of file, so it wont move any sections 
* or offset, we just need change the entry address. 
*/ 
static int write_phdr2(int fd_dst, void *ptr, size_t filesize) 
{ 
    /* ptr for Ehdr */ 
    Elf32_Ehdr *Elf32_ptr = NULL; 
    Elf32_ptr = (Elf32_Ehdr *)ptr; 

    /* ptr for Phdr */ 
// Elf32_Phdr *elf32_phdr = NULL; 

    Elf32_Phdr *new_ptr = malloc(sizeof(Elf32_Phdr)); 
    if (new_ptr == NULL) 
     return -1; 

    off_t phdr_size = Elf32_ptr->e_phentsize; 

    /* recalculate the entry */ 
// Elf32_ptr->e_entry += phdr_size; 

    write(fd_dst, ptr, filesize); 

    /* append the phdr to the tail of file */ 
    memset(new_ptr, 0, sizeof(Elf32_Phdr)); 
    new_ptr->p_type = PT_NULL; 
    new_ptr->p_offset = 0xffff; 
    new_ptr->p_vaddr = 0xffff; 
    new_ptr->p_paddr = 0xffff; 
    new_ptr->p_filesz = 0; 
    new_ptr->p_memsz = 0; 
    new_ptr->p_flags = PF_R; 
    new_ptr->p_align = 0x4; 
    write(fd_dst, new_ptr, phdr_size); 

    free(new_ptr); 

    return 0; 
} 

/* 
* we'll add a new phdr to the binary file 
*/ 
int main(int argc, char *argv[]) 
{ 
    int fd_src, fd_dst; 
    //size_t len = 0; 
    size_t filesize = 0; 
    void *ptr = NULL; /* ptr to binary file which mapped in memory */ 
    if (argc != 3) { 
     printf("Usage: %s [ src bin ] [ dst bin ]...\n", argv[0]); 
     exit(EXIT_FAILURE); 
    } 

    /* 
    * we'll calculate the file size then map to memory 
    */ 
    fd_src = open(argv[1], O_RDONLY); 

    if (fd_src < 0) { 
     printf("Failed to open %s!\n", argv[1]); 
     exit(EXIT_FAILURE); 
    } 

    fd_dst = open(argv[2], O_CREAT | O_WRONLY | O_TRUNC, 0755); 

    if (fd_dst < 0) { 
     printf("Failed to open %s!\n", argv[2]); 
     exit(EXIT_FAILURE); 
    } 

    /* get file size with lseek SEEK_END */ 
    filesize = lseek(fd_src, 0, SEEK_END); 
    if (filesize < 0) { 
     perror("lseek failed!"); 
     close(fd_src); 
     exit(EXIT_FAILURE); 
    } 

    ptr = mmap(0, filesize, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd_src, 0); 
    if (ptr < 0) { 
     perror("mmap failed!"); 
     close(fd_src); 
     exit(EXIT_FAILURE); 
    } 

    if (1) 
    write_phdr(fd_dst, ptr, filesize); 

    if (0) 
    write_phdr2(fd_dst, ptr, filesize); 

    /* copy the modified file to dst */ 
    /* do the clean work */ 
    munmap(ptr, filesize); 
    close(fd_src); 
    close(fd_dst); 

    return EXIT_SUCCESS; 
} 

тогда Makefile:

cat Makefile 
CC = $(CROSS_COMPILE)gcc 
LD = $(CROSS_COMPILE)ld 
LDFLAGS = -m elf_i386 
CFLAGS = -m32 -Wall -fPIE 

TARGETS = elf_parser show_addr without_libc add_phdr read_elf hello 

all: $(TARGETS) 

elf_parser:elf_parser.c 
    $(CC) $(CFLAGS) -o [email protected] $< 

show_addr:show_addr.c 
    $(CC) $(CFLAGS) -o [email protected] $< 

without_libc:without_libc.c 
    $(CC) $(CFLAGS) -nostdlib -o [email protected] $< 

add_phdr:add_phdr.c 
    $(CC) $(CFLAGS) -o [email protected] $< 

hello:hello.c 
    $(CC) $(CFLAGS) -o [email protected] $< 

read_elf:read_elf.o 
    $(LD) $(LDFLAGS) -o [email protected] $< 

read_elf.o:read_elf.asm 
    nasm -f elf32 -o [email protected] $< 

clean: 
    rm -rf $(TARGETS) 
    rm -rf *.o 

OK, есть много другого кода включает в себя код ассемблера, я просто перечислить read_elf.asm и hello.c как сравнение: кошка read_elf.asm:

global _start 
_start: 
    call main 
    xor  eax, eax 
    inc  eax 
    xor  ebx, ebx 
    int  0x80 

main: 
    call funA 
    ret 

funA: 
    call funB 
    ret 
funB: 
    call funC 
    ret 
funC: 
    push byte 4 
    pop  eax 
    xor  ebx, ebx 
    inc  ebx 
    mov  ecx, 0x08048001 
    push byte 3 
    pop  edx 
    int  0x80 
    ret 

кот hello.c:

int main() 
{ 
    return 10; 
} 

Далее, давайте компилировать коды, а затем запустить программу add_phdr:

./add_phdr read_elf test 

затем запустить тест, он работает хорошо, но когда я пытаюсь пропатчить программу приветствия, как показано ниже:

./add_phdr hello hello_test 
./hello_test 

Я получил это:

Inconsistency detected by ld.so: dl-lookup.c: 876: _dl_setup_hash: Assertion `(bitmask_nwords & (bitmask_nwords - 1)) == 0' failed! 

Я больше не мог запускать его!
Итак, какие-нибудь советы?

Update:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <fcntl.h> 
#include <unistd.h> 
#include <elf.h> 
#include <sys/mman.h> 
#include <stddef.h> 

static void calc_symtab(void **ehdr_ptr, size_t bound_size) 
{ 
    void *ptr = *ehdr_ptr; 
    Elf32_Shdr *shdr_ptr = NULL; 
    Elf32_Ehdr *Elf32_ptr = (Elf32_Ehdr *)ptr; 


    int n = Elf32_ptr->e_shnum; 
    char *shstrtab = NULL; 

    /* 
    * first of all, let's get the shstrtab, we'll get 
    * the name of each section with it 
    */ 
    shdr_ptr = (Elf32_Shdr *)(ptr + Elf32_ptr->e_shoff); 
    while (n--) { 
     if (shdr_ptr->sh_type == SHT_STRTAB) { 
      shstrtab = (char *)(ptr + shdr_ptr->sh_offset); 
      if (!strcmp(&shstrtab[shdr_ptr->sh_name], ".shstrtab")) 
       break; 
     } 
     shdr_ptr++; 
    } 

    /* list all of sections */ 
    shdr_ptr = (Elf32_Shdr *)(ptr + Elf32_ptr->e_shoff); 
    n = Elf32_ptr->e_shnum; 
    while (n--) { 
     if (shdr_ptr->sh_type == SHT_SYMTAB) { 
      int n2 = (shdr_ptr->sh_size/sizeof(Elf32_Sym)); 
      Elf32_Sym *sym = (Elf32_Sym *)(ptr + shdr_ptr->sh_offset); 
      while (n2--) { 
       if (sym->st_value > 0) 
        sym->st_value += bound_size; 
       sym++; 
      } 
     } 
     shdr_ptr++; 
    } 
} 

static void calc_dynsym(void **ehdr_ptr, size_t bound_size) 
{ 
    void *ptr = *ehdr_ptr; 
    Elf32_Shdr *shdr_ptr = NULL; 
    Elf32_Ehdr *Elf32_ptr = (Elf32_Ehdr *)ptr; 


    int n = Elf32_ptr->e_shnum; 
    char *shstrtab = NULL; 

    /* 
    * first of all, let's get the shstrtab, we'll get 
    * the name of each section with it 
    */ 
    shdr_ptr = (Elf32_Shdr *)(ptr + Elf32_ptr->e_shoff); 
    while (n--) { 
     if (shdr_ptr->sh_type == SHT_STRTAB) { 
      shstrtab = (char *)(ptr + shdr_ptr->sh_offset); 
      if (!strcmp(&shstrtab[shdr_ptr->sh_name], ".shstrtab")) 
       break; 
     } 
     shdr_ptr++; 
    } 

    /* list all of sections */ 
    shdr_ptr = (Elf32_Shdr *)(ptr + Elf32_ptr->e_shoff); 
    n = Elf32_ptr->e_shnum; 
    while (n--) { 
     if (shdr_ptr->sh_type == SHT_DYNSYM) { 
      int n2 = (shdr_ptr->sh_size/sizeof(Elf32_Sym)); 
      Elf32_Sym *sym = (Elf32_Sym *)(ptr + shdr_ptr->sh_offset); 
      while (n2--) { 
       if (sym->st_value > 0) 
        sym->st_value += bound_size; 
       sym++; 
      } 
     } 
     shdr_ptr++; 
    } 
} 

static void calc_relocs(void **ehdr_ptr, size_t bound_size) 
{ 
    void *ptr = *ehdr_ptr; 
    Elf32_Shdr *shdr_ptr = NULL; 
    Elf32_Ehdr *Elf32_ptr = (Elf32_Ehdr *)ptr; 


    int n = Elf32_ptr->e_shnum; 
    char *shstrtab = NULL; 

    /* 
    * first of all, let's get the shstrtab, we'll get 
    * the name of each section with it 
    */ 
    shdr_ptr = (Elf32_Shdr *)(ptr + Elf32_ptr->e_shoff); 
    while (n--) { 
     if (shdr_ptr->sh_type == SHT_STRTAB) { 
      shstrtab = (char *)(ptr + shdr_ptr->sh_offset); 
      if (!strcmp(&shstrtab[shdr_ptr->sh_name], ".shstrtab")) 
       break; 
     } 
     shdr_ptr++; 
    } 

    /* list all of sections */ 
    shdr_ptr = (Elf32_Shdr *)(ptr + Elf32_ptr->e_shoff); 
    n = Elf32_ptr->e_shnum; 
    while (n--) { 
     if (shdr_ptr->sh_type == SHT_REL || shdr_ptr->sh_type == SHT_RELA) { 

      int n2 = (shdr_ptr->sh_size/sizeof(Elf32_Rel)); 
      Elf32_Rel *rel = (Elf32_Rel *)(ptr + shdr_ptr->sh_offset); 
      while (n2--) { 
       rel->r_offset += bound_size; 
       rel++; 
      } 
     } 
     shdr_ptr++; 
    } 
} 

static void calc_dyntables(void **ehdr_ptr, size_t bound_size) 
{ 
    void *ptr = *ehdr_ptr; 
    Elf32_Ehdr *Elf32_ptr = NULL; 

    Elf32_ptr = (Elf32_Ehdr *)ptr; 
    Elf32_Phdr *elf32_phdr = NULL; 
    int n, found = 0; 

    n = Elf32_ptr->e_phnum; 
    elf32_phdr = ptr + Elf32_ptr->e_phoff; 
    while (n--) { 
     if (elf32_phdr->p_type == PT_DYNAMIC) { 
      found = 1; 
      break; 
     } 
     elf32_phdr++; 
    } 

    if (found) { 
     /* printf("=== PT_DYNAMIC: offset: 0x%x, size: 0x%x\n", */ 
       /* elf32_phdr->p_offset, elf32_phdr->p_filesz); */ 
     /* printf("sizeof(Elf32_Dyn): %d\n", sizeof(Elf32_Dyn)); */ 
    } 
    else 
     return; 

    /* list all of dynamic sections */ 
    found = 0; 
    Elf32_Dyn *dyn_entry = ptr + elf32_phdr->p_offset; 
    while (dyn_entry->d_tag != DT_NULL) { 
     switch (dyn_entry->d_tag) { 
      case DT_GNU_HASH: 
       dyn_entry->d_un.d_ptr += bound_size; 
       break; 
      case DT_VERSYM: 
       dyn_entry->d_un.d_ptr += bound_size; 
       break; 
      case DT_VERNEED: 
       dyn_entry->d_un.d_ptr += bound_size; 
       break; 
      case DT_INIT: 
       dyn_entry->d_un.d_ptr += bound_size; 
       break; 
      case DT_FINI: 
       dyn_entry->d_un.d_ptr += bound_size; 
       break; 
      case DT_INIT_ARRAY: 
       dyn_entry->d_un.d_ptr += bound_size; 
       break; 
      case DT_FINI_ARRAY: 
       dyn_entry->d_un.d_ptr += bound_size; 
       break; 
      case DT_STRTAB: 
       dyn_entry->d_un.d_ptr += bound_size; 
       break; 
      case DT_SYMTAB: 
       dyn_entry->d_un.d_ptr += bound_size; 
       break; 
      case DT_PLTGOT: 
       dyn_entry->d_un.d_ptr += bound_size; 
       break; 
      case DT_JMPREL: 
       dyn_entry->d_un.d_ptr += bound_size; 
       break; 
      case DT_REL: 
       dyn_entry->d_un.d_ptr += bound_size; 
       break; 
      default: 
       break; 
     } 
     /* printf("== tag: 0x%x, value: 0x%x\n", dyn_entry->d_tag, */ 
       /* dyn_entry->d_un.d_val); */ 
     dyn_entry++; 
    } 

} 

static int write_phdr(int fd_dst, void *ptr, size_t filesize) 
{ 
    /* ptr for Ehdr */ 
    Elf32_Ehdr *Elf32_ptr = NULL; 
    Elf32_ptr = (Elf32_Ehdr *)ptr; 

    /* ptr for Phdr */ 
    Elf32_Phdr *elf32_phdr = NULL; 
    /* ptr for Shdr */ 
    Elf32_Shdr *elf32_shdr = NULL; 

    int n; 

    /* 
    * We must find the phdr array's border, then recalcuate 
    * the offset of phdrs & shdrs which's offset beyond the 
    * offset of border. 
    */ 
    off_t old_phdr_border = Elf32_ptr->e_phoff + Elf32_ptr->e_phentsize * Elf32_ptr->e_phnum; 
    printf("=== border 0x%x\n", (unsigned int) (0x8048000 + old_phdr_border)); 
    off_t phdr_size = Elf32_ptr->e_phentsize; 

    /* recalcuate the hash table address */ 
    calc_dyntables(&ptr, phdr_size); 
    calc_relocs(&ptr, phdr_size); 
    calc_symtab(&ptr, phdr_size); 
    calc_dynsym(&ptr, phdr_size); 
    /* pdhr */ 
    n = Elf32_ptr->e_phnum; 
    elf32_phdr = ptr + Elf32_ptr->e_phoff; 

    /* recalculate phdr offset */ 
    while (n-- > 0) { 
     if (elf32_phdr->p_offset >= old_phdr_border) { 
      elf32_phdr->p_offset += phdr_size; 
      elf32_phdr->p_vaddr += phdr_size; 
      elf32_phdr->p_paddr += phdr_size; 
     } 
     else { 
      if ((elf32_phdr->p_offset + elf32_phdr->p_filesz) >= old_phdr_border) { 
       elf32_phdr->p_filesz += phdr_size; 
       elf32_phdr->p_memsz += phdr_size; 
      } 
     } 
     elf32_phdr++; 
    } 

    /* recalculate shdr offset */ 
    n = Elf32_ptr->e_shnum; 
    elf32_shdr = ptr + Elf32_ptr->e_shoff; 
    while (n-- > 0) { 
     if (elf32_shdr->sh_offset >= old_phdr_border) { 
      elf32_shdr->sh_offset += phdr_size; 
      if (elf32_shdr->sh_addr > 0) 
       elf32_shdr->sh_addr += phdr_size; 
     } 
     else { 
      if ((elf32_shdr->sh_offset + elf32_shdr->sh_size) >= old_phdr_border) { 
       elf32_shdr->sh_size += phdr_size; 
      } 
     } 
     elf32_shdr++; 
    } 

    Elf32_ptr->e_shoff += phdr_size; 

    Elf32_Phdr *new_ptr = malloc(sizeof(Elf32_Phdr)); 
    if (new_ptr == NULL) 
     return -1; 

    Elf32_ptr->e_phnum += 1; 

    /* recalculate the entry */ 
    if (Elf32_ptr->e_entry >= old_phdr_border) 
     Elf32_ptr->e_entry += phdr_size; 


    write(fd_dst, ptr, old_phdr_border); 
    memset(new_ptr, 0, sizeof(Elf32_Phdr)); 
    new_ptr->p_type = PT_NULL; 
    new_ptr->p_offset = 0xffff; 
    new_ptr->p_vaddr = 0xffff; 
    new_ptr->p_paddr = 0xffff; 
    new_ptr->p_filesz = 0x1111; 
    new_ptr->p_memsz = 0; 
    new_ptr->p_flags = PF_R; 
    new_ptr->p_align = 0x4; 
    write(fd_dst, new_ptr, phdr_size); 
    write(fd_dst, ptr + old_phdr_border, filesize - old_phdr_border); 

    free(new_ptr); 

    return 0; 
} 

/* 
* this version of write_phdr will apend phdr to 
* the tail of file, so it wont move any sections 
* or offset, we just need change the entry address. 
*/ 
static int write_phdr2(int fd_dst, void *ptr, size_t filesize) 
{ 
    /* ptr for Ehdr */ 
    Elf32_Ehdr *Elf32_ptr = NULL; 
    Elf32_ptr = (Elf32_Ehdr *)ptr; 

    /* ptr for Phdr */ 
// Elf32_Phdr *elf32_phdr = NULL; 

    Elf32_Phdr *new_ptr = malloc(sizeof(Elf32_Phdr)); 
    if (new_ptr == NULL) 
     return -1; 

    off_t phdr_size = Elf32_ptr->e_phentsize; 

    /* recalculate the entry */ 
// Elf32_ptr->e_entry += phdr_size; 

    write(fd_dst, ptr, filesize); 

    /* append the phdr to the tail of file */ 
    memset(new_ptr, 0, sizeof(Elf32_Phdr)); 
    new_ptr->p_type = PT_NULL; 
    new_ptr->p_offset = 0xffff; 
    new_ptr->p_vaddr = 0xffff; 
    new_ptr->p_paddr = 0xffff; 
    new_ptr->p_filesz = 0; 
    new_ptr->p_memsz = 0; 
    new_ptr->p_flags = PF_R; 
    new_ptr->p_align = 0x4; 
    write(fd_dst, new_ptr, phdr_size); 

    free(new_ptr); 

    return 0; 
} 

/* 
* we'll add a new phdr to the binary file 
*/ 
int main(int argc, char *argv[]) 
{ 
    int fd_src, fd_dst; 
    //size_t len = 0; 
    size_t filesize = 0; 
    void *ptr = NULL; /* ptr to binary file which mapped in memory */ 
    if (argc != 3) { 
     printf("Usage: %s [ src bin ] [ dst bin ]...\n", argv[0]); 
     exit(EXIT_FAILURE); 
    } 

    /* 
    * we'll calculate the file size then map to memory 
    */ 
    fd_src = open(argv[1], O_RDONLY); 

    if (fd_src < 0) { 
     printf("Failed to open %s!\n", argv[1]); 
     exit(EXIT_FAILURE); 
    } 

    fd_dst = open(argv[2], O_CREAT | O_WRONLY | O_TRUNC, 0755); 

    if (fd_dst < 0) { 
     printf("Failed to open %s!\n", argv[2]); 
     exit(EXIT_FAILURE); 
    } 

    /* get file size with lseek SEEK_END */ 
    filesize = lseek(fd_src, 0, SEEK_END); 
    if (filesize < 0) { 
     perror("lseek failed!"); 
     close(fd_src); 
     exit(EXIT_FAILURE); 
    } 

    ptr = mmap(0, filesize, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd_src, 0); 
    if (ptr < 0) { 
     perror("mmap failed!"); 
     close(fd_src); 
     exit(EXIT_FAILURE); 
    } 

    if (1) 
    write_phdr(fd_dst, ptr, filesize); 

    if (0) 
    write_phdr2(fd_dst, ptr, filesize); 

    /* copy the modified file to dst */ 
    /* do the clean work */ 
    munmap(ptr, filesize); 
    close(fd_src); 
    close(fd_dst); 

    return EXIT_SUCCESS; 
} 
+0

Ну, просто чтобы убедиться. Может быть, 'test' является неудачным именем для вашего целевого исполняемого файла, так как он совпадает со стандартной командой Linux. Вы используете его с './Test'? Не могли бы вы назвать его по-другому? Я думаю, что он работает нормально на моем ПК. – nickie

+0

Извините, ./test просто произвольное имя, ничего особенного, я просто назову его результатом вывода, спасибо! – liunx

+0

Если вы также получите ту же проблему, используя другое имя, вместо 'test', то, пожалуйста, помогите нам, сообщив, что вы ожидаете, и что на самом деле происходит. На моем ПК как 'read_elf', так и' test' вывод '' ELF'' и выходят нормально. – nickie

ответ

2

Итак, какие-нибудь советы?

формат ELF имеет множество указателей внутри него, и если вы перемещать данные (как ваша программа делает), вы должны настроить все эти указатели, чтобы указать на новое место/смещение (что ваша программа не делать).

ELF действительно не предназначен для обработки пост-ссылок, которую вы пытаетесь выполнить.

Ваш немедленным проблема заключается в том, что hello содержит DT_HASH или DT_GNU_HASH (или оба), что по-прежнему указывают на старое смещение .hash или .gnu.hash разделе, но вы переместили биты вокруг, и поэтому старое смещение нет более длинный содержит допустимую хеш-таблицу, которую ожидает загрузчик среды выполнения.

Запуск

for exe in hello hello_test; do 
    readelf -d $exe | grep HASH 
    readelf -WS $exe | grep hash 
done 

должны доказать, что это действительно так.

EDIT:

case 0x6ffffef5: 
      dyn_entry->d_un.d_ptr += bound_size; 
      break; 

Никогда не делать: это делает ваш код невозможно читать и понимать. Сделайте это вместо того, чтобы:

#include <elf.h> 
... 
    case DT_GNU_HASH: 
      dyn_entry->d_un.d_ptr += bound_size; 
      break; 

Поскольку у вас есть 12 таких случаев, я отказываюсь сопоставить их обратно в их символические имена.

В любом случае, мой ответ стоит: вы не обновляете код где-то, что делает ваш итоговый ELF самосогласованным, что делает динамический загрузчик недовольным.

Если вы действительно хотите, чтобы упорствовать в этом направлении, установить Glibc символы отладки и отладки загрузчика так:

gdb /path/to/ld-linux.so ./hello_test 

Это позволит вам определить , которые указатель вы не удалось обновить.

+0

Большое спасибо, я попробую! – liunx

+0

Вы правы, я обновляю динамические таблицы, все в порядке, readelf больше не жалуется, но я все еще не могу запустить модифицированный двоичный файл. – liunx

+0

У меня есть обновленный код, чтобы ближе к истине (надеюсь, так). – liunx

0

ли вы посмотреть на новый исполняемый файл с помощью "readelf"?

Я сам проверил, является ли phdr (уже) в конце файла (phoff + phentsize * phnum == file_size). Если нет, я просто добавляю копию таблицы phdr в конец файла и модифицирую член phoff в заголовке эльфа.

Затем я могу добавить разделы phdr в конце файла (и мне не нужно перемещать разделы).

Оригинальная таблица phdr останется в файле, но будет неактивной.

+0

Хорошая идея, у меня будет попытка, но я хочу, чтобы ответ вставлял новый phdr, я хочу знать, почему он не работает? – liunx

Смежные вопросы