1

我尝试编写一个程序以将一个空的(作为第一步)phdr 结构插入任何 elf 二进制文件,所以我编码如下:

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

然后生成文件:

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 $@ $<

show_addr:show_addr.c
    $(CC) $(CFLAGS) -o $@ $<

without_libc:without_libc.c
    $(CC) $(CFLAGS) -nostdlib -o $@ $<

add_phdr:add_phdr.c
    $(CC) $(CFLAGS) -o $@ $<

hello:hello.c
    $(CC) $(CFLAGS) -o $@ $<

read_elf:read_elf.o
    $(LD) $(LDFLAGS) -o $@ $<

read_elf.o:read_elf.asm
    nasm -f elf32 -o $@ $<

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

好的,还有很多其他的代码包括asm代码,我只是列出了read_elf.asm和hello.c作为比较:cat 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

猫你好.c:

int main()
{
    return 10;
}

接下来,让我们编译代码,然后运行 ​​add_phdr 程序:

./add_phdr read_elf test

然后运行测试,它运行良好,但是当我尝试修补 hello 程序时,如下所示:

./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!

我不能再运行它了!
那么有什么窍门吗?

更新:

#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;
}
4

2 回答 2

2

那么有什么窍门吗?

ELF 格式内部有许多指针,如果您移动数据(就像您的程序那样),您必须调整所有这些指针以指向新的位置/偏移量(您的程序无法做到这一点)。

ELF 实际上不是为您尝试执行的那种链接后处理而设计的。

您的直接问题是hello包含一个DT_HASHDT_GNU_HASH(或两者),它仍然指向.hash.gnu.hash部分的旧偏移量,但是您已经移动了这些位,因此旧偏移量不再包含运行时加载程序期望的有效哈希表在那里找到。

跑步

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

应该证明确实如此。

编辑

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

这应该允许您识别您未能更新的指针。

于 2013-08-31T05:40:56.147 回答
0

您是否使用“readelf”查看了新的可执行文件?

我自己会检查 phdr 是否(已经)在文件的末尾(phoff + phentsize * phnum == file_size)。如果不是,我只需将 phdr 表的副本附加到文件末尾并修改 elf 标头中的 phoff 成员。

然后我可以在文件末尾附加 phdr 部分(我不必移动部分)。

原始 phdr 表将保留在文件中,但处于非活动状态。

于 2013-08-29T11:54:01.823 回答