c - 将新部分插入二进制文件?

标签 c linux nasm elf

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

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

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作为比较: 猫 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;
}

最佳答案

So any tips?

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 self 不一致,这会让动态加载器不高兴。

如果你真的想坚持这个方向,安装glibc debug symbols,然后像这样调试loader:

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

这应该能让您识别哪个您更新失败的指针。

关于c - 将新部分插入二进制文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18505337/

相关文章:

c++ - 为什么我在 C 库中看到 THROW?

c - 尝试获取addq,但不断获取leaq

php - 公开访问服务器的 phpSysInfo - 安全吗?

c - 没有循环的 Fork-Exec 炸弹

python - 拆分由尾部连接的文件

assembly - NASM 是纯汇编,而 MASM 是高级汇编?

c++ - 长整数和 float

assembly - NASM 协处理器 - 舍入效果很差

assembly - nasm 语法中的 equ $ - 指令如何获取字符串的长度?

想不通C中pow()函数的计算